/src/inchi/INCHI-1-SRC/INCHI_BASE/src/ichirvr3.c
Line | Count | Source |
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 | | #include "mode.h" |
45 | | #include "ichicant.h" |
46 | | #include "ichitime.h" |
47 | | #include "ichirvrs.h" |
48 | | |
49 | | #include "bcf_s.h" |
50 | | |
51 | | #if ( READ_INCHI_STRING == 1 ) |
52 | | |
53 | 0 | #define INC_ADD_EDGE 64 |
54 | | |
55 | | /* local types */ |
56 | | |
57 | | /* types for TgDiffHChgFH */ |
58 | 0 | #define fNumRPosChgH 0 /* number of positive charges on endpoints that have H in at2[] */ |
59 | 0 | #define fNumRPosChgU 1 /* number of positive charges on endpoints that have no H in at2[] */ |
60 | 0 | #define fNumRNegChgO 2 /* number of negative charges on O endpoints */ |
61 | 0 | #define fNumRNegChgN 3 /* number of negative charges on N endpoints */ |
62 | 0 | #define fNumRNeutrlH 4 /* number of neutral endp that have H in at2[] */ |
63 | | |
64 | 0 | #define fNumNPosChgH 5 /* number of positive charges on endpoints that have H in atf[] */ |
65 | 0 | #define fNumNPosChgU 6 /* number of positive charges on endpoints that have no H in atf[] */ |
66 | 0 | #define fNumNNegChgO 7 /* number of negative charges on O endpoints */ |
67 | 0 | #define fNumNNegChgN 8 /* number of negative charges on N endpoints */ |
68 | 0 | #define fNumNNeutrlH 9 /* number of neutral endp that have H in atf[] */ |
69 | | |
70 | 0 | #define fNumAllChgT 10 /* total number of fNum... */ |
71 | | |
72 | | typedef struct tagTgDiffHChgFH { |
73 | | short itg; /* t-group index; endpoint = itg+1 */ |
74 | | short nNumHInchi; /* number of H in t-group from orig. InChI */ |
75 | | short nNumHRevrs; /* number of H in at2[] */ |
76 | | short nNumHNorml; /* number of H in Normalized atfMobile_H_Revrs[] */ |
77 | | short nNumMInchi; /* number of (-) in InChI */ |
78 | | short nNumMRevrs; /* number of (-) in at2[] */ |
79 | | short nNumMNorml; /* number of (-) in atf[] */ |
80 | | short nNumPRevrs; /* number of (+) in at2[] */ |
81 | | short nNumPNorml; /* number of (+) in Normalized atfMobile_H_Revrs[] */ |
82 | | short n[fNumAllChgT]; /* all numbers */ |
83 | | short i[fNumAllChgT]; /* all indices */ |
84 | | } TgDiffHChgFH; |
85 | | |
86 | | /* local prototypes */ |
87 | | static int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], int max_tdhc, inp_ATOM at2[], inp_ATOM atf[], |
88 | | AT_NUMB *nCanon2AtnoRevrs, VAL_AT *pVA, T_GROUP_INFO *ti, EDGE_LIST *pAtomIndList ); |
89 | | |
90 | | |
91 | | /****************************************************************************/ |
92 | | int bHas_N_V( inp_ATOM *at2, int num_atoms ) |
93 | 0 | { |
94 | 0 | int i, num_found = 0; |
95 | 0 | for (i = 0; i < num_atoms; i++) |
96 | 0 | { |
97 | 0 | if (at2[i].el_number == EL_NUMBER_N && |
98 | 0 | !at2[i].charge && |
99 | 0 | !at2[i].num_H && |
100 | 0 | !at2[i].radical && |
101 | 0 | at2[i].chem_bonds_valence == 5 && |
102 | 0 | ( at2[i].valence == 3 )) |
103 | 0 | { |
104 | 0 | num_found++; |
105 | 0 | } |
106 | 0 | } |
107 | |
|
108 | 0 | return num_found; |
109 | 0 | } |
110 | | |
111 | | |
112 | | /****************************************************************************/ |
113 | | int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], |
114 | | int max_tdhc, |
115 | | inp_ATOM at2[], |
116 | | inp_ATOM atf[], |
117 | | AT_NUMB *nCanon2AtnoRevrs, |
118 | | VAL_AT *pVA, |
119 | | T_GROUP_INFO *ti, |
120 | | EDGE_LIST *pAtomIndList ) |
121 | 0 | { |
122 | |
|
123 | 0 | int i, j, iat, itg, num, itg_out; /* djb-rwth: removing redundant variables */ |
124 | 0 | EDGE_LIST IndList; /* type, itg */ |
125 | 0 | TgDiffHChgFH cur_tdhc; |
126 | 0 | AT_NUMB *pEndp0; |
127 | 0 | inp_ATOM *at2i, *atfi; |
128 | 0 | int typeR, typeN, type, ret = 0, nCurIndListLen; |
129 | |
|
130 | 0 | AllocEdgeList( &IndList, EDGE_LIST_CLEAR ); |
131 | 0 | pAtomIndList->num_edges = 0; |
132 | 0 | itg_out = 0; |
133 | | /* djb-rwth: removing redundant code */ |
134 | 0 | memset( tdhc, 0, max_tdhc ); /* djb-rwth: memset_s C11/Annex K variant? */ |
135 | |
|
136 | 0 | for (itg = 0; itg < ti->num_t_groups; itg++) |
137 | 0 | { |
138 | 0 | memset( &cur_tdhc, 0, sizeof( cur_tdhc ) ); /* djb-rwth: memset_s C11/Annex K variant? */ |
139 | |
|
140 | 0 | cur_tdhc.itg = itg; |
141 | 0 | cur_tdhc.nNumHInchi = ti->t_group[itg].num[0] - ti->t_group[itg].num[1]; |
142 | 0 | cur_tdhc.nNumMInchi = ti->t_group[itg].num[1]; |
143 | |
|
144 | 0 | pEndp0 = ti->nEndpointAtomNumber + ti->t_group[itg].nFirstEndpointAtNoPos; |
145 | 0 | nCurIndListLen = IndList.num_edges; |
146 | 0 | for (j = 0; j < ti->t_group[itg].nNumEndpoints; j++) |
147 | 0 | { |
148 | 0 | i = pEndp0[j]; |
149 | 0 | iat = nCanon2AtnoRevrs[i]; |
150 | |
|
151 | 0 | at2i = at2 + iat; |
152 | 0 | atfi = atf + iat; |
153 | |
|
154 | 0 | typeR = typeN = -1; |
155 | 0 | if (at2i->charge == 1) |
156 | 0 | { |
157 | 0 | if (at2i->num_H) |
158 | 0 | { |
159 | 0 | typeR = fNumRPosChgH; |
160 | 0 | } |
161 | 0 | else |
162 | 0 | { |
163 | 0 | typeR = fNumRPosChgU; |
164 | 0 | } |
165 | 0 | cur_tdhc.nNumPRevrs++; |
166 | 0 | } |
167 | 0 | else |
168 | 0 | { |
169 | 0 | if (at2i->charge == -1) |
170 | 0 | { |
171 | 0 | if (pVA[iat].cNumValenceElectrons == 6) |
172 | 0 | { |
173 | 0 | typeR = fNumRNegChgO; |
174 | 0 | } |
175 | 0 | else |
176 | 0 | { |
177 | 0 | if (pVA[iat].cNumValenceElectrons == 5) |
178 | 0 | { |
179 | 0 | typeR = fNumRNegChgN; |
180 | 0 | } |
181 | 0 | } |
182 | 0 | cur_tdhc.nNumMRevrs++; |
183 | 0 | } |
184 | 0 | else |
185 | 0 | { |
186 | 0 | if (at2i->num_H && at2i->valence == at2i->chem_bonds_valence) |
187 | 0 | { |
188 | 0 | typeR = fNumRNeutrlH; |
189 | 0 | } |
190 | 0 | } |
191 | 0 | } |
192 | 0 | cur_tdhc.nNumHRevrs += at2i->num_H; |
193 | |
|
194 | 0 | if (atfi->charge == 1) |
195 | 0 | { |
196 | 0 | if (atfi->num_H) |
197 | 0 | { |
198 | 0 | typeN = fNumNPosChgH; |
199 | 0 | } |
200 | 0 | else |
201 | 0 | { |
202 | 0 | typeN = fNumNPosChgU; |
203 | 0 | } |
204 | 0 | cur_tdhc.nNumPNorml++; |
205 | 0 | } |
206 | 0 | else |
207 | 0 | { |
208 | 0 | if (atfi->charge == -1) |
209 | 0 | { |
210 | 0 | if (pVA[iat].cNumValenceElectrons == 6) |
211 | 0 | { |
212 | 0 | typeN = fNumNNegChgO; |
213 | 0 | } |
214 | 0 | else |
215 | 0 | if (pVA[iat].cNumValenceElectrons == 5) |
216 | 0 | { |
217 | 0 | typeN = fNumNNegChgN; |
218 | 0 | } |
219 | 0 | cur_tdhc.nNumMNorml++; |
220 | 0 | } |
221 | 0 | else |
222 | 0 | { |
223 | 0 | if (atfi->num_H && atfi->valence == atfi->chem_bonds_valence) |
224 | 0 | { |
225 | 0 | typeN = fNumNNeutrlH; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | } |
229 | 0 | cur_tdhc.nNumHNorml += atfi->num_H; |
230 | 0 | if (at2[iat].charge < 0 || 0 < pVA[iat].nCPlusGroupEdge) |
231 | 0 | { |
232 | 0 | if (typeR >= 0 && ( |
233 | 0 | ( ret = AddToEdgeList( &IndList, typeR, INC_ADD_EDGE ) ) || |
234 | 0 | ( ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE ) ) || |
235 | 0 | ( ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE ) ) )) |
236 | 0 | { |
237 | 0 | goto exit_function; |
238 | 0 | } |
239 | 0 | if (typeN >= 0 && ( |
240 | 0 | ( ret = AddToEdgeList( &IndList, typeN, INC_ADD_EDGE ) ) || |
241 | 0 | ( ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE ) ) || |
242 | 0 | ( ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE ) ) )) |
243 | 0 | { |
244 | 0 | goto exit_function; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | 0 | if (cur_tdhc.nNumHNorml == cur_tdhc.nNumHInchi && |
249 | 0 | cur_tdhc.nNumMNorml == cur_tdhc.nNumMInchi) |
250 | 0 | { |
251 | 0 | IndList.num_edges = nCurIndListLen; /* t-group seems to be correct */ |
252 | 0 | continue; |
253 | 0 | } |
254 | 0 | if (itg_out < max_tdhc) |
255 | 0 | { |
256 | 0 | tdhc[itg_out++] = cur_tdhc; |
257 | 0 | } |
258 | 0 | else |
259 | 0 | { |
260 | | /* djb-rwth: removing redundant code */ |
261 | 0 | IndList.num_edges = nCurIndListLen; |
262 | 0 | break; |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | /* fill out atom index list */ |
267 | 0 | if (itg_out) |
268 | 0 | { |
269 | 0 | itg_out--; /* djb-rwth: fixing undefined index value / buffer overflow */ |
270 | | /* djb-rwth: removing redundant code */ |
271 | 0 | for (type = 0; type < fNumAllChgT; type++) |
272 | 0 | { |
273 | 0 | j = 0; |
274 | 0 | for (i = 0; i < itg_out; i++) |
275 | 0 | { |
276 | 0 | num = 0; |
277 | 0 | itg = tdhc[i].itg; |
278 | 0 | tdhc[i].i[type] = -999; /* empty */ |
279 | 0 | while (IndList.pnEdges[j + 1] == itg) |
280 | 0 | { |
281 | 0 | if (IndList.pnEdges[j] == type) |
282 | 0 | { |
283 | 0 | if (!num++) |
284 | 0 | { |
285 | 0 | tdhc[i].i[type] = pAtomIndList->num_edges; |
286 | 0 | } |
287 | 0 | if ((ret = AddToEdgeList( pAtomIndList, IndList.pnEdges[j + 2], INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
288 | 0 | { |
289 | 0 | goto exit_function; |
290 | 0 | } |
291 | 0 | } |
292 | 0 | j += 3; |
293 | 0 | } |
294 | 0 | tdhc[i].n[type] = num; |
295 | 0 | } |
296 | 0 | } |
297 | 0 | } |
298 | 0 | ret = itg_out; |
299 | |
|
300 | 0 | exit_function: |
301 | |
|
302 | 0 | AllocEdgeList( &IndList, EDGE_LIST_FREE ); |
303 | |
|
304 | 0 | return ret; |
305 | | /* |
306 | | #undef fNumRPosChgH |
307 | | #undef fNumRPosChgU |
308 | | #undef fNumRNegChgO |
309 | | #undef fNumRNegChgN |
310 | | |
311 | | #undef fNumNPosChgH |
312 | | #undef fNumNPosChgU |
313 | | #undef fNumNNegChgO |
314 | | #undef fNumNNegChgN |
315 | | |
316 | | #undef fNumAllChgT |
317 | | */ |
318 | 0 | } |
319 | | |
320 | | |
321 | | /****************************************************************************/ |
322 | | /* djb-rwth: placed as global variables to avoid function buffer issues */ |
323 | | short iat_DB_O[MAX_DIFF_FIXH], iat_SB_O_Minus[MAX_DIFF_FIXH]; |
324 | | short iat_DB_O_Plus[MAX_DIFF_FIXH], iat_SB_NH[MAX_DIFF_FIXH]; |
325 | | short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_N[MAX_DIFF_FIXH]; |
326 | | short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH]; |
327 | | short iat_DB_NHn_Plus[MAX_DIFF_FIXH], iat_SB_NHm_Neutr[MAX_DIFF_FIXH]; |
328 | | short iat_DB_O_Neutr[MAX_DIFF_FIXH], iat_DB_N_Neutr[MAX_DIFF_FIXH]; |
329 | | short iat_SB_N_Neutr[MAX_DIFF_FIXH], iat_N_V_Array[MAX_DIFF_FIXH]; |
330 | | short iat_Central[MAX_DIFF_FIXH], iat_NO2[MAX_DIFF_FIXH]; |
331 | | TgDiffHChgFH tdhc[MAX_DIFF_FIXH]; |
332 | | |
333 | | int FixFixedHRestoredStructure( CANON_GLOBALS *pCG, |
334 | | INCHI_CLOCK *ic, |
335 | | ICHICONST INPUT_PARMS *ip, |
336 | | STRUCT_DATA *sd, |
337 | | BN_STRUCT *pBNS, |
338 | | BN_DATA *pBD, |
339 | | StrFromINChI *pStruct, |
340 | | inp_ATOM *at, |
341 | | inp_ATOM *at2, |
342 | | inp_ATOM *at3, |
343 | | VAL_AT *pVA, |
344 | | ALL_TC_GROUPS *pTCGroups, |
345 | | T_GROUP_INFO **ppt_group_info, |
346 | | inp_ATOM **ppat_norm, |
347 | | inp_ATOM **ppat_prep, |
348 | | INChI *pInChI[], |
349 | | long num_inp, |
350 | | int bHasSomeFixedH, |
351 | | int *pnNumRunBNS, |
352 | | int *pnTotalDelta, |
353 | | int forbidden_edge_mask, |
354 | | int forbidden_stereo_edge_mask ) |
355 | 0 | { |
356 | | /*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/ |
357 | | /* at2 should be the most recently restored atom, Fixed-H */ |
358 | 0 | int i, j, k, delta, num_try, tot_succes, cur_success, ret = 0, bAllowedNFlowerEdges = 0, num_zero_ret; |
359 | 0 | CMP2FHINCHI c2i; |
360 | 0 | CMP2FHINCHI *pc2i = &c2i; |
361 | |
|
362 | 0 | EDGE_LIST AllChargeEdges, CurrEdges, SFlowerEdges, NFlowerEdges, OtherNFlowerEdges, FixedLargeRingStereoEdges; |
363 | 0 | EDGE_LIST AllBondEdges; |
364 | |
|
365 | 0 | EdgeIndex e; |
366 | 0 | BNS_EDGE *pe; |
367 | 0 | Vertex v1, v2; |
368 | 0 | BNS_VERTEX *pv1, *pv2; |
369 | |
|
370 | 0 | Vertex vPathStart, vPathEnd; |
371 | 0 | int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms; |
372 | |
|
373 | 0 | int nNumRunBNS = 0, forbidden_edge_mask_inv = ~forbidden_edge_mask; /* djb-rwth: ignoring LLVM warning: variable used */ |
374 | | |
375 | | INCHI_HEAPCHK |
376 | |
|
377 | 0 | AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR ); |
378 | 0 | AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR ); |
379 | 0 | AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR ); |
380 | 0 | AllocEdgeList( &SFlowerEdges, EDGE_LIST_CLEAR ); |
381 | 0 | AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR ); |
382 | 0 | AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_CLEAR ); |
383 | 0 | AllocEdgeList( &AllBondEdges, EDGE_LIST_CLEAR ); |
384 | |
|
385 | 0 | tot_succes = 0; |
386 | |
|
387 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
388 | 0 | { |
389 | 0 | goto exit_function; /* no fixed-H found */ |
390 | 0 | } |
391 | | |
392 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
393 | 0 | { |
394 | 0 | if (( e = pVA[i].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden && |
395 | 0 | ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) )) |
396 | 0 | { |
397 | 0 | goto exit_function; |
398 | 0 | } |
399 | 0 | if (( e = pVA[i].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden) |
400 | 0 | { |
401 | 0 | if ((ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
402 | 0 | { |
403 | 0 | goto exit_function; |
404 | 0 | } |
405 | | |
406 | | /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */ |
407 | 0 | if (pVA[i].cNumValenceElectrons == 5 && !pVA[i].cMetal && /* N, P, As */ |
408 | 0 | NO_VERTEX != ( j = GetChargeFlowerUpperEdge( pBNS, pVA, e ) )) |
409 | 0 | { |
410 | |
|
411 | 0 | if (pBNS->edge[j].forbidden) |
412 | 0 | { |
413 | 0 | continue; |
414 | 0 | } |
415 | | |
416 | 0 | if (pBNS->edge[j].flow) |
417 | 0 | { |
418 | 0 | if ((ret = AddToEdgeList( &AllChargeEdges, j, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
419 | 0 | { |
420 | 0 | goto exit_function; |
421 | 0 | } |
422 | 0 | if ((ret = AddToEdgeList( &NFlowerEdges, j, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
423 | 0 | { |
424 | 0 | goto exit_function; |
425 | 0 | } |
426 | 0 | } |
427 | 0 | else |
428 | 0 | { |
429 | 0 | if ((ret = AddToEdgeList( &OtherNFlowerEdges, j, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
430 | 0 | { |
431 | 0 | goto exit_function; |
432 | 0 | } |
433 | 0 | } |
434 | 0 | } |
435 | 0 | else |
436 | 0 | { |
437 | | /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */ |
438 | 0 | if (pVA[i].cNumValenceElectrons == 6 && !pVA[i].cMetal && /* N, P, As */ |
439 | 0 | NO_VERTEX != ( j = GetChargeFlowerUpperEdge( pBNS, pVA, e ) )) |
440 | 0 | { |
441 | |
|
442 | 0 | if (pBNS->edge[j].forbidden) |
443 | 0 | { |
444 | 0 | continue; |
445 | 0 | } |
446 | | |
447 | 0 | if (pBNS->edge[j].flow) |
448 | 0 | { |
449 | 0 | if ((ret = AddToEdgeList( &SFlowerEdges, j, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
450 | 0 | { |
451 | 0 | goto exit_function; |
452 | 0 | } |
453 | 0 | } |
454 | 0 | } |
455 | 0 | } |
456 | 0 | } |
457 | 0 | for (j = 0; j < at2[i].valence; j++) |
458 | 0 | { |
459 | 0 | k = at2[i].neighbor[j]; |
460 | 0 | if (k < i && !pBNS->edge[e = pBNS->vert[i].iedge[j]].forbidden) |
461 | 0 | { |
462 | 0 | if ((ret = AddToEdgeList( &AllBondEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
463 | 0 | { |
464 | 0 | goto exit_function; |
465 | 0 | } |
466 | 0 | } |
467 | 0 | } |
468 | 0 | } |
469 | 0 | if (forbidden_stereo_edge_mask) |
470 | 0 | { |
471 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
472 | 0 | { |
473 | 0 | for (j = 0; j < at2[i].valence; j++) |
474 | 0 | { |
475 | 0 | if (pBNS->edge[k = pBNS->vert[i].iedge[j]].forbidden == forbidden_stereo_edge_mask) |
476 | 0 | { |
477 | 0 | int nMinRingSize = is_bond_in_Nmax_memb_ring( at2, i, j, pStruct->pbfsq->q, |
478 | 0 | pStruct->pbfsq->nAtomLevel, |
479 | 0 | pStruct->pbfsq->cSource, 99 /* max ring size */ ); |
480 | 0 | if (0 < nMinRingSize && ( ret = AddToEdgeList( &FixedLargeRingStereoEdges, k, INC_ADD_EDGE ) )) |
481 | 0 | { |
482 | 0 | goto exit_function; |
483 | 0 | } |
484 | 0 | } |
485 | 0 | } |
486 | 0 | } |
487 | 0 | } |
488 | | |
489 | 0 | INCHI_HEAPCHK |
490 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
491 | 0 | { |
492 | 0 | goto exit_function; |
493 | 0 | } |
494 | 0 | INCHI_HEAPCHK |
495 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
496 | 0 | { |
497 | 0 | goto exit_function; |
498 | 0 | } |
499 | | |
500 | | INCHI_HEAPCHK |
501 | | |
502 | 0 | if (!pc2i->bHasDifference || |
503 | 0 | (!pc2i->len_c2at && pc2i->nNumTgRevrs == pc2i->nNumTgInChI && |
504 | 0 | pc2i->nNumEndpRevrs == pc2i->nNumRemHInChI && |
505 | 0 | pc2i->nNumEndpRevrs == pc2i->nNumEndpInChI && |
506 | 0 | !pc2i->nNumTgDiffMinus && !pc2i->nNumTgDiffH)) /* djb-rwth: addressing LLVM warning */ |
507 | 0 | { |
508 | 0 | goto exit_function; /* nothing to do */ |
509 | 0 | } |
510 | | |
511 | | /*goto exit_function;*/ /* debug only*/ |
512 | | |
513 | 0 | if (pc2i->len_c2at >= 2) |
514 | 0 | { |
515 | | /*----------------------------------------------------*/ |
516 | | /* case 01: restored: O=AB-O(-) original: (-)O-AB=O */ |
517 | | /* FixH: 0 -1 -1 0 */ |
518 | | /* MobH: 0 1 1 0 */ |
519 | | /* non-taut non-taut */ |
520 | | /* O = O, S, Se; charged atoms O are not tautomeric */ |
521 | | /* Solution: move (-) from B-O(-) to O=A */ |
522 | | /*----------------------------------------------------*/ |
523 | 0 | int num_DB_O = 0, num_SB_O_Minus = 0, iat; |
524 | 0 | cur_success = 0; |
525 | |
|
526 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
527 | 0 | { |
528 | 0 | iat = pc2i->c2at[i].atomNumber; |
529 | 0 | if (pc2i->c2at[i].nValElectr == 6 /* && !pc2i->c2at[i].endptInChI -- mod#1*/ && |
530 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
531 | 0 | { |
532 | 0 | if ( /* orig. InChI info: */ |
533 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
534 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
535 | | /* reversed structure info: */ |
536 | 0 | pc2i->c2at[i].nFixHRevrs == -1 && pc2i->c2at[i].nMobHRevrs == 1 && |
537 | 0 | pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H && /* at2 is Fixed-H */ |
538 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1) |
539 | 0 | { |
540 | 0 | iat_SB_O_Minus[num_SB_O_Minus++] = iat; |
541 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
542 | 0 | { |
543 | 0 | goto exit_function; |
544 | 0 | } |
545 | 0 | } |
546 | 0 | else |
547 | 0 | { |
548 | 0 | if ( /* orig. InChI info: */ |
549 | 0 | num_DB_O < MAX_DIFF_FIXH && |
550 | 0 | pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 && |
551 | | /* reversed structure info: */ |
552 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
553 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
554 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) |
555 | 0 | { |
556 | 0 | iat_DB_O[num_DB_O++] = iat; |
557 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
558 | 0 | { |
559 | 0 | goto exit_function; |
560 | 0 | } |
561 | 0 | } |
562 | 0 | } |
563 | 0 | } |
564 | 0 | } |
565 | 0 | if ((num_try = inchi_min(num_SB_O_Minus, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
566 | 0 | { |
567 | | /* detected; attempt to fix */ |
568 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
569 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
570 | 0 | delta = 1; |
571 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
572 | 0 | { |
573 | 0 | iat = iat_SB_O_Minus[i]; |
574 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
575 | 0 | if (!pe->flow) |
576 | 0 | continue; |
577 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
578 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
579 | |
|
580 | 0 | pe->forbidden |= forbidden_edge_mask; |
581 | 0 | pe->flow -= delta; /* remove (-) from AB-O(-) */ |
582 | 0 | pv1->st_edge.flow -= delta; |
583 | 0 | pv2->st_edge.flow -= delta; |
584 | 0 | pBNS->tot_st_flow -= 2 * delta; |
585 | |
|
586 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
587 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
588 | |
|
589 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
590 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
591 | 0 | { |
592 | | /* Added (-)charge to O=AB => nDeltaCharge == -1 */ |
593 | | /* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */ |
594 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
595 | 0 | if (ret > 0) |
596 | 0 | { |
597 | 0 | nNumRunBNS++; |
598 | 0 | cur_success++; /* 01 */ |
599 | 0 | } |
600 | 0 | } |
601 | 0 | else |
602 | 0 | { |
603 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
604 | 0 | pe->flow += delta; |
605 | 0 | pv1->st_edge.flow += delta; |
606 | 0 | pv2->st_edge.flow += delta; |
607 | 0 | pBNS->tot_st_flow += 2 * delta; |
608 | 0 | } |
609 | 0 | INCHI_HEAPCHK |
610 | 0 | } |
611 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
612 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
613 | 0 | } |
614 | 0 | if (cur_success) |
615 | 0 | { |
616 | 0 | tot_succes += cur_success; |
617 | | /* recalculate InChI from the structure */ |
618 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, |
619 | 0 | ip, sd, pBNS, pStruct, |
620 | 0 | at, at2, at3, pVA, |
621 | 0 | pTCGroups, |
622 | 0 | ppt_group_info, ppat_norm, |
623 | 0 | ppat_prep))) |
624 | 0 | { |
625 | 0 | goto exit_function; |
626 | 0 | } |
627 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
628 | 0 | { |
629 | 0 | goto exit_function; |
630 | 0 | } |
631 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
632 | 0 | { |
633 | 0 | goto exit_function; /* no fixed-H found */ |
634 | 0 | } |
635 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
636 | 0 | { |
637 | 0 | goto exit_function; |
638 | 0 | } |
639 | 0 | if (!pc2i->bHasDifference) |
640 | 0 | { |
641 | 0 | goto exit_function; /* nothing to do */ |
642 | 0 | } |
643 | 0 | } |
644 | 0 | } |
645 | | |
646 | 0 | if (pc2i->len_c2at >= 1) |
647 | 0 | { |
648 | | /*--------------------------------------------------------------*/ |
649 | | /* case 02: restored: -O(+)=AB-NH2 original: -O-AB=NH2(+) */ |
650 | | /* FixH: 0 0 0 1 */ |
651 | | /* MobH: 0 2 0 1 */ |
652 | | /* O = P, As, Sb, O, S, Se, F, Cl, Br, I; not taut. in InChI */ |
653 | | /* N = N, O, S, Se, Te; has H; tautomeric or not tautomeric */ |
654 | | /* Solution: move (+) from O(+) to NH2 */ |
655 | | /*--------------------------------------------------------------*/ |
656 | 0 | int num_DB_O_Plus = 0, num_SB_NH = 0, iat; |
657 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
658 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
659 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : NULL; |
660 | 0 | cur_success = 0; |
661 | 0 | num_zero_ret = 0; |
662 | |
|
663 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
664 | 0 | { |
665 | 0 | iat = pc2i->c2at[i].atomNumber; |
666 | 0 | if ( /* orig. InChI info: =NH2(+), =OH(+) */ |
667 | 0 | num_SB_NH < MAX_DIFF_FIXH && |
668 | 0 | ((pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) || |
669 | 0 | pc2i->c2at[i].nValElectr == 6) /* N, O, S, Se, Te */ && |
670 | | /*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */ |
671 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
672 | 0 | pc2i->c2at[i].nFixHInChI>0 /*== 1 --modification#2*/ && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
673 | | /* reversed structure info: */ |
674 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && /* pc2i->c2at[i].nMobHRevrs == 0 &&*/ |
675 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && |
676 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence) /* djb-rwth: addressing LLVM warning */ |
677 | 0 | { |
678 | 0 | iat_SB_NH[num_SB_NH++] = iat; |
679 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
680 | 0 | { |
681 | 0 | goto exit_function; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | } |
685 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
686 | 0 | { |
687 | | /* i = canonical number - 1 */ |
688 | 0 | iat = nCanon2AtnoRevrs[i]; |
689 | 0 | if ( /* in restored atom: charge=+1, no H, has double bond, P, As, O, S, Se, Te, F, Cl, Br, I */ |
690 | 0 | num_DB_O_Plus < MAX_DIFF_FIXH && |
691 | 0 | at2[iat].charge == 1 && !at2[iat].num_H && |
692 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
693 | 0 | (pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 || |
694 | 0 | (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1)) && |
695 | | /* in orig.InChI: not an endpoint, has no H */ |
696 | 0 | !pStruct->endpoint[i] && |
697 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
698 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
699 | | /* has (+) edge */ |
700 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
701 | 0 | { |
702 | 0 | iat_DB_O_Plus[num_DB_O_Plus++] = iat; |
703 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
704 | 0 | { |
705 | 0 | goto exit_function; |
706 | 0 | } |
707 | 0 | } |
708 | 0 | } |
709 | 0 | if ((num_try = inchi_min(num_DB_O_Plus, num_SB_NH))) /* djb-rwth: addressing LLVM warning */ |
710 | 0 | { |
711 | | /* detected; attempt to fix */ |
712 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
713 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
714 | 0 | delta = 1; |
715 | 0 | repeat_02_allow_NV: |
716 | 0 | for (i = 0; i < num_SB_NH && cur_success < num_try; i++) |
717 | 0 | { |
718 | 0 | iat = iat_SB_NH[i]; |
719 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
720 | 0 | if (!pe->flow) |
721 | 0 | continue; |
722 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
723 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
724 | |
|
725 | 0 | pe->forbidden |= forbidden_edge_mask; |
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 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
732 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
733 | |
|
734 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
735 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warning */ |
736 | 0 | { |
737 | | /* Removed charge from O(+) => nDeltaCharge == -1 */ |
738 | | /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */ |
739 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
740 | 0 | if (ret > 0) |
741 | 0 | { |
742 | 0 | nNumRunBNS++; |
743 | 0 | cur_success++; /* 02 */ |
744 | 0 | } |
745 | 0 | } |
746 | 0 | else |
747 | 0 | { |
748 | 0 | num_zero_ret += !ret; |
749 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
750 | 0 | pe->flow += delta; |
751 | 0 | pv1->st_edge.flow += delta; |
752 | 0 | pv2->st_edge.flow += delta; |
753 | 0 | pBNS->tot_st_flow += 2 * delta; |
754 | 0 | } |
755 | 0 | INCHI_HEAPCHK |
756 | 0 | } |
757 | 0 | if (num_zero_ret == num_try && !bAllowedNFlowerEdges && NFlowerEdges.num_edges) |
758 | 0 | { |
759 | 0 | RemoveForbiddenEdgeMask(pBNS, &NFlowerEdges, forbidden_edge_mask); |
760 | 0 | bAllowedNFlowerEdges = 1; |
761 | 0 | goto repeat_02_allow_NV; |
762 | 0 | } |
763 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
764 | | /* djb-rwth: removing redundant code */ |
765 | 0 | } |
766 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
767 | 0 | if (cur_success) |
768 | 0 | { |
769 | 0 | tot_succes += cur_success; |
770 | | /* recalculate InChI from the structure */ |
771 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
772 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
773 | 0 | { |
774 | 0 | goto exit_function; |
775 | 0 | } |
776 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
777 | 0 | { |
778 | 0 | goto exit_function; |
779 | 0 | } |
780 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
781 | 0 | { |
782 | 0 | goto exit_function; /* no fixed-H found */ |
783 | 0 | } |
784 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
785 | 0 | { |
786 | 0 | goto exit_function; |
787 | 0 | } |
788 | 0 | if (!pc2i->bHasDifference) |
789 | 0 | { |
790 | 0 | goto exit_function; /* nothing to do */ |
791 | 0 | } |
792 | 0 | } |
793 | 0 | } |
794 | | |
795 | 0 | if (pc2i->len_c2at >= 1 && pc2i->nNumTgRevrs == 1 && |
796 | 0 | ( pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1 ) /* ADP in Revrs */) |
797 | 0 | { |
798 | | /*--------------------------------------------------------------*/ |
799 | | /* case 03: restored: -N(-)-AB=O original: -N=AB-O(-) */ |
800 | | /* FixH: 0 0 0 -1 */ |
801 | | /* MobH: 0 0 0 1 */ |
802 | | /* O = O, S, Se; N = N; */ |
803 | | /* restored atoms are tautomeric; original atoms are not taut. */ |
804 | | /* restored struct has 1 t-group; original has less endpoints */ |
805 | | /* and possibly >1 t-groups */ |
806 | | /* Solution: move (-) from N(-) to =O */ |
807 | | /* these atoms are tautomeric in restored structure */ |
808 | | /*--------------------------------------------------------------*/ |
809 | 0 | int num_SB_N_Minus = 0, num_DB_O = 0, iat; |
810 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
811 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
812 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
813 | | /* |
814 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
815 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
816 | | */ |
817 | 0 | cur_success = 0; |
818 | |
|
819 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
820 | 0 | { |
821 | 0 | iat = pc2i->c2at[i].atomNumber; |
822 | 0 | if ( /* orig. InChI info: -O(-) */ |
823 | 0 | num_DB_O < MAX_DIFF_FIXH && |
824 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
825 | 0 | !pc2i->c2at[i].endptInChI && |
826 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
827 | 0 | pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 && |
828 | | /* reversed structure info: */ |
829 | 0 | pc2i->c2at[i].endptRevrs && |
830 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
831 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
832 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) |
833 | 0 | { |
834 | 0 | iat_DB_O[num_DB_O++] = iat; |
835 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
836 | 0 | { |
837 | 0 | goto exit_function; |
838 | 0 | } |
839 | 0 | } |
840 | 0 | } |
841 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
842 | 0 | { |
843 | | /* i = canonical number - 1 */ |
844 | 0 | iat = nCanon2AtnoRevrs[i]; |
845 | 0 | if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */ |
846 | 0 | num_SB_N_Minus < MAX_DIFF_FIXH && |
847 | 0 | at2[iat].charge == -1 && /*!at2[iat].num_H &&*/ |
848 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
849 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
850 | 0 | at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && |
851 | | /* in orig.InChI: not an endpoint, has no H */ |
852 | | /* !pStruct->endpoint[i] && */ |
853 | | /* |
854 | | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
855 | | !(nMobHInChI && nMobHInChI[i] ) && |
856 | | */ |
857 | | /* has (-) edge */ |
858 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
859 | 0 | { |
860 | 0 | iat_SB_N_Minus[num_SB_N_Minus++] = iat; |
861 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
862 | 0 | { |
863 | 0 | goto exit_function; |
864 | 0 | } |
865 | 0 | } |
866 | 0 | } |
867 | 0 | if ((num_try = inchi_min(num_SB_N_Minus, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
868 | 0 | { |
869 | | /* detected; attempt to fix */ |
870 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
871 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
872 | 0 | delta = 1; |
873 | 0 | for (i = 0; i < num_SB_N_Minus && cur_success < num_try; i++) |
874 | 0 | { |
875 | 0 | iat = iat_SB_N_Minus[i]; |
876 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; /* 2006-03-03: changed from CPlusGroupEdge */ |
877 | 0 | if (!pe->flow) |
878 | 0 | continue; |
879 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
880 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
881 | |
|
882 | 0 | pe->forbidden |= forbidden_edge_mask; |
883 | 0 | pe->flow -= delta; |
884 | 0 | pv1->st_edge.flow -= delta; |
885 | 0 | pv2->st_edge.flow -= delta; |
886 | 0 | pBNS->tot_st_flow -= 2 * delta; |
887 | |
|
888 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
889 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
890 | |
|
891 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
892 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
893 | 0 | { |
894 | | /* Added (-) charge to =O => nDeltaCharge == 1 */ |
895 | | /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */ |
896 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
897 | 0 | if (ret > 0) |
898 | 0 | { |
899 | 0 | nNumRunBNS++; |
900 | 0 | cur_success++; /* 03 */ |
901 | 0 | } |
902 | 0 | } |
903 | 0 | else |
904 | 0 | { |
905 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
906 | 0 | pe->flow += delta; |
907 | 0 | pv1->st_edge.flow += delta; |
908 | 0 | pv2->st_edge.flow += delta; |
909 | 0 | pBNS->tot_st_flow += 2 * delta; |
910 | 0 | } |
911 | 0 | INCHI_HEAPCHK |
912 | 0 | } |
913 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
914 | 0 | } |
915 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
916 | 0 | if (cur_success) |
917 | 0 | { |
918 | 0 | tot_succes += cur_success; |
919 | | /* recalculate InChI from the structure */ |
920 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
921 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
922 | 0 | { |
923 | 0 | goto exit_function; |
924 | 0 | } |
925 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
926 | 0 | { |
927 | 0 | goto exit_function; |
928 | 0 | } |
929 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
930 | 0 | { |
931 | 0 | goto exit_function; /* no fixed-H found */ |
932 | 0 | } |
933 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
934 | 0 | { |
935 | 0 | goto exit_function; |
936 | 0 | } |
937 | 0 | if (!pc2i->bHasDifference) |
938 | 0 | { |
939 | 0 | goto exit_function; /* nothing to do */ |
940 | 0 | } |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | 0 | if (pc2i->nNumTgRevrs == 1 && /* pc2i->nNumRemHInChI < 0 &&*/ |
945 | 0 | ( pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1 ) /* ADP in Revrs */) |
946 | 0 | { |
947 | | /*--------------------------------------------------------------*/ |
948 | | /* case 03a:restored: -N(-)-AB=O original: -N=AB-O(-) */ |
949 | | /* FixH: 0 0 0 0 */ |
950 | | /* MobH: 0 0 0 0 */ |
951 | | /* O = O, S, Se; N = N; taut */ |
952 | | /* restored atoms are tautomeric; original atom is; N may be. */ |
953 | | /* restored struct has 1 t-group; original has less endpoints */ |
954 | | /* and possibly >1 t-groups */ |
955 | | /* Solution: move (-) from N(-) to =O */ |
956 | | /* these atoms are tautomeric in restored structure */ |
957 | | /*--------------------------------------------------------------*/ |
958 | 0 | int num_SB_N_Minus = 0, num_DB_O = 0, iat; |
959 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
960 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
961 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
962 | 0 | S_CHAR *pnMobHInChI = ( pInChI[1] && pInChI[1]->nNum_H ) ? pInChI[1]->nNum_H : |
963 | 0 | ( pInChI[0] && pInChI[0]->nNum_H ) ? pInChI[0]->nNum_H : NULL; |
964 | 0 | S_CHAR *pnFixHInChI = pStruct->fixed_H; |
965 | |
|
966 | 0 | cur_success = 0; |
967 | 0 | CurrEdges.num_edges = 0; |
968 | |
|
969 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
970 | 0 | { /* i = canonical number - 1 */ |
971 | 0 | iat = nCanon2AtnoRevrs[i]; |
972 | 0 | if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */ |
973 | 0 | num_SB_N_Minus < MAX_DIFF_FIXH && |
974 | 0 | at2[iat].charge == -1 && /*!at2[iat].num_H &&*/ |
975 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
976 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
977 | 0 | at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && |
978 | | /* in orig.InChI: may be an endpoint, has no H */ |
979 | | /* has (-) edge */ |
980 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
981 | 0 | { |
982 | 0 | iat_SB_N_Minus[num_SB_N_Minus++] = iat; |
983 | 0 | } |
984 | 0 | else |
985 | 0 | if (num_DB_O < MAX_DIFF_FIXH && |
986 | 0 | at2[iat].charge == 0 && /*!at2[iat].num_H &&*/ |
987 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
988 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
989 | 0 | at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && /* endpoint in Reconstructed */ |
990 | 0 | (pStruct->endpoint[i] || /* endpoint or H(+) acceptor in original */ |
991 | 0 | (pnMobHInChI && pnMobHInChI[i] == 1 && pnFixHInChI && pnFixHInChI[i] == -1)) && |
992 | | /* has (-) edge */ |
993 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
994 | 0 | { |
995 | 0 | iat_DB_O[num_DB_O++] = iat; |
996 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
997 | 0 | { |
998 | 0 | goto exit_function; |
999 | 0 | } |
1000 | 0 | } |
1001 | 0 | } |
1002 | 0 | if ((num_try = inchi_min(num_SB_N_Minus, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
1003 | 0 | { |
1004 | | /* detected; attempt to fix */ |
1005 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1006 | | /* allow charge transfer to all found =O */ |
1007 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
1008 | 0 | delta = 1; |
1009 | 0 | for (i = 0; i < num_SB_N_Minus && cur_success < num_try; i++) |
1010 | 0 | { |
1011 | 0 | iat = iat_SB_N_Minus[i]; |
1012 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
1013 | 0 | if (!pe->flow) |
1014 | 0 | continue; |
1015 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
1016 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
1017 | |
|
1018 | 0 | pe->forbidden |= forbidden_edge_mask; |
1019 | 0 | pe->flow -= delta; |
1020 | 0 | pv1->st_edge.flow -= delta; |
1021 | 0 | pv2->st_edge.flow -= delta; |
1022 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1023 | |
|
1024 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1025 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
1026 | |
|
1027 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
1028 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
1029 | 0 | { |
1030 | | /* Added (-) charge to =O => nDeltaCharge == 1 */ |
1031 | | /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */ |
1032 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
1033 | 0 | if (ret > 0) |
1034 | 0 | { |
1035 | 0 | nNumRunBNS++; |
1036 | 0 | cur_success++; /* 03a */ |
1037 | 0 | } |
1038 | 0 | } |
1039 | 0 | else |
1040 | 0 | { |
1041 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
1042 | 0 | pe->flow += delta; |
1043 | 0 | pv1->st_edge.flow += delta; |
1044 | 0 | pv2->st_edge.flow += delta; |
1045 | 0 | pBNS->tot_st_flow += 2 * delta; |
1046 | 0 | } |
1047 | 0 | INCHI_HEAPCHK |
1048 | 0 | } |
1049 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1050 | 0 | } |
1051 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1052 | 0 | if (cur_success) |
1053 | 0 | { |
1054 | 0 | tot_succes += cur_success; |
1055 | | /* recalculate InChI from the structure */ |
1056 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1057 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
1058 | 0 | { |
1059 | 0 | goto exit_function; |
1060 | 0 | } |
1061 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
1062 | 0 | { |
1063 | 0 | goto exit_function; |
1064 | 0 | } |
1065 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1066 | 0 | { |
1067 | 0 | goto exit_function; /* no fixed-H found */ |
1068 | 0 | } |
1069 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
1070 | 0 | { |
1071 | 0 | goto exit_function; |
1072 | 0 | } |
1073 | 0 | if (!pc2i->bHasDifference) |
1074 | 0 | { |
1075 | 0 | goto exit_function; /* nothing to do */ |
1076 | 0 | } |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | 0 | if (pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 && /* ADP in InChI */ |
1081 | 0 | ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 )) |
1082 | 0 | { |
1083 | | /*--------------------------------------------------------------*/ |
1084 | | /* case 04: restored: OH(+)=AB-O- OH- orig. HO-AB=O(+)- OH- */ |
1085 | | /* FixH: 1 0 0 1 0 1 */ |
1086 | | /* MobH: 0 0 1 0 0 0 */ |
1087 | | /* non-taut. taut taut */ |
1088 | | /* ADP: one t-group or more endpoints */ |
1089 | | /* O(+) = N, P, As, As, O, S, Se; OH = N, O, S, Se, Te */ |
1090 | | /* Solution: move (+) from O(+) to NH2 */ |
1091 | | /*--------------------------------------------------------------*/ |
1092 | 0 | int num_SB_Neutr = 0, num_DB_Charged = 0, iat; |
1093 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
1094 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
1095 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
1096 | 0 | cur_success = 0; |
1097 | |
|
1098 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
1099 | 0 | { /* i = canonical number - 1 */ |
1100 | 0 | iat = nCanon2AtnoRevrs[i]; |
1101 | 0 | if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */ |
1102 | 0 | num_DB_Charged < MAX_DIFF_FIXH && |
1103 | 0 | at2[iat].charge == 1 && at2[iat].num_H && |
1104 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
1105 | 0 | (pVA[iat].cNumValenceElectrons == 6 || |
1106 | 0 | (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1)) && |
1107 | | /* in orig.InChI: an endpoint, has fixed-H */ |
1108 | 0 | pStruct->endpoint[i] && |
1109 | 0 | (pStruct->fixed_H && pStruct->fixed_H[i]) && |
1110 | | /*!(nMobHInChI && nMobHInChI[i] ) &&*/ |
1111 | | /* has (+) edge */ |
1112 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
1113 | 0 | { |
1114 | |
|
1115 | 0 | iat_DB_Charged[num_DB_Charged++] = iat; |
1116 | |
|
1117 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1118 | 0 | { |
1119 | 0 | goto exit_function; |
1120 | 0 | } |
1121 | 0 | } |
1122 | 0 | else |
1123 | 0 | { |
1124 | 0 | if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */ |
1125 | 0 | num_SB_Neutr < MAX_DIFF_FIXH && |
1126 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
1127 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
1128 | 0 | (pVA[iat].cNumValenceElectrons == 6 || |
1129 | 0 | pVA[iat].cNumValenceElectrons == 5) && |
1130 | | /* in orig.InChI: an endpoint, has fixed-H */ |
1131 | | /* pStruct->endpoint[i] && */ |
1132 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
1133 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
1134 | | /* has (+) edge */ |
1135 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && |
1136 | 0 | 0 == pBNS->edge[e].forbidden) |
1137 | 0 | { |
1138 | |
|
1139 | 0 | iat_SB_Neutr[num_SB_Neutr++] = iat; |
1140 | |
|
1141 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1142 | 0 | { |
1143 | 0 | goto exit_function; |
1144 | 0 | } |
1145 | 0 | } |
1146 | 0 | } |
1147 | 0 | } |
1148 | 0 | if ((num_try = inchi_min(num_SB_Neutr, num_DB_Charged))) /* djb-rwth: addressing LLVM warning */ |
1149 | 0 | { |
1150 | | /* detected; attempt to fix */ |
1151 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1152 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
1153 | 0 | delta = 1; |
1154 | 0 | for (i = 0; i < num_SB_Neutr && cur_success < num_try; i++) |
1155 | 0 | { |
1156 | 0 | iat = iat_SB_Neutr[i]; |
1157 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
1158 | 0 | if (!pe->flow) |
1159 | 0 | continue; |
1160 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
1161 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
1162 | |
|
1163 | 0 | pe->forbidden |= forbidden_edge_mask; |
1164 | 0 | pe->flow -= delta; |
1165 | 0 | pv1->st_edge.flow -= delta; |
1166 | 0 | pv2->st_edge.flow -= delta; |
1167 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1168 | |
|
1169 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1170 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
1171 | |
|
1172 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
1173 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
1174 | 0 | { |
1175 | | /* Removed charge from O(+) => nDeltaCharge == -1 */ |
1176 | | /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */ |
1177 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
1178 | 0 | if (ret > 0) |
1179 | 0 | { |
1180 | 0 | nNumRunBNS++; |
1181 | 0 | cur_success++; /* 04 */ |
1182 | 0 | } |
1183 | 0 | } |
1184 | 0 | else |
1185 | 0 | { |
1186 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
1187 | 0 | pe->flow += delta; |
1188 | 0 | pv1->st_edge.flow += delta; |
1189 | 0 | pv2->st_edge.flow += delta; |
1190 | 0 | pBNS->tot_st_flow += 2 * delta; |
1191 | 0 | } |
1192 | 0 | INCHI_HEAPCHK |
1193 | 0 | } |
1194 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1195 | 0 | } |
1196 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1197 | 0 | if (cur_success) |
1198 | 0 | { |
1199 | 0 | tot_succes += cur_success; |
1200 | | /* recalculate InChI from the structure */ |
1201 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1202 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
1203 | 0 | { |
1204 | 0 | goto exit_function; |
1205 | 0 | } |
1206 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
1207 | 0 | { |
1208 | 0 | goto exit_function; |
1209 | 0 | } |
1210 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1211 | 0 | { |
1212 | 0 | goto exit_function; /* no fixed-H found */ |
1213 | 0 | } |
1214 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
1215 | 0 | { |
1216 | 0 | goto exit_function; |
1217 | 0 | } |
1218 | 0 | if (!pc2i->bHasDifference) |
1219 | 0 | { |
1220 | 0 | goto exit_function; /* nothing to do */ |
1221 | 0 | } |
1222 | 0 | } |
1223 | 0 | } |
1224 | | |
1225 | 0 | if (pc2i->len_c2at > 1) |
1226 | 0 | { |
1227 | | /*--------------------------------------------------------------*/ |
1228 | | /* case 05: restored: O=AB-NH original:(-)O-AB=NH(+) */ |
1229 | | /* FixH: 0 0 -1 1 */ |
1230 | | /* MobH: 0 1 1 0 */ |
1231 | | /* O = O, S, Se; N = N, O, S, Se, Te; all atoms not tautomeric */ |
1232 | | /* Solution: Separate charges */ |
1233 | | /*--------------------------------------------------------------*/ |
1234 | 0 | int num_DB_O = 0, num_SB_NH = 0, iat; |
1235 | 0 | cur_success = 0; |
1236 | |
|
1237 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
1238 | 0 | { |
1239 | 0 | iat = pc2i->c2at[i].atomNumber; |
1240 | 0 | if ( /* orig. InChI info: =NH2(+), =OH(+) */ |
1241 | 0 | num_SB_NH < MAX_DIFF_FIXH && |
1242 | 0 | ((pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) || |
1243 | 0 | pc2i->c2at[i].nValElectr == 6) /* N, O, S, Se, Te */ && |
1244 | 0 | !pc2i->c2at[i].endptInChI && |
1245 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
1246 | 0 | pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
1247 | | /* reversed structure info: */ |
1248 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs && |
1249 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && |
1250 | 0 | !pc2i->c2at[i].endptRevrs && |
1251 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence) |
1252 | 0 | { |
1253 | 0 | iat_SB_NH[num_SB_NH++] = iat; |
1254 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1255 | 0 | { |
1256 | 0 | goto exit_function; |
1257 | 0 | } |
1258 | 0 | } |
1259 | 0 | else |
1260 | 0 | { |
1261 | 0 | if ( /* orig. InChI info: -O(-) */ |
1262 | 0 | num_DB_O < MAX_DIFF_FIXH && |
1263 | 0 | (pc2i->c2at[i].nValElectr == 6) /* O, S, Se, Te */ && |
1264 | 0 | !pc2i->c2at[i].endptInChI && |
1265 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
1266 | 0 | pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 && |
1267 | | /* reversed structure info: */ |
1268 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
1269 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
1270 | 0 | !pc2i->c2at[i].endptRevrs && |
1271 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence) |
1272 | 0 | { |
1273 | 0 | iat_DB_O[num_DB_O++] = iat; |
1274 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1275 | 0 | { |
1276 | 0 | goto exit_function; |
1277 | 0 | } |
1278 | 0 | } |
1279 | 0 | } |
1280 | 0 | } |
1281 | 0 | if ((num_try = inchi_min(num_DB_O, num_SB_NH))) /* djb-rwth: addressing LLVM warning */ |
1282 | 0 | { |
1283 | | /* detected; attempt to fix */ |
1284 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1285 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
1286 | 0 | delta = 1; |
1287 | 0 | for (i = 0; i < num_SB_NH && cur_success < num_try; i++) |
1288 | 0 | { |
1289 | 0 | iat = iat_SB_NH[i]; |
1290 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
1291 | 0 | if (!pe->flow) |
1292 | 0 | continue; |
1293 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
1294 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
1295 | |
|
1296 | 0 | pe->forbidden |= forbidden_edge_mask; |
1297 | 0 | pe->flow -= delta; |
1298 | 0 | pv1->st_edge.flow -= delta; |
1299 | 0 | pv2->st_edge.flow -= delta; |
1300 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1301 | |
|
1302 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1303 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
1304 | |
|
1305 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
1306 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
1307 | 0 | { |
1308 | | /* Added charge to =O => nDeltaCharge == 1 */ |
1309 | | /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */ |
1310 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
1311 | 0 | if (ret > 0) |
1312 | 0 | { |
1313 | 0 | nNumRunBNS++; |
1314 | 0 | cur_success++; /* 05 */ |
1315 | 0 | } |
1316 | 0 | } |
1317 | 0 | else |
1318 | 0 | { |
1319 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
1320 | 0 | pe->flow += delta; |
1321 | 0 | pv1->st_edge.flow += delta; |
1322 | 0 | pv2->st_edge.flow += delta; |
1323 | 0 | pBNS->tot_st_flow += 2 * delta; |
1324 | 0 | } |
1325 | 0 | INCHI_HEAPCHK |
1326 | 0 | } |
1327 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1328 | 0 | } |
1329 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1330 | 0 | if (cur_success) |
1331 | 0 | { |
1332 | 0 | tot_succes += cur_success; |
1333 | | /* recalculate InChI from the structure */ |
1334 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1335 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
1336 | 0 | { |
1337 | 0 | goto exit_function; |
1338 | 0 | } |
1339 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
1340 | 0 | { |
1341 | 0 | goto exit_function; |
1342 | 0 | } |
1343 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1344 | 0 | { |
1345 | 0 | goto exit_function; /* no fixed-H found */ |
1346 | 0 | } |
1347 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
1348 | 0 | { |
1349 | 0 | goto exit_function; |
1350 | 0 | } |
1351 | 0 | if (!pc2i->bHasDifference) |
1352 | 0 | { |
1353 | 0 | goto exit_function; /* nothing to do */ |
1354 | 0 | } |
1355 | 0 | } |
1356 | 0 | } |
1357 | | |
1358 | 0 | if (pStruct->fixed_H && pStruct->endpoint && pc2i->nChargeFixHInChI > 0 && pc2i->nChargeFixHInChI > pc2i->nChargeMobHInChI) |
1359 | 0 | { |
1360 | | /*----------------------------------------------------------*/ |
1361 | | /* case 06c: restored -NH- or -NH(+) orig: -NH- */ |
1362 | | /* Fixed-H 1 1 0 */ |
1363 | | /* Mobile-H 0 0 1 */ |
1364 | | /* not tautomeric not tautomeric */ |
1365 | | /* has adjacent (+) */ |
1366 | | /* charges */ |
1367 | | /* Solution: move (+) charges to the -NH- unless it already*/ |
1368 | | /* N = N, O, S, Se, Te */ |
1369 | | /* has (+) charge blocked by adjacent (+) */ |
1370 | | /*----------------------------------------------------------*/ |
1371 | 0 | int iat; |
1372 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
1373 | | /* |
1374 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
1375 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
1376 | | inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] && |
1377 | | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds? |
1378 | | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL; |
1379 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
1380 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : NULL; |
1381 | | */ |
1382 | 0 | EDGE_LIST CurChargeEdges; |
1383 | 0 | EdgeIndex e2; |
1384 | 0 | cur_success = 0; |
1385 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR ); |
1386 | 0 | CurrEdges.num_edges = 0; |
1387 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
1388 | 0 | { |
1389 | | /* atoms -NH- from which H(+) were removed by the Normalization in orig. InChI */ |
1390 | 0 | iat = pc2i->c2at[i].atomNumber; |
1391 | 0 | if (( pc2i->c2at[i].nValElectr == 6 || |
1392 | 0 | (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) ) && |
1393 | 0 | !pc2i->c2at[i].endptInChI && |
1394 | 0 | ( e = pVA[iat].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
1395 | 0 | { |
1396 | 0 | if ( /* orig. InChI info: -NH- */ |
1397 | 0 | pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 && |
1398 | | /* reversed structure info: */ |
1399 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 1 && /* was not removed */ |
1400 | 0 | /*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ at2[iat].num_H && /* at2 is Fixed-H */ |
1401 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence) |
1402 | 0 | { |
1403 | 0 | if ((ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
1404 | 0 | { |
1405 | 0 | goto exit_function; |
1406 | 0 | } |
1407 | 0 | } |
1408 | 0 | } |
1409 | 0 | } |
1410 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
1411 | 0 | { |
1412 | | /* find adjacent charged atoms */ |
1413 | 0 | iat = nCanon2AtnoRevrs[i]; |
1414 | 0 | if (pStruct->endpoint[i] || at2[iat].charge != 1 || at2[iat].radical || pVA[iat].cMetal) |
1415 | 0 | { |
1416 | 0 | continue; |
1417 | 0 | } |
1418 | 0 | if (0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow && pVA[iat].cNumValenceElectrons >= 5) |
1419 | 0 | { |
1420 | | /* positively charged atom */ |
1421 | 0 | for (j = 0; j < at2[iat].valence; j++) |
1422 | 0 | { |
1423 | 0 | if (at2[k = (int) at2[iat].neighbor[j]].charge == 1 && !pVA[k].cMetal && |
1424 | 0 | 0 <= ( e2 = pVA[k].nCPlusGroupEdge - 1 ) && !pBNS->edge[e2].forbidden && !pBNS->edge[e2].flow) |
1425 | 0 | { |
1426 | 0 | if (0 > FindInEdgeList( &CurrEdges, e ) && |
1427 | 0 | 0 > FindInEdgeList( &CurChargeEdges, e ) && |
1428 | 0 | ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) )) |
1429 | 0 | { |
1430 | 0 | goto exit_case_06c; |
1431 | 0 | } |
1432 | 0 | if (0 > FindInEdgeList( &CurrEdges, e2 ) && |
1433 | 0 | 0 > FindInEdgeList( &CurChargeEdges, e2 ) && |
1434 | 0 | ( ret = AddToEdgeList( &CurChargeEdges, e2, INC_ADD_EDGE ) )) |
1435 | 0 | { |
1436 | 0 | goto exit_case_06c; |
1437 | 0 | } |
1438 | 0 | } |
1439 | 0 | } |
1440 | 0 | } |
1441 | 0 | } |
1442 | 0 | if ((num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ))) /* djb-rwth: addressing LLVM warning */ |
1443 | 0 | { |
1444 | | /* detected; attempt to fix */ |
1445 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1446 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask ); |
1447 | 0 | delta = 1; |
1448 | 0 | for (i = 0; i < CurrEdges.num_edges && cur_success < num_try; i++) |
1449 | 0 | { |
1450 | 0 | e = CurrEdges.pnEdges[i]; |
1451 | 0 | pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */ |
1452 | 0 | if (!pe->flow) |
1453 | 0 | continue; |
1454 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
1455 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
1456 | |
|
1457 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
1458 | 0 | pv1->st_edge.flow -= delta; |
1459 | 0 | pv2->st_edge.flow -= delta; |
1460 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1461 | |
|
1462 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1463 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
1464 | |
|
1465 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
1466 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warning */ |
1467 | 0 | { |
1468 | | /* Removed (+)charge from -NH- => nDeltaCharge == -1 */ |
1469 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
1470 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
1471 | 0 | if (ret > 0) |
1472 | 0 | { |
1473 | 0 | nNumRunBNS++; |
1474 | 0 | cur_success++; /* 06c */ |
1475 | 0 | } |
1476 | 0 | } |
1477 | 0 | else |
1478 | 0 | { |
1479 | 0 | pe->flow += delta; |
1480 | 0 | pv1->st_edge.flow += delta; |
1481 | 0 | pv2->st_edge.flow += delta; |
1482 | 0 | pBNS->tot_st_flow += 2 * delta; |
1483 | 0 | } |
1484 | 0 | INCHI_HEAPCHK |
1485 | 0 | } |
1486 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1487 | 0 | } |
1488 | 0 | exit_case_06c: |
1489 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1490 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE ); |
1491 | 0 | if (ret < 0) |
1492 | 0 | { |
1493 | 0 | goto exit_function; |
1494 | 0 | } |
1495 | 0 | if (cur_success) |
1496 | 0 | { |
1497 | 0 | tot_succes += cur_success; |
1498 | | /* recalculate InChI from the structure */ |
1499 | 0 | if (0 >( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1500 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
1501 | 0 | { |
1502 | 0 | goto exit_function; |
1503 | 0 | } |
1504 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
1505 | 0 | { |
1506 | 0 | goto exit_function; |
1507 | 0 | } |
1508 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1509 | 0 | { |
1510 | 0 | goto exit_function; /* no fixed-H found */ |
1511 | 0 | } |
1512 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
1513 | 0 | { |
1514 | 0 | goto exit_function; |
1515 | 0 | } |
1516 | 0 | if (!pc2i->bHasDifference) |
1517 | 0 | { |
1518 | 0 | goto exit_function; /* nothing to do */ |
1519 | 0 | } |
1520 | 0 | } |
1521 | 0 | } |
1522 | | |
1523 | 0 | if (pc2i->len_c2at >= 2) |
1524 | 0 | { |
1525 | | /*------------------------------------------------------------*/ |
1526 | | /* case 06d: restored: XH(+)=-AB-NH orig.: XH-=AB=NH(+) */ |
1527 | | /* FixH: 1 1 0 0 1 1 */ |
1528 | | /* MobH: 0 taut 1 1 taut 0 */ |
1529 | | /* */ |
1530 | | /* */ |
1531 | | /* N = N, O, S, Se; atoms N are not tautomeric in orig InChI */ |
1532 | | /* X = N, O, S, Se, Te, F, Cl, Br, I; atom X is non-taut */ |
1533 | | /* Solution: move (+) from X to NH */ |
1534 | | /*------------------------------------------------------------*/ |
1535 | 0 | int iat; |
1536 | | /* |
1537 | | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
1538 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
1539 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
1540 | | inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] && |
1541 | | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds? |
1542 | | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : |
1543 | | pStruct->pOne_norm_data[TAUT_NON]->at; |
1544 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
1545 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
1546 | | */ |
1547 | 0 | EDGE_LIST CurChargeEdges; |
1548 | 0 | cur_success = 0; |
1549 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR ); |
1550 | 0 | CurrEdges.num_edges = 0; |
1551 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
1552 | 0 | { |
1553 | 0 | iat = pc2i->c2at[i].atomNumber; |
1554 | | /* XH(+) */ |
1555 | 0 | if ( /* reconstructed: non-taut and (+) */ |
1556 | 0 | ( pc2i->c2at[i].nMobHRevrs + 1 == pc2i->c2at[i].nFixHRevrs && |
1557 | 0 | pc2i->c2at[i].nFixHRevrs > 0 && !pc2i->c2at[i].endptRevrs && |
1558 | 0 | pc2i->c2at[i].nAtChargeRevrs == 1 && |
1559 | | /* original InChI: non-taut & has H or an endpoint, has Fixed H */ |
1560 | 0 | ( (!pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].nMobHInChI == pc2i->c2at[i].nFixHRevrs) || |
1561 | 0 | (pc2i->c2at[i].nFixHInChI == pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].endptInChI) ) ) && |
1562 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow) /* djb-rwth: addressing LLVM warnings */ |
1563 | 0 | { |
1564 | |
|
1565 | 0 | if ((ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
1566 | 0 | { |
1567 | 0 | goto exit_case_06d; |
1568 | 0 | } |
1569 | 0 | } |
1570 | 0 | else |
1571 | 0 | { |
1572 | | /* -NH- */ |
1573 | 0 | if ( /* original InChI: has H and is not an endpoint */ |
1574 | 0 | ( pc2i->c2at[i].nMobHInChI + 1 == pc2i->c2at[i].nFixHInChI && |
1575 | 0 | pc2i->c2at[i].nFixHInChI > 0 && !pc2i->c2at[i].endptInChI && |
1576 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && |
1577 | | /* reconstructed InChI: non-taut & has H or an endpoint, has Fixed H */ |
1578 | 0 | ( (!pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs == pc2i->c2at[i].nFixHInChI) || |
1579 | 0 | (pc2i->c2at[i].nFixHRevrs == pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].endptRevrs) ) ) && |
1580 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && |
1581 | 0 | pBNS->edge[e].flow) /* djb-rwth: addressing LLVM warnings */ |
1582 | 0 | { |
1583 | |
|
1584 | 0 | if ((ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
1585 | 0 | { |
1586 | 0 | goto exit_case_06d; |
1587 | 0 | } |
1588 | 0 | } |
1589 | 0 | } |
1590 | 0 | } |
1591 | 0 | if ((num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ))) /* djb-rwth: addressing LLVM warning */ |
1592 | 0 | { |
1593 | | /* detected; attempt to fix */ |
1594 | 0 | int bSFlowerEdgesMayBeForbidden = ( SFlowerEdges.num_edges > 0 ); |
1595 | 0 | int bSFlowerEdgesIsForbidden; |
1596 | 0 | for (bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden; |
1597 | 0 | 0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden--) |
1598 | 0 | { |
1599 | 0 | if (bSFlowerEdgesIsForbidden) |
1600 | 0 | { |
1601 | | /* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */ |
1602 | 0 | SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask ); |
1603 | 0 | } |
1604 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1605 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask ); |
1606 | 0 | delta = 1; |
1607 | 0 | for (i = 0; i < CurrEdges.num_edges && cur_success < num_try; i++) |
1608 | 0 | { |
1609 | 0 | e = CurrEdges.pnEdges[i]; |
1610 | 0 | pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */ |
1611 | 0 | if (!pe->flow) |
1612 | 0 | continue; |
1613 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
1614 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
1615 | |
|
1616 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
1617 | 0 | pv1->st_edge.flow -= delta; |
1618 | 0 | pv2->st_edge.flow -= delta; |
1619 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1620 | |
|
1621 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1622 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
1623 | |
|
1624 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
1625 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
1626 | 0 | { |
1627 | | /* Removed (+)charge from -NH- => nDeltaCharge == -1 */ |
1628 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
1629 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
1630 | 0 | if (ret > 0) |
1631 | 0 | { |
1632 | 0 | nNumRunBNS++; |
1633 | 0 | cur_success++; /* 06d */ |
1634 | 0 | } |
1635 | 0 | } |
1636 | 0 | else |
1637 | 0 | { |
1638 | 0 | pe->flow += delta; |
1639 | 0 | pv1->st_edge.flow += delta; |
1640 | 0 | pv2->st_edge.flow += delta; |
1641 | 0 | pBNS->tot_st_flow += 2 * delta; |
1642 | 0 | } |
1643 | 0 | INCHI_HEAPCHK |
1644 | 0 | } |
1645 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1646 | 0 | RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask ); |
1647 | 0 | } |
1648 | 0 | } |
1649 | 0 | exit_case_06d: |
1650 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1651 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE ); |
1652 | 0 | if (cur_success) |
1653 | 0 | { |
1654 | 0 | tot_succes += cur_success; |
1655 | | /* recalculate InChI from the structure */ |
1656 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1657 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
1658 | 0 | { |
1659 | 0 | goto exit_function; |
1660 | 0 | } |
1661 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
1662 | 0 | { |
1663 | 0 | goto exit_function; |
1664 | 0 | } |
1665 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1666 | 0 | { |
1667 | 0 | goto exit_function; /* no fixed-H found */ |
1668 | 0 | } |
1669 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
1670 | 0 | { |
1671 | 0 | goto exit_function; |
1672 | 0 | } |
1673 | 0 | if (!pc2i->bHasDifference) |
1674 | 0 | { |
1675 | 0 | goto exit_function; /* nothing to do */ |
1676 | 0 | } |
1677 | 0 | } |
1678 | 0 | } |
1679 | | |
1680 | 0 | if (pc2i->len_c2at >= 2) |
1681 | 0 | { |
1682 | | /*--------------------------------------------------------*/ |
1683 | | /* case 06: restored: NHn(+)=AB-NHm orig.: NHn-AB=NHm(+) */ |
1684 | | /* FixH: 1 0 0 1 */ |
1685 | | /* MobH: n-1 m n m-1 */ |
1686 | | /* N = N, O, S, Se; atoms N are not tautomeric */ |
1687 | | /* Solution: move (+) from NHn(+) to NHn */ |
1688 | | /*--------------------------------------------------------*/ |
1689 | 0 | int num_DB_NHn_Plus = 0, num_SB_NHm_Neutr = 0, iat; |
1690 | 0 | cur_success = 0; |
1691 | |
|
1692 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
1693 | 0 | { |
1694 | 0 | iat = pc2i->c2at[i].atomNumber; |
1695 | 0 | if ((pc2i->c2at[i].nValElectr == 6 || |
1696 | 0 | (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1)) && |
1697 | 0 | !pc2i->c2at[i].endptInChI && |
1698 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
1699 | 0 | { |
1700 | 0 | if ( /* orig. InChI info: NHm */ |
1701 | 0 | num_SB_NHm_Neutr < MAX_DIFF_FIXH && |
1702 | 0 | pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI == 0 &&*/ |
1703 | | /* reversed structure info: */ |
1704 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && /*pc2i->c2at[i].nMobHRevrs == 1 &&*/ |
1705 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && /* at2 is Fixed-H */ |
1706 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence) |
1707 | 0 | { |
1708 | 0 | iat_SB_NHm_Neutr[num_SB_NHm_Neutr++] = iat; |
1709 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1710 | 0 | { |
1711 | 0 | goto exit_function; |
1712 | 0 | } |
1713 | 0 | } |
1714 | 0 | else |
1715 | 0 | { |
1716 | 0 | if ( /* orig. InChI info: */ |
1717 | 0 | num_DB_NHn_Plus < MAX_DIFF_FIXH && |
1718 | 0 | pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI &&*/ |
1719 | | /* reversed structure info: */ |
1720 | 0 | pc2i->c2at[i].nFixHRevrs == 1 && /*pc2i->c2at[i].nMobHRevrs == 0 &&*/ |
1721 | 0 | pc2i->c2at[i].nAtChargeRevrs == 1 && at2[iat].num_H && |
1722 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence) |
1723 | 0 | { |
1724 | 0 | iat_DB_NHn_Plus[num_DB_NHn_Plus++] = iat; |
1725 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
1726 | 0 | { |
1727 | 0 | goto exit_function; |
1728 | 0 | } |
1729 | 0 | } |
1730 | 0 | } |
1731 | 0 | } |
1732 | 0 | } |
1733 | 0 | if ((num_try = inchi_min(num_SB_NHm_Neutr, num_DB_NHn_Plus))) /* djb-rwth: addressing LLVM warning */ |
1734 | 0 | { |
1735 | | /* detected; attempt to fix */ |
1736 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1737 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
1738 | 0 | delta = 1; |
1739 | 0 | for (i = 0; i < num_SB_NHm_Neutr && cur_success < num_try; i++) |
1740 | 0 | { |
1741 | 0 | iat = iat_SB_NHm_Neutr[i]; |
1742 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
1743 | 0 | if (!pe->flow) |
1744 | 0 | continue; |
1745 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
1746 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
1747 | |
|
1748 | 0 | pe->forbidden |= forbidden_edge_mask; |
1749 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
1750 | 0 | pv1->st_edge.flow -= delta; |
1751 | 0 | pv2->st_edge.flow -= delta; |
1752 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1753 | |
|
1754 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1755 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
1756 | |
|
1757 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
1758 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
1759 | 0 | { |
1760 | | /* Removed (+)charge from -NHn => nDeltaCharge == -1 */ |
1761 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
1762 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
1763 | 0 | if (ret > 0) |
1764 | 0 | { |
1765 | 0 | nNumRunBNS++; |
1766 | 0 | cur_success++; /* 06 */ |
1767 | 0 | } |
1768 | 0 | } |
1769 | 0 | else |
1770 | 0 | { |
1771 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
1772 | 0 | pe->flow += delta; |
1773 | 0 | pv1->st_edge.flow += delta; |
1774 | 0 | pv2->st_edge.flow += delta; |
1775 | 0 | pBNS->tot_st_flow += 2 * delta; |
1776 | 0 | } |
1777 | 0 | INCHI_HEAPCHK |
1778 | 0 | } |
1779 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
1780 | 0 | } |
1781 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1782 | 0 | if (cur_success) |
1783 | 0 | { |
1784 | 0 | tot_succes += cur_success; |
1785 | | /* recalculate InChI from the structure */ |
1786 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1787 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
1788 | 0 | { |
1789 | 0 | goto exit_function; |
1790 | 0 | } |
1791 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
1792 | 0 | { |
1793 | 0 | goto exit_function; |
1794 | 0 | } |
1795 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1796 | 0 | { |
1797 | 0 | goto exit_function; /* no fixed-H found */ |
1798 | 0 | } |
1799 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
1800 | 0 | { |
1801 | 0 | goto exit_function; |
1802 | 0 | } |
1803 | 0 | if (!pc2i->bHasDifference) |
1804 | 0 | { |
1805 | 0 | goto exit_function; /* nothing to do */ |
1806 | 0 | } |
1807 | 0 | } |
1808 | 0 | } |
1809 | | |
1810 | 0 | if (( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1) || |
1811 | 0 | pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) && |
1812 | 0 | pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons && |
1813 | 0 | pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES] && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds) /* djb-rwth: addressing LLVM warning; fixing a NULL pointer dereference */ |
1814 | 0 | { |
1815 | | /*----------------------------------------------------------*/ |
1816 | | /* case 06a: restored: N'(+)=-AB-NH orig.: N'-=AB=NH(+) */ |
1817 | | /* FixH: 0 1 0 1 */ |
1818 | | /* MobH: 0 0 0 0 */ |
1819 | | /* single t-group multiple t-groups */ |
1820 | | /* N = N, O, S, Se; atoms N are not tautomeric */ |
1821 | | /* N' = N atom N' is not tautomeric */ |
1822 | | /* Solution: move (+) from N' to NH */ |
1823 | | /*----------------------------------------------------------*/ |
1824 | 0 | int iat; |
1825 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
1826 | | /* |
1827 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
1828 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
1829 | | */ |
1830 | 0 | inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] && |
1831 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ? |
1832 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL; |
1833 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
1834 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
1835 | 0 | EDGE_LIST CurChargeEdges; |
1836 | 0 | cur_success = 0; |
1837 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR ); |
1838 | 0 | CurrEdges.num_edges = 0; |
1839 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
1840 | 0 | { |
1841 | 0 | iat = nCanon2AtnoRevrs[i]; |
1842 | 0 | if (pStruct->endpoint[i]) |
1843 | 0 | { |
1844 | 0 | continue; |
1845 | 0 | } |
1846 | | /* -NH-, -OH */ |
1847 | 0 | if (pStruct->fixed_H[i] && nMobHInChI && !nMobHInChI[i] && |
1848 | 0 | at2[iat].charge == 0 && at2[iat].radical == 0 && |
1849 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
1850 | 0 | ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) )) /* djb-rwth: fixing a NULL pointer dereference */ |
1851 | 0 | { |
1852 | 0 | goto exit_case_06a; |
1853 | 0 | } |
1854 | 0 | else |
1855 | 0 | { |
1856 | | /* >N(+)= */ |
1857 | 0 | if (at2[iat].charge == 1 && !at2[iat].num_H && |
1858 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
1859 | 0 | atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 0 && |
1860 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow && |
1861 | 0 | ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) )) |
1862 | 0 | { |
1863 | 0 | goto exit_case_06a; |
1864 | 0 | } |
1865 | 0 | } |
1866 | 0 | } |
1867 | 0 | if ((num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ))) /* djb-rwth: addressing LLVM warning */ |
1868 | 0 | { |
1869 | | /* detected; attempt to fix */ |
1870 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1871 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask ); |
1872 | 0 | delta = 1; |
1873 | 0 | for (i = 0; i < CurrEdges.num_edges && cur_success < num_try; i++) |
1874 | 0 | { |
1875 | 0 | e = CurrEdges.pnEdges[i]; |
1876 | 0 | pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */ |
1877 | 0 | if (!pe->flow) |
1878 | 0 | continue; |
1879 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
1880 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
1881 | |
|
1882 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
1883 | 0 | pv1->st_edge.flow -= delta; |
1884 | 0 | pv2->st_edge.flow -= delta; |
1885 | 0 | pBNS->tot_st_flow -= 2 * delta; |
1886 | |
|
1887 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
1888 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
1889 | |
|
1890 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
1891 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
1892 | 0 | { |
1893 | | /* Removed (+)charge from -NH- => nDeltaCharge == -1 */ |
1894 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
1895 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
1896 | 0 | if (ret > 0) |
1897 | 0 | { |
1898 | 0 | nNumRunBNS++; |
1899 | 0 | cur_success++; /* 06a */ |
1900 | 0 | } |
1901 | 0 | } |
1902 | 0 | else |
1903 | 0 | { |
1904 | 0 | pe->flow += delta; |
1905 | 0 | pv1->st_edge.flow += delta; |
1906 | 0 | pv2->st_edge.flow += delta; |
1907 | 0 | pBNS->tot_st_flow += 2 * delta; |
1908 | 0 | } |
1909 | 0 | INCHI_HEAPCHK |
1910 | 0 | } |
1911 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
1912 | 0 | } |
1913 | 0 | exit_case_06a: |
1914 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
1915 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE ); |
1916 | 0 | if (cur_success) |
1917 | 0 | { |
1918 | 0 | tot_succes += cur_success; |
1919 | | /* recalculate InChI from the structure */ |
1920 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
1921 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
1922 | 0 | { |
1923 | 0 | goto exit_function; |
1924 | 0 | } |
1925 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
1926 | 0 | { |
1927 | 0 | goto exit_function; |
1928 | 0 | } |
1929 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
1930 | 0 | { |
1931 | 0 | goto exit_function; /* no fixed-H found */ |
1932 | 0 | } |
1933 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
1934 | 0 | { |
1935 | 0 | goto exit_function; |
1936 | 0 | } |
1937 | 0 | if (!pc2i->bHasDifference) |
1938 | 0 | { |
1939 | 0 | goto exit_function; /* nothing to do */ |
1940 | 0 | } |
1941 | 0 | } |
1942 | 0 | } |
1943 | 0 | if (( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1) || |
1944 | 0 | pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) && |
1945 | 0 | ( pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons || |
1946 | 0 | pStruct->nNumRemovedProtonsMobHInChI > pStruct->One_ti.tni.nNumRemovedProtons ) && |
1947 | 0 | pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES] && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds) /* djb-rwth: addressing LLVM warning; fixing a NULL pointer dereference */ |
1948 | 0 | { |
1949 | | /*----------------------------------------------------------*/ |
1950 | | /* case 06b: restored: X(+)=-AB-NH orig.: X-=AB=NH(+) */ |
1951 | | /* FixH: 0 1 1 0 1 */ |
1952 | | /* MobH: 0 0 t 0 0 */ |
1953 | | /* single t-group multiple t-groups */ |
1954 | | /* or no t-groupd */ |
1955 | | /* N = N, O, S, Se; atoms N are not tautomeric */ |
1956 | | /* X = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/ |
1957 | | /* Solution: move (+) from X to NH */ |
1958 | | /*----------------------------------------------------------*/ |
1959 | 0 | int iat; |
1960 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
1961 | | /* |
1962 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
1963 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
1964 | | */ |
1965 | 0 | inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] && |
1966 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ? |
1967 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL; |
1968 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
1969 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
1970 | 0 | EDGE_LIST CurChargeEdges; |
1971 | 0 | cur_success = 0; |
1972 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR ); |
1973 | 0 | CurrEdges.num_edges = 0; |
1974 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
1975 | 0 | { |
1976 | 0 | iat = nCanon2AtnoRevrs[i]; |
1977 | 0 | if (pStruct->endpoint[i]) |
1978 | 0 | { |
1979 | 0 | continue; |
1980 | 0 | } |
1981 | | /* -NH-, -OH */ |
1982 | 0 | if (pStruct->fixed_H[i] && nMobHInChI && !nMobHInChI[i] && |
1983 | 0 | at2[iat].charge == 0 && at2[iat].radical == 0 && |
1984 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
1985 | 0 | ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) )) /* djb-rwth: fixing a NULL pointer dereference */ |
1986 | 0 | { |
1987 | 0 | goto exit_case_06b; |
1988 | 0 | } |
1989 | 0 | else |
1990 | 0 | { |
1991 | | /* X(+)= */ |
1992 | 0 | if (at2[iat].charge == 1 && !at2[iat].num_H && |
1993 | 0 | ( pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cPeriodicRowNumber == 7 ) && |
1994 | 0 | atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 1 && |
1995 | 0 | 0 <= ( e = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow && |
1996 | 0 | ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) )) |
1997 | 0 | { |
1998 | 0 | goto exit_case_06b; |
1999 | 0 | } |
2000 | 0 | } |
2001 | 0 | } |
2002 | 0 | if ((num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ))) /* djb-rwth: addressing LLVM warning */ |
2003 | 0 | { |
2004 | | /* detected; attempt to fix */ |
2005 | 0 | int bSFlowerEdgesMayBeForbidden = ( SFlowerEdges.num_edges > 0 ); |
2006 | 0 | int bSFlowerEdgesIsForbidden; |
2007 | 0 | for (bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden; |
2008 | 0 | 0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden--) |
2009 | 0 | { |
2010 | 0 | if (bSFlowerEdgesIsForbidden) |
2011 | 0 | { |
2012 | | /* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */ |
2013 | 0 | SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask ); |
2014 | 0 | } |
2015 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
2016 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask ); |
2017 | 0 | delta = 1; |
2018 | 0 | for (i = 0; i < CurrEdges.num_edges && cur_success < num_try; i++) |
2019 | 0 | { |
2020 | 0 | e = CurrEdges.pnEdges[i]; |
2021 | 0 | pe = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */ |
2022 | 0 | if (!pe->flow) |
2023 | 0 | continue; |
2024 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
2025 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
2026 | |
|
2027 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
2028 | 0 | pv1->st_edge.flow -= delta; |
2029 | 0 | pv2->st_edge.flow -= delta; |
2030 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2031 | |
|
2032 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2033 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
2034 | |
|
2035 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
2036 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
2037 | 0 | { |
2038 | | /* Removed (+)charge from -NH- => nDeltaCharge == -1 */ |
2039 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
2040 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
2041 | 0 | if (ret > 0) |
2042 | 0 | { |
2043 | 0 | nNumRunBNS++; |
2044 | 0 | cur_success++; /* 06b */ |
2045 | 0 | } |
2046 | 0 | } |
2047 | 0 | else |
2048 | 0 | { |
2049 | 0 | pe->flow += delta; |
2050 | 0 | pv1->st_edge.flow += delta; |
2051 | 0 | pv2->st_edge.flow += delta; |
2052 | 0 | pBNS->tot_st_flow += 2 * delta; |
2053 | 0 | } |
2054 | 0 | INCHI_HEAPCHK |
2055 | 0 | } |
2056 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
2057 | 0 | RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask ); |
2058 | 0 | } |
2059 | 0 | } |
2060 | 0 | exit_case_06b: |
2061 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2062 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE ); |
2063 | 0 | if (cur_success) |
2064 | 0 | { |
2065 | 0 | tot_succes += cur_success; |
2066 | | /* recalculate InChI from the structure */ |
2067 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2068 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
2069 | 0 | { |
2070 | 0 | goto exit_function; |
2071 | 0 | } |
2072 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
2073 | 0 | { |
2074 | 0 | goto exit_function; |
2075 | 0 | } |
2076 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2077 | 0 | { |
2078 | 0 | goto exit_function; /* no fixed-H found */ |
2079 | 0 | } |
2080 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
2081 | 0 | { |
2082 | 0 | goto exit_function; |
2083 | 0 | } |
2084 | 0 | if (!pc2i->bHasDifference) |
2085 | 0 | { |
2086 | 0 | goto exit_function; /* nothing to do */ |
2087 | 0 | } |
2088 | 0 | } |
2089 | 0 | } |
2090 | | |
2091 | 0 | if (pc2i->nNumTgInChI > 1 && |
2092 | 0 | ( pStruct->nNumRemovedProtonsMobHInChI > 0 || pStruct->ti.tni.nNumRemovedProtons > 0 ) && |
2093 | 0 | pStruct->fixed_H && pStruct->endpoint && |
2094 | 0 | pStruct->pOne_norm_data[TAUT_YES] && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds) |
2095 | 0 | { |
2096 | | /*----------------------------------------------------------*/ |
2097 | | /* case 06e:restored: XHn(+)=-AB-YHm orig.: XHn-=AB=YHm(+) */ |
2098 | | /* FixH: 1 0 1 1 */ |
2099 | | /* MobH: 0 1 t t */ |
2100 | | /* non-taut atoms multiple t-groups */ |
2101 | | /* */ |
2102 | | /* 1. orig. t-group has more H on its endpoints counted */ |
2103 | | /* in atf and has no (+) on endpoint that has H */ |
2104 | | /* 2. orig. t-group has less H on its endpoints counted */ |
2105 | | /* in atf and has (+) on endpoint that has H */ |
2106 | | /* in reconstructed struct and less H in atf */ |
2107 | | /* Solution: move (+) from (2) to atom in (1) that has H */ |
2108 | | /* */ |
2109 | | /* tg1 reconstr: XHn and more H than in orig t-group */ |
2110 | | /* atf: XHn */ |
2111 | | /* tg2 reconstr: XHm(+) and less H than in */ |
2112 | | /* atf: XH(m-1) orig in t-group */ |
2113 | | /* */ |
2114 | | /* N = N, O, S, Se; atoms N are not tautomeric */ |
2115 | | /* X = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/ |
2116 | | /* Solution: move (+) from X to NH */ |
2117 | | /*----------------------------------------------------------*/ |
2118 | |
|
2119 | 0 | int iat, nNumWrongTg, jjoffs, jj, nNum2RemovePlus, nNum2AddPlus, nNum2MovePlus; |
2120 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
2121 | | /* |
2122 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
2123 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
2124 | | */ |
2125 | 0 | inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] && |
2126 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ? |
2127 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : |
2128 | 0 | pStruct->pOne_norm_data[TAUT_YES] && |
2129 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at ? |
2130 | 0 | pStruct->pOne_norm_data[TAUT_YES]->at : NULL; |
2131 | | /* |
2132 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
2133 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
2134 | | */ |
2135 | 0 | EDGE_LIST CurChargeEdges /* source of (+)*/, EndpList; |
2136 | 0 | BNS_VERTEX *pv1n, *pv2n; |
2137 | 0 | BNS_EDGE *pe1n, *pe2n; |
2138 | 0 | Vertex v1n, v2n; |
2139 | |
|
2140 | 0 | cur_success = 0; |
2141 | 0 | AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR ); |
2142 | 0 | AllocEdgeList( &EndpList, EDGE_LIST_CLEAR ); |
2143 | 0 | CurrEdges.num_edges = 0; /* receptors of (+) */ |
2144 | | |
2145 | 0 | if (!atfMobile_H_Revrs) |
2146 | 0 | { |
2147 | 0 | goto exit_case_06e; |
2148 | 0 | } |
2149 | 0 | nNumWrongTg = FillTgDiffHChgFH(tdhc, MAX_DIFF_FIXH, at2, atfMobile_H_Revrs, |
2150 | 0 | nCanon2AtnoRevrs, pVA, &pStruct->ti, &EndpList); |
2151 | 0 | if (nNumWrongTg < 1) |
2152 | 0 | { |
2153 | 0 | goto exit_case_06e; /* for now only transfer (+) from one Mobile-H group to another */ |
2154 | 0 | } |
2155 | 0 | nNum2RemovePlus = nNum2AddPlus = 0; /* djb-rwth: removing redundant code */ |
2156 | 0 | for (i = 0; i < nNumWrongTg; i++) |
2157 | 0 | { |
2158 | | /* detect t-group that has extra (+) on H */ |
2159 | 0 | if (tdhc[i].nNumHInchi > tdhc[i].nNumHNorml && |
2160 | 0 | tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH]) |
2161 | 0 | { |
2162 | | /* count how many (+) to remove */ |
2163 | | /* store XH(+) atom numbers */ |
2164 | 0 | int nNumNeeded = inchi_min(tdhc[i].nNumHInchi - tdhc[i].nNumHNorml, tdhc[i].n[fNumRPosChgH]); |
2165 | 0 | nNum2RemovePlus += nNumNeeded; |
2166 | 0 | jjoffs = tdhc[i].i[fNumRPosChgH]; |
2167 | 0 | for (jj = 0; jj < tdhc[i].n[fNumRPosChgH]; jj++) |
2168 | 0 | { |
2169 | 0 | iat = EndpList.pnEdges[jjoffs + jj]; |
2170 | 0 | e = pVA[iat].nCPlusGroupEdge - 1; |
2171 | 0 | if ((ret = AddToEdgeList(&CurChargeEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2172 | 0 | { |
2173 | 0 | goto exit_case_06e; |
2174 | 0 | } |
2175 | 0 | } |
2176 | 0 | } |
2177 | 0 | else |
2178 | 0 | { |
2179 | | /* detect t-group that needs (+) on XH to reduce number of H */ |
2180 | 0 | if (tdhc[i].nNumHInchi < tdhc[i].nNumHNorml && tdhc[i].n[fNumRNeutrlH]) |
2181 | 0 | { |
2182 | | /* store XH atom numbers */ |
2183 | 0 | int nNumNeeded = inchi_min(tdhc[i].nNumHNorml - tdhc[i].nNumHInchi, tdhc[i].n[fNumRNeutrlH]); |
2184 | 0 | nNum2AddPlus += nNumNeeded; |
2185 | 0 | jjoffs = tdhc[i].i[fNumRNeutrlH]; |
2186 | 0 | for (jj = 0; jj < tdhc[i].n[fNumRNeutrlH]; jj++) |
2187 | 0 | { |
2188 | 0 | iat = EndpList.pnEdges[jjoffs + jj]; |
2189 | 0 | e = pVA[iat].nCPlusGroupEdge - 1; |
2190 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2191 | 0 | { |
2192 | 0 | goto exit_case_06e; |
2193 | 0 | } |
2194 | 0 | } |
2195 | 0 | } |
2196 | 0 | } |
2197 | 0 | } |
2198 | 0 | nNum2MovePlus = inchi_min(nNum2RemovePlus, nNum2AddPlus); |
2199 | 0 | if (CurrEdges.num_edges > 0 && CurChargeEdges.num_edges > 0) |
2200 | 0 | { |
2201 | 0 | for (i = 0; 0 < nNum2MovePlus && i < nNumWrongTg; i++) |
2202 | 0 | { |
2203 | | /* detect t-group that has extra (+) on H */ |
2204 | 0 | if (tdhc[i].nNumHInchi > tdhc[i].nNumHNorml && |
2205 | 0 | tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH]) |
2206 | 0 | { |
2207 | 0 | int nNum2Remove = tdhc[i].nNumHInchi - tdhc[i].nNumHNorml; |
2208 | 0 | if (nNum2Remove < tdhc[i].n[fNumRPosChgH]) |
2209 | 0 | { |
2210 | 0 | nNum2Remove = tdhc[i].n[fNumRPosChgH]; |
2211 | 0 | } |
2212 | | /* store XH(+) atom numbers */ |
2213 | 0 | jjoffs = tdhc[i].i[fNumRPosChgH]; |
2214 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2215 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
2216 | 0 | for (jj = 0; 0 < nNum2MovePlus && 0 < nNum2Remove && jj < tdhc[i].n[fNumRPosChgH]; jj++) |
2217 | 0 | { |
2218 | 0 | iat = EndpList.pnEdges[jjoffs + jj]; |
2219 | 0 | e = pVA[iat].nCPlusGroupEdge - 1; |
2220 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
2221 | 0 | if (pe->flow) |
2222 | 0 | continue; |
2223 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
2224 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
2225 | |
|
2226 | 0 | for (j = pv1->num_adj_edges - 1; 0 <= j; j--) |
2227 | 0 | { |
2228 | 0 | pe1n = pBNS->edge + pv1->iedge[j]; |
2229 | 0 | if (pe1n->flow && !pe1n->forbidden) |
2230 | 0 | { |
2231 | 0 | pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1); |
2232 | 0 | break; |
2233 | 0 | } |
2234 | 0 | } |
2235 | 0 | if (j < 0) |
2236 | 0 | { |
2237 | 0 | continue; /* not found */ |
2238 | 0 | } |
2239 | 0 | for (j = pv2->num_adj_edges - 2; 0 <= j; j--) |
2240 | 0 | { |
2241 | 0 | pe2n = pBNS->edge + pv2->iedge[j]; |
2242 | 0 | if (pe2n->flow && !pe2n->forbidden) |
2243 | 0 | { |
2244 | 0 | pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2); |
2245 | 0 | break; |
2246 | 0 | } |
2247 | 0 | } |
2248 | 0 | if (j < 0) |
2249 | 0 | { |
2250 | 0 | continue; /* not found */ |
2251 | 0 | } |
2252 | 0 | delta = 1; |
2253 | 0 | pe->flow += delta; |
2254 | 0 | pe1n->flow -= delta; |
2255 | 0 | pe2n->flow -= delta; |
2256 | 0 | pv1n->st_edge.flow -= delta; |
2257 | 0 | pv2n->st_edge.flow -= delta; |
2258 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2259 | |
|
2260 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2261 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
2262 | |
|
2263 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
2264 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
2265 | 0 | (nDeltaCharge == 0 || nDeltaCharge == 1)) /* djb-rwth: addressing LLVM warnings */ |
2266 | 0 | { |
2267 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
2268 | 0 | if (ret > 0) |
2269 | 0 | { |
2270 | 0 | nNumRunBNS++; |
2271 | 0 | nNum2Remove--; |
2272 | 0 | nNum2MovePlus--; |
2273 | 0 | cur_success++; /* 06e */ |
2274 | 0 | } |
2275 | 0 | } |
2276 | 0 | else |
2277 | 0 | { |
2278 | 0 | pe->flow -= delta; |
2279 | 0 | pe1n->flow += delta; |
2280 | 0 | pe2n->flow += delta; |
2281 | 0 | pv1n->st_edge.flow += delta; |
2282 | 0 | pv2n->st_edge.flow += delta; |
2283 | 0 | pBNS->tot_st_flow += 2 * delta; |
2284 | 0 | } |
2285 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) |
2286 | 0 | { |
2287 | 0 | goto exit_case_06e; |
2288 | 0 | } |
2289 | 0 | } |
2290 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2291 | 0 | } |
2292 | 0 | } |
2293 | 0 | } |
2294 | 0 | exit_case_06e: |
2295 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2296 | 0 | AllocEdgeList(&CurChargeEdges, EDGE_LIST_FREE); |
2297 | 0 | AllocEdgeList(&EndpList, EDGE_LIST_FREE); |
2298 | 0 | if (cur_success) |
2299 | 0 | { |
2300 | 0 | tot_succes += cur_success; |
2301 | | /* recalculate InChI from the structure */ |
2302 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2303 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
2304 | 0 | { |
2305 | 0 | goto exit_function; |
2306 | 0 | } |
2307 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
2308 | 0 | { |
2309 | 0 | goto exit_function; |
2310 | 0 | } |
2311 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2312 | 0 | { |
2313 | 0 | goto exit_function; /* no fixed-H found */ |
2314 | 0 | } |
2315 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
2316 | 0 | { |
2317 | 0 | goto exit_function; |
2318 | 0 | } |
2319 | 0 | if (!pc2i->bHasDifference) |
2320 | 0 | { |
2321 | 0 | goto exit_function; /* nothing to do */ |
2322 | 0 | } |
2323 | 0 | } |
2324 | 0 | } |
2325 | | |
2326 | 0 | if (pc2i->len_c2at >= 1) |
2327 | 0 | { |
2328 | | /*--------------------------------------------------------------*/ |
2329 | | /* case 07: restored: O(-)-AB=O original: O=AB-O(-) */ |
2330 | | /* FixH: 0 0 0 -1 */ |
2331 | | /* MobH: 0 0 0 1 */ |
2332 | | /* taut (non-taut) (taut) non-taut */ |
2333 | | /* taut (taut) (non-taut) non-taut */ |
2334 | | /* O = O, S, Se, Te */ |
2335 | | /* Solution: move (-) from O(-)-AB to AB=O */ |
2336 | | /*--------------------------------------------------------------*/ |
2337 | 0 | int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat; |
2338 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
2339 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
2340 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
2341 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
2342 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
2343 | 0 | cur_success = 0; |
2344 | |
|
2345 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
2346 | 0 | { |
2347 | 0 | iat = pc2i->c2at[i].atomNumber; |
2348 | 0 | if ( /* orig. InChI info: -O(-), non-taut */ |
2349 | 0 | num_DB_O_Neutr < MAX_DIFF_FIXH && |
2350 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
2351 | 0 | !pc2i->c2at[i].endptInChI && |
2352 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
2353 | 0 | pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 && |
2354 | | /* reversed structure info: */ |
2355 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
2356 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
2357 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence) |
2358 | 0 | { |
2359 | 0 | iat_DB_O_Neutr[num_DB_O_Neutr++] = iat; |
2360 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2361 | 0 | { |
2362 | 0 | goto exit_function; |
2363 | 0 | } |
2364 | 0 | } |
2365 | 0 | } |
2366 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
2367 | 0 | { |
2368 | | /* i = canonical number - 1 */ |
2369 | 0 | iat = nCanon2AtnoRevrs[i]; |
2370 | 0 | if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */ |
2371 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
2372 | 0 | at2[iat].charge == -1 && !at2[iat].num_H && |
2373 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
2374 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
2375 | 0 | at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && |
2376 | | /* in orig.InChI: not an endpoint, has no H */ |
2377 | | /*pStruct->endpoint[i] && -- modificatuion#1 */ |
2378 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
2379 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
2380 | | /* has (-) edge */ |
2381 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
2382 | 0 | { |
2383 | 0 | iat_SB_O_Minus[num_SB_O_Minus++] = iat; |
2384 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2385 | 0 | { |
2386 | 0 | goto exit_function; |
2387 | 0 | } |
2388 | 0 | } |
2389 | 0 | } |
2390 | 0 | if ((num_try = inchi_min(num_SB_O_Minus, num_DB_O_Neutr))) /* djb-rwth: addressing LLVM warning */ |
2391 | 0 | { |
2392 | | /* detected; attempt to fix */ |
2393 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2394 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
2395 | 0 | delta = 1; |
2396 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
2397 | 0 | { |
2398 | 0 | iat = iat_SB_O_Minus[i]; |
2399 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
2400 | 0 | if (!pe->flow) |
2401 | 0 | continue; |
2402 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
2403 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
2404 | |
|
2405 | 0 | pe->forbidden |= forbidden_edge_mask; |
2406 | 0 | pe->flow -= delta; |
2407 | 0 | pv1->st_edge.flow -= delta; |
2408 | 0 | pv2->st_edge.flow -= delta; |
2409 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2410 | |
|
2411 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2412 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
2413 | |
|
2414 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
2415 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
2416 | 0 | { |
2417 | | /* Moved (-) charge to AB=O => nDeltaCharge == 1 */ |
2418 | | /* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */ |
2419 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
2420 | 0 | if (ret > 0) |
2421 | 0 | { |
2422 | 0 | nNumRunBNS++; |
2423 | 0 | cur_success++; /* 07 */ |
2424 | 0 | } |
2425 | 0 | } |
2426 | 0 | else |
2427 | 0 | { |
2428 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
2429 | 0 | pe->flow += delta; |
2430 | 0 | pv1->st_edge.flow += delta; |
2431 | 0 | pv2->st_edge.flow += delta; |
2432 | 0 | pBNS->tot_st_flow += 2 * delta; |
2433 | 0 | } |
2434 | 0 | INCHI_HEAPCHK |
2435 | 0 | } |
2436 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2437 | 0 | } |
2438 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2439 | 0 | if (cur_success) |
2440 | 0 | { |
2441 | 0 | tot_succes += cur_success; |
2442 | | /* recalculate InChI from the structure */ |
2443 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2444 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
2445 | 0 | { |
2446 | 0 | goto exit_function; |
2447 | 0 | } |
2448 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
2449 | 0 | { |
2450 | 0 | goto exit_function; |
2451 | 0 | } |
2452 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2453 | 0 | { |
2454 | 0 | goto exit_function; /* no fixed-H found */ |
2455 | 0 | } |
2456 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
2457 | 0 | { |
2458 | 0 | goto exit_function; |
2459 | 0 | } |
2460 | 0 | if (!pc2i->bHasDifference) |
2461 | 0 | { |
2462 | 0 | goto exit_function; /* nothing to do */ |
2463 | 0 | } |
2464 | 0 | } |
2465 | 0 | } |
2466 | | |
2467 | 0 | if (pc2i->len_c2at >= 1) |
2468 | 0 | { |
2469 | | /*--------------------------------------------------------------*/ |
2470 | | /* case 07a: restored: O(-)-N(V)B=O original: O=N(V)B-O(-) */ |
2471 | | /* FixH: 0 0 0 -1 */ |
2472 | | /* MobH: 0 0 0 1 */ |
2473 | | /* non-taut (non-taut) non-taut non-taut */ |
2474 | | /* non-taut (taut) non-taut non-taut */ |
2475 | | /* O = O, S, Se, Te */ |
2476 | | /* Solution: move (-) from O(-)-AB to AB=O */ |
2477 | | /*--------------------------------------------------------------*/ |
2478 | 0 | int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat, iN; |
2479 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
2480 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
2481 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
2482 | 0 | cur_success = 0; |
2483 | |
|
2484 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
2485 | 0 | { |
2486 | 0 | iat = pc2i->c2at[i].atomNumber; |
2487 | 0 | if ( /* orig. InChI info: -O(-), non-taut */ |
2488 | 0 | num_DB_O_Neutr < MAX_DIFF_FIXH && |
2489 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
2490 | 0 | !pc2i->c2at[i].endptInChI && |
2491 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
2492 | 0 | pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI == 1 && |
2493 | | /* reversed structure info: */ |
2494 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
2495 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
2496 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence) |
2497 | 0 | { |
2498 | 0 | iat_DB_O_Neutr[num_DB_O_Neutr++] = iat; |
2499 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2500 | 0 | { |
2501 | 0 | goto exit_function; |
2502 | 0 | } |
2503 | 0 | } |
2504 | 0 | } |
2505 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
2506 | 0 | { |
2507 | | /* i = canonical number - 1 */ |
2508 | 0 | iat = nCanon2AtnoRevrs[i]; |
2509 | 0 | if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */ |
2510 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
2511 | 0 | at2[iat].charge == -1 && !at2[iat].num_H && |
2512 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
2513 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
2514 | | /*at_Mobile_H_Revrs && !at_Mobile_H_Revrs[iat].endpoint &&*/ |
2515 | | /* in orig.InChI: not an endpoint, has no H */ |
2516 | 0 | !pStruct->endpoint[i] && |
2517 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
2518 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
2519 | | /* has N(V) neighbor */ |
2520 | 0 | 1 == at2[iat].valence && at2[iN = at2[iat].neighbor[0]].chem_bonds_valence == 5 && |
2521 | 0 | !at2[iN].charge && pVA[iN].cNumValenceElectrons == 5 && |
2522 | | /* has (-) edge */ |
2523 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
2524 | 0 | { |
2525 | 0 | iat_SB_O_Minus[num_SB_O_Minus++] = iat; |
2526 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2527 | 0 | { |
2528 | 0 | goto exit_function; |
2529 | 0 | } |
2530 | 0 | } |
2531 | 0 | } |
2532 | 0 | if ((num_try = inchi_min(num_SB_O_Minus, num_DB_O_Neutr))) /* djb-rwth: addressing LLVM warning */ |
2533 | 0 | { |
2534 | | /* detected; attempt to fix */ |
2535 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2536 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
2537 | 0 | delta = 1; |
2538 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
2539 | 0 | { |
2540 | 0 | iat = iat_SB_O_Minus[i]; |
2541 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
2542 | 0 | if (!pe->flow) |
2543 | 0 | continue; |
2544 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
2545 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
2546 | |
|
2547 | 0 | pe->forbidden |= forbidden_edge_mask; |
2548 | 0 | pe->flow -= delta; |
2549 | 0 | pv1->st_edge.flow -= delta; |
2550 | 0 | pv2->st_edge.flow -= delta; |
2551 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2552 | |
|
2553 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2554 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
2555 | |
|
2556 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
2557 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
2558 | 0 | { |
2559 | | /* Moved (-) charge to AB=O => nDeltaCharge == 1 */ |
2560 | | /* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */ |
2561 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
2562 | 0 | if (ret > 0) |
2563 | 0 | { |
2564 | 0 | nNumRunBNS++; |
2565 | 0 | cur_success++; /* 07 */ |
2566 | 0 | } |
2567 | 0 | } |
2568 | 0 | else |
2569 | 0 | { |
2570 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
2571 | 0 | pe->flow += delta; |
2572 | 0 | pv1->st_edge.flow += delta; |
2573 | 0 | pv2->st_edge.flow += delta; |
2574 | 0 | pBNS->tot_st_flow += 2 * delta; |
2575 | 0 | } |
2576 | 0 | INCHI_HEAPCHK |
2577 | 0 | } |
2578 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2579 | 0 | } |
2580 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2581 | 0 | if (cur_success) |
2582 | 0 | { |
2583 | 0 | tot_succes += cur_success; |
2584 | | /* recalculate InChI from the structure */ |
2585 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2586 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
2587 | 0 | { |
2588 | 0 | goto exit_function; |
2589 | 0 | } |
2590 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
2591 | 0 | { |
2592 | 0 | goto exit_function; |
2593 | 0 | } |
2594 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2595 | 0 | { |
2596 | 0 | goto exit_function; /* no fixed-H found */ |
2597 | 0 | } |
2598 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
2599 | 0 | { |
2600 | 0 | goto exit_function; |
2601 | 0 | } |
2602 | 0 | if (!pc2i->bHasDifference) |
2603 | 0 | { |
2604 | 0 | goto exit_function; /* nothing to do */ |
2605 | 0 | } |
2606 | 0 | } |
2607 | 0 | } |
2608 | | |
2609 | 0 | if ( /*(pc2i->len_c2at >= 1 || pc2i->nNumRemHRevrs) &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */ |
2610 | 0 | (pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1)) |
2611 | 0 | { |
2612 | | /*----------------------------------------------------------------*/ |
2613 | | /* case 08: restored: O(-)-AB=N- OH- orig. O=AB-N(-)- OH- */ |
2614 | | /* FixH: 1 0 0 0 0 1 */ |
2615 | | /* MobH: 0 0 1 0 0 0 */ |
2616 | | /* may be taut or not non-taut taut taut taut */ |
2617 | | /* ADP: one t-group or more endpoints */ |
2618 | | /* O(-) = S, Se, Te; N = N; */ |
2619 | | /* Solution: move (-) from O(-) to =N-; avoid stereogenic DB on N */ |
2620 | | /*----------------------------------------------------------------*/ |
2621 | 0 | int num_DB_N_Neutr = 0, num_SB_O_Minus = 0, iat; |
2622 | |
|
2623 | 0 | AT_NUMB* nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
2624 | 0 | S_CHAR* nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
2625 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
2626 | 0 | cur_success = 0; |
2627 | |
|
2628 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
2629 | 0 | { |
2630 | | /* i = canonical number - 1 */ |
2631 | 0 | iat = nCanon2AtnoRevrs[i]; |
2632 | 0 | if ( /* in restored atom: charge=-1, has no H, has single bond, O, S, Se, Te */ |
2633 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
2634 | 0 | at2[iat].charge == -1 && !at2[iat].num_H && |
2635 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
2636 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
2637 | | /* in orig.InChI: an endpoint, may have fixed-H */ |
2638 | 0 | pStruct->endpoint[i] && |
2639 | | /*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/ |
2640 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
2641 | | /* has (-) edge */ |
2642 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
2643 | 0 | { |
2644 | |
|
2645 | 0 | iat_SB_O_Minus[num_SB_O_Minus++] = iat; |
2646 | |
|
2647 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2648 | 0 | { |
2649 | 0 | goto exit_function; |
2650 | 0 | } |
2651 | 0 | } |
2652 | 0 | else |
2653 | 0 | { |
2654 | 0 | if ( /* in restored atom: charge=0, has no H, has double non-stereogenic bond, N */ |
2655 | 0 | num_DB_N_Neutr < MAX_DIFF_FIXH && |
2656 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && !at2[iat].sb_parity[0] && |
2657 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
2658 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
2659 | | /* in orig.InChI: an endpoint, has no fixed-H */ |
2660 | 0 | pStruct->endpoint[i] && |
2661 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
2662 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
2663 | | /* has (-) edge */ |
2664 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && |
2665 | 0 | 0 == pBNS->edge[e].forbidden) |
2666 | 0 | { |
2667 | |
|
2668 | 0 | iat_DB_N_Neutr[num_DB_N_Neutr++] = iat; |
2669 | |
|
2670 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
2671 | 0 | { |
2672 | 0 | goto exit_function; |
2673 | 0 | } |
2674 | 0 | } |
2675 | 0 | } |
2676 | 0 | } |
2677 | 0 | if ((num_try = inchi_min(num_DB_N_Neutr, num_SB_O_Minus))) /* djb-rwth: addressing LLVM warning */ |
2678 | 0 | { |
2679 | | /* detected; attempt to fix */ |
2680 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2681 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
2682 | | /* allow stereobonds in rings change */ |
2683 | 0 | if (forbidden_stereo_edge_mask) |
2684 | 0 | RemoveForbiddenEdgeMask(pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask); |
2685 | |
|
2686 | 0 | delta = 1; |
2687 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
2688 | 0 | { |
2689 | 0 | iat = iat_SB_O_Minus[i]; |
2690 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
2691 | 0 | if (!pe->flow) |
2692 | 0 | continue; |
2693 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
2694 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
2695 | |
|
2696 | 0 | pe->forbidden |= forbidden_edge_mask; |
2697 | 0 | pe->flow -= delta; |
2698 | 0 | pv1->st_edge.flow -= delta; |
2699 | 0 | pv2->st_edge.flow -= delta; |
2700 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2701 | |
|
2702 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2703 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
2704 | |
|
2705 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
2706 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
2707 | 0 | { |
2708 | | /* Moved (-) charge to =N- => nDeltaCharge == 1 */ |
2709 | | /* Flow change on pe (-)charge edge (atom (-)O-) is not known to RunBnsTestOnce()) */ |
2710 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
2711 | 0 | if (ret > 0) |
2712 | 0 | { |
2713 | 0 | nNumRunBNS++; |
2714 | 0 | cur_success++; /* 08 */ |
2715 | 0 | } |
2716 | 0 | } |
2717 | 0 | else |
2718 | 0 | { |
2719 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
2720 | 0 | pe->flow += delta; |
2721 | 0 | pv1->st_edge.flow += delta; |
2722 | 0 | pv2->st_edge.flow += delta; |
2723 | 0 | pBNS->tot_st_flow += 2 * delta; |
2724 | 0 | } |
2725 | 0 | INCHI_HEAPCHK |
2726 | 0 | } |
2727 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
2728 | 0 | if (forbidden_stereo_edge_mask) |
2729 | 0 | SetForbiddenEdgeMask(pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask); |
2730 | 0 | } |
2731 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2732 | 0 | if (cur_success) |
2733 | 0 | { |
2734 | 0 | tot_succes += cur_success; |
2735 | | /* recalculate InChI from the structure */ |
2736 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2737 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
2738 | 0 | { |
2739 | 0 | goto exit_function; |
2740 | 0 | } |
2741 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
2742 | 0 | { |
2743 | 0 | goto exit_function; |
2744 | 0 | } |
2745 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2746 | 0 | { |
2747 | 0 | goto exit_function; /* no fixed-H found */ |
2748 | 0 | } |
2749 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
2750 | 0 | { |
2751 | 0 | goto exit_function; |
2752 | 0 | } |
2753 | 0 | if (!pc2i->bHasDifference) |
2754 | 0 | { |
2755 | 0 | goto exit_function; /* nothing to do */ |
2756 | 0 | } |
2757 | 0 | } |
2758 | 0 | } |
2759 | | |
2760 | 0 | if (pc2i->len_c2at >= 2) |
2761 | 0 | { |
2762 | | /*--------------------------------------------------------*/ |
2763 | | /* case 09: restored: NH2(+)=C--NH2 orig.: NH2-C(+)-NH2 */ |
2764 | | /* FixH: 2 | 2 0 | 0 */ |
2765 | | /* MobH: 0 0 2 2 */ |
2766 | | /* N = N, taut taut non-taut non-taut*/ |
2767 | | /* Solution: move (+) from NH2(+) to C */ |
2768 | | /*--------------------------------------------------------*/ |
2769 | 0 | int iat; |
2770 | 0 | cur_success = 0; |
2771 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
2772 | 0 | { |
2773 | 0 | iat = pc2i->c2at[i].atomNumber; |
2774 | 0 | if (( pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1 ) && |
2775 | | /* orig. InChI info: */ |
2776 | 0 | !pc2i->c2at[i].endptInChI && |
2777 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI && |
2778 | | /* reversed structure info: */ |
2779 | 0 | pc2i->c2at[i].endptRevrs && |
2780 | 0 | pc2i->c2at[i].nFixHRevrs && !pc2i->c2at[i].nMobHRevrs && |
2781 | 0 | pc2i->c2at[i].nAtChargeRevrs == 1 && |
2782 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence && |
2783 | 0 | ( e = pVA[iat].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden) |
2784 | 0 | { |
2785 | 0 | EdgeIndex eNC = NO_VERTEX, eCPlusC; |
2786 | 0 | int iNH2, iatC, iatNH2; /* djb-rwth: removing redundant variables */ |
2787 | | /* found NH2(+)=; locate =C< and find whether it has -NH2 neighbor */ |
2788 | 0 | for (j = 0; j < at2[iat].valence; j++) |
2789 | 0 | { |
2790 | 0 | if (at2[iat].bond_type[j] == BOND_TYPE_DOUBLE) |
2791 | 0 | break; |
2792 | 0 | } |
2793 | 0 | if (j == at2[iat].valence) |
2794 | 0 | { |
2795 | 0 | continue; |
2796 | 0 | } |
2797 | 0 | eNC = pBNS->vert[iat].iedge[j]; /* edge NH2(+)=C */ |
2798 | 0 | iatC = at2[iat].neighbor[j]; |
2799 | 0 | if (pVA[iatC].cNumValenceElectrons != 4 || pVA[iatC].cMetal || at2[iatC].charge || |
2800 | 0 | at2[iatC].valence != 3 || at2[iatC].valence + 1 != at2[iatC].chem_bonds_valence || |
2801 | 0 | ( eCPlusC = pVA[iatC].nCPlusGroupEdge - 1 ) < 0 || pBNS->edge[eCPlusC].forbidden) |
2802 | 0 | { |
2803 | 0 | continue; |
2804 | 0 | } |
2805 | 0 | for (j = 0; j < at2[iatC].valence; j++) |
2806 | 0 | { |
2807 | 0 | iatNH2 = at2[iatC].neighbor[j]; |
2808 | 0 | if (iatNH2 == iat || pVA[iatNH2].cNumValenceElectrons != 5 || |
2809 | 0 | pVA[iatNH2].cPeriodicRowNumber != 1 || !at2[iatNH2].num_H || at2[iatNH2].charge) |
2810 | 0 | continue; |
2811 | | /* djb-rwth: removing redundant code */ |
2812 | 0 | for (iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2++) |
2813 | 0 | { |
2814 | 0 | if (iatNH2 == pc2i->c2at[iNH2].atomNumber) |
2815 | 0 | break; |
2816 | 0 | } |
2817 | 0 | if (iNH2 == pc2i->len_c2at) |
2818 | 0 | { |
2819 | 0 | continue; |
2820 | 0 | } |
2821 | | |
2822 | 0 | if (( pc2i->c2at[iNH2].nValElectr == 5 && pc2i->c2at[iNH2].nPeriodNum == 1 ) && |
2823 | | /* orig. InChI info: */ |
2824 | 0 | !pc2i->c2at[iNH2].endptInChI && |
2825 | 0 | pc2i->c2at[iNH2].nFixHInChI == 0 && pc2i->c2at[iNH2].nMobHInChI && |
2826 | | /* reversed structure info: */ |
2827 | 0 | pc2i->c2at[iNH2].endptRevrs && |
2828 | 0 | pc2i->c2at[iNH2].nFixHRevrs && !pc2i->c2at[iNH2].nMobHRevrs && |
2829 | 0 | pc2i->c2at[iNH2].nAtChargeRevrs == 0 && |
2830 | 0 | at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence) |
2831 | 0 | { |
2832 | | /* we have found NH2(+)=, =C<, and bond between them */ |
2833 | |
|
2834 | 0 | if ((ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
2835 | 0 | { |
2836 | 0 | goto exit_function; |
2837 | 0 | } |
2838 | 0 | if ((ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
2839 | 0 | { |
2840 | 0 | goto exit_function; |
2841 | 0 | } |
2842 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
2843 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask ); |
2844 | 0 | delta = 1; |
2845 | |
|
2846 | 0 | pe = pBNS->edge + eNC; |
2847 | 0 | if (!pe->flow) |
2848 | 0 | continue; |
2849 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
2850 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
2851 | |
|
2852 | 0 | pe->forbidden |= forbidden_edge_mask; |
2853 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
2854 | 0 | pv1->st_edge.flow -= delta; |
2855 | 0 | pv2->st_edge.flow -= delta; |
2856 | 0 | pBNS->tot_st_flow -= 2 * delta; |
2857 | |
|
2858 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
2859 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
2860 | |
|
2861 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
2862 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 0) /* djb-rwth: addressing LLVM warnings */ |
2863 | 0 | { |
2864 | | /* Removed (+)charge from -NHn => nDeltaCharge == -1 */ |
2865 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
2866 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
2867 | 0 | if (ret > 0) |
2868 | 0 | { |
2869 | 0 | nNumRunBNS++; |
2870 | 0 | cur_success++; /* 09 */ |
2871 | 0 | } |
2872 | 0 | } |
2873 | 0 | else |
2874 | 0 | { |
2875 | 0 | pe->flow += delta; |
2876 | 0 | pv1->st_edge.flow += delta; |
2877 | 0 | pv2->st_edge.flow += delta; |
2878 | 0 | pBNS->tot_st_flow += 2 * delta; |
2879 | 0 | } |
2880 | 0 | INCHI_HEAPCHK |
2881 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
2882 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
2883 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
2884 | 0 | break; |
2885 | 0 | } |
2886 | 0 | } |
2887 | 0 | } |
2888 | 0 | } |
2889 | 0 | if (cur_success) |
2890 | 0 | { |
2891 | 0 | tot_succes += cur_success; |
2892 | | /* recalculate InChI from the structure */ |
2893 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
2894 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
2895 | 0 | { |
2896 | 0 | goto exit_function; |
2897 | 0 | } |
2898 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
2899 | 0 | { |
2900 | 0 | goto exit_function; |
2901 | 0 | } |
2902 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
2903 | 0 | { |
2904 | 0 | goto exit_function; /* no fixed-H found */ |
2905 | 0 | } |
2906 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
2907 | 0 | { |
2908 | 0 | goto exit_function; |
2909 | 0 | } |
2910 | 0 | if (!pc2i->bHasDifference) |
2911 | 0 | { |
2912 | 0 | goto exit_function; /* nothing to do */ |
2913 | 0 | } |
2914 | 0 | } |
2915 | 0 | } |
2916 | | |
2917 | 0 | if (pc2i->len_c2at >= 2) |
2918 | 0 | { |
2919 | | /*--------------------------------------------------------*/ |
2920 | | /* case 10: restored: NH2-X(+)-NH- orig.: NH2(+)=X-NH- */ |
2921 | | /* FixH: 0 0 2 1 */ |
2922 | | /* MobH: 2 1 0 0 */ |
2923 | | /* N = N,O,S,Se,Te non-taut non-taut taut taut */ |
2924 | | /* Solution: move (+) from X(+) to NH2 or NH */ |
2925 | | /*--------------------------------------------------------*/ |
2926 | 0 | int iat; |
2927 | 0 | cur_success = 0; |
2928 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
2929 | 0 | { |
2930 | 0 | if (pc2i->c2at[i].nValue) |
2931 | 0 | continue; |
2932 | 0 | iat = pc2i->c2at[i].atomNumber; |
2933 | 0 | if (( pc2i->c2at[i].nValElectr == 6 || |
2934 | 0 | (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) ) && |
2935 | | /* orig. InChI info: */ |
2936 | 0 | pc2i->c2at[i].endptInChI && |
2937 | 0 | pc2i->c2at[i].nFixHInChI && !pc2i->c2at[i].nMobHInChI && |
2938 | | /* reversed structure info: */ |
2939 | 0 | !pc2i->c2at[i].endptRevrs && |
2940 | 0 | !pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs && |
2941 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && |
2942 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && |
2943 | 0 | ( e = pVA[iat].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
2944 | 0 | { |
2945 | |
|
2946 | 0 | EdgeIndex eCPlusC, eCPlusNH2, bContinue = 1; |
2947 | 0 | int iNH2, iatC, iatNH2, j1, j2; /* djb-rwth: removing redundant variables */ |
2948 | 0 | BNS_EDGE *pe_iat, *pe_iNH2; |
2949 | | /* found NH2- locate -X(+) and find whether it has another -NH2 neighbor */ |
2950 | 0 | for (j1 = 0; j1 < at2[iat].valence && bContinue; j1++) |
2951 | 0 | { |
2952 | 0 | if (at2[iat].bond_type[j1] == BOND_TYPE_SINGLE && |
2953 | 0 | at2[iatC = at2[iat].neighbor[j1]].charge == 1 && |
2954 | 0 | ( 4 <= pVA[iatC].cNumValenceElectrons && pVA[iatC].cNumValenceElectrons <= 6 ) && |
2955 | 0 | at2[iatC].valence == at2[iatC].chem_bonds_valence && |
2956 | 0 | ( eCPlusC = pVA[iatC].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[eCPlusC].forbidden) |
2957 | 0 | { |
2958 | | /* found a candidate for X; find another NH2 */ |
2959 | 0 | for (j2 = 0; j2 < at2[iatC].valence && bContinue; j2++) |
2960 | 0 | { |
2961 | 0 | if (at2[iatC].bond_type[j2] == BOND_TYPE_SINGLE && |
2962 | 0 | iat != ( iatNH2 = at2[iatC].neighbor[j2] ) && |
2963 | 0 | at2[iatNH2].charge == 0 && at2[iatNH2].num_H && |
2964 | 0 | ( pVA[iatNH2].cNumValenceElectrons == 5 || pVA[iatNH2].cNumValenceElectrons == 6 ) && |
2965 | 0 | at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence && |
2966 | 0 | ( eCPlusNH2 = pVA[iatNH2].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[eCPlusNH2].forbidden) |
2967 | 0 | { |
2968 | 0 | for (iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2++) |
2969 | 0 | { |
2970 | 0 | if (iatNH2 != pc2i->c2at[iNH2].atomNumber || pc2i->c2at[iNH2].nValue) |
2971 | 0 | continue; |
2972 | | /* check the second -NH */ |
2973 | | /* djb-rwth: removing redundant code */ |
2974 | 0 | if ( /* orig. InChI info: */ |
2975 | 0 | pc2i->c2at[iNH2].endptInChI && |
2976 | 0 | pc2i->c2at[iNH2].nFixHInChI && !pc2i->c2at[iNH2].nMobHInChI && |
2977 | | /* reversed structure info: */ |
2978 | 0 | !pc2i->c2at[iNH2].endptRevrs && |
2979 | 0 | !pc2i->c2at[iNH2].nFixHRevrs && pc2i->c2at[iNH2].nMobHRevrs && |
2980 | 0 | pc2i->c2at[iNH2].nAtChargeRevrs == 0) |
2981 | 0 | { |
2982 | | /* we have found NH-X(+)-NH; remove charge from X(+) */ |
2983 | 0 | pe_iat = pBNS->edge + pBNS->vert[iat].iedge[j1]; |
2984 | 0 | pe_iNH2 = pBNS->edge + pBNS->vert[iatC].iedge[j2]; |
2985 | | /* pick up one of -NH to move (+) to it */ |
2986 | 0 | if (!pe_iat->forbidden && pBNS->edge[e].flow) |
2987 | 0 | { |
2988 | 0 | pe = pBNS->edge + e; |
2989 | 0 | } |
2990 | 0 | else |
2991 | 0 | if (!pe_iNH2->forbidden && pBNS->edge[eCPlusNH2].flow) |
2992 | 0 | { |
2993 | 0 | pe = pBNS->edge + eCPlusNH2; |
2994 | 0 | } |
2995 | 0 | else |
2996 | 0 | { |
2997 | 0 | continue; /* none of the two -X(+)- bonds may be changed */ |
2998 | 0 | } |
2999 | 0 | if ((ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
3000 | 0 | { |
3001 | 0 | goto exit_function; |
3002 | 0 | } |
3003 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
3004 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask ); |
3005 | 0 | delta = 1; |
3006 | |
|
3007 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
3008 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
3009 | | |
3010 | | /*pe->forbidden |= forbidden_edge_mask;*/ |
3011 | 0 | pe->flow -= delta; /* add (+) to -NHm */ |
3012 | 0 | pv1->st_edge.flow -= delta; |
3013 | 0 | pv2->st_edge.flow -= delta; |
3014 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3015 | |
|
3016 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3017 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
3018 | |
|
3019 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
3020 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == -1) /* djb-rwth: addressing LLVM warnings */ |
3021 | 0 | { |
3022 | | /* Removed (+)charge from -NHn => nDeltaCharge == -1 */ |
3023 | | /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */ |
3024 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
3025 | 0 | if (ret > 0) |
3026 | 0 | { |
3027 | 0 | nNumRunBNS++; |
3028 | 0 | cur_success++; /* 10 */ |
3029 | 0 | bContinue = 0; |
3030 | 0 | pc2i->c2at[i].nValue = 1; /* mark as used */ |
3031 | 0 | pc2i->c2at[iNH2].nValue = 1; /* mark as used */ |
3032 | 0 | } |
3033 | 0 | } |
3034 | 0 | else |
3035 | 0 | { |
3036 | 0 | pe->flow += delta; |
3037 | 0 | pv1->st_edge.flow += delta; |
3038 | 0 | pv2->st_edge.flow += delta; |
3039 | 0 | pBNS->tot_st_flow += 2 * delta; |
3040 | 0 | } |
3041 | 0 | INCHI_HEAPCHK |
3042 | | |
3043 | | /*pe->forbidden &= forbidden_edge_mask_inv;*/ |
3044 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
3045 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
3046 | 0 | break; |
3047 | 0 | } |
3048 | 0 | } /* iNH2: pc2i->c2at[iNH2] cycle */ |
3049 | 0 | } |
3050 | 0 | } /* j2: iatC neighbors cycle */ |
3051 | 0 | } |
3052 | 0 | } /* j1: iat neighbors cycle */ |
3053 | 0 | } |
3054 | 0 | } /* i: pc2i->c2at[i] cycle */ |
3055 | | |
3056 | 0 | if (cur_success) |
3057 | 0 | { |
3058 | | /* |
3059 | | for ( i = 0; i < pc2i->len_c2at; i ++ ) { |
3060 | | pc2i->c2at[i].nValue = 0; |
3061 | | } |
3062 | | */ |
3063 | 0 | tot_succes += cur_success; |
3064 | | /* recalculate InChI from the structure */ |
3065 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
3066 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
3067 | 0 | { |
3068 | 0 | goto exit_function; |
3069 | 0 | } |
3070 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
3071 | 0 | { |
3072 | 0 | goto exit_function; |
3073 | 0 | } |
3074 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
3075 | 0 | { |
3076 | 0 | goto exit_function; /* no fixed-H found */ |
3077 | 0 | } |
3078 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
3079 | 0 | { |
3080 | 0 | goto exit_function; |
3081 | 0 | } |
3082 | 0 | if (!pc2i->bHasDifference) |
3083 | 0 | { |
3084 | 0 | goto exit_function; /* nothing to do */ |
3085 | 0 | } |
3086 | 0 | } |
3087 | 0 | } |
3088 | | |
3089 | 0 | if ( /*pc2i->len_c2at >= 1 &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */ |
3090 | 0 | ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 )) |
3091 | 0 | { |
3092 | | /*--------------------------------------------------------------*/ |
3093 | | /* case 11: restored: NH(+)=AB-N< OH- orig. NH-AB=N(+)< OH- */ |
3094 | | /* FixH: 0 0 0 1 0 1 */ |
3095 | | /* MobH: 1 0 1 0 0 0 */ |
3096 | | /* non-taut. taut taut */ |
3097 | | /* ADP: one t-group or more endpoints */ |
3098 | | /* NH(+)= => N, O, S, Se; -N< => N */ |
3099 | | /* Solution: move (+) from NH(+) to -N< */ |
3100 | | /*--------------------------------------------------------------*/ |
3101 | 0 | int num_SB_Neutr = 0, num_DB_Charged = 0, iat; |
3102 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
3103 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
3104 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
3105 | 0 | cur_success = 0; |
3106 | | |
3107 | | /* search for NH(+)= */ |
3108 | | /* search for -N< */ |
3109 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
3110 | 0 | { /* i = canonical number - 1 */ |
3111 | 0 | iat = nCanon2AtnoRevrs[i]; |
3112 | 0 | if ( /* in restored atom: charge=0, has no H, has no double bond, N only */ |
3113 | 0 | num_DB_Charged < MAX_DIFF_FIXH && |
3114 | 0 | at2[iat].charge == 1 && at2[iat].num_H && |
3115 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
3116 | 0 | ((pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) || |
3117 | 0 | pVA[iat].cNumValenceElectrons == 6) && |
3118 | | /* in orig.InChI: an endpoint, has fixed-H */ |
3119 | | /*pStruct->endpoint[i] &&*/ |
3120 | 0 | (pStruct->fixed_H && pStruct->fixed_H[i]) && |
3121 | | /*!(nMobHInChI && nMobHInChI[i] ) &&*/ |
3122 | | /* has (+) edge */ |
3123 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && 0 == pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
3124 | 0 | { |
3125 | |
|
3126 | 0 | iat_DB_Charged[num_DB_Charged++] = iat; |
3127 | | /* |
3128 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
3129 | | goto exit_function; |
3130 | | } |
3131 | | */ |
3132 | 0 | } |
3133 | 0 | else |
3134 | 0 | { |
3135 | 0 | if ( /* in restored atom: charge=0, has no H, has no double bond, N only */ |
3136 | 0 | num_SB_Neutr < MAX_DIFF_FIXH && |
3137 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
3138 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
3139 | 0 | (pVA[iat].cNumValenceElectrons == 5 && |
3140 | 0 | pVA[iat].cPeriodicRowNumber == 1) && |
3141 | | /* in orig.InChI: an endpoint, has fixed-H */ |
3142 | | /*pStruct->endpoint[i] &&*/ |
3143 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
3144 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
3145 | | /* has (+) edge */ |
3146 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && 0 == pBNS->edge[e].forbidden) |
3147 | 0 | { |
3148 | |
|
3149 | 0 | iat_SB_Neutr[num_SB_Neutr++] = iat; |
3150 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3151 | 0 | { |
3152 | 0 | goto exit_function; |
3153 | 0 | } |
3154 | 0 | } |
3155 | 0 | } |
3156 | 0 | } |
3157 | 0 | if ((num_try = inchi_min(num_SB_Neutr, num_DB_Charged))) /* djb-rwth: addressing LLVM warning */ |
3158 | 0 | { |
3159 | | /* detected; attempt to fix */ |
3160 | 0 | BNS_VERTEX* pv1n, * pv2n; |
3161 | 0 | BNS_EDGE* pe1n, * pe2n; |
3162 | 0 | Vertex v1n, v2n; |
3163 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3164 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
3165 | 0 | delta = 1; |
3166 | 0 | for (i = 0; i < num_DB_Charged && cur_success < num_try; i++) |
3167 | 0 | { |
3168 | 0 | iat = iat_DB_Charged[i]; |
3169 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
3170 | 0 | if (pe->flow) |
3171 | 0 | continue; |
3172 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
3173 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
3174 | |
|
3175 | 0 | for (j = pv1->num_adj_edges - 1; 0 <= j; j--) |
3176 | 0 | { |
3177 | 0 | pe1n = pBNS->edge + pv1->iedge[j]; |
3178 | 0 | if (pe1n->flow && !pe1n->forbidden) |
3179 | 0 | { |
3180 | 0 | pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1); |
3181 | 0 | break; |
3182 | 0 | } |
3183 | 0 | } |
3184 | 0 | if (j < 0) |
3185 | 0 | { |
3186 | 0 | continue; /* not found */ |
3187 | 0 | } |
3188 | | |
3189 | 0 | for (j = pv2->num_adj_edges - 2; 0 <= j; j--) |
3190 | 0 | { |
3191 | 0 | pe2n = pBNS->edge + pv2->iedge[j]; |
3192 | 0 | if (pe2n->flow && !pe2n->forbidden) |
3193 | 0 | { |
3194 | 0 | pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2); |
3195 | 0 | break; |
3196 | 0 | } |
3197 | 0 | } |
3198 | 0 | if (j < 0) |
3199 | 0 | { |
3200 | 0 | continue; /* not found */ |
3201 | 0 | } |
3202 | | |
3203 | 0 | pe->flow += delta; |
3204 | 0 | pe1n->flow -= delta; |
3205 | 0 | pe2n->flow -= delta; |
3206 | 0 | pv1n->st_edge.flow -= delta; |
3207 | 0 | pv2n->st_edge.flow -= delta; |
3208 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3209 | |
|
3210 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3211 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
3212 | |
|
3213 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
3214 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
3215 | 0 | (nDeltaCharge == 0 || nDeltaCharge == 1)) /* djb-rwth: addressing LLVM warnings */ |
3216 | 0 | { |
3217 | | /* before setting flows the structure could be: |
3218 | | [NH+ neigh, v1n]=e1n=[NH+,v1]-pe-[+,v2]=e2n=[another at or its chargeStruct] |
3219 | | or |
3220 | | |
3221 | | [NH+ or ChStr, v1n]=pe1n=[NH+ or ChStr, v1]-pe-[+,v2]=pe2n=[at2 or ChStr, v2n] |
3222 | | ^ ^ ^ |
3223 | | NH+(+)edge | N (+) edge: only |
3224 | | | these are not forbidden |
3225 | | | |
3226 | | hetero (+) vertex |
3227 | | |
3228 | | After setting flows (* mark radicals, =pe= is forbidden): |
3229 | | |
3230 | | *[NH+ or ChStr, v1n]-pe1n-[NH+ or ChStr, v1]=pe=[+,v2]-pe2n-[at2 or ChStr, v2n]* |
3231 | | ^ ^ ^ |
3232 | | NH+(+)edge | N (+) edge: only |
3233 | | | these are not forbidden |
3234 | | | |
3235 | | hetero (+) vertex |
3236 | | |
3237 | | Flow in |
3238 | | pe1n and pe2n will or will not change, depending on the structure. |
3239 | | |
3240 | | Consider what happens if pe2n changes. It may only increment. |
3241 | | If pe2n flow increments then another (+)edge flow dectrements. If |
3242 | | [at2 or ChStr, v2n] is at2 then at2 charge would change from (+) to 0, |
3243 | | and another N charge would change from 0 to (+), giving tot. change of |
3244 | | number of charges (-1)+(+1)=0. However, if [at2 or ChStr, v2n] is |
3245 | | ChargeStruct then at2 will not be on the alt path and only the creation |
3246 | | of another (+) will be detected. |
3247 | | */ |
3248 | | /* Removed charge from O(+) => nDeltaCharge == -1 */ |
3249 | | /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */ |
3250 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
3251 | 0 | if (ret > 0) |
3252 | 0 | { |
3253 | 0 | nNumRunBNS++; |
3254 | 0 | cur_success++; /* 11 */ |
3255 | 0 | } |
3256 | 0 | } |
3257 | 0 | else |
3258 | 0 | { |
3259 | 0 | pe->flow -= delta; |
3260 | 0 | pe1n->flow += delta; |
3261 | 0 | pe2n->flow += delta; |
3262 | 0 | pv1n->st_edge.flow += delta; |
3263 | 0 | pv2n->st_edge.flow += delta; |
3264 | 0 | pBNS->tot_st_flow += 2 * delta; |
3265 | 0 | } |
3266 | 0 | INCHI_HEAPCHK |
3267 | 0 | } |
3268 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3269 | 0 | } |
3270 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
3271 | 0 | if (cur_success) |
3272 | 0 | { |
3273 | 0 | tot_succes += cur_success; |
3274 | | /* recalculate InChI from the structure */ |
3275 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
3276 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
3277 | 0 | { |
3278 | 0 | goto exit_function; |
3279 | 0 | } |
3280 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
3281 | 0 | { |
3282 | 0 | goto exit_function; |
3283 | 0 | } |
3284 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
3285 | 0 | { |
3286 | 0 | goto exit_function; /* no fixed-H found */ |
3287 | 0 | } |
3288 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
3289 | 0 | { |
3290 | 0 | goto exit_function; |
3291 | 0 | } |
3292 | 0 | if (!pc2i->bHasDifference) |
3293 | 0 | { |
3294 | 0 | goto exit_function; /* nothing to do */ |
3295 | 0 | } |
3296 | 0 | } |
3297 | 0 | } |
3298 | | |
3299 | 0 | if (pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 && |
3300 | 0 | pc2i->nNumRemHInChI >= -1 && /* 2006-03-03 */ |
3301 | 0 | ( pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs || pc2i->nNumTgRevrs > 1 ) /* ADP in InChI */) |
3302 | 0 | { |
3303 | | /*--------------------------------------------------------------*/ |
3304 | | /* case 12: restored: O=AB-N< original: (-)O-AB=N(+)< */ |
3305 | | /* FixH: 0 0 0 0 */ |
3306 | | /* MobH: 0 0 0 0 */ |
3307 | | /* non-taut taut */ |
3308 | | /* O = O, S, Se, N; N = N; */ |
3309 | | /* restored atom O is not tautomeric; original atom O is taut. */ |
3310 | | /* original struct has 1 t-group; restored has less endpoints */ |
3311 | | /* and/or possibly >1 t-groups */ |
3312 | | /* Solution: separate charges between O= and -N< */ |
3313 | | /* allow moving charge to N(V) to make it N(IV)(+) */ |
3314 | | /*--------------------------------------------------------------*/ |
3315 | 0 | int bOnly_N_V = 1; |
3316 | | /* djb-rwth: removing redundant code */ |
3317 | 0 | while (1) |
3318 | 0 | { |
3319 | 0 | int num_SB_N_Neutr = 0, num_DB_O = 0, iat, num_N_V = 0, bN_V; |
3320 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
3321 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
3322 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
3323 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
3324 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
3325 | 0 | cur_success = 0; |
3326 | |
|
3327 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
3328 | 0 | { |
3329 | 0 | iat = pc2i->c2at[i].atomNumber; |
3330 | 0 | if ( /* orig. InChI info: -O(-) */ |
3331 | 0 | num_DB_O < MAX_DIFF_FIXH && |
3332 | 0 | (pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ || |
3333 | 0 | (pc2i->c2at[i].nValElectr == 5 && |
3334 | 0 | pc2i->c2at[i].nPeriodNum == 1) /* N */) && /* djb-rwth: addressing LLVM warning */ |
3335 | 0 | pc2i->c2at[i].endptInChI && |
3336 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
3337 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
3338 | | /* reversed structure info: */ |
3339 | 0 | !pc2i->c2at[i].endptRevrs && |
3340 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
3341 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
3342 | 0 | ((pc2i->c2at[i].nValElectr == 6) ? |
3343 | 0 | (at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) : |
3344 | 0 | (pc2i->c2at[i].nValElectr == 5) ? |
3345 | 0 | (at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3) : |
3346 | 0 | 0)) |
3347 | 0 | { |
3348 | |
|
3349 | 0 | iat_DB_O[num_DB_O++] = iat; |
3350 | | /* |
3351 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
3352 | | goto exit_function; |
3353 | | } |
3354 | | */ |
3355 | 0 | } |
3356 | 0 | } |
3357 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
3358 | 0 | { |
3359 | | /* i = canonical number - 1 */ |
3360 | 0 | iat = nCanon2AtnoRevrs[i]; |
3361 | 0 | bN_V = 0; |
3362 | 0 | if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */ |
3363 | 0 | num_SB_N_Neutr < MAX_DIFF_FIXH && |
3364 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
3365 | 0 | (at2[iat].valence == at2[iat].chem_bonds_valence || |
3366 | 0 | (bN_V = at2[iat].valence + 2 == at2[iat].chem_bonds_valence)) && |
3367 | 0 | !pVA[iat].cMetal && |
3368 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
3369 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) && |
3370 | | /* in orig.InChI: not an endpoint, has no H */ |
3371 | 0 | !pStruct->endpoint[i] && |
3372 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
3373 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
3374 | | /* has (+) edge */ |
3375 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
3376 | 0 | { |
3377 | |
|
3378 | 0 | if (bOnly_N_V && bN_V && |
3379 | 0 | NO_VERTEX != (j = GetChargeFlowerUpperEdge(pBNS, pVA, e)) && |
3380 | 0 | !pBNS->edge[j].forbidden && !pBNS->edge[j].flow) |
3381 | 0 | { |
3382 | 0 | if (!num_N_V) |
3383 | 0 | { |
3384 | | /* switch to N(V) only mode */ |
3385 | 0 | CurrEdges.num_edges = 0; |
3386 | 0 | num_SB_N_Neutr = 0; |
3387 | 0 | } |
3388 | 0 | iat_SB_N_Neutr[num_SB_N_Neutr++] = iat; |
3389 | 0 | num_N_V++; |
3390 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3391 | 0 | { |
3392 | 0 | goto exit_function; |
3393 | 0 | } |
3394 | 0 | if ((ret = AddToEdgeList(&CurrEdges, j, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3395 | 0 | { |
3396 | 0 | goto exit_function; |
3397 | 0 | } |
3398 | 0 | } |
3399 | 0 | else |
3400 | 0 | { |
3401 | 0 | if (!num_N_V) |
3402 | 0 | { |
3403 | 0 | iat_SB_N_Neutr[num_SB_N_Neutr++] = iat; |
3404 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3405 | 0 | { |
3406 | 0 | goto exit_function; |
3407 | 0 | } |
3408 | | /* in addition, permit N(V)=>N(IV)(+) change by allowing charge flower edge change flow */ |
3409 | 0 | if (bN_V && NO_VERTEX != (j = GetChargeFlowerUpperEdge(pBNS, pVA, e)) && |
3410 | 0 | !pBNS->edge[j].forbidden && !pBNS->edge[j].flow) |
3411 | 0 | { |
3412 | 0 | if ((ret = AddToEdgeList(&CurrEdges, j, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3413 | 0 | { |
3414 | 0 | goto exit_function; |
3415 | 0 | } |
3416 | 0 | } |
3417 | 0 | } |
3418 | 0 | } |
3419 | 0 | } |
3420 | 0 | } |
3421 | 0 | if ((num_try = inchi_min(num_SB_N_Neutr, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
3422 | 0 | { |
3423 | | /* detected; attempt to fix */ |
3424 | 0 | BNS_EDGE* pe_CMinus; |
3425 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3426 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
3427 | 0 | delta = 1; |
3428 | 0 | for (i = 0; i < num_DB_O && cur_success < num_try; i++) |
3429 | 0 | { |
3430 | 0 | iat = iat_DB_O[i]; |
3431 | 0 | pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
3432 | 0 | pe_CMinus->forbidden &= forbidden_edge_mask_inv; |
3433 | |
|
3434 | 0 | pe = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/ |
3435 | 0 | if (!pe->flow) |
3436 | 0 | continue; |
3437 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
3438 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
3439 | |
|
3440 | 0 | pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */ |
3441 | 0 | pe->flow -= delta; |
3442 | 0 | pv1->st_edge.flow -= delta; |
3443 | 0 | pv2->st_edge.flow -= delta; |
3444 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3445 | |
|
3446 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3447 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
3448 | |
|
3449 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
3450 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 2) /* djb-rwth: addressing LLVM warnings */ |
3451 | 0 | { |
3452 | | /* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */ |
3453 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
3454 | 0 | if (ret > 0) |
3455 | 0 | { |
3456 | 0 | nNumRunBNS++; |
3457 | 0 | cur_success++; /* 12 */ |
3458 | 0 | } |
3459 | 0 | } |
3460 | 0 | else |
3461 | 0 | { |
3462 | 0 | pe->flow += delta; |
3463 | 0 | pv1->st_edge.flow += delta; |
3464 | 0 | pv2->st_edge.flow += delta; |
3465 | 0 | pBNS->tot_st_flow += 2 * delta; |
3466 | 0 | } |
3467 | 0 | pe->forbidden &= forbidden_edge_mask_inv; /* allow changes to O=X bond */ |
3468 | 0 | INCHI_HEAPCHK |
3469 | 0 | } |
3470 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3471 | 0 | } |
3472 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
3473 | 0 | if (cur_success) |
3474 | 0 | { |
3475 | 0 | tot_succes += cur_success; |
3476 | | /* recalculate InChI from the structure */ |
3477 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
3478 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
3479 | 0 | { |
3480 | 0 | goto exit_function; |
3481 | 0 | } |
3482 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
3483 | 0 | { |
3484 | 0 | goto exit_function; |
3485 | 0 | } |
3486 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
3487 | 0 | { |
3488 | 0 | goto exit_function; /* no fixed-H found */ |
3489 | 0 | } |
3490 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
3491 | 0 | { |
3492 | 0 | goto exit_function; |
3493 | 0 | } |
3494 | 0 | if (!pc2i->bHasDifference) |
3495 | 0 | { |
3496 | 0 | goto exit_function; /* nothing to do */ |
3497 | 0 | } |
3498 | 0 | break; |
3499 | 0 | } |
3500 | 0 | else |
3501 | 0 | { |
3502 | 0 | if (bOnly_N_V) |
3503 | 0 | { |
3504 | 0 | bOnly_N_V = 0; |
3505 | 0 | } |
3506 | 0 | else |
3507 | 0 | { |
3508 | 0 | break; |
3509 | 0 | } |
3510 | 0 | } |
3511 | 0 | } |
3512 | 0 | } |
3513 | | |
3514 | | |
3515 | 0 | if (pc2i->nNumTgDiffMinus /*|| pc2i->nNumTgDiffH */ /* no ADP in InChI needed */) |
3516 | 0 | { |
3517 | | /*--------------------------------------------------------------*/ |
3518 | | /* | | */ |
3519 | | /* case 13: restored: O=AB=N= original: (-)O-AB-N(+)= */ |
3520 | | /* FixH: 0 0 0 0 */ |
3521 | | /* MobH: 0 0 0 0 */ |
3522 | | /* non-taut taut non-taut */ |
3523 | | /* O = O, S, Se, N; N = N, P, ... */ |
3524 | | /* t-group in original has same num. endpoints */ |
3525 | | /* same num_H and less (-) than in the restored structure */ |
3526 | | /* original atom O is tautomeric, N is not taut in both */ |
3527 | | /* original struct has 1 t-group; restored has less endpoints */ |
3528 | | /* and/or possibly >1 t-groups */ |
3529 | | /* Solution: separate charges between O= and -N< */ |
3530 | | /* allow moving charge to N(V) to make it N(IV)(+) */ |
3531 | | /*--------------------------------------------------------------*/ |
3532 | 0 | int itg; |
3533 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
3534 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
3535 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
3536 | |
|
3537 | 0 | S_CHAR *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed ? pStruct->pOneINChI[0]->nNum_H_fixed : NULL; |
3538 | 0 | S_CHAR *pnMobHRevrs = ( pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H ) ? |
3539 | 0 | pStruct->pOneINChI[1]->nNum_H : |
3540 | 0 | ( pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H ) ? |
3541 | 0 | pStruct->pOneINChI[0]->nNum_H : NULL; |
3542 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
3543 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
3544 | | /* djb-rwth: removing redundant code */ |
3545 | | /* find whether this may help */ |
3546 | 0 | for (itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg++) |
3547 | 0 | { |
3548 | 0 | if (pStruct->ti.t_group[itg].nNumEndpoints == pStruct->One_ti.t_group[itg].nNumEndpoints && |
3549 | 0 | pStruct->ti.t_group[itg].num[0] - pStruct->ti.t_group[itg].num[1] == |
3550 | 0 | pStruct->One_ti.t_group[itg].num[0] - pStruct->One_ti.t_group[itg].num[1] && |
3551 | 0 | pStruct->ti.t_group[itg].num[1] > pStruct->One_ti.t_group[itg].num[1]) |
3552 | 0 | { |
3553 | | /* restored InChI t-group has more (-) and same number of H */ |
3554 | 0 | int num_SB_N_Neutr = 0, num_DB_O = 0, iat; |
3555 | 0 | cur_success = 0; |
3556 | |
|
3557 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
3558 | 0 | { /* i = canonical number - 1 */ |
3559 | 0 | iat = nCanon2AtnoRevrs[i]; |
3560 | 0 | if ( /* orig. InChI info: -O(-) */ |
3561 | 0 | num_DB_O < MAX_DIFF_FIXH && |
3562 | 0 | (pVA[i].cNumValenceElectrons == 6 /* O, S, Se, Te */) && |
3563 | 0 | pStruct->endpoint[i] == itg + 1 && |
3564 | 0 | (e = pVA[i].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
3565 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
3566 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
3567 | | /* reversed structure info: */ |
3568 | | /*!pc2i->c2at[i].endptRevrs &&*/ |
3569 | 0 | !(num_Fixed_H_Revrs && num_Fixed_H_Revrs[iat]) && |
3570 | 0 | !(pnMobHRevrs && pnMobHRevrs[iat]) && |
3571 | 0 | at2[iat].charge == 0 && at2[iat].num_H == 0 && |
3572 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) |
3573 | 0 | { |
3574 | |
|
3575 | 0 | iat_DB_O[num_DB_O++] = iat; |
3576 | | /* |
3577 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
3578 | | goto exit_function; |
3579 | | } |
3580 | | */ |
3581 | 0 | } |
3582 | 0 | else |
3583 | 0 | { |
3584 | 0 | if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */ |
3585 | 0 | num_SB_N_Neutr < MAX_DIFF_FIXH && |
3586 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
3587 | | /*at2[iat].valence == at2[iat].chem_bonds_valence ||*/ |
3588 | 0 | (at2[iat].valence == 4 && at2[iat].chem_bonds_valence == 5) && |
3589 | 0 | !pVA[iat].cMetal && |
3590 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber >= 1 && |
3591 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) && |
3592 | | /* in orig.InChI: not an endpoint, has no H */ |
3593 | 0 | !pStruct->endpoint[i] && |
3594 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
3595 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
3596 | | /* has (+) edge */ |
3597 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
3598 | 0 | { |
3599 | |
|
3600 | 0 | iat_SB_N_Neutr[num_SB_N_Neutr++] = iat; |
3601 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
3602 | 0 | { |
3603 | 0 | goto exit_function; |
3604 | 0 | } |
3605 | 0 | } |
3606 | 0 | } |
3607 | 0 | } |
3608 | 0 | if ((num_try = inchi_min(num_SB_N_Neutr, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
3609 | 0 | { |
3610 | | /* detected; attempt to fix */ |
3611 | 0 | BNS_EDGE* pe_CMinus; |
3612 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3613 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
3614 | 0 | delta = 1; |
3615 | 0 | for (i = 0; i < num_DB_O && cur_success < num_try; i++) |
3616 | 0 | { |
3617 | 0 | iat = iat_DB_O[i]; |
3618 | 0 | pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
3619 | 0 | pe_CMinus->forbidden &= forbidden_edge_mask_inv; |
3620 | |
|
3621 | 0 | pe = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/ |
3622 | 0 | if (!pe->flow) |
3623 | 0 | continue; |
3624 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
3625 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
3626 | |
|
3627 | 0 | pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */ |
3628 | 0 | pe->flow -= delta; |
3629 | 0 | pv1->st_edge.flow -= delta; |
3630 | 0 | pv2->st_edge.flow -= delta; |
3631 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3632 | |
|
3633 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3634 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
3635 | |
|
3636 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
3637 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 2) /* djb-rwth: addressing LLVM warning */ |
3638 | 0 | { |
3639 | | /* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */ |
3640 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
3641 | 0 | if (ret > 0) |
3642 | 0 | { |
3643 | 0 | nNumRunBNS++; |
3644 | 0 | cur_success++; /* 13 */ |
3645 | 0 | } |
3646 | 0 | } |
3647 | 0 | else |
3648 | 0 | { |
3649 | 0 | pe->flow += delta; |
3650 | 0 | pv1->st_edge.flow += delta; |
3651 | 0 | pv2->st_edge.flow += delta; |
3652 | 0 | pBNS->tot_st_flow += 2 * delta; |
3653 | 0 | } |
3654 | 0 | pe->forbidden &= forbidden_edge_mask_inv; /* allow changes to O=X bond */ |
3655 | 0 | INCHI_HEAPCHK |
3656 | 0 | } |
3657 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3658 | 0 | } |
3659 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
3660 | 0 | if (cur_success) |
3661 | 0 | { |
3662 | 0 | tot_succes += cur_success; |
3663 | | /* recalculate InChI from the structure */ |
3664 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
3665 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
3666 | 0 | { |
3667 | 0 | goto exit_function; |
3668 | 0 | } |
3669 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
3670 | 0 | { |
3671 | 0 | goto exit_function; |
3672 | 0 | } |
3673 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
3674 | 0 | { |
3675 | 0 | goto exit_function; /* no fixed-H found */ |
3676 | 0 | } |
3677 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
3678 | 0 | { |
3679 | 0 | goto exit_function; |
3680 | 0 | } |
3681 | 0 | if (!pc2i->bHasDifference) |
3682 | 0 | { |
3683 | 0 | goto exit_function; /* nothing to do */ |
3684 | 0 | } |
3685 | 0 | break; |
3686 | 0 | }/* else |
3687 | | if ( bOnly_N_V ) { |
3688 | | bOnly_N_V = 0; |
3689 | | } |
3690 | | */ |
3691 | 0 | } |
3692 | 0 | } |
3693 | 0 | } |
3694 | | |
3695 | 0 | if (( (pc2i->nNumTgInChI <= 1 && |
3696 | 0 | pc2i->nNumRemHInChI > pc2i->nNumRemHRevrs) || pc2i->len_c2at ) && |
3697 | 0 | bHas_N_V( at2, pStruct->num_atoms )) /* djb-rwth: addressing LLVM warnings */ |
3698 | 0 | { |
3699 | | /*-----------------------------------------------------------------*/ |
3700 | | /* | | */ |
3701 | | /* case 14: restored:-N=AB=N=CD-XH original: (-)N-AB-N(+)=CD-XH */ |
3702 | | /* FixH: 0 0 0/1 0 1 */ |
3703 | | /* MobH: 0 0 1/0 0 0 */ |
3704 | | /* non-taut n/t any non any */ |
3705 | | /* taut */ |
3706 | | /* X = O, S, Se, N; N = N */ |
3707 | | /* t-group in original may have more (-) than in restored */ |
3708 | | /* same num_H and less (-) than in the restored structure */ |
3709 | | /* atom N(V)/N(IV)(+) is not taut in both */ |
3710 | | /* The following transformation should be possible: */ |
3711 | | /* | | */ |
3712 | | /* N=AB=N=CD-XH -> (-)N-AB-N-CD=XH(+) */ |
3713 | | /* This allows ADP to remove H(+) from -XH */ |
3714 | | /* As the result, the original structure has 0 or 1 t-group */ |
3715 | | /* Solution: separate charges between -N(III)= and N(V) */ |
3716 | | /*-----------------------------------------------------------------*/ |
3717 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
3718 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
3719 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
3720 | |
|
3721 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
3722 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
3723 | 0 | int num_N_V = 0, iat, i1, i2, i3, e1Flower, e1Plus, e2Plus, e2Minus, e3Plus; |
3724 | 0 | int max_success = pc2i->nNumRemHInChI - pc2i->nNumRemHRevrs; |
3725 | 0 | EDGE_LIST iat_X_List, iat_N_III_List; |
3726 | 0 | AllocEdgeList( &iat_X_List, EDGE_LIST_CLEAR ); |
3727 | 0 | AllocEdgeList( &iat_N_III_List, EDGE_LIST_CLEAR ); |
3728 | 0 | cur_success = 0; |
3729 | 0 | ret = 0; |
3730 | |
|
3731 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
3732 | 0 | { |
3733 | 0 | iat = nCanon2AtnoRevrs[i]; |
3734 | | /* search for N(V), 3 bonds */ |
3735 | 0 | if ( /* restored structure */ |
3736 | 0 | num_N_V < MAX_DIFF_FIXH && |
3737 | 0 | at2[iat].chem_bonds_valence == 5 && at2[iat].valence == 3 && |
3738 | 0 | !at2[iat].charge && !at2[iat].radical && |
3739 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
3740 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) && |
3741 | 0 | !at2[iat].num_H && |
3742 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
3743 | 0 | pBNS->edge[e].flow /* no charge */ && |
3744 | 0 | NO_VERTEX != (j = GetChargeFlowerUpperEdge(pBNS, pVA, e)) && !pBNS->edge[j].forbidden && |
3745 | 0 | !pBNS->edge[j].flow /* neutral, valence=5 */ && |
3746 | | /* orig. InChI */ |
3747 | 0 | !pStruct->endpoint[i] && |
3748 | 0 | !(nMobHInChI && nMobHInChI[i]) && pStruct->fixed_H && !pStruct->fixed_H[i]) /* djb-rwth: fixing a NULL pointer dereference */ |
3749 | 0 | { |
3750 | 0 | iat_N_V_Array[num_N_V++] = iat; |
3751 | 0 | } |
3752 | 0 | else |
3753 | 0 | { |
3754 | | /* search for -N= */ |
3755 | 0 | if ( /* restored structure */ |
3756 | 0 | at2[iat].chem_bonds_valence == 3 && at2[iat].valence == 2 && |
3757 | 0 | !at2[iat].charge && !at2[iat].radical && |
3758 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
3759 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) && |
3760 | 0 | !at2[iat].num_H && |
3761 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
3762 | 0 | !pBNS->edge[e].flow /* no charge */ && |
3763 | | /* orig. InChI */ |
3764 | | /*!pStruct->endpoint[i] &&*/ |
3765 | 0 | !(nMobHInChI && nMobHInChI[i]) && pStruct->fixed_H && !pStruct->fixed_H[i]) /* djb-rwth: fixing a NULL pointer dereference */ |
3766 | 0 | { |
3767 | |
|
3768 | 0 | if ((ret = AddToEdgeList(&iat_N_III_List, iat, 32))) /* djb-rwth: addressing LLVM warning */ |
3769 | 0 | { |
3770 | 0 | goto exit_case_14; |
3771 | 0 | } |
3772 | 0 | } |
3773 | 0 | else |
3774 | 0 | { |
3775 | | /* search for -OH -NH-, -NH2 */ |
3776 | 0 | if ( /* restored structure */ |
3777 | 0 | at2[iat].chem_bonds_valence == at2[iat].valence && |
3778 | 0 | !at2[iat].charge && !at2[iat].radical && |
3779 | 0 | ((pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) || |
3780 | 0 | pVA[iat].cNumValenceElectrons == 6) && |
3781 | 0 | at2[iat].num_H && |
3782 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
3783 | 0 | pBNS->edge[e].flow /* no charge */ && |
3784 | | /* orig. InChI */ |
3785 | 0 | !(nMobHInChI && nMobHInChI[i]) && pStruct->fixed_H && pStruct->fixed_H[i]) /* djb-rwth: addressing LLVM warning; fixing a NULL pointer dereference */ |
3786 | 0 | { |
3787 | |
|
3788 | 0 | if ((ret = AddToEdgeList(&iat_X_List, iat, 32))) /* djb-rwth: addressing LLVM warning */ |
3789 | 0 | { |
3790 | 0 | goto exit_case_14; |
3791 | 0 | } |
3792 | 0 | } |
3793 | 0 | } |
3794 | 0 | } |
3795 | 0 | } |
3796 | 0 | if (!max_success) |
3797 | 0 | { |
3798 | 0 | max_success = inchi_min(num_N_V, iat_N_III_List.num_edges); |
3799 | 0 | max_success = inchi_min(max_success, iat_X_List.num_edges); |
3800 | 0 | } |
3801 | 0 | if (num_N_V && iat_N_III_List.num_edges && iat_X_List.num_edges) |
3802 | 0 | { |
3803 | 0 | for (i1 = 0; i1 < num_N_V && cur_success < max_success; i1++) |
3804 | 0 | { |
3805 | 0 | int iat_N_V = iat_N_V_Array[i1]; |
3806 | 0 | if (NO_VERTEX == iat_N_V || |
3807 | 0 | 0 >= (e1Plus = pVA[iat_N_V].nCPlusGroupEdge - 1) || |
3808 | 0 | NO_VERTEX == (e1Flower = GetChargeFlowerUpperEdge(pBNS, pVA, e1Plus)) || |
3809 | 0 | 1 != pBNS->edge[e1Plus].flow || |
3810 | 0 | 0 != pBNS->edge[e1Flower].flow) |
3811 | 0 | { |
3812 | 0 | continue; |
3813 | 0 | } |
3814 | 0 | for (i2 = iat_N_III_List.num_edges - 1; 0 <= i2 && cur_success < max_success; i2--) |
3815 | 0 | { |
3816 | 0 | int iat_N_III = iat_N_III_List.pnEdges[i2]; |
3817 | 0 | if (NO_VERTEX == iat_N_III || |
3818 | 0 | 0 >= (e2Minus = pVA[iat_N_III].nCMinusGroupEdge - 1) || |
3819 | 0 | 0 >= (e2Plus = pVA[iat_N_III].nCPlusGroupEdge - 1) || |
3820 | 0 | 0 != pBNS->edge[e2Minus].flow || |
3821 | 0 | 1 != pBNS->edge[e2Plus].flow) |
3822 | 0 | { |
3823 | | /* do not consider this atom anymore */ |
3824 | 0 | iat_N_III_List.pnEdges[i2] = NO_VERTEX; |
3825 | 0 | continue; |
3826 | 0 | } |
3827 | 0 | for (i3 = iat_X_List.num_edges - 1; 0 <= i3 && cur_success < max_success; i3--) |
3828 | 0 | { |
3829 | 0 | int iat_X = iat_X_List.pnEdges[i3]; |
3830 | 0 | BNS_VERTEX* pv1n, * pv2n; |
3831 | 0 | BNS_EDGE* pe1n, * pe2n, * pe1Plus, * pe2Minus, * pe3Plus; |
3832 | 0 | Vertex v1n, v2n; |
3833 | 0 | ret = 0; |
3834 | 0 | if (NO_VERTEX == iat_X || |
3835 | 0 | 0 >= (e3Plus = pVA[iat_X].nCPlusGroupEdge - 1) || |
3836 | 0 | 1 != pBNS->edge[e3Plus].flow) |
3837 | 0 | { |
3838 | | /* do not consider this atom anymore */ |
3839 | 0 | iat_X_List.pnEdges[i3] = NO_VERTEX; |
3840 | 0 | continue; |
3841 | 0 | } |
3842 | | /* all is ready to check whether the following applies: |
3843 | | forbid changes of all charges and N,P,... flowers |
3844 | | allow to change edges: e2Minus, e3Plus |
3845 | | Increment flow in e1Flower |
3846 | | The result should be: increase in number of charges by 2 |
3847 | | */ |
3848 | 0 | pe1Plus = pBNS->edge + e1Plus; /* N(V) positive charge edge */ |
3849 | 0 | pe2Minus = pBNS->edge + e2Minus; /* =N- negative charge edge */ |
3850 | 0 | pe3Plus = pBNS->edge + e3Plus; /* -XH positive charge edge */ |
3851 | 0 | pe = pBNS->edge + e1Flower; /* N(V) flower edge */ |
3852 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
3853 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
3854 | 0 | for (j = pv1->num_adj_edges - 1; 0 <= j; j--) |
3855 | 0 | { |
3856 | 0 | pe1n = pBNS->edge + pv1->iedge[j]; |
3857 | 0 | if (pe1n->flow && !pe1n->forbidden && pe1n != pe1Plus) |
3858 | 0 | { |
3859 | 0 | pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1); |
3860 | 0 | break; |
3861 | 0 | } |
3862 | 0 | } |
3863 | 0 | if (j < 0) |
3864 | 0 | { |
3865 | 0 | continue; /* not found -- should not happen */ |
3866 | 0 | } |
3867 | 0 | for (j = pv2->num_adj_edges - 1; 0 <= j; j--) |
3868 | 0 | { /* was -2; changed 2006-2-28 12:35pm*/ |
3869 | 0 | pe2n = pBNS->edge + pv2->iedge[j]; |
3870 | 0 | if (pe2n->flow && !pe2n->forbidden && pe2n != pe1Plus) |
3871 | 0 | { |
3872 | 0 | pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2); |
3873 | 0 | break; |
3874 | 0 | } |
3875 | 0 | } |
3876 | 0 | if (j < 0) |
3877 | 0 | { |
3878 | 0 | continue; /* not found -- should not happen */ |
3879 | 0 | } |
3880 | 0 | delta = 1; |
3881 | 0 | pe->flow += delta; |
3882 | 0 | pe1n->flow -= delta; |
3883 | 0 | pe2n->flow -= delta; |
3884 | 0 | pv1n->st_edge.flow -= delta; |
3885 | 0 | pv2n->st_edge.flow -= delta; |
3886 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3887 | |
|
3888 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3889 | 0 | SetForbiddenEdgeMask(pBNS, &OtherNFlowerEdges, forbidden_edge_mask); |
3890 | | |
3891 | | /* allow two charges to change */ |
3892 | 0 | pe2Minus->forbidden &= forbidden_edge_mask_inv; |
3893 | 0 | pe3Plus->forbidden &= forbidden_edge_mask_inv; |
3894 | | /* test #1 */ |
3895 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3896 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
3897 | 0 | INCHI_HEAPCHK |
3898 | 0 | if (ret < 0) |
3899 | 0 | { |
3900 | 0 | goto exit_case_14; |
3901 | 0 | } |
3902 | 0 | else |
3903 | 0 | { |
3904 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
3905 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
3906 | 0 | nDeltaCharge == 2) /* djb-rwth: addressing LLVM warning */ |
3907 | 0 | { |
3908 | 0 | ; /* success */ |
3909 | 0 | } |
3910 | 0 | else |
3911 | 0 | { |
3912 | 0 | ret = 0; |
3913 | 0 | } |
3914 | 0 | } |
3915 | | /* restore BNS */ |
3916 | 0 | pe2Minus->forbidden |= forbidden_edge_mask; |
3917 | 0 | pe3Plus->forbidden |= forbidden_edge_mask; |
3918 | 0 | pe->flow -= delta; |
3919 | 0 | pe1n->flow += delta; |
3920 | 0 | pe2n->flow += delta; |
3921 | 0 | pv1n->st_edge.flow += delta; |
3922 | 0 | pv2n->st_edge.flow += delta; |
3923 | 0 | pBNS->tot_st_flow += 2 * delta; |
3924 | 0 | if (ret == 1) |
3925 | 0 | { |
3926 | | /* test #2: check if charge separation is possible */ |
3927 | 0 | pe->flow += delta; |
3928 | 0 | pe1n->flow -= delta; |
3929 | 0 | pe2n->flow -= delta; |
3930 | 0 | pv1n->st_edge.flow -= delta; |
3931 | 0 | pv2n->st_edge.flow -= delta; |
3932 | 0 | pBNS->tot_st_flow -= 2 * delta; |
3933 | | |
3934 | | /* allow two charges (N(V) and N(III)) to change */ |
3935 | 0 | pe2Minus->forbidden &= forbidden_edge_mask_inv; |
3936 | 0 | pe1Plus->forbidden &= forbidden_edge_mask_inv; |
3937 | | /* test #2 */ |
3938 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
3939 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
3940 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
3941 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
3942 | 0 | nDeltaCharge == 2) /* djb-rwth: addressing LLVM warnings */ |
3943 | 0 | { |
3944 | | /* success; actually change charges */ |
3945 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
3946 | 0 | if (ret > 0) |
3947 | 0 | { |
3948 | 0 | nNumRunBNS++; |
3949 | 0 | cur_success++; /* 14 */ |
3950 | 0 | } |
3951 | 0 | } |
3952 | 0 | if (ret <= 0) |
3953 | 0 | { |
3954 | | /* failed: restore BNS flow */ |
3955 | 0 | pe->flow -= delta; |
3956 | 0 | pe1n->flow += delta; |
3957 | 0 | pe2n->flow += delta; |
3958 | 0 | pv1n->st_edge.flow += delta; |
3959 | 0 | pv2n->st_edge.flow += delta; |
3960 | 0 | pBNS->tot_st_flow += 2 * delta; |
3961 | 0 | } |
3962 | 0 | INCHI_HEAPCHK |
3963 | 0 | } |
3964 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3965 | 0 | RemoveForbiddenEdgeMask(pBNS, &OtherNFlowerEdges, forbidden_edge_mask); |
3966 | 0 | if (ret > 0) |
3967 | 0 | { |
3968 | | /* do not repeat for the same atoms */ |
3969 | 0 | iat_N_V_Array[i1] = NO_VERTEX; |
3970 | 0 | iat_N_III_List.pnEdges[i2] = NO_VERTEX; |
3971 | 0 | iat_X_List.pnEdges[i3] = NO_VERTEX; |
3972 | 0 | } |
3973 | 0 | if (ret < 0) |
3974 | 0 | { |
3975 | 0 | goto exit_case_14; |
3976 | 0 | } |
3977 | 0 | if (ret > 0) |
3978 | 0 | { |
3979 | 0 | break; |
3980 | 0 | } |
3981 | 0 | } /* i3 cycle */ |
3982 | 0 | if (ret > 0) |
3983 | 0 | { |
3984 | 0 | break; |
3985 | 0 | } |
3986 | 0 | } /* i2 cycle */ |
3987 | 0 | } |
3988 | 0 | } |
3989 | 0 | exit_case_14: |
3990 | 0 | AllocEdgeList(&iat_X_List, EDGE_LIST_FREE); |
3991 | 0 | AllocEdgeList(&iat_N_III_List, EDGE_LIST_FREE); |
3992 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
3993 | 0 | RemoveForbiddenEdgeMask(pBNS, &OtherNFlowerEdges, forbidden_edge_mask); |
3994 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
3995 | 0 | if (ret < 0) |
3996 | 0 | { |
3997 | 0 | goto exit_function; |
3998 | 0 | } |
3999 | 0 | if (cur_success) |
4000 | 0 | { |
4001 | 0 | tot_succes += cur_success; |
4002 | | /* recalculate InChI from the structure */ |
4003 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4004 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
4005 | 0 | { |
4006 | 0 | goto exit_function; |
4007 | 0 | } |
4008 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
4009 | 0 | { |
4010 | 0 | goto exit_function; |
4011 | 0 | } |
4012 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4013 | 0 | { |
4014 | 0 | goto exit_function; /* no fixed-H found */ |
4015 | 0 | } |
4016 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
4017 | 0 | { |
4018 | 0 | goto exit_function; |
4019 | 0 | } |
4020 | 0 | if (!pc2i->bHasDifference) |
4021 | 0 | { |
4022 | 0 | goto exit_function; /* nothing to do */ |
4023 | 0 | } |
4024 | 0 | } |
4025 | 0 | } |
4026 | | |
4027 | 0 | if (pc2i->nNumTgMRevrs > pc2i->nNumTgMInChI || |
4028 | 0 | pc2i->nNumRemHRevrs < pc2i->nNumRemHInChI || |
4029 | 0 | pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || |
4030 | 0 | (pc2i->nNumTgInChI <= 1 && pc2i->nNumTgRevrs > pc2i->nNumTgInChI)) /* djb-rwth: addressing LLVM warning */ |
4031 | 0 | { |
4032 | | /*--------------------------------------------------------------*/ |
4033 | | /* case 15: restored: -(+)O=AB-N< orig: -O-AB=N(+)< */ |
4034 | | /* (a) restored t-groups have more (-) than in original InChI */ |
4035 | | /* (b) Mobile-H charge: restored > original InChI *and* */ |
4036 | | /* removed H: restored < original InChI */ |
4037 | | /* (c) restored t-groups have less endpnoits than in orig InChI */ |
4038 | | /* O = O, S, Se, Te; N = N */ |
4039 | | /* Solution: move (+) from -O(+)= to -N< */ |
4040 | | /*--------------------------------------------------------------*/ |
4041 | 0 | int num_SB_Neutr = 0, num_DB_Charged = 0, iat; |
4042 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
4043 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
4044 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
4045 | 0 | cur_success = 0; |
4046 | | |
4047 | | /* search for -O(+)= */ |
4048 | | /* search for -N< */ |
4049 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
4050 | 0 | { /* i = canonical number - 1 */ |
4051 | 0 | iat = nCanon2AtnoRevrs[i]; |
4052 | 0 | if ( /* -O(+)= in restored atom: charge=1, has no H, a double bond */ |
4053 | 0 | num_DB_Charged < MAX_DIFF_FIXH && |
4054 | 0 | at2[iat].charge == 1 && !at2[iat].num_H && |
4055 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4056 | 0 | (pVA[iat].cNumValenceElectrons == 6) && |
4057 | | /* in orig.InChI: an endpoint, has fixed-H */ |
4058 | | /*pStruct->endpoint[i] &&*/ |
4059 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
4060 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
4061 | | /* has (+) edge */ |
4062 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && 0 == pBNS->edge[e].forbidden) |
4063 | 0 | { |
4064 | |
|
4065 | 0 | iat_DB_Charged[num_DB_Charged++] = iat; |
4066 | | /* |
4067 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
4068 | | goto exit_function; |
4069 | | } |
4070 | | */ |
4071 | 0 | } |
4072 | 0 | else |
4073 | 0 | { |
4074 | 0 | if ( /* -N< in restored atom: charge=0, has no H, has no double bond, N only */ |
4075 | 0 | num_SB_Neutr < MAX_DIFF_FIXH && |
4076 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
4077 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4078 | 0 | (pVA[iat].cNumValenceElectrons == 5 && |
4079 | 0 | pVA[iat].cPeriodicRowNumber == 1) && |
4080 | | /* in orig.InChI: an endpoint, has fixed-H */ |
4081 | | /*pStruct->endpoint[i] &&*/ |
4082 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
4083 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
4084 | | /* has (+) edge */ |
4085 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && 0 == pBNS->edge[e].forbidden) |
4086 | 0 | { |
4087 | |
|
4088 | 0 | iat_SB_Neutr[num_SB_Neutr++] = iat; |
4089 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
4090 | 0 | { |
4091 | 0 | goto exit_function; |
4092 | 0 | } |
4093 | 0 | } |
4094 | 0 | } |
4095 | 0 | } |
4096 | 0 | if ((num_try = inchi_min(num_SB_Neutr, num_DB_Charged))) /* djb-rwth: addressing LLVM warning */ |
4097 | 0 | { |
4098 | | /* detected; attempt to fix */ |
4099 | 0 | BNS_VERTEX* pv1n, * pv2n; |
4100 | 0 | BNS_EDGE* pe1n, * pe2n; |
4101 | 0 | Vertex v1n, v2n; |
4102 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4103 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
4104 | 0 | delta = 1; |
4105 | 0 | for (i = 0; i < num_DB_Charged && cur_success < num_try; i++) |
4106 | 0 | { |
4107 | 0 | iat = iat_DB_Charged[i]; |
4108 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
4109 | 0 | if (pe->flow) |
4110 | 0 | continue; |
4111 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
4112 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
4113 | |
|
4114 | 0 | for (j = pv1->num_adj_edges - 1; 0 <= j; j--) |
4115 | 0 | { |
4116 | 0 | pe1n = pBNS->edge + pv1->iedge[j]; |
4117 | 0 | if (pe1n->flow && !pe1n->forbidden) |
4118 | 0 | { |
4119 | 0 | pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1); |
4120 | 0 | break; |
4121 | 0 | } |
4122 | 0 | } |
4123 | 0 | if (j < 0) |
4124 | 0 | { |
4125 | 0 | continue; /* not found */ |
4126 | 0 | } |
4127 | | |
4128 | 0 | for (j = pv2->num_adj_edges - 1; 0 <= j; j--) |
4129 | 0 | { /* was -2; changed 2006-2-28 12:35pm*/ |
4130 | 0 | pe2n = pBNS->edge + pv2->iedge[j]; |
4131 | 0 | if (pe2n->flow && !pe2n->forbidden) |
4132 | 0 | { |
4133 | 0 | pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2); |
4134 | 0 | break; |
4135 | 0 | } |
4136 | 0 | } |
4137 | 0 | if (j < 0) |
4138 | 0 | { |
4139 | 0 | continue; /* not found */ |
4140 | 0 | } |
4141 | | |
4142 | 0 | pe->flow += delta; |
4143 | 0 | pe1n->flow -= delta; |
4144 | 0 | pe2n->flow -= delta; |
4145 | 0 | pv1n->st_edge.flow -= delta; |
4146 | 0 | pv2n->st_edge.flow -= delta; |
4147 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4148 | |
|
4149 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4150 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
4151 | |
|
4152 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
4153 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
4154 | 0 | (nDeltaCharge == 0 || nDeltaCharge == 1)) /* djb-rwth: addressing LLVM warnings */ |
4155 | 0 | { |
4156 | | /* Moved charge from O(+) to -N< => nDeltaCharge == 1 or 0 if pe2n = -N< charge edge */ |
4157 | | /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */ |
4158 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
4159 | 0 | if (ret > 0) |
4160 | 0 | { |
4161 | 0 | nNumRunBNS++; |
4162 | 0 | cur_success++; /* 15 */ |
4163 | 0 | } |
4164 | 0 | } |
4165 | 0 | else |
4166 | 0 | { |
4167 | 0 | pe->flow -= delta; |
4168 | 0 | pe1n->flow += delta; |
4169 | 0 | pe2n->flow += delta; |
4170 | 0 | pv1n->st_edge.flow += delta; |
4171 | 0 | pv2n->st_edge.flow += delta; |
4172 | 0 | pBNS->tot_st_flow += 2 * delta; |
4173 | 0 | } |
4174 | 0 | INCHI_HEAPCHK |
4175 | 0 | } |
4176 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4177 | 0 | } |
4178 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4179 | 0 | if (cur_success) |
4180 | 0 | { |
4181 | 0 | tot_succes += cur_success; |
4182 | | /* recalculate InChI from the structure */ |
4183 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4184 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
4185 | 0 | { |
4186 | 0 | goto exit_function; |
4187 | 0 | } |
4188 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
4189 | 0 | { |
4190 | 0 | goto exit_function; |
4191 | 0 | } |
4192 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4193 | 0 | { |
4194 | 0 | goto exit_function; /* no fixed-H found */ |
4195 | 0 | } |
4196 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
4197 | 0 | { |
4198 | 0 | goto exit_function; |
4199 | 0 | } |
4200 | 0 | if (!pc2i->bHasDifference) |
4201 | 0 | { |
4202 | 0 | goto exit_function; /* nothing to do */ |
4203 | 0 | } |
4204 | 0 | } |
4205 | 0 | } |
4206 | | |
4207 | 0 | if (pc2i->nNumTgDiffMinus) |
4208 | 0 | { |
4209 | | /*----------------------------------------------------------------*/ |
4210 | | /* case 16: restored: O=X-NH(-) orig.: O(-)-X=NH */ |
4211 | | /* t-group: (H,-) (2H) */ |
4212 | | /* O(-) = S, Se, Te; N = N; */ |
4213 | | /* Solution: move (-) from O(-) to -NH(-) */ |
4214 | | /*----------------------------------------------------------------*/ |
4215 | 0 | int num_SB_N_Minus = 0, num_DB_O_Neutr = 0, iat, itg; |
4216 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
4217 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
4218 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
4219 | 0 | cur_success = 0; /* djb-rwth: ignoring LLVM warning: variable used */ |
4220 | |
|
4221 | 0 | for (itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg++) |
4222 | 0 | { |
4223 | 0 | if (pStruct->ti.t_group[itg].nNumEndpoints != pStruct->One_ti.t_group[itg].nNumEndpoints || |
4224 | 0 | pStruct->ti.t_group[itg].num[1] >= pStruct->One_ti.t_group[itg].num[1]) |
4225 | 0 | { |
4226 | 0 | continue; |
4227 | 0 | } |
4228 | 0 | CurrEdges.num_edges = num_SB_N_Minus = num_DB_O_Neutr = 0; |
4229 | 0 | cur_success = 0; |
4230 | 0 | for (j = 0, k = pStruct->One_ti.t_group[itg].nFirstEndpointAtNoPos; |
4231 | 0 | j < pStruct->One_ti.t_group[itg].nNumEndpoints; j++) |
4232 | 0 | { |
4233 | 0 | i = pStruct->One_ti.nEndpointAtomNumber[k + j]; /* canonical number in restored struct. */ |
4234 | 0 | iat = nCanon2AtnoRevrs[i]; |
4235 | 0 | if ( /* in restored atom: charge=0, has no H, has double bond, O, S, Se, Te */ |
4236 | 0 | num_DB_O_Neutr < MAX_DIFF_FIXH && |
4237 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
4238 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4239 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
4240 | | /* in orig.InChI: an endpoint, may have fixed-H */ |
4241 | 0 | pStruct->endpoint[i] && |
4242 | | /*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/ |
4243 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
4244 | | /* has (-) edge */ |
4245 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) |
4246 | 0 | { |
4247 | |
|
4248 | 0 | iat_DB_O_Neutr[num_DB_O_Neutr++] = iat; |
4249 | |
|
4250 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
4251 | 0 | { |
4252 | 0 | goto exit_function; |
4253 | 0 | } |
4254 | 0 | } |
4255 | 0 | else |
4256 | 0 | { |
4257 | 0 | if ( /* in restored atom: charge=-1, has H, has double bond, N */ |
4258 | 0 | num_SB_N_Minus < MAX_DIFF_FIXH && |
4259 | 0 | at2[iat].charge == -1 && at2[iat].num_H && |
4260 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4261 | 0 | pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 && |
4262 | | /* in orig.InChI: an endpoint, has no fixed-H */ |
4263 | 0 | pStruct->endpoint[i] && |
4264 | 0 | (pStruct->fixed_H && pStruct->fixed_H[i]) && |
4265 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
4266 | | /* has (-) edge */ |
4267 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && |
4268 | 0 | 0 == pBNS->edge[e].forbidden) |
4269 | 0 | { |
4270 | |
|
4271 | 0 | iat_SB_N_Minus[num_SB_N_Minus++] = iat; |
4272 | | /* |
4273 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
4274 | | goto exit_function; |
4275 | | } |
4276 | | */ |
4277 | 0 | } |
4278 | 0 | } |
4279 | 0 | } |
4280 | 0 | if ((num_try = inchi_min(num_SB_N_Minus, num_DB_O_Neutr))) /* djb-rwth: addressing LLVM warning */ |
4281 | 0 | { |
4282 | | /* detected; attempt to fix */ |
4283 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4284 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
4285 | | /* allow stereobonds in rings change */ |
4286 | | /* |
4287 | | if ( forbidden_stereo_edge_mask ) |
4288 | | RemoveForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask ); |
4289 | | */ |
4290 | 0 | delta = 1; |
4291 | 0 | for (i = 0; i < num_SB_N_Minus && cur_success < num_try; i++) |
4292 | 0 | { |
4293 | 0 | iat = iat_SB_N_Minus[i]; |
4294 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
4295 | 0 | if (!pe->flow) |
4296 | 0 | continue; |
4297 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
4298 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
4299 | | |
4300 | | /*pe->forbidden |= forbidden_edge_mask;*/ |
4301 | 0 | pe->flow -= delta; |
4302 | 0 | pv1->st_edge.flow -= delta; |
4303 | 0 | pv2->st_edge.flow -= delta; |
4304 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4305 | |
|
4306 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4307 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
4308 | |
|
4309 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
4310 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
4311 | 0 | { |
4312 | | /* Moved (-) charge to =O => nDeltaCharge == 1 */ |
4313 | | /* Flow change on pe (-)charge edge (atom -NH(-)) is not known to RunBnsTestOnce()) */ |
4314 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
4315 | 0 | if (ret > 0) |
4316 | 0 | { |
4317 | 0 | nNumRunBNS++; |
4318 | 0 | cur_success++; /* 16 */ |
4319 | 0 | } |
4320 | 0 | } |
4321 | 0 | else |
4322 | 0 | { |
4323 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
4324 | 0 | pe->flow += delta; |
4325 | 0 | pv1->st_edge.flow += delta; |
4326 | 0 | pv2->st_edge.flow += delta; |
4327 | 0 | pBNS->tot_st_flow += 2 * delta; |
4328 | 0 | } |
4329 | 0 | INCHI_HEAPCHK |
4330 | 0 | } |
4331 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4332 | | /* |
4333 | | if ( forbidden_stereo_edge_mask ) |
4334 | | SetForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask ); |
4335 | | */ |
4336 | 0 | } |
4337 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4338 | 0 | if (cur_success) |
4339 | 0 | { |
4340 | 0 | tot_succes += cur_success; |
4341 | | /* recalculate InChI from the structure */ |
4342 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4343 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
4344 | 0 | { |
4345 | 0 | goto exit_function; |
4346 | 0 | } |
4347 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
4348 | 0 | { |
4349 | 0 | goto exit_function; |
4350 | 0 | } |
4351 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4352 | 0 | { |
4353 | 0 | goto exit_function; /* no fixed-H found */ |
4354 | 0 | } |
4355 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
4356 | 0 | { |
4357 | 0 | goto exit_function; |
4358 | 0 | } |
4359 | 0 | if (!pc2i->bHasDifference) |
4360 | 0 | { |
4361 | 0 | goto exit_function; /* nothing to do */ |
4362 | 0 | } |
4363 | 0 | } |
4364 | 0 | } |
4365 | 0 | } |
4366 | | |
4367 | 0 | if (pc2i->nNumRemHInChI < pc2i->nNumRemHRevrs) |
4368 | 0 | { |
4369 | | /*--------------------------------------------------------------*/ |
4370 | | /* case 17: restored: OH(+)=AB-O- orig. HO-AB=O(+)- */ |
4371 | | /* number of removed H: n+m n */ |
4372 | | /* OH(+) = N, O, S, Se; -O- = P,As,O,S,Se,Te,F,Cl,Br,I */ |
4373 | | /* Solution: move (+) from OH(+) to -O- */ |
4374 | | /*--------------------------------------------------------------*/ |
4375 | 0 | int num_SB_Neutr = 0, num_DB_Charged = 0, iat; |
4376 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
4377 | 0 | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H : |
4378 | 0 | pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H : 0; |
4379 | 0 | cur_success = 0; |
4380 | |
|
4381 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
4382 | 0 | { /* i = canonical number - 1 */ |
4383 | 0 | iat = nCanon2AtnoRevrs[i]; |
4384 | 0 | if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */ |
4385 | 0 | num_DB_Charged < MAX_DIFF_FIXH && |
4386 | 0 | at2[iat].charge == 1 && at2[iat].num_H && |
4387 | 0 | at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4388 | 0 | (pVA[iat].cNumValenceElectrons == 6 || |
4389 | 0 | (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1)) && |
4390 | | /* has (+) edge */ |
4391 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warnings */ |
4392 | 0 | { |
4393 | |
|
4394 | 0 | iat_DB_Charged[num_DB_Charged++] = iat; |
4395 | | /* |
4396 | | if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) { |
4397 | | goto exit_function; |
4398 | | } |
4399 | | */ |
4400 | 0 | } |
4401 | 0 | else |
4402 | 0 | { |
4403 | 0 | if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */ |
4404 | 0 | num_SB_Neutr < MAX_DIFF_FIXH && |
4405 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
4406 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4407 | 0 | (pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 || |
4408 | 0 | (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1)) && |
4409 | | /* in orig.InChI: not an endpoint */ |
4410 | 0 | !pStruct->endpoint[i] && |
4411 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
4412 | 0 | !(nMobHInChI && nMobHInChI[i]) && |
4413 | | /* has (+) edge */ |
4414 | 0 | (e = pVA[iat].nCPlusGroupEdge - 1) >= 0 && |
4415 | 0 | 0 == pBNS->edge[e].forbidden) /* djb-rwth: addressing LLVM warning */ |
4416 | 0 | { |
4417 | |
|
4418 | 0 | iat_SB_Neutr[num_SB_Neutr++] = iat; |
4419 | |
|
4420 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
4421 | 0 | { |
4422 | 0 | goto exit_function; |
4423 | 0 | } |
4424 | 0 | } |
4425 | 0 | } |
4426 | 0 | } |
4427 | 0 | if ((num_try = inchi_min(num_SB_Neutr, num_DB_Charged))) /* djb-rwth: addressing LLVM warning */ |
4428 | 0 | { |
4429 | 0 | BNS_VERTEX* pv1n, * pv2n; |
4430 | 0 | BNS_EDGE* pe1n, * pe2n; |
4431 | 0 | Vertex v1n, v2n; |
4432 | |
|
4433 | 0 | num_try = inchi_min(num_try, pc2i->nNumRemHRevrs - pc2i->nNumRemHInChI); |
4434 | | /* detected; attempt to fix */ |
4435 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4436 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
4437 | 0 | delta = 1; |
4438 | 0 | for (i = 0; i < num_DB_Charged && cur_success < num_try; i++) |
4439 | 0 | { |
4440 | 0 | iat = iat_DB_Charged[i]; |
4441 | 0 | pe = pBNS->edge + pVA[iat].nCPlusGroupEdge - 1; |
4442 | 0 | if (pe->flow) |
4443 | 0 | { |
4444 | 0 | continue; |
4445 | 0 | } |
4446 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
4447 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
4448 | |
|
4449 | 0 | for (j = pv1->num_adj_edges - 1; 0 <= j; j--) |
4450 | 0 | { |
4451 | 0 | pe1n = pBNS->edge + pv1->iedge[j]; |
4452 | 0 | if (pe1n->flow && !pe1n->forbidden) |
4453 | 0 | { |
4454 | 0 | pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1); |
4455 | 0 | break; |
4456 | 0 | } |
4457 | 0 | } |
4458 | 0 | if (j < 0) |
4459 | 0 | { |
4460 | 0 | continue; /* not found */ |
4461 | 0 | } |
4462 | | |
4463 | 0 | for (j = pv2->num_adj_edges - 1; 0 <= j; j--) |
4464 | 0 | { /* was -2; changed 2006-2-28 12:35pm*/ |
4465 | 0 | pe2n = pBNS->edge + pv2->iedge[j]; |
4466 | 0 | if (pe2n->flow && !pe2n->forbidden) |
4467 | 0 | { |
4468 | 0 | pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2); |
4469 | 0 | break; |
4470 | 0 | } |
4471 | 0 | } |
4472 | 0 | if (j < 0) |
4473 | 0 | continue; /* not found */ |
4474 | | |
4475 | 0 | pe->flow += delta; |
4476 | 0 | pe1n->flow -= delta; |
4477 | 0 | pe2n->flow -= delta; |
4478 | 0 | pv1n->st_edge.flow -= delta; |
4479 | 0 | pv2n->st_edge.flow -= delta; |
4480 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4481 | |
|
4482 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4483 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
4484 | |
|
4485 | 0 | if (ret == 1 && ((vPathEnd == v1n && vPathStart == v2n) || |
4486 | 0 | (vPathEnd == v2n && vPathStart == v1n)) && |
4487 | 0 | (nDeltaCharge == 0 || nDeltaCharge == 1)) /* djb-rwth: addressing LLVM warnings */ |
4488 | 0 | { |
4489 | | /* Moved charge from OH(+) to -O- => nDeltaCharge == 1 or 0 if pe2n = -O- charge edge */ |
4490 | | /* Flow change on pe (+)charge edge (atom OH(+)) is not known to RunBnsTestOnce()) */ |
4491 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
4492 | 0 | if (ret > 0) |
4493 | 0 | { |
4494 | 0 | nNumRunBNS++; |
4495 | 0 | cur_success++; /* 17 */ |
4496 | 0 | } |
4497 | 0 | } |
4498 | 0 | else |
4499 | 0 | { |
4500 | 0 | pe->flow -= delta; |
4501 | 0 | pe1n->flow += delta; |
4502 | 0 | pe2n->flow += delta; |
4503 | 0 | pv1n->st_edge.flow += delta; |
4504 | 0 | pv2n->st_edge.flow += delta; |
4505 | 0 | pBNS->tot_st_flow += 2 * delta; |
4506 | 0 | } |
4507 | 0 | INCHI_HEAPCHK |
4508 | 0 | } |
4509 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4510 | 0 | } |
4511 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4512 | 0 | if (cur_success) |
4513 | 0 | { |
4514 | 0 | tot_succes += cur_success; |
4515 | | /* recalculate InChI from the structure */ |
4516 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4517 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
4518 | 0 | { |
4519 | 0 | goto exit_function; |
4520 | 0 | } |
4521 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
4522 | 0 | { |
4523 | 0 | goto exit_function; |
4524 | 0 | } |
4525 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4526 | 0 | { |
4527 | 0 | goto exit_function; /* no fixed-H found */ |
4528 | 0 | } |
4529 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
4530 | 0 | { |
4531 | 0 | goto exit_function; |
4532 | 0 | } |
4533 | 0 | if (!pc2i->bHasDifference) |
4534 | 0 | { |
4535 | 0 | goto exit_function; /* nothing to do */ |
4536 | 0 | } |
4537 | 0 | } |
4538 | 0 | } |
4539 | | |
4540 | 0 | if (( pc2i->nNumTgInChI && pStruct->endpoint && |
4541 | 0 | pc2i->nNumTgMInChI > pc2i->nNumTgMRevrs && pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs )) |
4542 | 0 | { |
4543 | | /*-----------------------------------------------------------------*/ |
4544 | | /* */ |
4545 | | /* case 18: restored:-N=AB-X -(-)N-AB-X(+) */ |
4546 | | /* FixH: 0 0 0 0 */ |
4547 | | /* MobH: 0 0 0 0 */ |
4548 | | /* non non taut non */ |
4549 | | /* taut taut taut */ |
4550 | | /* X = any heteroatom N=N */ |
4551 | | /* t-group in original has (Hn,-m) in the restored: (Hn,-m+1) */ |
4552 | | /* same num_H and more (-) than in the restored structure */ |
4553 | | /* atom X is not taut in both */ |
4554 | | /* Solution: separate charges between -N(III)= and X */ |
4555 | | /*-----------------------------------------------------------------*/ |
4556 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
4557 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
4558 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
4559 | 0 | int iat, e1, itg, max_success; |
4560 | 0 | CurrEdges.num_edges = 0; |
4561 | 0 | cur_success = 0; |
4562 | 0 | ret = 0; |
4563 | | /* search for -N= */ |
4564 | 0 | for (itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg++) |
4565 | 0 | { |
4566 | 0 | if (pStruct->ti.t_group[itg].nNumEndpoints <= pStruct->One_ti.t_group[itg].nNumEndpoints || |
4567 | 0 | pStruct->ti.t_group[itg].num[1] <= pStruct->One_ti.t_group[itg].num[1]) |
4568 | 0 | { |
4569 | 0 | continue; |
4570 | 0 | } |
4571 | 0 | CurrEdges.num_edges = 0; |
4572 | 0 | cur_success = 0; |
4573 | 0 | for (j = 0, k = pStruct->ti.t_group[itg].nFirstEndpointAtNoPos; |
4574 | 0 | j < pStruct->ti.t_group[itg].nNumEndpoints; j++) |
4575 | 0 | { |
4576 | 0 | i = pStruct->ti.nEndpointAtomNumber[k + j]; /* canonical number in restored struct. */ |
4577 | 0 | iat = nCanon2AtnoRevrs[i]; |
4578 | 0 | if (!pStruct->endpoint[i] || !at_Mobile_H_Revrs || at_Mobile_H_Revrs[iat].endpoint || |
4579 | 0 | pVA[i].cNumValenceElectrons != 5 || pVA[i].cPeriodicRowNumber != 1 || |
4580 | 0 | 2 != at2[iat].valence || at2[iat].num_H || at2[iat].radical || |
4581 | 0 | (0 <= ( e1 = pVA[iat].nCPlusGroupEdge - 1 ) && !pBNS->edge[e1].flow) || |
4582 | 0 | 0 >( e = pVA[iat].nCMinusGroupEdge - 1 ) || pBNS->edge[e].forbidden || pBNS->edge[e].flow) /* djb-rwth: addressing LLVM warning */ |
4583 | 0 | { |
4584 | 0 | continue; |
4585 | 0 | } |
4586 | | /* found -N= */ |
4587 | 0 | if ((ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
4588 | 0 | { |
4589 | 0 | goto exit_function; |
4590 | 0 | } |
4591 | 0 | } |
4592 | 0 | } |
4593 | 0 | if (!( max_success = CurrEdges.num_edges )) |
4594 | 0 | { |
4595 | 0 | goto exit_case_18; |
4596 | 0 | } |
4597 | | /* search for X */ |
4598 | 0 | for (i = 0; i < pStruct->num_atoms && cur_success < max_success; i++) |
4599 | 0 | { |
4600 | 0 | iat = nCanon2AtnoRevrs[i]; |
4601 | 0 | if (pStruct->endpoint[i] || !pVA[i].cNumValenceElectrons || pVA[i].cNumValenceElectrons == 4 || |
4602 | 0 | at2[iat].num_H || at2[iat].radical || |
4603 | 0 | (0 <= ( e1 = pVA[iat].nCMinusGroupEdge - 1 ) && !pBNS->edge[e1].flow) || |
4604 | 0 | 0 >( e = pVA[iat].nCPlusGroupEdge - 1 ) || pBNS->edge[e].forbidden || pBNS->edge[e].flow != 1) /* djb-rwth: addressing LLVM warnings */ |
4605 | 0 | { |
4606 | 0 | continue; |
4607 | 0 | } |
4608 | | /* try to move the charge */ |
4609 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
4610 | 0 | SetForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask ); |
4611 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask ); |
4612 | |
|
4613 | 0 | pe = pBNS->edge + e; |
4614 | 0 | if (!pe->flow) |
4615 | 0 | continue; |
4616 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
4617 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
4618 | |
|
4619 | 0 | delta = 1; |
4620 | 0 | pe->flow -= delta; |
4621 | 0 | pv1->st_edge.flow -= delta; |
4622 | 0 | pv2->st_edge.flow -= delta; |
4623 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4624 | |
|
4625 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4626 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
4627 | |
|
4628 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
4629 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
4630 | 0 | { |
4631 | | /* Created (-) charge on -N= => nDeltaCharge == 1 */ |
4632 | | /* Flow change on pe (+)charge edge (atom X) is not known to RunBnsTestOnce()) */ |
4633 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
4634 | 0 | if (ret > 0) |
4635 | 0 | { |
4636 | 0 | nNumRunBNS++; |
4637 | 0 | cur_success++; /* 18 */ |
4638 | 0 | } |
4639 | 0 | } |
4640 | 0 | else |
4641 | 0 | { |
4642 | 0 | pe->flow += delta; |
4643 | 0 | pv1->st_edge.flow += delta; |
4644 | 0 | pv2->st_edge.flow += delta; |
4645 | 0 | pBNS->tot_st_flow += 2 * delta; |
4646 | 0 | } |
4647 | 0 | INCHI_HEAPCHK |
4648 | 0 | } |
4649 | 0 | exit_case_18: |
4650 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
4651 | 0 | RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask ); |
4652 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4653 | 0 | if (ret < 0) |
4654 | 0 | { |
4655 | 0 | goto exit_function; |
4656 | 0 | } |
4657 | 0 | if (cur_success) |
4658 | 0 | { |
4659 | 0 | tot_succes += cur_success; |
4660 | | /* recalculate InChI from the structure */ |
4661 | 0 | if (0 >( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4662 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
4663 | 0 | { |
4664 | 0 | goto exit_function; |
4665 | 0 | } |
4666 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
4667 | 0 | { |
4668 | 0 | goto exit_function; |
4669 | 0 | } |
4670 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4671 | 0 | { |
4672 | 0 | goto exit_function; /* no fixed-H found */ |
4673 | 0 | } |
4674 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
4675 | 0 | { |
4676 | 0 | goto exit_function; |
4677 | 0 | } |
4678 | 0 | if (!pc2i->bHasDifference) |
4679 | 0 | { |
4680 | 0 | goto exit_function; /* nothing to do */ |
4681 | 0 | } |
4682 | 0 | } |
4683 | 0 | } |
4684 | | |
4685 | 0 | if (pc2i->len_c2at >= 1) |
4686 | 0 | { |
4687 | | /*--------------------------------------------------------------*/ |
4688 | | /* case 19 restored: M--OH original: M(-)==OH(+) */ |
4689 | | /* FixH: metal 0 1 */ |
4690 | | /* MobH: 1 0 */ |
4691 | | /* O = O, S, Se, Te; not taut. in InChI */ |
4692 | | /* In restored structure has H; tautomeric or not tautomeric */ |
4693 | | /* Solution: move (+) from -OH to M; charhe on M may vary */ |
4694 | | /*--------------------------------------------------------------*/ |
4695 | 0 | int iat; |
4696 | 0 | EdgeIndex eMPlus, eMMinus; /* djb-rwth: removing redundant variables/code */ |
4697 | 0 | BNS_EDGE *peOHPlus, *peMPlus, *peMMinus, *peOMBond; |
4698 | 0 | int iatMetal, ChargeOnMetal, DeltaChargeExpected; |
4699 | 0 | cur_success = 0; |
4700 | | /* djb-rwth: removing redundant code */ |
4701 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
4702 | 0 | { |
4703 | 0 | iat = pc2i->c2at[i].atomNumber; |
4704 | 0 | if ( /* orig. InChI info: =NH2(+), =OH(+) */ |
4705 | 0 | ( pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ && |
4706 | | /*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */ |
4707 | 0 | ( e = pVA[iat].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
4708 | 0 | pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 && |
4709 | | /* reversed structure info: */ |
4710 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 1 && |
4711 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && |
4712 | 0 | at2[iat].valence == 1 && |
4713 | 0 | at2[iat].valence == at2[iat].chem_bonds_valence && |
4714 | | /* metal atom */ |
4715 | 0 | pVA[iatMetal = at2[iat].neighbor[0]].cMetal && |
4716 | 0 | ( eMPlus = pVA[iatMetal].nCPlusGroupEdge - 1 ) >= 0 && !pBNS->edge[eMPlus].forbidden && |
4717 | 0 | ( eMMinus = pVA[iatMetal].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[eMMinus].forbidden && |
4718 | 0 | !pBNS->edge[pBNS->vert[iat].iedge[0]].forbidden |
4719 | 0 | ) /* djb-rwth: removing redundant code */ |
4720 | 0 | { |
4721 | | /* -OH charge edges */ |
4722 | 0 | if ((ret = AddToEdgeList( &CurrEdges, iat, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
4723 | 0 | { |
4724 | 0 | goto exit_function; |
4725 | 0 | } |
4726 | 0 | } |
4727 | 0 | } |
4728 | 0 | if (CurrEdges.num_edges) |
4729 | 0 | { |
4730 | | /* detected; fix */ |
4731 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
4732 | 0 | SetForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask ); |
4733 | 0 | SetForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask ); |
4734 | 0 | for (i = 0; i < CurrEdges.num_edges; i++) |
4735 | 0 | { |
4736 | | /* v1 is -OH, v2 is adjacent to it Metal */ |
4737 | 0 | iat = CurrEdges.pnEdges[i]; |
4738 | 0 | iatMetal = at2[iat].neighbor[0]; |
4739 | 0 | peOHPlus = pBNS->edge + ( (long long)pVA[iat].nCPlusGroupEdge - 1 ); /* djb-rwth: removing redundant variables/code */ |
4740 | 0 | peMPlus = pBNS->edge + ( (long long)pVA[iatMetal].nCPlusGroupEdge - 1 ); /* djb-rwth: removing redundant variables/code */ |
4741 | 0 | peMMinus = pBNS->edge + ( (long long)pVA[iatMetal].nCMinusGroupEdge - 1 ); /* djb-rwth: removing redundant variables/code */ |
4742 | 0 | peOMBond = pBNS->edge + ( pBNS->vert[iat].iedge[0] ); /* djb-rwth: removing redundant variables/code */ |
4743 | | /* remove forbidden edge masks */ |
4744 | 0 | peMPlus->forbidden &= forbidden_edge_mask_inv; |
4745 | 0 | peMMinus->forbidden &= forbidden_edge_mask_inv; |
4746 | 0 | peOMBond->forbidden &= forbidden_edge_mask_inv; |
4747 | |
|
4748 | 0 | ChargeOnMetal = ( peMPlus->cap - peMPlus->flow ) - peMMinus->flow; |
4749 | 0 | if (1 == ChargeOnMetal) |
4750 | 0 | { |
4751 | | /* We are going to subtract 1 from the charge on Metal */ |
4752 | | /* Added (+)charge to -OH is not known to RunBnsTestOnce() */ |
4753 | 0 | DeltaChargeExpected = -1; /* charge will become = 0 */ |
4754 | 0 | } |
4755 | 0 | else |
4756 | 0 | { |
4757 | 0 | if (0 == ChargeOnMetal) |
4758 | 0 | { |
4759 | 0 | DeltaChargeExpected = 1; /* charge on Metal will be created */ |
4760 | 0 | } |
4761 | 0 | else |
4762 | 0 | { |
4763 | 0 | DeltaChargeExpected = 0; |
4764 | 0 | } |
4765 | 0 | } |
4766 | |
|
4767 | 0 | delta = 1; |
4768 | 0 | pe = peOHPlus; |
4769 | 0 | if (!pe->flow) |
4770 | 0 | continue; |
4771 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
4772 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
4773 | |
|
4774 | 0 | pe->flow -= delta; /* remove (-) from AB-O(-) */ |
4775 | 0 | pv1->st_edge.flow -= delta; |
4776 | 0 | pv2->st_edge.flow -= delta; |
4777 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4778 | |
|
4779 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4780 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
4781 | |
|
4782 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
4783 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == DeltaChargeExpected) /* djb-rwth: addressing LLVM warnings */ |
4784 | 0 | { |
4785 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
4786 | 0 | if (ret > 0) |
4787 | 0 | { |
4788 | 0 | nNumRunBNS++; |
4789 | 0 | cur_success++; /* 19 */ |
4790 | 0 | } |
4791 | 0 | } |
4792 | 0 | else |
4793 | 0 | { |
4794 | 0 | pe->flow += delta; |
4795 | 0 | pv1->st_edge.flow += delta; |
4796 | 0 | pv2->st_edge.flow += delta; |
4797 | 0 | pBNS->tot_st_flow += 2 * delta; |
4798 | 0 | } |
4799 | 0 | INCHI_HEAPCHK |
4800 | | /* set forbidden edge masks back */ |
4801 | 0 | peMPlus->forbidden |= forbidden_edge_mask; |
4802 | 0 | peMMinus->forbidden |= forbidden_edge_mask; |
4803 | 0 | peOMBond->forbidden |= forbidden_edge_mask; |
4804 | 0 | } |
4805 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
4806 | 0 | RemoveForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask ); |
4807 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask ); |
4808 | |
|
4809 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4810 | 0 | if (cur_success) |
4811 | 0 | { |
4812 | 0 | tot_succes += cur_success; |
4813 | | /* recalculate InChI from the structure */ |
4814 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4815 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
4816 | 0 | { |
4817 | 0 | goto exit_function; |
4818 | 0 | } |
4819 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
4820 | 0 | { |
4821 | 0 | goto exit_function; |
4822 | 0 | } |
4823 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4824 | 0 | { |
4825 | 0 | goto exit_function; /* no fixed-H found */ |
4826 | 0 | } |
4827 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
4828 | 0 | { |
4829 | 0 | goto exit_function; |
4830 | 0 | } |
4831 | 0 | if (!pc2i->bHasDifference) |
4832 | 0 | { |
4833 | 0 | goto exit_function; /* nothing to do */ |
4834 | 0 | } |
4835 | 0 | } |
4836 | 0 | } |
4837 | 0 | } |
4838 | | |
4839 | 0 | if (pc2i->len_c2at > 1 && pc2i->nNumTgRevrs && pc2i->nNumTgInChI) |
4840 | 0 | { |
4841 | | /*--------------------------------------------------------------*/ |
4842 | | /* case 20: restored: O(-)-AB=N- original: O=AB-N(-)- */ |
4843 | | /* FixH: 0 0 0 -1 */ |
4844 | | /* MobH: 0 0 0 1 */ |
4845 | | /* taut non-taut non-taut taut */ |
4846 | | /* or taut no H */ |
4847 | | /* no H */ |
4848 | | /* O = O, S, Se; N = N, O, S, Se, Te; */ |
4849 | | /* restored atoms are taut/non-taut; original are opposite. */ |
4850 | | /* Solution: move (-) from O(-) to =N- */ |
4851 | | /*--------------------------------------------------------------*/ |
4852 | 0 | int num_SB_O_Minus = 0, num_DB_N = 0, iat; |
4853 | |
|
4854 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
4855 | | /* |
4856 | | inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
4857 | | pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL; |
4858 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
4859 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
4860 | | */ |
4861 | 0 | cur_success = 0; |
4862 | |
|
4863 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4864 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
4865 | 0 | { |
4866 | 0 | iat = pc2i->c2at[i].atomNumber; |
4867 | 0 | if ( /* orig. InChI info: =O or -N= */ |
4868 | 0 | num_DB_N < MAX_DIFF_FIXH && |
4869 | 0 | pc2i->c2at[i].endptInChI && |
4870 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
4871 | 0 | pBNS->edge[e].flow == 0 && |
4872 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
4873 | | /* if more than 1 t-group are in orig. InChI then do not move (-) to N */ |
4874 | 0 | (pc2i->nNumTgInChI == 1 || pc2i->c2at[i].nValElectr == 6) && |
4875 | | /* reversed structure info: */ |
4876 | 0 | !pc2i->c2at[i].endptRevrs && |
4877 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && /*pc2i->c2at[i].nMobHRevrs == 0 &&*/ |
4878 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
4879 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence) |
4880 | 0 | { |
4881 | 0 | iat_DB_N[num_DB_N++] = iat; |
4882 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
4883 | 0 | { |
4884 | 0 | goto exit_function; |
4885 | 0 | } |
4886 | 0 | } |
4887 | 0 | else |
4888 | 0 | { |
4889 | 0 | if ( /* orig. InChI info: -O(-) */ |
4890 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
4891 | 0 | !pc2i->c2at[i].endptInChI && |
4892 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
4893 | 0 | pBNS->edge[e].flow == 1 && |
4894 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
4895 | 0 | pc2i->c2at[i].nValElectr == 6 && |
4896 | | /* reversed structure info: */ |
4897 | 0 | pc2i->c2at[i].endptRevrs && |
4898 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 0 && |
4899 | 0 | pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H && |
4900 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1) |
4901 | 0 | { |
4902 | 0 | iat_SB_O_Minus[num_SB_O_Minus++] = iat; |
4903 | 0 | } |
4904 | 0 | } |
4905 | 0 | } |
4906 | 0 | if (!num_DB_N) |
4907 | 0 | { |
4908 | | /* search among N that are tautomeric in both cases */ |
4909 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
4910 | 0 | { /* i = canonical number - 1 */ |
4911 | 0 | if (!pStruct->endpoint[i]) |
4912 | 0 | { |
4913 | 0 | continue; |
4914 | 0 | } |
4915 | 0 | iat = nCanon2AtnoRevrs[i]; |
4916 | 0 | if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */ |
4917 | 0 | num_DB_N < MAX_DIFF_FIXH && |
4918 | 0 | at2[iat].charge == 0 && !at2[iat].num_H && |
4919 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
4920 | | /* in orig.InChI: an endpoint, has no H */ |
4921 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
4922 | | /*!(nMobHInChI && nMobHInChI[i] ) &&*/ |
4923 | | /* has (-) edge */ |
4924 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
4925 | 0 | !pBNS->edge[e].flow) |
4926 | 0 | { |
4927 | |
|
4928 | 0 | iat_DB_N[num_DB_N++] = iat; |
4929 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
4930 | 0 | { |
4931 | 0 | goto exit_function; |
4932 | 0 | } |
4933 | 0 | } |
4934 | 0 | } |
4935 | 0 | } |
4936 | 0 | if ((num_try = inchi_min(num_SB_O_Minus, num_DB_N))) /* djb-rwth: addressing LLVM warning */ |
4937 | 0 | { |
4938 | | /* detected; attempt to fix */ |
4939 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4940 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
4941 | 0 | delta = 1; |
4942 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
4943 | 0 | { |
4944 | 0 | iat = iat_SB_O_Minus[i]; |
4945 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
4946 | 0 | if (!pe->flow) |
4947 | 0 | continue; |
4948 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
4949 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
4950 | |
|
4951 | 0 | pe->flow -= delta; |
4952 | 0 | pv1->st_edge.flow -= delta; |
4953 | 0 | pv2->st_edge.flow -= delta; |
4954 | 0 | pBNS->tot_st_flow -= 2 * delta; |
4955 | |
|
4956 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
4957 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
4958 | |
|
4959 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
4960 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
4961 | 0 | { |
4962 | | /* Added (-) charge to =N- => nDeltaCharge == 1 */ |
4963 | | /* Flow change on pe (-)charge edge (atom -O(-)) is not known to RunBnsTestOnce()) */ |
4964 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
4965 | 0 | if (ret > 0) |
4966 | 0 | { |
4967 | 0 | nNumRunBNS++; |
4968 | 0 | cur_success++; /* 20 */ |
4969 | 0 | } |
4970 | 0 | } |
4971 | 0 | else |
4972 | 0 | { |
4973 | 0 | pe->flow += delta; |
4974 | 0 | pv1->st_edge.flow += delta; |
4975 | 0 | pv2->st_edge.flow += delta; |
4976 | 0 | pBNS->tot_st_flow += 2 * delta; |
4977 | 0 | } |
4978 | 0 | INCHI_HEAPCHK |
4979 | 0 | } |
4980 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
4981 | 0 | } |
4982 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
4983 | 0 | if (cur_success) |
4984 | 0 | { |
4985 | 0 | tot_succes += cur_success; |
4986 | | /* recalculate InChI from the structure */ |
4987 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
4988 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
4989 | 0 | { |
4990 | 0 | goto exit_function; |
4991 | 0 | } |
4992 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
4993 | 0 | { |
4994 | 0 | goto exit_function; |
4995 | 0 | } |
4996 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
4997 | 0 | { |
4998 | 0 | goto exit_function; /* no fixed-H found */ |
4999 | 0 | } |
5000 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
5001 | 0 | { |
5002 | 0 | goto exit_function; |
5003 | 0 | } |
5004 | 0 | if (!pc2i->bHasDifference) |
5005 | 0 | { |
5006 | 0 | goto exit_function; /* nothing to do */ |
5007 | 0 | } |
5008 | 0 | } |
5009 | 0 | } |
5010 | | |
5011 | 0 | if (pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumTgHInChI && pStruct->endpoint) |
5012 | 0 | { |
5013 | | /*--------------------------------------------------------------*/ |
5014 | | /* O(-) O */ |
5015 | | /* | || */ |
5016 | | /* case 21: restored: R=S=O original: R-S=O */ |
5017 | | /* | | */ |
5018 | | /* O(-) O(-) */ |
5019 | | /* All O are taut R is not taut */ |
5020 | | /* */ |
5021 | | /* In addition, another atom O that should have been tautomeric */ |
5022 | | /* or has H(+) added in Mobile-H layer is not like that */ |
5023 | | /* O = O, S, Se; S=S, Se, Te */ |
5024 | | /* Solution: move (-) from O(-) to =O */ |
5025 | | /* these atoms are tautomeric in restored structure */ |
5026 | | /*--------------------------------------------------------------*/ |
5027 | 0 | int num_SB_O_Minus = 0, num_DB_O = 0, iat, iS; |
5028 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
5029 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
5030 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
5031 | | /* |
5032 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
5033 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
5034 | | */ |
5035 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5036 | 0 | cur_success = 0; |
5037 | |
|
5038 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
5039 | 0 | { |
5040 | 0 | iat = pc2i->c2at[i].atomNumber; |
5041 | 0 | if ( /* orig. InChI info: =O */ |
5042 | 0 | num_DB_O < MAX_DIFF_FIXH && |
5043 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
5044 | 0 | (pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) && |
5045 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
5046 | 0 | pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
5047 | | /* reversed structure info: */ |
5048 | 0 | !(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) && |
5049 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
5050 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
5051 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) |
5052 | 0 | { |
5053 | 0 | iat_DB_O[num_DB_O++] = iat; |
5054 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
5055 | 0 | { |
5056 | 0 | goto exit_function; |
5057 | 0 | } |
5058 | 0 | } |
5059 | 0 | } |
5060 | 0 | for (i = 0; num_DB_O && i < pStruct->num_atoms; i++) |
5061 | 0 | { |
5062 | | /* i = canonical number - 1 */ |
5063 | 0 | if (!pStruct->endpoint[i]) |
5064 | 0 | { |
5065 | 0 | continue; |
5066 | 0 | } |
5067 | 0 | iat = nCanon2AtnoRevrs[i]; |
5068 | 0 | if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */ |
5069 | 0 | num_SB_O_Minus < MAX_DIFF_FIXH && |
5070 | 0 | at2[iat].charge == -1 && !at2[iat].num_H && |
5071 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence && !pVA[iat].cMetal && |
5072 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
5073 | 0 | (at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) && |
5074 | | /* in orig.InChI: an endpoint, has no H */ |
5075 | 0 | !(pStruct->fixed_H && pStruct->fixed_H[i]) && |
5076 | | /*!(nMobHInChI && nMobHInChI[i] ) &&*/ |
5077 | | /* has (-) edge */ |
5078 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
5079 | 0 | pBNS->edge[e].flow) |
5080 | 0 | { |
5081 | 0 | int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0, nNumOthers = 0, nNumNegEndp = 0; /* djb-rwth: ignoring LLVM warning: variables used */ |
5082 | | /* traverse neighbors of the centerpoint iS */ |
5083 | 0 | iS = at2[i].neighbor[0]; |
5084 | 0 | for (j = 0; j < num_SB_O_Minus; j++) |
5085 | 0 | { |
5086 | 0 | if (iat_Central[j] == iS) |
5087 | 0 | break; |
5088 | 0 | } |
5089 | 0 | if (j < num_SB_O_Minus) |
5090 | 0 | { |
5091 | 0 | continue; /* have already been there */ |
5092 | 0 | } |
5093 | 0 | for (j = 0; j < at[iS].valence; j++) |
5094 | 0 | { |
5095 | 0 | int bond_type = at2[iS].bond_type[j]; |
5096 | 0 | k = at2[iS].neighbor[j]; |
5097 | 0 | if (k == i) |
5098 | 0 | { |
5099 | 0 | continue; |
5100 | 0 | } |
5101 | 0 | if (pStruct->endpoint[k] == pStruct->endpoint[i]) |
5102 | 0 | { |
5103 | 0 | nNumTautSB += (bond_type == BOND_TYPE_SINGLE); |
5104 | 0 | nNumTautDB += (bond_type == BOND_TYPE_DOUBLE); |
5105 | 0 | } |
5106 | 0 | else |
5107 | 0 | { |
5108 | 0 | if (bond_type == BOND_TYPE_DOUBLE) |
5109 | 0 | { |
5110 | 0 | nNumOtherDB++; |
5111 | 0 | } |
5112 | 0 | else |
5113 | 0 | { |
5114 | 0 | if (bond_type == BOND_TYPE_SINGLE) |
5115 | 0 | { |
5116 | 0 | nNumOtherSB++; |
5117 | 0 | } |
5118 | 0 | else |
5119 | 0 | { |
5120 | 0 | nNumOthers++; |
5121 | 0 | } |
5122 | 0 | } |
5123 | 0 | } |
5124 | 0 | if (at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 && |
5125 | 0 | at2[k].charge == -1 && pVA[k].cNumValenceElectrons == 6) |
5126 | 0 | { |
5127 | 0 | nNumNegEndp++; |
5128 | 0 | } |
5129 | 0 | } |
5130 | 0 | if (!nNumTautSB) |
5131 | 0 | { |
5132 | 0 | continue; |
5133 | 0 | } |
5134 | 0 | if (!(nNumOtherDB && nNumTautDB)) |
5135 | 0 | { |
5136 | 0 | continue; /* ignore */ |
5137 | 0 | } |
5138 | | |
5139 | 0 | iat_SB_O_Minus[num_SB_O_Minus] = iat; |
5140 | 0 | iat_Central[num_SB_O_Minus++] = iS; |
5141 | 0 | } |
5142 | 0 | } |
5143 | 0 | if ((num_try = inchi_min(num_SB_O_Minus, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
5144 | 0 | { |
5145 | | /* detected; attempt to fix */ |
5146 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5147 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
5148 | 0 | delta = 1; |
5149 | 0 | for (i = 0; i < num_SB_O_Minus && cur_success < num_try; i++) |
5150 | 0 | { |
5151 | 0 | iat = iat_SB_O_Minus[i]; |
5152 | 0 | pe = pBNS->edge + pVA[iat].nCMinusGroupEdge - 1; |
5153 | 0 | if (!pe->flow) |
5154 | 0 | continue; |
5155 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
5156 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
5157 | |
|
5158 | 0 | pe->forbidden |= forbidden_edge_mask; |
5159 | 0 | pe->flow -= delta; |
5160 | 0 | pv1->st_edge.flow -= delta; |
5161 | 0 | pv2->st_edge.flow -= delta; |
5162 | 0 | pBNS->tot_st_flow -= 2 * delta; |
5163 | |
|
5164 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
5165 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
5166 | |
|
5167 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
5168 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warning */ |
5169 | 0 | { |
5170 | | /* Added (-) charge to =O => nDeltaCharge == 1 */ |
5171 | | /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */ |
5172 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
5173 | 0 | if (ret > 0) |
5174 | 0 | { |
5175 | 0 | nNumRunBNS++; |
5176 | 0 | cur_success++; /* 21 */ |
5177 | 0 | } |
5178 | 0 | } |
5179 | 0 | else |
5180 | 0 | { |
5181 | 0 | pe->flow += delta; |
5182 | 0 | pv1->st_edge.flow += delta; |
5183 | 0 | pv2->st_edge.flow += delta; |
5184 | 0 | pBNS->tot_st_flow += 2 * delta; |
5185 | 0 | } |
5186 | 0 | INCHI_HEAPCHK |
5187 | 0 | } |
5188 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5189 | 0 | } |
5190 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5191 | 0 | if (cur_success) |
5192 | 0 | { |
5193 | 0 | tot_succes += cur_success; |
5194 | | /* recalculate InChI from the structure */ |
5195 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
5196 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
5197 | 0 | { |
5198 | 0 | goto exit_function; |
5199 | 0 | } |
5200 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
5201 | 0 | { |
5202 | 0 | goto exit_function; |
5203 | 0 | } |
5204 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
5205 | 0 | { |
5206 | 0 | goto exit_function; /* no fixed-H found */ |
5207 | 0 | } |
5208 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
5209 | 0 | { |
5210 | 0 | goto exit_function; |
5211 | 0 | } |
5212 | 0 | if (!pc2i->bHasDifference) |
5213 | 0 | { |
5214 | 0 | goto exit_function; /* nothing to do */ |
5215 | 0 | } |
5216 | 0 | } |
5217 | 0 | } |
5218 | | |
5219 | 0 | if (pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs) |
5220 | 0 | { |
5221 | | /*--------------------------------------------------------------*/ |
5222 | | /* O O */ |
5223 | | /* || || */ |
5224 | | /* case 21a:restored: R=S-R' =X original: R-S-R' -X(-) */ |
5225 | | /* | || */ |
5226 | | /* O(-) O(-) */ |
5227 | | /* All O and X are taut O and X are not taut */ |
5228 | | /* it is possible that X is R */ |
5229 | | /* */ |
5230 | | /* O = O, S, Se; S=S, Se, Te; X = N, O, S, Se, Te */ |
5231 | | /* Solution: move (-) from O(-) to =X */ |
5232 | | /* these atoms are tautomeric in restored structure */ |
5233 | | /*--------------------------------------------------------------*/ |
5234 | 0 | int iat, iS; |
5235 | | /* |
5236 | | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
5237 | | */ |
5238 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
5239 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
5240 | | /* |
5241 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
5242 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
5243 | | */ |
5244 | 0 | EDGE_LIST OtherSO, CentralS, SOMinus, MinusAcceptord; |
5245 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5246 | 0 | AllocEdgeList( &OtherSO, EDGE_LIST_CLEAR ); |
5247 | 0 | AllocEdgeList( &CentralS, EDGE_LIST_CLEAR ); |
5248 | 0 | AllocEdgeList( &SOMinus, EDGE_LIST_CLEAR ); |
5249 | 0 | AllocEdgeList( &MinusAcceptord, EDGE_LIST_CLEAR ); |
5250 | 0 | cur_success = 0; |
5251 | 0 | if (!at_Mobile_H_Revrs) |
5252 | 0 | { |
5253 | 0 | goto exit_case_21a; |
5254 | 0 | } |
5255 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
5256 | 0 | { |
5257 | 0 | iat = pc2i->c2at[i].atomNumber; |
5258 | 0 | if ( /* orig. InChI info: -X(-) */ |
5259 | | /*num_DB_O < MAX_DIFF_FIXH &&*/ |
5260 | | /*pc2i->c2at[i].nValElectr == 6 */ /* O, S, Se, Te */ |
5261 | 0 | !pc2i->c2at[i].endptInChI && |
5262 | 0 | ( e = pVA[iat].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden && |
5263 | 0 | pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
5264 | | /* reversed structure info: */ |
5265 | 0 | ( pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs ) && |
5266 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
5267 | 0 | /*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ !at2[iat].num_H) |
5268 | 0 | { |
5269 | 0 | if (pVA[iat].cNumValenceElectrons == 6 && at2[iat].charge == -1 && |
5270 | 0 | pBNS->edge[e].flow && |
5271 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 && |
5272 | 0 | pVA[iS = (int) at2[iat].neighbor[0]].cNumValenceElectrons == 6 && pVA[iS].cPeriodicRowNumber > 1 && |
5273 | 0 | at2[iS].valence >= 4) |
5274 | 0 | { |
5275 | | /* a candidate for S in -SO2- */ |
5276 | 0 | int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0; /* djb-rwth: ignoring LLVM warning: variables used */ |
5277 | 0 | int nNumOthers = 0, nNumNegEndp = 0, nNumEndpO = 0; |
5278 | | /* check whether we have already found it */ |
5279 | 0 | if (0 <= FindInEdgeList( &CentralS, iS )) |
5280 | 0 | { |
5281 | 0 | continue; |
5282 | 0 | } |
5283 | 0 | for (j = 0; j < at[iS].valence; j++) |
5284 | 0 | { |
5285 | 0 | int bond_type = at2[iS].bond_type[j]; |
5286 | 0 | k = at2[iS].neighbor[j]; |
5287 | 0 | if (k == iat) |
5288 | 0 | { |
5289 | 0 | continue; |
5290 | 0 | } |
5291 | 0 | if (pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint && !at2[k].endpoint) |
5292 | 0 | { |
5293 | 0 | nNumTautSB += ( bond_type == BOND_TYPE_SINGLE ); |
5294 | 0 | nNumTautDB += ( bond_type == BOND_TYPE_DOUBLE ); |
5295 | 0 | nNumEndpO += ( pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1 ); |
5296 | 0 | } |
5297 | 0 | else |
5298 | 0 | { |
5299 | 0 | if (bond_type == BOND_TYPE_DOUBLE) |
5300 | 0 | { |
5301 | 0 | nNumOtherDB++; |
5302 | 0 | } |
5303 | 0 | else |
5304 | 0 | { |
5305 | 0 | if (bond_type == BOND_TYPE_SINGLE) |
5306 | 0 | { |
5307 | 0 | nNumOtherSB++; |
5308 | 0 | } |
5309 | 0 | else |
5310 | 0 | { |
5311 | 0 | nNumOthers++; |
5312 | 0 | } |
5313 | 0 | } |
5314 | 0 | } |
5315 | 0 | if (at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 && |
5316 | 0 | at2[k].charge == -1 && pVA[k].cNumValenceElectrons == 6) |
5317 | 0 | { |
5318 | 0 | nNumNegEndp++; |
5319 | 0 | } |
5320 | 0 | } |
5321 | 0 | if (!nNumEndpO) |
5322 | 0 | { |
5323 | 0 | continue; |
5324 | 0 | } |
5325 | 0 | if (nNumTautSB + nNumTautDB + nNumOtherDB <= nNumEndpO) |
5326 | 0 | { |
5327 | 0 | continue; /* ignore */ |
5328 | 0 | } |
5329 | | /* collect double bond taut =O */ |
5330 | 0 | for (j = 0; j < at[iS].valence; j++) |
5331 | 0 | { |
5332 | 0 | int bond_type = at2[iS].bond_type[j]; |
5333 | 0 | k = at2[iS].neighbor[j]; |
5334 | 0 | if (pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint && |
5335 | 0 | !at2[k].endpoint && pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1 && |
5336 | 0 | 0 <= ( e = pVA[k].nCMinusGroupEdge - 1 ) && !pBNS->edge[e].forbidden) |
5337 | 0 | { |
5338 | 0 | if (bond_type == BOND_TYPE_DOUBLE && !at2[k].charge && !pBNS->edge[e].flow) |
5339 | 0 | { |
5340 | | /* charges to be unchanged */ |
5341 | 0 | if ((ret = AddToEdgeList( &OtherSO, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
5342 | 0 | { |
5343 | 0 | goto exit_case_21a; |
5344 | 0 | } |
5345 | 0 | } |
5346 | 0 | else |
5347 | 0 | { |
5348 | 0 | if (bond_type == BOND_TYPE_SINGLE && at2[k].charge == -1 && pBNS->edge[e].flow) |
5349 | 0 | { |
5350 | | /* charges to be removed */ |
5351 | 0 | if ((ret = AddToEdgeList( &SOMinus, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
5352 | 0 | { |
5353 | 0 | goto exit_case_21a; |
5354 | 0 | } |
5355 | 0 | } |
5356 | 0 | } |
5357 | 0 | } |
5358 | 0 | } |
5359 | 0 | if ((ret = AddToEdgeList( &CentralS, iS, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
5360 | 0 | { |
5361 | 0 | goto exit_case_21a; |
5362 | 0 | } |
5363 | 0 | } |
5364 | 0 | else |
5365 | 0 | if (at2[iat].charge == 0 && !pBNS->edge[e].flow && |
5366 | 0 | at2[iat].valence + 1 == at2[iat].chem_bonds_valence) |
5367 | 0 | { |
5368 | | /* changeable charges */ |
5369 | 0 | if ((ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
5370 | 0 | { |
5371 | 0 | goto exit_function; |
5372 | 0 | } |
5373 | 0 | } |
5374 | 0 | } |
5375 | 0 | } |
5376 | | /* remove unchangeable from changeable */ |
5377 | 0 | for (i = 0; i < OtherSO.num_edges; i++) |
5378 | 0 | { |
5379 | 0 | RemoveFromEdgeListByValue( &CurrEdges, OtherSO.pnEdges[i] ); |
5380 | 0 | } |
5381 | |
|
5382 | 0 | if ((num_try = inchi_min( SOMinus.num_edges, CurrEdges.num_edges ))) /* djb-rwth: addressing LLVM warning */ |
5383 | 0 | { |
5384 | | /* detected; attempt to fix */ |
5385 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
5386 | 0 | RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask ); |
5387 | 0 | delta = 1; |
5388 | 0 | for (i = 0; i < SOMinus.num_edges && cur_success < num_try; i++) |
5389 | 0 | { |
5390 | 0 | pe = pBNS->edge + SOMinus.pnEdges[i]; |
5391 | 0 | if (!pe->flow) |
5392 | 0 | continue; |
5393 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
5394 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
5395 | | |
5396 | | /*pe->forbidden |= forbidden_edge_mask;*/ |
5397 | 0 | pe->flow -= delta; |
5398 | 0 | pv1->st_edge.flow -= delta; |
5399 | 0 | pv2->st_edge.flow -= delta; |
5400 | 0 | pBNS->tot_st_flow -= 2 * delta; |
5401 | |
|
5402 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
5403 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
5404 | |
|
5405 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
5406 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && nDeltaCharge == 1) /* djb-rwth: addressing LLVM warnings */ |
5407 | 0 | { |
5408 | | /* Added (-) charge to =O => nDeltaCharge == 1 */ |
5409 | | /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */ |
5410 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
5411 | 0 | if (ret > 0) |
5412 | 0 | { |
5413 | 0 | nNumRunBNS++; |
5414 | 0 | cur_success++; /* 21a */ |
5415 | 0 | } |
5416 | 0 | } |
5417 | 0 | else |
5418 | 0 | { |
5419 | 0 | pe->flow += delta; |
5420 | 0 | pv1->st_edge.flow += delta; |
5421 | 0 | pv2->st_edge.flow += delta; |
5422 | 0 | pBNS->tot_st_flow += 2 * delta; |
5423 | 0 | } |
5424 | 0 | INCHI_HEAPCHK |
5425 | 0 | } |
5426 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
5427 | 0 | } |
5428 | 0 | exit_case_21a: |
5429 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5430 | 0 | AllocEdgeList( &OtherSO, EDGE_LIST_FREE ); |
5431 | 0 | AllocEdgeList( &CentralS, EDGE_LIST_FREE ); |
5432 | 0 | AllocEdgeList( &SOMinus, EDGE_LIST_FREE ); |
5433 | 0 | AllocEdgeList( &MinusAcceptord, EDGE_LIST_FREE ); |
5434 | 0 | if (cur_success) |
5435 | 0 | { |
5436 | 0 | tot_succes += cur_success; |
5437 | | /* recalculate InChI from the structure */ |
5438 | 0 | if (0 > ( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
5439 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
5440 | 0 | { |
5441 | 0 | goto exit_function; |
5442 | 0 | } |
5443 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
5444 | 0 | { |
5445 | 0 | goto exit_function; |
5446 | 0 | } |
5447 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
5448 | 0 | { |
5449 | 0 | goto exit_function; /* no fixed-H found */ |
5450 | 0 | } |
5451 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
5452 | 0 | { |
5453 | 0 | goto exit_function; |
5454 | 0 | } |
5455 | 0 | if (!pc2i->bHasDifference) |
5456 | 0 | { |
5457 | 0 | goto exit_function; /* nothing to do */ |
5458 | 0 | } |
5459 | 0 | } |
5460 | 0 | } |
5461 | | |
5462 | 0 | if (pc2i->len_c2at) |
5463 | 0 | { |
5464 | | /*------------------------------------------------------------------*/ |
5465 | | /* case 22: restored: N(-)=N(+)=C...=O orig: N#N-N=...-O(-) */ |
5466 | | /* im InChI -O(-) may have H(+) added by Normalization */ |
5467 | | /* or may be tautomeric */ |
5468 | | /* Solution: move (-) from N(-) to =O */ |
5469 | | /* */ |
5470 | | /*------------------------------------------------------------------*/ |
5471 | 0 | int num_DB_O = 0, iat; |
5472 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
5473 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
5474 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
5475 | 0 | int iN2, iC; |
5476 | 0 | BNS_EDGE *peDB_O_Minus; |
5477 | | /* |
5478 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
5479 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
5480 | | */ |
5481 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5482 | 0 | cur_success = 0; |
5483 | |
|
5484 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
5485 | 0 | { |
5486 | 0 | iat = pc2i->c2at[i].atomNumber; |
5487 | 0 | if ( /* orig. InChI info: =O */ |
5488 | 0 | num_DB_O < MAX_DIFF_FIXH && |
5489 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
5490 | 0 | (pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) && |
5491 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
5492 | 0 | pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
5493 | | /* reversed structure info: */ |
5494 | 0 | !(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) && |
5495 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
5496 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
5497 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2) |
5498 | 0 | { |
5499 | 0 | iat_DB_O[num_DB_O++] = iat; |
5500 | 0 | } |
5501 | 0 | } |
5502 | 0 | for (i = 0; num_DB_O && i < pStruct->num_atoms; i++) |
5503 | 0 | { |
5504 | | /* i = canonical number - 1 */ |
5505 | 0 | iat = nCanon2AtnoRevrs[i]; |
5506 | 0 | if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */ |
5507 | 0 | at2[iat].charge == -1 && !at2[iat].num_H && |
5508 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 && !pVA[iat].cMetal && |
5509 | 0 | pVA[iat].cNumValenceElectrons == 5 && |
5510 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
5511 | 0 | pBNS->edge[e].flow && |
5512 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) && |
5513 | 0 | pVA[iN2 = at2[iat].neighbor[0]].cNumValenceElectrons == 5 && |
5514 | 0 | at2[iat].bond_type[0] == BOND_TYPE_DOUBLE && |
5515 | 0 | at2[iN2].charge == 1 && at2[iN2].valence == 2 && at2[iN2].chem_bonds_valence == 4 && |
5516 | 0 | pVA[iC = at2[iN2].neighbor[at2[iN2].neighbor[0] == iN2]].cNumValenceElectrons == 4) /* djb-rwth: ignoring LLVM warning: variable used */ |
5517 | 0 | { |
5518 | |
|
5519 | 0 | if ((ret = AddToEdgeList(&CurrEdges, e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
5520 | 0 | { |
5521 | 0 | goto exit_function; |
5522 | 0 | } |
5523 | 0 | } |
5524 | 0 | } |
5525 | 0 | if ((num_try = inchi_min(CurrEdges.num_edges, num_DB_O))) /* djb-rwth: addressing LLVM warning */ |
5526 | 0 | { |
5527 | | /* detected; attempt to fix */ |
5528 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5529 | 0 | RemoveForbiddenEdgeMask(pBNS, &CurrEdges, forbidden_edge_mask); |
5530 | 0 | delta = 1; |
5531 | 0 | for (i = 0; i < num_DB_O && cur_success < num_try; i++) |
5532 | 0 | { |
5533 | 0 | iat = iat_DB_O[i]; |
5534 | |
|
5535 | 0 | peDB_O_Minus = pBNS->edge + ((long long)pVA[iat].nCMinusGroupEdge - 1); /* djb-rwth: cast operator added */ |
5536 | 0 | pe = pBNS->edge + pBNS->vert[iat].iedge[0]; |
5537 | 0 | if (!pe->flow) |
5538 | 0 | continue; |
5539 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
5540 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
5541 | |
|
5542 | 0 | pe->forbidden |= forbidden_edge_mask; |
5543 | 0 | peDB_O_Minus->forbidden &= forbidden_edge_mask_inv; |
5544 | |
|
5545 | 0 | pe->flow -= delta; |
5546 | 0 | pv1->st_edge.flow -= delta; |
5547 | 0 | pv2->st_edge.flow -= delta; |
5548 | 0 | pBNS->tot_st_flow -= 2 * delta; |
5549 | |
|
5550 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
5551 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
5552 | |
|
5553 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
5554 | 0 | (vPathEnd == v2 && vPathStart == v1)) && nDeltaCharge == 0) /* djb-rwth: addressing LLVM warnings */ |
5555 | 0 | { |
5556 | | /* Added (-) charge to =O and removed from =N(-) => nDeltaCharge == 0 */ |
5557 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
5558 | 0 | if (ret > 0) |
5559 | 0 | { |
5560 | 0 | nNumRunBNS++; |
5561 | 0 | cur_success++; /* 22 */ |
5562 | 0 | } |
5563 | 0 | } |
5564 | 0 | else |
5565 | 0 | { |
5566 | 0 | pe->flow += delta; |
5567 | 0 | pv1->st_edge.flow += delta; |
5568 | 0 | pv2->st_edge.flow += delta; |
5569 | 0 | pBNS->tot_st_flow += 2 * delta; |
5570 | 0 | } |
5571 | 0 | INCHI_HEAPCHK |
5572 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
5573 | 0 | peDB_O_Minus->forbidden |= forbidden_edge_mask; |
5574 | 0 | } |
5575 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5576 | 0 | } |
5577 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5578 | 0 | if (cur_success) |
5579 | 0 | { |
5580 | 0 | tot_succes += cur_success; |
5581 | | /* recalculate InChI from the structure */ |
5582 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
5583 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
5584 | 0 | { |
5585 | 0 | goto exit_function; |
5586 | 0 | } |
5587 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct))) /* djb-rwth: addressing LLVM warning */ |
5588 | 0 | { |
5589 | 0 | goto exit_function; |
5590 | 0 | } |
5591 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
5592 | 0 | { |
5593 | 0 | goto exit_function; /* no fixed-H found */ |
5594 | 0 | } |
5595 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
5596 | 0 | { |
5597 | 0 | goto exit_function; |
5598 | 0 | } |
5599 | 0 | if (!pc2i->bHasDifference) |
5600 | 0 | { |
5601 | 0 | goto exit_function; /* nothing to do */ |
5602 | 0 | } |
5603 | 0 | } |
5604 | 0 | } |
5605 | | |
5606 | 0 | if (pc2i->len_c2at && pc2i->nNumTgInChI == 1) |
5607 | 0 | { |
5608 | | /*------------------------------------------------------------------*/ |
5609 | | /* case 23: -NO2 are to be tautomeric but they are not AND */ |
5610 | | /* InChI has a SINGLE tautomeric group */ |
5611 | | /* */ |
5612 | | /* (-)O (-)O */ |
5613 | | /* Solution: convert \ \ */ |
5614 | | /* N-X=...-Z(-) => N(+)=X- ...=Z */ |
5615 | | /* // / */ |
5616 | | /* O (-)O */ |
5617 | | /* */ |
5618 | | /* O O */ |
5619 | | /* or \\ \\ */ |
5620 | | /* N-X=...-Z(-) => N=X- ...=Z */ |
5621 | | /* // / */ |
5622 | | /* O (-)O */ |
5623 | | /* */ |
5624 | | /* */ |
5625 | | /* (a) move (-) from other tautomeric atom to O in O=N-X */ |
5626 | | /* or from other atom that has to be tautomeric */ |
5627 | | /* but is not */ |
5628 | | /* (b) create (+) [ion pair creation] on N as in */ |
5629 | | /* */ |
5630 | | /* OH OH */ |
5631 | | /* / / */ |
5632 | | /* -C=N => =C-N(+) */ |
5633 | | /* \\ \\ */ |
5634 | | /* O O */ |
5635 | | /* */ |
5636 | | /*------------------------------------------------------------------*/ |
5637 | 0 | int num_DB_O = 0, iat; |
5638 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
5639 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
5640 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
5641 | | /* |
5642 | | inp_ATOM *atfMobile_H_Revrs = (pStruct->pOne_norm_data[1] && |
5643 | | pStruct->pOne_norm_data[1]->at_fixed_bonds)? |
5644 | | pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL; |
5645 | | */ |
5646 | 0 | S_CHAR *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed ? pStruct->pOneINChI[0]->nNum_H_fixed : NULL; |
5647 | 0 | S_CHAR *pnMobHRevrs = ( pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H ) ? |
5648 | 0 | pStruct->pOneINChI[1]->nNum_H : |
5649 | 0 | ( pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H ) ? |
5650 | 0 | pStruct->pOneINChI[0]->nNum_H : NULL; |
5651 | 0 | int iN, one_success; |
5652 | 0 | BNS_EDGE *peDB_O_Minus; |
5653 | 0 | int neigh, nNumO, nNumOthers; |
5654 | 0 | #define CHG_SET_NOOH 0 |
5655 | 0 | #define CHG_SET_WRONG_TAUT 1 |
5656 | 0 | #define CHG_SET_TAUT 2 |
5657 | 0 | #define CHG_LAST_SET 2 /* the last index in trying */ |
5658 | 0 | #define CHG_SET_O_FIXED 3 |
5659 | 0 | #define CHG_SET_NUM 4 |
5660 | 0 | EDGE_LIST ChangeableEdges[CHG_SET_NUM]; |
5661 | 0 | memset( ChangeableEdges, 0, sizeof( ChangeableEdges ) ); /* djb-rwth: memset_s C11/Annex K variant? */ |
5662 | | /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */ |
5663 | | /* |
5664 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
5665 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
5666 | | */ |
5667 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5668 | 0 | cur_success = 0; |
5669 | |
|
5670 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
5671 | 0 | { |
5672 | 0 | iat = pc2i->c2at[i].atomNumber; |
5673 | 0 | if ( /* orig. InChI info: taut in orig. InChI =O located in -NO2 that is not taut in Reconstructed InChI */ |
5674 | 0 | num_DB_O < MAX_DIFF_FIXH && |
5675 | 0 | pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ && |
5676 | 0 | (pc2i->c2at[i].endptInChI /*|| pc2i->c2at[i].nMobHInChI*/) && |
5677 | 0 | (e = pVA[iat].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].forbidden && |
5678 | 0 | pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/ |
5679 | | /* reversed structure info: */ |
5680 | 0 | !(pc2i->c2at[i].endptRevrs /*|| pc2i->c2at[i].nMobHRevrs*/) && |
5681 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
5682 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
5683 | 0 | at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 && |
5684 | | /* find whether it belongs to NO2 */ |
5685 | 0 | pVA[iN = at2[iat].neighbor[0]].cNumValenceElectrons == 5 && |
5686 | 0 | at2[iN].valence == 3 && (at2[iN].charge == 0 || at2[iN].charge == 1) && |
5687 | 0 | at2[iN].chem_bonds_valence == 5 - at2[iN].charge) |
5688 | 0 | { |
5689 | | /* find the second O */ |
5690 | 0 | nNumO = nNumOthers = 0; |
5691 | 0 | for (k = 0; k < at2[iN].valence; k++) |
5692 | 0 | { |
5693 | 0 | neigh = at2[iN].neighbor[k]; |
5694 | 0 | if (neigh == iat) |
5695 | 0 | { |
5696 | 0 | continue; |
5697 | 0 | } |
5698 | 0 | if (pVA[neigh].cNumValenceElectrons == 6 && |
5699 | 0 | pStruct->endpoint[neigh] && |
5700 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[neigh].endpoint) && |
5701 | 0 | at2[neigh].valence == 1 && at2[neigh].num_H == 0 && |
5702 | 0 | at2[neigh].radical == 0 && (at2[neigh].charge == 0 || at2[neigh].charge == -1) && |
5703 | 0 | at2[neigh].chem_bonds_valence - at2[neigh].charge == 2) |
5704 | 0 | { |
5705 | 0 | nNumO++; |
5706 | 0 | } |
5707 | 0 | else |
5708 | 0 | { |
5709 | 0 | if (at2[iN].bond_type[k] == BOND_TYPE_SINGLE && |
5710 | 0 | at2[neigh].valence > 1 && |
5711 | 0 | at2[neigh].valence < at2[neigh].chem_bonds_valence) |
5712 | 0 | { |
5713 | 0 | nNumOthers++; |
5714 | 0 | } |
5715 | 0 | } |
5716 | 0 | } |
5717 | 0 | if (nNumO != 1 || nNumOthers != 1) |
5718 | 0 | { |
5719 | 0 | continue; |
5720 | 0 | } |
5721 | 0 | for (k = 0; k < num_DB_O; k++) |
5722 | 0 | { |
5723 | 0 | if (iat_NO2[k] == iN) |
5724 | 0 | { |
5725 | 0 | break; |
5726 | 0 | } |
5727 | 0 | } |
5728 | 0 | if (k == num_DB_O) |
5729 | 0 | { |
5730 | 0 | iat_NO2[num_DB_O] = iN; |
5731 | 0 | iat_DB_O[num_DB_O++] = iat; |
5732 | 0 | } |
5733 | | /* save the edge to avoid interference */ |
5734 | 0 | if ((ret = AddToEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE))) /* djb-rwth: addressing LLVM warning */ |
5735 | 0 | { |
5736 | 0 | goto exit_case_23; |
5737 | 0 | } |
5738 | 0 | } |
5739 | 0 | } |
5740 | 0 | if (num_DB_O) |
5741 | 0 | { |
5742 | | /* 1. search for =N(=O)-OH; assume =N(+)(-O(-))(-OH) does not happen */ |
5743 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
5744 | 0 | { |
5745 | | /* i = canonical number - 1 */ |
5746 | | /* find O=N(V) */ |
5747 | 0 | iat = nCanon2AtnoRevrs[i]; |
5748 | 0 | if (!pStruct->endpoint[i] || pVA[i].cNumValenceElectrons != 6 || |
5749 | 0 | at2[iat].valence != 1 || at2[iat].charge || |
5750 | 0 | 0 > (e = pVA[iat].nCMinusGroupEdge - 1) || |
5751 | 0 | at2[iat].num_H + at2[iat].chem_bonds_valence != 2 || |
5752 | 0 | pVA[iN = at2[iat].neighbor[0]].cNumValenceElectrons != 5 || |
5753 | 0 | 0 > (e = pVA[iN].nCPlusGroupEdge - 1) || |
5754 | 0 | pBNS->edge[e].forbidden || !pBNS->edge[e].flow || |
5755 | 0 | at2[iN].charge || at2[iN].valence != 3 || at2[iN].chem_bonds_valence != 5) /* djb-rwth: ignoring LLVM warning: variable used */ |
5756 | 0 | { |
5757 | 0 | continue; |
5758 | 0 | } |
5759 | | /* find the second O, -OH */ |
5760 | 0 | nNumO = nNumOthers = 0; |
5761 | 0 | for (k = 0; k < at2[iN].valence; k++) |
5762 | 0 | { |
5763 | 0 | neigh = at2[iN].neighbor[k]; |
5764 | 0 | if (neigh == iat) |
5765 | 0 | { |
5766 | 0 | continue; |
5767 | 0 | } |
5768 | 0 | if (pVA[neigh].cNumValenceElectrons == 6 && |
5769 | 0 | pStruct->endpoint[neigh] && |
5770 | 0 | at2[neigh].valence == 1 && at2[neigh].num_H == 1 && |
5771 | 0 | at2[neigh].radical == 0 && (at2[neigh].charge == 0)) |
5772 | 0 | { |
5773 | 0 | nNumO++; |
5774 | 0 | } |
5775 | 0 | else |
5776 | 0 | if (at2[iN].bond_type[k] == BOND_TYPE_DOUBLE && |
5777 | 0 | at2[neigh].valence >= 2 && |
5778 | 0 | at2[neigh].valence < at2[neigh].chem_bonds_valence) |
5779 | 0 | { |
5780 | 0 | nNumOthers++; |
5781 | 0 | } |
5782 | 0 | } |
5783 | 0 | if (nNumO != 1 || nNumOthers != 1) |
5784 | 0 | { |
5785 | 0 | continue; |
5786 | 0 | } |
5787 | | /* save edges to be changed */ |
5788 | 0 | if ((ret = AddToEdgeList(&ChangeableEdges[CHG_SET_NOOH], e, INC_ADD_EDGE)) || |
5789 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE))) |
5790 | 0 | { |
5791 | 0 | goto exit_case_23; |
5792 | 0 | } |
5793 | 0 | if (NO_VERTEX != (j = GetChargeFlowerUpperEdge(pBNS, pVA, e)) && |
5794 | 0 | ((ret = AddToEdgeList(&ChangeableEdges[CHG_SET_NOOH], j, INC_ADD_EDGE)) || |
5795 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE)))) |
5796 | 0 | { |
5797 | 0 | goto exit_case_23; |
5798 | 0 | } |
5799 | 0 | } |
5800 | | /* 2. search for (-) atoms that are tautomeric but should not be */ |
5801 | | /* or that got H from Normalization but they shouldn't */ |
5802 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
5803 | 0 | { /* i = canonical number - 1 */ |
5804 | 0 | iat = nCanon2AtnoRevrs[i]; |
5805 | 0 | if (at2[iat].charge == -1 && |
5806 | 0 | !pStruct->endpoint[i] && |
5807 | 0 | (at_Mobile_H_Revrs && |
5808 | 0 | (at_Mobile_H_Revrs[i].endpoint || at2[iat].num_H < at_Mobile_H_Revrs[i].num_H))) |
5809 | 0 | { |
5810 | |
|
5811 | 0 | if (0 <= (e = pVA[iat].nCMinusGroupEdge - 1) && |
5812 | 0 | 0 > FindInEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e) && |
5813 | 0 | !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
5814 | 0 | ( |
5815 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE)) || |
5816 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE)) |
5817 | 0 | )) |
5818 | 0 | { |
5819 | 0 | goto exit_case_23; |
5820 | 0 | } |
5821 | 0 | } |
5822 | 0 | else |
5823 | 0 | { |
5824 | | /* negatively charged atom in Reconstructed structure got H(+) from Normalization */ |
5825 | | /* and is not tautomeric; in the original structure it is tautomeric */ |
5826 | 0 | if (at2[iat].charge == -1 && |
5827 | 0 | pStruct->endpoint[i] && |
5828 | 0 | !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) && |
5829 | 0 | (num_Fixed_H_Revrs && num_Fixed_H_Revrs[i] == -1) && |
5830 | 0 | (pnMobHRevrs && pnMobHRevrs[i] == 1) && |
5831 | 0 | pStruct->fixed_H[i] == 0) |
5832 | 0 | { |
5833 | |
|
5834 | 0 | if (0 <= (e = pVA[iat].nCMinusGroupEdge - 1) && |
5835 | 0 | 0 > FindInEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e) && |
5836 | 0 | !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
5837 | 0 | ( |
5838 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE)) || |
5839 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE)) |
5840 | 0 | )) |
5841 | 0 | { |
5842 | 0 | goto exit_case_23; |
5843 | 0 | } |
5844 | 0 | } |
5845 | 0 | } |
5846 | 0 | } |
5847 | | /* 3. Search for (-) atoms that are tautomeric */ |
5848 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
5849 | 0 | { |
5850 | | /* i = canonical number - 1 */ |
5851 | 0 | iat = nCanon2AtnoRevrs[i]; |
5852 | 0 | if (pStruct->endpoint[i] && |
5853 | 0 | (at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) && |
5854 | 0 | at2[iat].charge == -1 |
5855 | 0 | /*&& pVA[i].cNumValenceElectrons == 6*/) |
5856 | 0 | { |
5857 | 0 | if (0 <= (e = pVA[iat].nCMinusGroupEdge - 1) && |
5858 | 0 | !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
5859 | 0 | 0 > FindInEdgeList(&ChangeableEdges[CHG_SET_O_FIXED], e) && |
5860 | 0 | (ret = AddToEdgeList(&ChangeableEdges[CHG_SET_TAUT], e, INC_ADD_EDGE))) |
5861 | 0 | { |
5862 | 0 | goto exit_case_23; |
5863 | 0 | } |
5864 | 0 | } |
5865 | 0 | } |
5866 | | |
5867 | | /* ------- finally, try to move charges from O=N --------------*/ |
5868 | 0 | for (i = 0; i < num_DB_O; i++) |
5869 | 0 | { |
5870 | 0 | int nDeltaChargeExpected; |
5871 | 0 | one_success = 0; |
5872 | 0 | delta = 1; |
5873 | 0 | iat = iat_DB_O[i]; |
5874 | 0 | peDB_O_Minus = pBNS->edge + ((long long)pVA[iat].nCMinusGroupEdge - 1);/* djb-rwth: cast operator added */ |
5875 | 0 | pe = pBNS->edge + pBNS->vert[iat].iedge[0]; |
5876 | |
|
5877 | 0 | if (!pe->flow) |
5878 | 0 | continue; |
5879 | 0 | pv1 = pBNS->vert + (v1 = pe->neighbor1); |
5880 | 0 | pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); |
5881 | |
|
5882 | 0 | pe->forbidden |= forbidden_edge_mask; |
5883 | |
|
5884 | 0 | pe->flow -= delta; |
5885 | 0 | pv1->st_edge.flow -= delta; |
5886 | 0 | pv2->st_edge.flow -= delta; |
5887 | 0 | pBNS->tot_st_flow -= 2 * delta; |
5888 | |
|
5889 | 0 | for (k = 0; !one_success && k <= CHG_LAST_SET; k++) |
5890 | 0 | { |
5891 | 0 | if (!ChangeableEdges[k].num_edges) |
5892 | 0 | { |
5893 | 0 | continue; |
5894 | 0 | } |
5895 | 0 | nDeltaChargeExpected = (k == CHG_SET_NOOH) ? 2 : 0; |
5896 | |
|
5897 | 0 | SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5898 | 0 | RemoveForbiddenEdgeMask(pBNS, &ChangeableEdges[k], forbidden_edge_mask); |
5899 | | /* allow (-) charge to move to N=O */ |
5900 | 0 | peDB_O_Minus->forbidden &= forbidden_edge_mask_inv; |
5901 | |
|
5902 | 0 | ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
5903 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms); |
5904 | |
|
5905 | 0 | if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) || |
5906 | 0 | (vPathEnd == v2 && vPathStart == v1)) && |
5907 | 0 | nDeltaCharge == nDeltaChargeExpected) /* djb-rwth: addressing LLVM warnings */ |
5908 | 0 | { |
5909 | | /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */ |
5910 | 0 | ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups); |
5911 | 0 | if (ret > 0) |
5912 | 0 | { |
5913 | 0 | nNumRunBNS++; |
5914 | 0 | one_success++; /* 23 */ |
5915 | 0 | } |
5916 | 0 | } |
5917 | 0 | INCHI_HEAPCHK |
5918 | 0 | } |
5919 | 0 | cur_success += one_success; |
5920 | |
|
5921 | 0 | RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask); |
5922 | 0 | pe->forbidden &= forbidden_edge_mask_inv; |
5923 | |
|
5924 | 0 | if (!one_success) |
5925 | 0 | { |
5926 | 0 | pe->flow += delta; |
5927 | 0 | pv1->st_edge.flow += delta; |
5928 | 0 | pv2->st_edge.flow += delta; |
5929 | 0 | pBNS->tot_st_flow += 2 * delta; |
5930 | 0 | } |
5931 | 0 | } |
5932 | 0 | } |
5933 | 0 | exit_case_23: |
5934 | 0 | for (i = 0; i < CHG_SET_NUM; i++) |
5935 | 0 | { |
5936 | 0 | AllocEdgeList(&ChangeableEdges[i], EDGE_LIST_FREE); |
5937 | 0 | } |
5938 | |
|
5939 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
5940 | 0 | if (cur_success) |
5941 | 0 | { |
5942 | 0 | tot_succes += cur_success; |
5943 | | /* recalculate InChI from the structure */ |
5944 | 0 | if (0 > (ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
5945 | 0 | ppt_group_info, ppat_norm, ppat_prep))) |
5946 | 0 | { |
5947 | 0 | goto exit_function; |
5948 | 0 | } |
5949 | 0 | if ((ret = FillOutExtraFixedHDataRestr(pStruct)))/* djb-rwth: addressing LLVM warning */ |
5950 | 0 | { |
5951 | 0 | goto exit_function; |
5952 | 0 | } |
5953 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
5954 | 0 | { |
5955 | 0 | goto exit_function; /* no fixed-H found */ |
5956 | 0 | } |
5957 | 0 | if ((ret = FillOutCMP2FHINCHI(pStruct, at2, pVA, pInChI, pc2i))) /* djb-rwth: addressing LLVM warning */ |
5958 | 0 | { |
5959 | 0 | goto exit_function; |
5960 | 0 | } |
5961 | 0 | if (!pc2i->bHasDifference) |
5962 | 0 | { |
5963 | 0 | goto exit_function; /* nothing to do */ |
5964 | 0 | } |
5965 | 0 | } |
5966 | |
|
5967 | 0 | #undef CHG_SET_NOOH |
5968 | 0 | #undef CHG_SET_WRONG_TAUT |
5969 | 0 | #undef CHG_SET_TAUT |
5970 | 0 | #undef CHG_LAST_SET |
5971 | 0 | #undef CHG_SET_O_FIXED |
5972 | 0 | #undef CHG_SET_NUM |
5973 | 0 | } |
5974 | | |
5975 | 0 | if (pc2i->len_c2at && pc2i->nNumTgInChI == 1) |
5976 | 0 | { |
5977 | | /*------------------------------------------------------------------*/ |
5978 | | /* case 24: InChI norm. -N(-)-N(+)(IV) => -N=N(V) prevents tauto- */ |
5979 | | /* merism on -N(-)- in case of ADP */ |
5980 | | /* */ |
5981 | | /* Solution: convert N(V)=N- ...=X -> N(IV)(+)-N=...-X(-)*/ |
5982 | | /* N(IV)(+)-N(-)-...=X */ |
5983 | | /* */ |
5984 | | /* Orig InChI taut taut, 1 t-group only(ADP?) */ |
5985 | | /* Reconstructed struct non-taut possibly not taut */ |
5986 | | /* */ |
5987 | | /* Details: 1a. store next to N(V) (+)edge its flower edge */ |
5988 | | /* 1b. store next to N(-) edge NO_VERTEX */ |
5989 | | /* 2. Release (-) edges of other missing endpoints or */ |
5990 | | /* all endpoints if no other is missing */ |
5991 | | /* 3. Decrement flow on (+) edge */ |
5992 | | /* if flower edge is stored then expect DeltaCharge=2*/ |
5993 | | /* otherwise DeltaCharge = 0 */ |
5994 | | /*------------------------------------------------------------------*/ |
5995 | 0 | int iat; |
5996 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
5997 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
5998 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
5999 | 0 | inp_ATOM *atf = ( pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds ) ? |
6000 | 0 | pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL; |
6001 | 0 | int iN, one_success; |
6002 | 0 | EdgeIndex ef, e1; |
6003 | 0 | BNS_EDGE *pef; |
6004 | 0 | #define CHG_SET_MISSED_TAUT 0 |
6005 | 0 | #define CHG_SET_OTHER_TAUT_O 1 |
6006 | 0 | #define CHG_SET_OTHER_TAUT_N 2 |
6007 | 0 | #define CHG_LAST_SET 2 /* the last index in trying */ |
6008 | 0 | #define CHG_SET_NN 3 |
6009 | 0 | #define CHG_SET_AVOID 4 |
6010 | 0 | #define CHG_SET_NUM 5 |
6011 | 0 | EDGE_LIST ChangeableEdges[CHG_SET_NUM]; |
6012 | 0 | memset( ChangeableEdges, 0, sizeof( ChangeableEdges ) ); /* djb-rwth: memset_s C11/Annex K variant? */ |
6013 | | /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */ |
6014 | | /* |
6015 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
6016 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
6017 | | */ |
6018 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
6019 | 0 | cur_success = 0; |
6020 | 0 | for (i = 0; i < pc2i->len_c2at; i++) |
6021 | 0 | { |
6022 | 0 | iat = pc2i->c2at[i].atomNumber; |
6023 | 0 | if ( /* orig. InChI info: -N=N(V) */ |
6024 | 0 | pc2i->c2at[i].nValElectr == 5 /* N or P */ && |
6025 | 0 | ( pc2i->c2at[i].endptInChI /* only N */ ) && |
6026 | 0 | ( e1 = pVA[iat].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[e1].forbidden && |
6027 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
6028 | | /* reversed structure info: */ |
6029 | 0 | !pc2i->c2at[i].endptRevrs && |
6030 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
6031 | 0 | pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H && |
6032 | 0 | at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3 && |
6033 | | /* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */ |
6034 | 0 | ( iN = at2[iat].neighbor[at2[iat].bond_type[0] != BOND_TYPE_DOUBLE], |
6035 | 0 | pVA[iN].cNumValenceElectrons == 5 ) && |
6036 | 0 | at2[iN].chem_bonds_valence == 5 && |
6037 | 0 | at2[iN].charge == 0 && !at2[iN].num_H && !at2[iN].radical && |
6038 | 0 | 0 <= ( e = pVA[iN].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
6039 | 0 | 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) |
6040 | 0 | { |
6041 | |
|
6042 | 0 | ef = GetChargeFlowerUpperEdge( pBNS, pVA, e ); /* == NO_VERTEX if N(V) has 4 bonds */ |
6043 | 0 | if (( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE ) ) || |
6044 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], ef, INC_ADD_EDGE ) ) || |
6045 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE ) ) || /* expected nDeltaCharge */ |
6046 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE ) ) || |
6047 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) ) || |
6048 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], ef, INC_ADD_EDGE ) )) |
6049 | 0 | { |
6050 | 0 | goto exit_case_24; |
6051 | 0 | } |
6052 | | /* mark -N= so that (-) will not be moved to it */ |
6053 | 0 | if (0 <= ( e = pVA[iat].nCMinusGroupEdge ) && !pBNS->edge[e].forbidden && |
6054 | 0 | 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && |
6055 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) )) |
6056 | 0 | { |
6057 | 0 | goto exit_case_24; |
6058 | 0 | } |
6059 | 0 | } |
6060 | 0 | else |
6061 | 0 | { |
6062 | 0 | if ( /* orig. InChI info: -N(-)N(IV)(+) */ |
6063 | 0 | atf && |
6064 | 0 | pc2i->c2at[i].nValElectr == 5 /* N or P */ && |
6065 | 0 | pc2i->c2at[i].endptInChI /* only N */ && |
6066 | 0 | ( e = pVA[iat].nCMinusGroupEdge - 1 ) >= 0 && !pBNS->edge[e].forbidden && |
6067 | 0 | pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 && |
6068 | | /* reversed structure info: */ |
6069 | 0 | !pc2i->c2at[i].endptRevrs && |
6070 | 0 | pc2i->c2at[i].nFixHRevrs == 0 && |
6071 | 0 | pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H && |
6072 | 0 | at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 2 && |
6073 | 0 | atf[iat].valence == 2 && atf[iat].chem_bonds_valence == 3 && |
6074 | | /* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */ |
6075 | 0 | ( iN = atf[iat].neighbor[atf[iat].bond_type[0] != BOND_TYPE_DOUBLE], |
6076 | 0 | pVA[iN].cNumValenceElectrons == 5 ) && |
6077 | 0 | at2[iN].charge == 1 && /* double bond neighbor */ |
6078 | 0 | at2[iN].chem_bonds_valence == 4 && |
6079 | 0 | atf[iN].charge == 0 && |
6080 | 0 | atf[iN].chem_bonds_valence == 5 && /* InChI normalization created N(V)=N- out of N(IV)(+)-N(-)- */ |
6081 | 0 | !at2[iN].num_H && !at2[iN].radical && |
6082 | 0 | 0 <= ( e = pVA[iat].nCMinusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow && |
6083 | 0 | 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) |
6084 | 0 | { |
6085 | | /* save (-) edge */ |
6086 | 0 | if (( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE ) ) || |
6087 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], NO_VERTEX, INC_ADD_EDGE ) ) || |
6088 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE ) ) || /* expected nDeltaCharge */ |
6089 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) )) |
6090 | 0 | { |
6091 | 0 | goto exit_case_24; |
6092 | 0 | } |
6093 | 0 | } |
6094 | 0 | } |
6095 | 0 | } |
6096 | 0 | if (!ChangeableEdges[CHG_SET_NN].num_edges) |
6097 | 0 | { |
6098 | 0 | goto exit_case_24; |
6099 | 0 | } |
6100 | | /* Collect all relevant tautomeric atoms */ |
6101 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
6102 | 0 | { |
6103 | | /* i = canonical number - 1 */ |
6104 | 0 | if (!pStruct->endpoint[i]) |
6105 | 0 | { |
6106 | 0 | continue; |
6107 | 0 | } |
6108 | 0 | iat = nCanon2AtnoRevrs[i]; |
6109 | 0 | if (at2[iat].charge || at2[iat].radical || at2[iat].valence == at2[iat].chem_bonds_valence) |
6110 | 0 | { |
6111 | 0 | continue; /* cannot be an acceptor of (-) */ |
6112 | 0 | } |
6113 | 0 | if (0 > ( e = pVA[iat].nCMinusGroupEdge - 1 ) || pBNS->edge[e].forbidden || pBNS->edge[e].flow) |
6114 | 0 | { |
6115 | 0 | continue; |
6116 | 0 | } |
6117 | 0 | if (0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) |
6118 | 0 | { |
6119 | 0 | continue; /* has already been used */ |
6120 | 0 | } |
6121 | | /* missing endpoint */ |
6122 | 0 | if (!( at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint )) |
6123 | 0 | { |
6124 | 0 | if (0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && ( |
6125 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT], e, INC_ADD_EDGE ) ) || |
6126 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) ) )) |
6127 | 0 | { |
6128 | 0 | goto exit_case_24; |
6129 | 0 | } |
6130 | 0 | } |
6131 | 0 | else |
6132 | 0 | { |
6133 | | /* endpoint O */ |
6134 | 0 | if (pVA[iat].cNumValenceElectrons == 6) |
6135 | 0 | { |
6136 | 0 | if (0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && ( |
6137 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_O], e, INC_ADD_EDGE ) ) || |
6138 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) ) )) |
6139 | 0 | { |
6140 | 0 | goto exit_case_24; |
6141 | 0 | } |
6142 | 0 | } |
6143 | 0 | else |
6144 | 0 | { |
6145 | | /* endpoint N */ |
6146 | 0 | if (pVA[iat].cNumValenceElectrons == 5) |
6147 | 0 | { |
6148 | 0 | if (0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && ( |
6149 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_N], e, INC_ADD_EDGE ) ) || |
6150 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) ) )) |
6151 | 0 | { |
6152 | 0 | goto exit_case_24; |
6153 | 0 | } |
6154 | 0 | } |
6155 | 0 | } |
6156 | 0 | } |
6157 | 0 | } |
6158 | | /* ------- finally, try to move charges from -N(-)-N(+) or to N(V) --------------*/ |
6159 | 0 | for (i = 0; i < ChangeableEdges[CHG_SET_NN].num_edges; i += 3) |
6160 | 0 | { |
6161 | 0 | int nDeltaChargeExpected; |
6162 | 0 | one_success = 0; |
6163 | 0 | delta = 1; |
6164 | 0 | pe = pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i]; |
6165 | 0 | pef = ( NO_VERTEX != ChangeableEdges[CHG_SET_NN].pnEdges[i + 1] ) ? |
6166 | 0 | pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i + 1] : NULL; |
6167 | 0 | nDeltaChargeExpected = ChangeableEdges[CHG_SET_NN].pnEdges[i + 2]; |
6168 | |
|
6169 | 0 | if (!pe->flow) |
6170 | 0 | continue; |
6171 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
6172 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
6173 | |
|
6174 | 0 | pe->flow -= delta; |
6175 | 0 | pv1->st_edge.flow -= delta; |
6176 | 0 | pv2->st_edge.flow -= delta; |
6177 | 0 | pBNS->tot_st_flow -= 2 * delta; |
6178 | |
|
6179 | 0 | for (k = 0; !one_success && k <= CHG_LAST_SET; k++) |
6180 | 0 | { |
6181 | 0 | if (!ChangeableEdges[k].num_edges) |
6182 | 0 | { |
6183 | 0 | continue; |
6184 | 0 | } |
6185 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
6186 | 0 | RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask ); |
6187 | | /* allow change of N(V) flower edge */ |
6188 | 0 | if (pef) |
6189 | 0 | { |
6190 | 0 | pef->forbidden &= forbidden_edge_mask_inv; |
6191 | 0 | } |
6192 | |
|
6193 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
6194 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
6195 | |
|
6196 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
6197 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && |
6198 | 0 | nDeltaCharge == nDeltaChargeExpected) /* djb-rwth: addressing LLVM warnings */ |
6199 | 0 | { |
6200 | | /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */ |
6201 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
6202 | 0 | if (ret > 0) |
6203 | 0 | { |
6204 | 0 | nNumRunBNS++; |
6205 | 0 | one_success++; /* 24 */ |
6206 | 0 | } |
6207 | 0 | } |
6208 | 0 | INCHI_HEAPCHK |
6209 | 0 | } |
6210 | 0 | cur_success += one_success; |
6211 | |
|
6212 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
6213 | |
|
6214 | 0 | if (!one_success) |
6215 | 0 | { |
6216 | 0 | pe->flow += delta; |
6217 | 0 | pv1->st_edge.flow += delta; |
6218 | 0 | pv2->st_edge.flow += delta; |
6219 | 0 | pBNS->tot_st_flow += 2 * delta; |
6220 | 0 | } |
6221 | 0 | } |
6222 | 0 | exit_case_24: |
6223 | 0 | for (i = 0; i < CHG_SET_NUM; i++) |
6224 | 0 | { |
6225 | 0 | AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE ); |
6226 | 0 | } |
6227 | |
|
6228 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
6229 | 0 | if (cur_success) |
6230 | 0 | { |
6231 | 0 | tot_succes += cur_success; |
6232 | | /* recalculate InChI from the structure */ |
6233 | 0 | if (0 >( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
6234 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
6235 | 0 | { |
6236 | 0 | goto exit_function; |
6237 | 0 | } |
6238 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
6239 | 0 | { |
6240 | 0 | goto exit_function; |
6241 | 0 | } |
6242 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
6243 | 0 | { |
6244 | 0 | goto exit_function; /* no fixed-H found */ |
6245 | 0 | } |
6246 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
6247 | 0 | { |
6248 | 0 | goto exit_function; |
6249 | 0 | } |
6250 | 0 | if (!pc2i->bHasDifference) |
6251 | 0 | { |
6252 | 0 | goto exit_function; /* nothing to do */ |
6253 | 0 | } |
6254 | 0 | } |
6255 | 0 | #undef CHG_SET_NN |
6256 | 0 | #undef CHG_SET_MISSED_TAUT |
6257 | 0 | #undef CHG_SET_OTHER_TAUT_O |
6258 | 0 | #undef CHG_SET_OTHER_TAUT_N |
6259 | 0 | #undef CHG_LAST_SET |
6260 | 0 | #undef CHG_SET_AVOID |
6261 | 0 | #undef CHG_SET_NUM |
6262 | 0 | } |
6263 | | |
6264 | | /* pStruct->nNumRemovedProtonsMobHInChI == pc2i->nNumRemHInChI */ |
6265 | | |
6266 | 0 | if (pc2i->len_c2at && pc2i->nNumTgInChI == 1 && |
6267 | 0 | pc2i->nNumRemHRevrs > pc2i->nNumRemHInChI && 0 > pc2i->nNumRemHInChI && |
6268 | 0 | ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || |
6269 | 0 | pc2i->nNumTgRevrs > pc2i->nNumTgInChI )) |
6270 | 0 | { |
6271 | | /*------------------------------------------------------------------*/ |
6272 | | /* case 25: Restored InChI does not have 2 or more added protons */ |
6273 | | /* possibly taut. endpoints are missing */ |
6274 | | /* has -N(-O(-))-O(-) group(s) */ |
6275 | | /* Original InChI has only one t-group */ |
6276 | | /* */ |
6277 | | /* Solution: convert -N(-O(-))-O(-) -> -N(+)(=O)-O(-) */ |
6278 | | /* and direct 2(-) to the missing taut atoms*/ |
6279 | | /* at first attempt try to move (-) to N only */ |
6280 | | /* */ |
6281 | | /*------------------------------------------------------------------*/ |
6282 | 0 | int iat; |
6283 | 0 | AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0]; |
6284 | 0 | AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0]; |
6285 | 0 | inp_ATOM *at_Mobile_H_Revrs = ( pStruct->pOne_norm_data[1] && |
6286 | 0 | pStruct->pOne_norm_data[1]->at ) ? pStruct->pOne_norm_data[1]->at : NULL; |
6287 | | /* |
6288 | | inp_ATOM *atf = (pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds)? |
6289 | | pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL; |
6290 | | */ |
6291 | 0 | int iN, neigh, one_success; |
6292 | 0 | EdgeIndex e1, bFirst; |
6293 | 0 | BNS_EDGE *pef; |
6294 | 0 | #define CHG_SET_MISSED_TAUT_1 0 |
6295 | 0 | #define CHG_SET_MISSED_TAUT_ALL 1 |
6296 | 0 | #define CHG_SET_OTHER_TAUT_1 2 |
6297 | 0 | #define CHG_SET_OTHER_TAUT_ALL 3 |
6298 | 0 | #define CHG_LAST_SET 3 /* the last index in trying */ |
6299 | 0 | #define CHG_SET_NO_IN_NO2M2 4 |
6300 | 0 | #define CHG_SET_AVOID 5 |
6301 | 0 | #define CHG_SET_NUM 6 |
6302 | 0 | EDGE_LIST ChangeableEdges[CHG_SET_NUM]; |
6303 | 0 | memset( ChangeableEdges, 0, sizeof( ChangeableEdges ) ); /* djb-rwth: memset_s C11/Annex K variant? */ |
6304 | | /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */ |
6305 | | /* |
6306 | | S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H : |
6307 | | pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0; |
6308 | | */ |
6309 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
6310 | 0 | cur_success = 0; |
6311 | | /* find all -N(-O(-))-O(-) */ |
6312 | 0 | for (i = 0; i < pStruct->num_atoms; i++) |
6313 | 0 | { |
6314 | 0 | iat = nCanon2AtnoRevrs[i]; |
6315 | 0 | if (pStruct->endpoint[i]) |
6316 | 0 | { |
6317 | 0 | if (0 >( e = pVA[iat].nCMinusGroupEdge - 1 ) || pBNS->edge[e].forbidden || |
6318 | 0 | 0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) |
6319 | 0 | { |
6320 | 0 | continue; |
6321 | 0 | } |
6322 | 0 | bFirst = ( (pVA[iat].cNumValenceElectrons == 5 && pc2i->nNumTgInChI == 1) || |
6323 | 0 | (pVA[iat].cNumValenceElectrons == 6 && pc2i->nNumTgInChI != 1) ); /* djb-rwth: addressing LLVM warnings */ |
6324 | | /* many or no t-groups -> try O only first */ |
6325 | | /* single t-group -> try only N first */ |
6326 | 0 | if (!( at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint )) |
6327 | 0 | { |
6328 | | /* missed tautomeric endpoint */ |
6329 | 0 | if (bFirst && |
6330 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_1], e, INC_ADD_EDGE ) )) |
6331 | 0 | { |
6332 | 0 | goto exit_case_25; |
6333 | 0 | } |
6334 | 0 | if ((ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_ALL], e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
6335 | 0 | { |
6336 | 0 | goto exit_case_25; |
6337 | 0 | } |
6338 | 0 | } |
6339 | 0 | if (bFirst && |
6340 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_1], e, INC_ADD_EDGE ) )) |
6341 | 0 | { |
6342 | 0 | goto exit_case_25; |
6343 | 0 | } |
6344 | 0 | if ((ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_ALL], e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
6345 | 0 | { |
6346 | 0 | goto exit_case_25; |
6347 | 0 | } |
6348 | 0 | if ((ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ))) /* djb-rwth: addressing LLVM warning */ |
6349 | 0 | { |
6350 | 0 | goto exit_case_25; |
6351 | 0 | } |
6352 | 0 | } |
6353 | 0 | else |
6354 | 0 | { |
6355 | 0 | if (at2[iat].valence == 1 && at2[iat].charge == -1 && |
6356 | 0 | pVA[iat].cNumValenceElectrons == 6 && |
6357 | 0 | pVA[iN = at2[iat].neighbor[0]].cNumValenceElectrons == 5 && /* -O(-) */ |
6358 | 0 | !pStruct->endpoint[nAtno2CanonRevrs[iN]] && |
6359 | 0 | at2[iN].valence == 3 && at2[iN].chem_bonds_valence == 3 && |
6360 | 0 | !at2[iN].charge && !at2[iN].radical && |
6361 | 0 | 0 <= ( e = pVA[iN].nCPlusGroupEdge - 1 ) && !pBNS->edge[e].forbidden && |
6362 | 0 | pBNS->edge[e].flow && /* NPlus edge */ |
6363 | 0 | 0 <= ( e1 = pVA[iat].nCMinusGroupEdge - 1 ) && !pBNS->edge[e1].forbidden && |
6364 | 0 | pBNS->edge[e1].flow && /* OMinus edge */ |
6365 | 0 | 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && |
6366 | 0 | 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1 )) |
6367 | 0 | { |
6368 | | /* found >N-O(-) */ |
6369 | 0 | int nNumO = 0, nNumOthers = 0; |
6370 | 0 | for (k = 0; k < at2[iN].valence; k++) |
6371 | 0 | { |
6372 | 0 | neigh = at2[iN].neighbor[k]; |
6373 | 0 | if (neigh == iat) |
6374 | 0 | { |
6375 | 0 | continue; |
6376 | 0 | } |
6377 | 0 | if (pVA[neigh].cNumValenceElectrons == 6 && |
6378 | 0 | !pStruct->endpoint[neigh] && |
6379 | 0 | at2[neigh].valence == 1 && at2[neigh].num_H == 0 && |
6380 | 0 | at2[neigh].radical == 0 && at2[neigh].charge == -1 && |
6381 | 0 | at2[neigh].chem_bonds_valence == 1) |
6382 | 0 | { |
6383 | 0 | nNumO++; |
6384 | 0 | } |
6385 | 0 | else |
6386 | 0 | { |
6387 | 0 | if (at2[iN].bond_type[k] == BOND_TYPE_SINGLE && |
6388 | 0 | at2[neigh].valence > 1 && |
6389 | 0 | at2[neigh].valence < at2[neigh].chem_bonds_valence) |
6390 | 0 | { |
6391 | 0 | nNumOthers++; |
6392 | 0 | } |
6393 | 0 | } |
6394 | 0 | } |
6395 | 0 | if (nNumO != 1 && nNumOthers != 1) |
6396 | 0 | { |
6397 | 0 | continue; |
6398 | 0 | } |
6399 | | /* save charge edges: NPlus first, OMinus second */ |
6400 | 0 | if (( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e, INC_ADD_EDGE ) ) || |
6401 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e1, INC_ADD_EDGE ) ) || |
6402 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ) ) || |
6403 | 0 | ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE ) )) |
6404 | 0 | { |
6405 | 0 | goto exit_case_25; |
6406 | 0 | } |
6407 | 0 | } |
6408 | 0 | } |
6409 | 0 | } |
6410 | 0 | if (!ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges || |
6411 | 0 | !ChangeableEdges[CHG_SET_OTHER_TAUT_ALL].num_edges) |
6412 | 0 | { |
6413 | 0 | goto exit_case_25; |
6414 | 0 | } |
6415 | | /* ------- finally, try to move charges from -NO2(2-) or to tautomeric endpoints ----*/ |
6416 | 0 | for (i = 0; i < ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges; i += 2) |
6417 | 0 | { |
6418 | 0 | int nDeltaChargeExpected = 3; |
6419 | | /* change flow on O(-) to make it neutral; 3 new charges will be created: |
6420 | | N(+), and two (-) on InChI endpoints |
6421 | | alternatively, if we change flow on N to make N(+) then O(-) will |
6422 | | be nutralized (-1 charge) and two (-) charges on taut. endpoints will be |
6423 | | created (+2); the total change in this case would be (-1)+(+2) = +1 |
6424 | | */ |
6425 | 0 | one_success = 0; |
6426 | 0 | delta = 1; |
6427 | 0 | pe = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i + 1]; /* O(-) edge */ |
6428 | 0 | pef = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i]; /* >N- (+) edge */ |
6429 | |
|
6430 | 0 | if (!pe->flow) |
6431 | 0 | continue; |
6432 | 0 | pv1 = pBNS->vert + ( v1 = pe->neighbor1 ); |
6433 | 0 | pv2 = pBNS->vert + ( v2 = pe->neighbor12 ^ v1 ); |
6434 | |
|
6435 | 0 | pe->flow -= delta; |
6436 | 0 | pv1->st_edge.flow -= delta; |
6437 | 0 | pv2->st_edge.flow -= delta; |
6438 | 0 | pBNS->tot_st_flow -= 2 * delta; |
6439 | |
|
6440 | 0 | for (k = 0; !one_success && k <= CHG_LAST_SET; k++) |
6441 | 0 | { |
6442 | 0 | if (!ChangeableEdges[k].num_edges) |
6443 | 0 | { |
6444 | 0 | continue; |
6445 | 0 | } |
6446 | 0 | SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
6447 | 0 | RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask ); |
6448 | | /* allow change of N(V) flower edge */ |
6449 | 0 | pef->forbidden &= forbidden_edge_mask_inv; |
6450 | |
|
6451 | 0 | ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen, |
6452 | 0 | &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms ); |
6453 | |
|
6454 | 0 | if (ret == 1 && ( (vPathEnd == v1 && vPathStart == v2) || |
6455 | 0 | (vPathEnd == v2 && vPathStart == v1) ) && |
6456 | 0 | nDeltaCharge == nDeltaChargeExpected) /* djb-rwth: addressing LLVM warnings */ |
6457 | 0 | { |
6458 | | /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */ |
6459 | 0 | ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups ); |
6460 | 0 | if (ret > 0) |
6461 | 0 | { |
6462 | 0 | nNumRunBNS++; |
6463 | 0 | one_success++; /* 24 */ |
6464 | 0 | } |
6465 | 0 | } |
6466 | 0 | INCHI_HEAPCHK |
6467 | 0 | } |
6468 | 0 | cur_success += one_success; |
6469 | |
|
6470 | 0 | RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask ); |
6471 | |
|
6472 | 0 | if (!one_success) |
6473 | 0 | { |
6474 | 0 | pe->flow += delta; |
6475 | 0 | pv1->st_edge.flow += delta; |
6476 | 0 | pv2->st_edge.flow += delta; |
6477 | 0 | pBNS->tot_st_flow += 2 * delta; |
6478 | 0 | } |
6479 | 0 | } |
6480 | 0 | exit_case_25: |
6481 | 0 | for (i = 0; i < CHG_SET_NUM; i++) |
6482 | 0 | { |
6483 | 0 | AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE ); |
6484 | 0 | } |
6485 | |
|
6486 | 0 | CurrEdges.num_edges = 0; /* clear current edge list */ |
6487 | 0 | if (cur_success) |
6488 | 0 | { |
6489 | 0 | tot_succes += cur_success; |
6490 | | /* recalculate InChI from the structure */ |
6491 | 0 | if (0 >( ret = MakeOneInChIOutOfStrFromINChI2( pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups, |
6492 | 0 | ppt_group_info, ppat_norm, ppat_prep ) )) |
6493 | 0 | { |
6494 | 0 | goto exit_function; |
6495 | 0 | } |
6496 | 0 | if ((ret = FillOutExtraFixedHDataRestr( pStruct ))) /* djb-rwth: addressing LLVM warning */ |
6497 | 0 | { |
6498 | 0 | goto exit_function; |
6499 | 0 | } |
6500 | 0 | if (!pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed) |
6501 | 0 | { |
6502 | 0 | goto exit_function; /* no fixed-H found */ |
6503 | 0 | } |
6504 | 0 | if ((ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ))) /* djb-rwth: addressing LLVM warning */ |
6505 | 0 | { |
6506 | 0 | goto exit_function; |
6507 | 0 | } |
6508 | 0 | if (!pc2i->bHasDifference) |
6509 | 0 | { |
6510 | 0 | goto exit_function; /* nothing to do */ |
6511 | 0 | } |
6512 | 0 | } |
6513 | 0 | #undef CHG_SET_NN |
6514 | 0 | #undef CHG_SET_MISSED_TAUT |
6515 | 0 | #undef CHG_SET_OTHER_TAUT_O |
6516 | 0 | #undef CHG_SET_OTHER_TAUT_N |
6517 | 0 | #undef CHG_LAST_SET |
6518 | 0 | #undef CHG_SET_AVOID |
6519 | 0 | #undef CHG_SET_NUM |
6520 | 0 | } |
6521 | | |
6522 | | |
6523 | 0 | exit_function: |
6524 | |
|
6525 | 0 | AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE ); |
6526 | 0 | AllocEdgeList( &CurrEdges, EDGE_LIST_FREE ); |
6527 | 0 | AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE ); |
6528 | 0 | AllocEdgeList( &SFlowerEdges, EDGE_LIST_FREE ); |
6529 | 0 | AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE ); |
6530 | 0 | AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_FREE ); |
6531 | 0 | AllocEdgeList( &AllBondEdges, EDGE_LIST_FREE ); |
6532 | |
|
6533 | 0 | return ret < 0 ? ret : ( tot_succes && pc2i->bHasDifference ); |
6534 | 0 | } |
6535 | | |
6536 | | #endif |