Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : : #include <string.h>
42 : :
43 : : /*#define CHECK_WIN32_VC_HEAP*/
44 : :
45 : : #include "mode.h"
46 : :
47 : : #if ( READ_INCHI_STRING == 1 )
48 : : #include "ichitime.h"
49 : : #include "ichirvrs.h"
50 : : #include "ichicant.h"
51 : : #include "ichi_io.h"
52 : : #include "ichimake.h"
53 : :
54 : : #include "bcf_s.h"
55 : :
56 : : /****************************************************************************/
57 : 0 : int ForbidCarbonChargeEdges(BN_STRUCT* pBNS,
58 : : ALL_TC_GROUPS* pTCGroups,
59 : : EDGE_LIST* pCarbonChargeEdges,
60 : : int forbidden_edge_mask)
61 : : {
62 : : #define MAX_NUM_CARBON_CHARGE_EDGES 2
63 : : int nType, i, k, ret;
64 : : BNS_EDGE* pEdge;
65 [ # # ]: 0 : if ((ret = AllocEdgeList(pCarbonChargeEdges, MAX_NUM_CARBON_CHARGE_EDGES))) /* djb-rwth: addressing LLVM warning */
66 : : {
67 : 0 : goto exit_function;
68 : : }
69 : 0 : pCarbonChargeEdges->num_edges = 0;
70 [ # # ]: 0 : for (i = 0; i < MAX_NUM_CARBON_CHARGE_EDGES; i++)
71 : : {
72 [ # # # ]: 0 : switch (i)
73 : : {
74 : 0 : case 0:
75 : 0 : nType = TCG_Plus_C0;
76 : 0 : break;
77 : 0 : case 1:
78 : 0 : nType = TCG_Minus_C0;
79 : 0 : break;
80 : 0 : default:
81 : 0 : ret = RI_ERR_PROGR;
82 : 0 : goto exit_function;
83 : : }
84 [ # # ]: 0 : if ((k = pTCGroups->nGroup[nType]) >= 0)
85 : : {
86 : 0 : k = pTCGroups->pTCG[k].nForwardEdge;
87 [ # # ]: 0 : if (k > 0)
88 : : {
89 : 0 : pEdge = pBNS->edge + k;
90 [ # # ]: 0 : if (!(pEdge->forbidden & forbidden_edge_mask))
91 : : {
92 : 0 : pEdge->forbidden |= forbidden_edge_mask;
93 [ # # ]: 0 : if ((ret = AddToEdgeList(pCarbonChargeEdges, k, 0))) /* djb-rwth: addressing LLVM warning */
94 : : {
95 : 0 : goto exit_function;
96 : : }
97 : : }
98 : : }
99 : : else
100 : : {
101 : 0 : ret = RI_ERR_PROGR;
102 : 0 : goto exit_function;
103 : : }
104 : : }
105 : : }
106 : 0 : ret = pCarbonChargeEdges->num_edges;
107 : :
108 : 0 : exit_function:
109 : :
110 : 0 : return ret;
111 : : #undef MAX_NUM_CARBON_CHARGE_EDGES
112 : : }
113 : :
114 : :
115 : : /****************************************************************************/
116 : 0 : int ForbidNintrogenPlus2BondsInSmallRings(BN_STRUCT* pBNS,
117 : : inp_ATOM* at,
118 : : int num_at,
119 : : VAL_AT* pVA,
120 : : int min_ring_size,
121 : : ALL_TC_GROUPS* pTCGroups,
122 : : EDGE_LIST* pNplus2BondsEdges,
123 : : int forbidden_edge_mask)
124 : : {
125 : : int i, j, ret;
126 : : BNS_EDGE* e;
127 : :
128 : : /* djb-rwth: removing redundant code */
129 : : /* --- forbid edges that allow to make =N(+)= or #N(+)- in small ring */
130 [ # # ]: 0 : for (i = 0; i < num_at; i++)
131 : : {
132 [ # # ]: 0 : if (at[i].valence == 2 &&
133 [ # # # # ]: 0 : !at[i].num_H && !at[i].endpoint &&
134 [ # # ]: 0 : pVA[i].cNumValenceElectrons == 5 &&
135 [ # # ]: 0 : pVA[i].cPeriodicRowNumber == 1 &&
136 [ # # # # ]: 0 : !pVA[i].cMaxFlowToMetal && pVA[i].nCPlusGroupEdge > 0 &&
137 [ # # # # ]: 0 : pVA[i].cnListIndex > 0 && cnList[pVA[i].cnListIndex - 1].bits == cn_bits_MNP &&
138 [ # # # # ]: 0 : pVA[i].cMinRingSize && pVA[i].cMinRingSize <= min_ring_size)
139 : : {
140 : :
141 : 0 : e = pBNS->edge + (j = pVA[i].nCPlusGroupEdge - 1);
142 [ # # ]: 0 : if (!(e->forbidden & forbidden_edge_mask))
143 : : {
144 : 0 : e->forbidden |= forbidden_edge_mask;
145 [ # # ]: 0 : if ((ret = AddToEdgeList(pNplus2BondsEdges, j, 128))) /* djb-rwth: addressing LLVM warning */
146 : : {
147 : 0 : goto exit_function;
148 : : }
149 : : }
150 : : }
151 : : }
152 : 0 : ret = 0;
153 : :
154 : 0 : exit_function:
155 : :
156 : 0 : return ret;
157 : : }
158 : :
159 : :
160 : : /****************************************************************************
161 : : Problem: Formula in InChI from the reversed structure has
162 : : less H than in the input InChI
163 : : Solutions:
164 : :
165 : : (a) | |
166 : : -B(-)-NH-=..-=N(+)< => -B(-)-NH(+)=-..=-N<
167 : : | |
168 : :
169 : : (H is not removed from the ion pair)
170 : :
171 : : | |
172 : : (b) >N(+)=-=...-=N-NH => >N-=-...=-N(+)-NH
173 : : | |
174 : :
175 : : (charge from onium cannot be moved to remove H+)
176 : : ****************************************************************************/
177 : 0 : int FixLessHydrogenInFormula(BN_STRUCT* pBNS,
178 : : BN_DATA* pBD,
179 : : StrFromINChI* pStruct,
180 : : inp_ATOM* at,
181 : : inp_ATOM* at2,
182 : : inp_ATOM* atf,
183 : : VAL_AT* pVA,
184 : : ALL_TC_GROUPS* pTCGroups,
185 : : int* pnNumRunBNS,
186 : : int* pnTotalDelta, int forbidden_edge_mask)
187 : : {
188 : 0 : int iBPlus = NO_VERTEX, iNV = NO_VERTEX, iNH = NO_VERTEX, neigh;
189 : : EDGE_LIST NewlyFixedEdges;
190 : : int ret, i, j;
191 : 0 : int num_at = pStruct->num_atoms;
192 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
193 : : /* for RunBnsTestOnce */
194 : : Vertex vPathStart, vPathEnd;
195 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
196 : :
197 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_CLEAR);
198 [ # # ]: 0 : if ((ret = AllocEdgeList(&NewlyFixedEdges, 2 * num_at))) /* djb-rwth: addressing LLVM warning */
199 : : {
200 : 0 : goto exit_function;
201 : : }
202 [ # # ]: 0 : for (i = 0; i < num_at; i++)
203 : : {
204 [ # # ]: 0 : if ((j = pVA[i].nCMinusGroupEdge - 1) >= 0)
205 : : {
206 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
207 : : {
208 : 0 : goto exit_function;
209 : : }
210 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
211 : : }
212 [ # # ]: 0 : if ((j = pVA[i].nCPlusGroupEdge - 1) >= 0)
213 : : {
214 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
215 : : {
216 : 0 : goto exit_function;
217 : : }
218 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
219 : : }
220 : : }
221 : : /* extra H has been removed; check non-tautomeric atoms */
222 [ # # ]: 0 : for (i = 0; i < num_at; i++)
223 : : {
224 [ # # # # ]: 0 : if (!at2[i].endpoint && !pVA[i].cMetal &&
225 [ # # # # ]: 0 : pVA[i].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
226 [ # # ]: 0 : at2[i].num_H == atf[i].num_H + 1)
227 : : {
228 : : /* H was removed from N */
229 : 0 : iNH = i;
230 : 0 : break;
231 : : }
232 : : }
233 [ # # # # ]: 0 : if (0 <= iNH && iNH < num_at)
234 : : {
235 : : /* check neighbors for | |
236 : : (a) -B(+)- or (b) =N-
237 : : | |
238 : : */
239 [ # # ]: 0 : for (j = 0; j < at2[i].valence; j++)
240 : : {
241 : 0 : neigh = at2[iNH].neighbor[j];
242 [ # # ]: 0 : if (at2[neigh].valence == 4)
243 : : {
244 [ # # # # ]: 0 : if (at2[neigh].charge == -1 && at2[neigh].chem_bonds_valence == 4 &&
245 [ # # # # ]: 0 : !at2[neigh].radical && !at[neigh].num_H)
246 : : {
247 : 0 : iBPlus = neigh;
248 : : }
249 : : }
250 : : }
251 : : }
252 [ # # # # ]: 0 : if (0 <= iNH && iNH < num_at)
253 : : {
254 : : int bond_type_at2;
255 : : int bond_type_atf;
256 : : /* djb-rwth: removing redundant variables */
257 : 0 : int delta = -1, nxt = iNH, prv = NO_VERTEX, nxt_is_NPlus;
258 : : /* the changed bond to the dehydrogenated atom H should have greater order */
259 : : /* delta = (new bond order in atf[]) - (restored bond order in at2[]) */
260 : 0 : nxt_is_NPlus = 0;
261 : : do
262 : : {
263 : 0 : i = nxt;
264 : 0 : nxt = NO_VERTEX;
265 : 0 : delta = -delta;
266 [ # # ]: 0 : for (j = 0; j < at2[i].valence; j++)
267 : : {
268 : 0 : bond_type_at2 = at2[i].bond_type[j] & BOND_TYPE_MASK; /* restored bond */
269 : 0 : bond_type_atf = atf[i].bond_type[j] & BOND_TYPE_MASK; /* normalized bond */
270 : 0 : nxt_is_NPlus = 0;
271 [ # # # # ]: 0 : if ((bond_type_atf - bond_type_at2 == delta || bond_type_atf == BOND_ALT12NS) &&
272 [ # # # # ]: 0 : BOND_TYPE_SINGLE <= bond_type_at2 + delta && bond_type_at2 + delta <= BOND_TYPE_TRIPLE &&
273 [ # # ]: 0 : !at2[(int)at2[i].neighbor[j]].cFlags)
274 : : {
275 : 0 : prv = i;
276 : 0 : nxt = at2[i].neighbor[j];
277 [ # # ]: 0 : nxt_is_NPlus = at2[nxt].charge == 1 && atf[nxt].charge == 0 &&
278 [ # # # # : 0 : pVA[nxt].cNumValenceElectrons == 5 && pVA[nxt].cPeriodicRowNumber == 1;
# # ]
279 : 0 : at2[i].cFlags |= 1; /* avoid cycling */
280 : : /* djb-rwth: removing redundant code */
281 [ # # # # : 0 : if (delta == -1 && at2[prv].valence == 4 && at2[prv].chem_bonds_valence == 5 &&
# # ]
282 [ # # # # : 0 : !at2[prv].charge && !at2[prv].radical && pVA[prv].cNumValenceElectrons == 5 &&
# # ]
283 [ # # ]: 0 : pVA[prv].nCPlusGroupEdge > 0)
284 : : {
285 : 0 : iNV = prv;
286 : : }
287 [ # # ]: 0 : if (at2[nxt].charge != atf[nxt].charge)
288 : : {
289 [ # # # # ]: 0 : if ((at2[nxt].charge == 1 || atf[nxt].charge == 1) &&
290 [ # # ]: 0 : pVA[nxt].nCPlusGroupEdge > 0)
291 : : {
292 : 0 : pBNS->edge[pVA[nxt].nCPlusGroupEdge - 1].forbidden &= inv_forbidden_edge_mask;
293 : : }
294 [ # # # # ]: 0 : if ((at2[nxt].charge == -1 || atf[nxt].charge == -1) &&
295 [ # # ]: 0 : pVA[nxt].nCMinusGroupEdge > 0)
296 : : {
297 : 0 : pBNS->edge[pVA[nxt].nCMinusGroupEdge - 1].forbidden &= inv_forbidden_edge_mask;
298 : : }
299 : : }
300 : 0 : break; /* found */
301 : : }
302 : : }
303 [ # # # # : 0 : } while (nxt >= 0 && !(nxt_is_NPlus && delta == -1));
# # ]
304 [ # # ]: 0 : for (i = 0; i < num_at; i++)
305 : : {
306 : 0 : at2[i].cFlags = 0;
307 : : }
308 [ # # # # : 0 : if (nxt >= 0 && nxt_is_NPlus && delta == -1)
# # ]
309 : : {
310 : : /* a simple alt path from NH-= to =N(+) has been found */
311 [ # # # # ]: 0 : if (iBPlus || iNV)
312 : : {
313 : : /* move (+) charge from N(+) to iNV or, if iBPlus, then to iNH */
314 [ # # # # : 0 : if ((iNV >= 0 && (j = pVA[iNV].nCPlusGroupEdge - 1) > 0 && pBNS->edge[j].flow > 0) ||
# # # # ]
315 [ # # # # ]: 0 : (iNH >= 0 && (j = pVA[iNH].nCPlusGroupEdge - 1) > 0 && pBNS->edge[j].flow > 0)) /* djb-rwth: addressing LLVM warnings */
316 : : {
317 : : int ieFlower;
318 : 0 : BNS_EDGE* pe = pBNS->edge + j, * peFlower = NULL;
319 : 0 : Vertex v1 = pe->neighbor1;
320 : 0 : Vertex v2 = v1 ^ pe->neighbor12;
321 : 0 : BNS_VERTEX* pv1 = pBNS->vert + v1;
322 : 0 : BNS_VERTEX* pv2 = pBNS->vert + v2;
323 : :
324 : 0 : delta = 1;
325 : : /* prevent conversion of >N(+)= into N(V) neutral */
326 : 0 : ieFlower = GetChargeFlowerUpperEdge(pBNS, pVA, pVA[nxt].nCPlusGroupEdge - 1);
327 [ # # ]: 0 : if (ieFlower >= 0)
328 : : {
329 : 0 : peFlower = pBNS->edge + ieFlower;
330 [ # # ]: 0 : if (peFlower->flow == delta)
331 : : {
332 : 0 : peFlower->forbidden |= forbidden_edge_mask;
333 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, ieFlower, 0))) /* djb-rwth: addressing LLVM warning */
334 : : {
335 : 0 : goto exit_function;
336 : : }
337 : : }
338 : : }
339 : 0 : pe->forbidden |= forbidden_edge_mask;
340 : 0 : pe->flow -= delta;
341 : 0 : pv1->st_edge.flow -= delta;
342 : 0 : pv2->st_edge.flow -= delta;
343 : 0 : pBNS->tot_st_flow -= 2 * delta;
344 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
345 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
346 [ # # ]: 0 : if (ret < 0)
347 : : {
348 : 0 : goto exit_function;
349 : : }
350 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) ||
# # ]
351 [ # # # # ]: 0 : (vPathEnd == v2 && vPathStart == v1)) &&
352 [ # # ]: 0 : nDeltaCharge <= 0 /* charge moving to this atom disappers*/) /* djb-rwth: addressing LLVM warnings */
353 : : {
354 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
355 : 0 : (*pnNumRunBNS)++;
356 [ # # ]: 0 : if (ret < 0)
357 : : {
358 : 0 : goto exit_function;
359 : : }
360 : : else
361 [ # # ]: 0 : if (ret == 1)
362 : : {
363 : 0 : *pnTotalDelta += ret;
364 : : }
365 : : else
366 : : {
367 : 0 : ret = RI_ERR_PROGR;
368 : 0 : goto exit_function;
369 : : }
370 : : }
371 : : else
372 : : {
373 : 0 : ret = 0;
374 : 0 : pe->flow += delta;
375 : 0 : pv1->st_edge.flow += delta;
376 : 0 : pv2->st_edge.flow += delta;
377 : 0 : pBNS->tot_st_flow += 2 * delta;
378 : : }
379 : : }
380 : : }
381 : : }
382 : : }
383 : :
384 : 0 : exit_function:
385 : : /* remove bond fixation */
386 : 0 : RemoveForbiddenEdgeMask(pBNS, &NewlyFixedEdges, forbidden_edge_mask);
387 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_FREE);
388 : :
389 : 0 : return ret;
390 : : }
391 : :
392 : :
393 : : /****************************************************************************
394 : :
395 : : X=Y-O(-) => X(-)-Y=O
396 : :
397 : : ****************************************************************************/
398 : 0 : int FixMoreHydrogenInFormula(BN_STRUCT* pBNS,
399 : : BN_DATA* pBD,
400 : : StrFromINChI* pStruct,
401 : : inp_ATOM* at,
402 : : inp_ATOM* at2,
403 : : inp_ATOM* atf,
404 : : VAL_AT* pVA,
405 : : ALL_TC_GROUPS* pTCGroups,
406 : : int* pnNumRunBNS,
407 : : int* pnTotalDelta,
408 : : int forbidden_edge_mask)
409 : : {
410 : 0 : int iNH = NO_VERTEX, neigh, neigh2;
411 : : EDGE_LIST NewlyFixedEdges;
412 : 0 : int ret, i, j, k, k2 = 0, delta;
413 : 0 : int num_at = pStruct->num_atoms;
414 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
415 : : Vertex v1, v2;
416 : : /* for RunBnsTestOnce */
417 : : Vertex vPathStart, vPathEnd;
418 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
419 : : BNS_EDGE* pe, * pe2;
420 : :
421 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_CLEAR);
422 [ # # ]: 0 : if ((ret = AllocEdgeList(&NewlyFixedEdges, 2 * num_at))) /* djb-rwth: addressing LLVM warning */
423 : : {
424 : 0 : goto exit_function;
425 : : }
426 : : /* fix all charges */
427 [ # # ]: 0 : for (i = 0; i < num_at; i++)
428 : : {
429 [ # # ]: 0 : if ((j = pVA[i].nCMinusGroupEdge - 1) >= 0)
430 : : {
431 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
432 : : {
433 : 0 : goto exit_function;
434 : : }
435 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
436 : : }
437 [ # # ]: 0 : if ((j = pVA[i].nCPlusGroupEdge - 1) >= 0)
438 : : {
439 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
440 : : {
441 : 0 : goto exit_function;
442 : : }
443 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
444 : : }
445 : : }
446 : :
447 : : /* H(+) has been added to -O(-); check non-tautomeric atoms */
448 [ # # ]: 0 : for (i = 0; i < num_at; i++)
449 : : {
450 : 0 : neigh = at2[i].neighbor[0]; /* djb-rwth: avoiding unsequenced modification and access to neigh */
451 [ # # # # : 0 : if (!(pStruct->bMobileH ? at2[i].endpoint : pStruct->endpoint[i]) && !pVA[i].cMetal &&
# # ]
452 [ # # ]: 0 : at2[i].num_H + 1 == atf[i].num_H && /* normalization added H ??? What would happen in Fixed-H case?*/
453 [ # # ]: 0 : (k = pVA[i].nCMinusGroupEdge - 1) >= 0 &&
454 [ # # ]: 0 : pBNS->edge[k].flow == 1 && /* atom had (-) charge before preprocessing */
455 [ # # # # ]: 0 : at2[i].charge == -1 && atf[i].charge == 0 && /* and has no charge after preprocessing */
456 [ # # # # ]: 0 : at2[i].valence == 1 && at2[i].chem_bonds_valence == 1 && /* connected by a single bond */
457 [ # # ]: 0 : pVA[i].cNumValenceElectrons == 6 && /* atom is O, S, Se, Te */
458 [ # # ]: 0 : at2[neigh].chem_bonds_valence > at2[neigh].valence
459 : : /* atom's single neighbor has multiple bond(s)*/
460 : : )
461 : : {
462 : : /* H(+) was added to O in Y=X-O(-), where X is the only neighbor of O, X=neigh, Y=neigh2 */
463 : 0 : iNH = i;
464 [ # # ]: 0 : for (j = 0; j < at2[neigh].valence; j++)
465 : : {
466 : 0 : neigh2 = at2[neigh].neighbor[j];
467 [ # # # # ]: 0 : if (neigh2 != iNH && !at2[neigh2].endpoint &&
468 [ # # ]: 0 : !pBNS->edge[(int)pBNS->vert[neigh].iedge[j]].forbidden &&
469 [ # # ]: 0 : 4 <= pVA[neigh2].cNumValenceElectrons &&
470 [ # # ]: 0 : pVA[neigh2].cNumValenceElectrons <= 5 && /* neig2 is C or N */
471 [ # # ]: 0 : (k2 = pVA[neigh2].nCMinusGroupEdge - 1) >= 0 &&
472 [ # # ]: 0 : !pBNS->edge[k2].flow /* negative charge may be moved to neigh2 */)
473 : : {
474 : 0 : break;
475 : : }
476 : : }
477 [ # # ]: 0 : if (j < at2[neigh].valence)
478 : : {
479 : 0 : delta = 1;
480 : 0 : pe = pBNS->edge + k; /* -O(-) negative charge edge; flow = 1 */
481 : 0 : pe2 = pBNS->edge + k2; /* X charge edge; flow = 0 */
482 : 0 : v1 = pe->neighbor1;
483 : 0 : v2 = pe->neighbor12 ^ v1;
484 : 0 : pe->flow -= delta;
485 : 0 : pBNS->vert[v1].st_edge.flow -= delta;
486 : 0 : pBNS->vert[v2].st_edge.flow -= delta;
487 : 0 : pBNS->tot_st_flow -= 2 * delta;
488 : 0 : pe2->forbidden &= inv_forbidden_edge_mask; /* allow the charge to move */
489 : :
490 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
491 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
492 [ # # ]: 0 : if (ret < 0)
493 : : {
494 : 0 : goto exit_function;
495 : : }
496 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) ||
# # ]
497 [ # # # # ]: 0 : (vPathEnd == v2 && vPathStart == v1)) &&
498 [ # # ]: 0 : nDeltaCharge <= 1) /* djb-rwth: addressing LLVM warnings */
499 : : {
500 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
501 : 0 : (*pnNumRunBNS)++;
502 [ # # ]: 0 : if (ret < 0)
503 : : {
504 : 0 : goto exit_function;
505 : : }
506 : : else
507 [ # # ]: 0 : if (ret)
508 : : {
509 : 0 : *pnTotalDelta += ret;
510 : : }
511 : : else
512 : : {
513 : 0 : ret = RI_ERR_PROGR;
514 : : }
515 : 0 : break;
516 : : }
517 : : else
518 : : {
519 : : /* the attempt has failed; restore the flow */
520 : 0 : ret = 0;
521 : 0 : pe->flow += delta;
522 : 0 : pBNS->vert[v1].st_edge.flow += delta;
523 : 0 : pBNS->vert[v2].st_edge.flow += delta;
524 : 0 : pBNS->tot_st_flow += 2 * delta;
525 : : }
526 : : }
527 : : }
528 : : }
529 : :
530 : 0 : exit_function:
531 : : /* remove bond fixation */
532 : 0 : RemoveForbiddenEdgeMask(pBNS, &NewlyFixedEdges, forbidden_edge_mask);
533 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_FREE);
534 : :
535 : 0 : return ret;
536 : : }
537 : :
538 : :
539 : : #if ( FIX_ADD_PROTON_FOR_ADP == 1 )
540 : : /****************************************************************************/
541 : : int FixAddProtonForADP(BN_STRUCT* pBNS,
542 : : BN_DATA* pBD,
543 : : StrFromINChI* pStruct,
544 : : inp_ATOM* at,
545 : : inp_ATOM* at2,
546 : : inp_ATOM* atf,
547 : : VAL_AT* pVA,
548 : : ALL_TC_GROUPS* pTCGroups,
549 : : ICR* picr,
550 : : int* pnNumRunBNS,
551 : : int* pnTotalDelta,
552 : : int forbidden_edge_mask)
553 : : {
554 : : int iBPlus = NO_VERTEX, iNV = NO_VERTEX, iNH = NO_VERTEX, neigh, neigh2;
555 : : EDGE_LIST NewlyFixedEdges;
556 : : int ret, i, j, k, k2, delta;
557 : : int num_at = pStruct->num_atoms;
558 : : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
559 : : Vertex v1, v2;
560 : : /* for RunBnsTestOnce */
561 : : Vertex vPathStart, vPathEnd;
562 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
563 : : BNS_EDGE* pe, * pe2;
564 : :
565 : : ret = 0;
566 : : /*
567 : : AllocEdgeList( &NewlyFixedEdges, EDGE_LIST_CLEAR );
568 : :
569 : : for ( i = 0; i < num_at; i ++ ) {
570 : : if ( at2[i].radical == RADICAL_DOUBLET && at2[i].endpoint ) {
571 : : pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;
572 : : ret = 1;
573 : : break;
574 : : }
575 : : }
576 : : */
577 : : return ret;
578 : : }
579 : : #endif
580 : :
581 : :
582 : : /****************************************************************************
583 : : OH OH
584 : : / /
585 : : -NH => -NH(+) to eliminate false tautomerism.
586 : : \\ \ S(IV) or N(V) or P(V) may be a centerpoint
587 : : O O(-)
588 : : ****************************************************************************/
589 : 0 : int FixRemoveExtraTautEndpoints(BN_STRUCT* pBNS,
590 : : BN_DATA* pBD,
591 : : StrFromINChI* pStruct,
592 : : inp_ATOM* at,
593 : : inp_ATOM* at2,
594 : : inp_ATOM* atf,
595 : : inp_ATOM* atn,
596 : : VAL_AT* pVA,
597 : : ALL_TC_GROUPS* pTCGroups, ICR* picr,
598 : : int* pnNumRunBNS,
599 : : int* pnTotalDelta,
600 : : int forbidden_edge_mask)
601 : : {
602 : : EDGE_LIST NewlyFixedEdges;
603 : : int ret, i, j, k, delta, centerpoint, endpoint1, endpoint2;
604 : 0 : int num_at = pStruct->num_atoms;
605 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
606 : : Vertex v1, v2;
607 : : /* for RunBnsTestOnce */
608 : : Vertex vPathStart, vPathEnd;
609 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
610 : : BNS_EDGE* pe, * pe2;
611 : :
612 : 0 : ret = 0; /* djb-rwth: ignoring LLVM warning: value might be returned */
613 : :
614 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_CLEAR);
615 [ # # ]: 0 : if ((ret = AllocEdgeList(&NewlyFixedEdges, 2 * num_at))) /* djb-rwth: addressing LLVM warning */
616 : : {
617 : 0 : goto exit_function;
618 : : }
619 : : /* fix all charges */
620 [ # # ]: 0 : for (i = 0; i < num_at; i++)
621 : : {
622 [ # # ]: 0 : if ((j = pVA[i].nCMinusGroupEdge - 1) >= 0)
623 : : {
624 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
625 : : {
626 : 0 : goto exit_function;
627 : : }
628 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
629 : : }
630 [ # # ]: 0 : if ((j = pVA[i].nCPlusGroupEdge - 1) >= 0)
631 : : {
632 [ # # ]: 0 : if ((ret = AddToEdgeList(&NewlyFixedEdges, j, 0))) /* djb-rwth: addressing LLVM warning */
633 : : {
634 : 0 : goto exit_function;
635 : : }
636 : 0 : pBNS->edge[j].forbidden |= forbidden_edge_mask;
637 : : }
638 : : }
639 : :
640 [ # # ]: 0 : for (i = 0; i < picr->num_endp_in1_only; i++)
641 : : {
642 : 0 : endpoint1 = picr->endp_in1_only[i] - 1;
643 [ # # ]: 0 : if (at2[endpoint1].valence == at2[endpoint1].chem_bonds_valence ||
644 [ # # ]: 0 : pVA[endpoint1].nCMinusGroupEdge <= 0)
645 : : {
646 : 0 : continue;
647 : : }
648 : : /* find centerpoint */
649 [ # # ]: 0 : for (j = 0; j < at2[endpoint1].valence; j++)
650 : : {
651 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == (BOND_TYPE_MASK & at2[endpoint1].bond_type[j]))
652 : : {
653 : 0 : centerpoint = at2[endpoint1].neighbor[j];
654 [ # # # # : 0 : if (at2[centerpoint].charge || pVA[centerpoint].nCPlusGroupEdge <= 0 ||
# # ]
655 : 0 : !is_centerpoint_elem(at2[centerpoint].el_number))
656 : : {
657 : 0 : continue;
658 : : }
659 : : /* -- the centerpoint as depicted has no ChargeStruct flower ---
660 : : m = GetChargeFlowerUpperEdge( pBNS, pVA, pVA[centerpoint].nCPlusGroupEdge-1 );
661 : : if ( m < 0 || pBNS->edge[m].flow ) {
662 : : continue;
663 : : }
664 : : */
665 : : /* find 2nd endpoint */
666 [ # # ]: 0 : for (k = 0; k < at2[centerpoint].valence; k++)
667 : : {
668 [ # # ]: 0 : if (BOND_TYPE_SINGLE != (BOND_TYPE_MASK & at2[centerpoint].bond_type[k]))
669 : : {
670 : 0 : continue;
671 : : }
672 : 0 : endpoint2 = at2[centerpoint].neighbor[k];
673 [ # # # # ]: 0 : if (!at2[endpoint2].endpoint && atn[endpoint2].endpoint)
674 : : {
675 : 0 : break;
676 : : }
677 : : }
678 [ # # ]: 0 : if (k == at2[centerpoint].valence)
679 : : {
680 : 0 : continue;
681 : : }
682 : : /* the centerpoint and two extra endpoints have been found */
683 : 0 : pe = pBNS->edge + pVA[centerpoint].nCPlusGroupEdge - 1;
684 [ # # ]: 0 : if (!pe->flow)
685 : : {
686 : 0 : continue;
687 : : }
688 : 0 : pe2 = pBNS->edge + pVA[endpoint1].nCMinusGroupEdge - 1;
689 [ # # ]: 0 : if (pe2->flow)
690 : : {
691 : 0 : continue;
692 : : }
693 : 0 : delta = 1;
694 : 0 : v1 = pe->neighbor1;
695 : 0 : v2 = pe->neighbor12 ^ v1;
696 : 0 : pe->flow -= delta;
697 : 0 : pBNS->vert[v1].st_edge.flow -= delta;
698 : 0 : pBNS->vert[v2].st_edge.flow -= delta;
699 : 0 : pBNS->tot_st_flow -= 2 * delta;
700 : 0 : pe2->forbidden &= inv_forbidden_edge_mask; /* allow the charge to move */
701 : :
702 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
703 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
704 [ # # ]: 0 : if (ret < 0)
705 : : {
706 : 0 : goto exit_function;
707 : : }
708 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) ||
# # ]
709 [ # # # # ]: 0 : (vPathEnd == v2 && vPathStart == v1)) &&
710 [ # # ]: 0 : nDeltaCharge <= 1) /* djb-rwth: addressing LLVM warnings */
711 : : {
712 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
713 : 0 : (*pnNumRunBNS)++;
714 [ # # ]: 0 : if (ret < 0)
715 : : {
716 : 0 : goto exit_function;
717 : : }
718 : : else
719 : : {
720 [ # # ]: 0 : if (ret)
721 : : {
722 : 0 : *pnTotalDelta += ret;
723 : : }
724 : : else
725 : : {
726 : 0 : ret = RI_ERR_PROGR;
727 : : }
728 : : }
729 : 0 : goto exit_function;
730 : : }
731 : : else
732 : : {
733 : 0 : ret = 0;
734 : 0 : pe->flow += delta;
735 : 0 : pBNS->vert[v1].st_edge.flow += delta;
736 : 0 : pBNS->vert[v2].st_edge.flow += delta;
737 : 0 : pBNS->tot_st_flow += 2 * delta;
738 : 0 : pe2->forbidden |= forbidden_edge_mask;
739 : : }
740 : : }
741 : : }
742 : : }
743 : :
744 : 0 : exit_function:
745 : : /* remove bond fixation */
746 : 0 : RemoveForbiddenEdgeMask(pBNS, &NewlyFixedEdges, forbidden_edge_mask);
747 : 0 : AllocEdgeList(&NewlyFixedEdges, EDGE_LIST_FREE);
748 : :
749 : 0 : return ret;
750 : : }
751 : :
752 : :
753 : : /****************************************************************************/
754 : 0 : int FillOutExtraFixedHDataRestr(StrFromINChI* pStruct)
755 : : {
756 : 0 : int i, j, k, len, ret = 0;
757 : : AT_NUMB* pNum;
758 [ # # ]: 0 : for (i = 0; i < TAUT_NUM; i++)
759 : : {
760 [ # # ]: 0 : if (pStruct->pOneINChI_Aux[i])
761 : : {
762 : 0 : pNum = (pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd &&
763 [ # # ]: 0 : pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd[0]) ?
764 [ # # ]: 0 : pStruct->pOneINChI_Aux[i]->nIsotopicOrigAtNosInCanonOrd :
765 : 0 : (pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd &&
766 [ # # ]: 0 : pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd[0]) ?
767 [ # # ]: 0 : pStruct->pOneINChI_Aux[i]->nOrigAtNosInCanonOrd : NULL;
768 : : }
769 : : else
770 : : {
771 : 0 : pNum = NULL;
772 : : }
773 [ # # ]: 0 : if (pNum)
774 : : {
775 : 0 : len = pStruct->num_atoms * sizeof(pStruct->nCanon2Atno[0][0]);
776 [ # # ]: 0 : if ((!pStruct->nCanon2Atno[i] &&
777 [ # # ]: 0 : !(pStruct->nCanon2Atno[i] = (AT_NUMB*)inchi_malloc(len))) ||
778 [ # # ]: 0 : (!pStruct->nAtno2Canon[i] &&
779 [ # # ]: 0 : !(pStruct->nAtno2Canon[i] = (AT_NUMB*)inchi_malloc(len)))) /* djb-rwth: addressing LLVM warnings */
780 : : {
781 : 0 : ret = RI_ERR_ALLOC;
782 : 0 : goto exit_function;
783 : : }
784 : :
785 : : INCHI_HEAPCHK
786 : :
787 : 0 : memcpy(pStruct->nCanon2Atno[i], pNum, len); /* ??? the next for(...) fills it out */
788 : :
789 : : INCHI_HEAPCHK
790 : :
791 [ # # ]: 0 : for (j = 0; j < pStruct->num_atoms; j++)
792 : : {
793 : 0 : k = pNum[j] - 1; /* atom number */
794 : 0 : pStruct->nCanon2Atno[i][j] = (AT_NUMB)k;
795 : 0 : pStruct->nAtno2Canon[i][k] = (AT_NUMB)j;
796 : : INCHI_HEAPCHK
797 : : }
798 : : }
799 : : else
800 : : {
801 [ # # ]: 0 : if (!i)
802 : : {
803 : 0 : ret = RI_ERR_PROGR;
804 : 0 : goto exit_function;
805 : : }
806 : : else
807 : : {
808 [ # # ]: 0 : if (pStruct->nCanon2Atno[i])
809 : : {
810 [ # # ]: 0 : inchi_free(pStruct->nCanon2Atno[i]);
811 : 0 : pStruct->nCanon2Atno[i] = NULL;
812 : : }
813 : : INCHI_HEAPCHK
814 [ # # ]: 0 : if (pStruct->nAtno2Canon[i])
815 : : {
816 [ # # ]: 0 : inchi_free(pStruct->nAtno2Canon[i]);
817 : 0 : pStruct->nAtno2Canon[i] = NULL;
818 : : }
819 : : INCHI_HEAPCHK
820 : : }
821 : : }
822 : : }
823 : :
824 : 0 : exit_function:
825 : :
826 : 0 : return ret;
827 : : }
828 : :
829 : :
830 : : /****************************************************************************/
831 : 0 : int FillOutExtraFixedHDataInChI(StrFromINChI* pStruct, INChI* pInChI[])
832 : : {
833 : 0 : int ret = 0;
834 : : /*--- allocate memory for Mobile/Fixed-H data from the input InChI ---*/
835 [ # # ]: 0 : if (NULL == pStruct->endpoint)
836 : : {
837 : 0 : pStruct->endpoint = (AT_NUMB*)inchi_calloc(pStruct->num_atoms, sizeof(pStruct->endpoint[0]));
838 : : }
839 : : else
840 : : {
841 : 0 : memset(pStruct->endpoint, 0, pStruct->num_atoms * sizeof(pStruct->endpoint[0])); /* djb-rwth: memset_s C11/Annex K variant? */
842 : : }
843 [ # # ]: 0 : if (NULL == pStruct->fixed_H)
844 : : {
845 : 0 : pStruct->fixed_H = (S_CHAR*)inchi_malloc(pStruct->num_atoms * sizeof(pStruct->fixed_H[0]));
846 : : }
847 [ # # # # ]: 0 : if (!pStruct->endpoint || !pStruct->fixed_H)
848 : : {
849 : 0 : ret = RI_ERR_ALLOC;
850 : 0 : goto exit_function;
851 : : }
852 : : /*--- fill out Mobile/Fixed-H data from the input InChI ---*/
853 : 0 : GetTgroupInfoFromInChI(&pStruct->ti, NULL, pStruct->endpoint, pInChI[1]);
854 [ # # ]: 0 : if (pInChI[0]->nNum_H_fixed)
855 : : {
856 : 0 : memcpy(pStruct->fixed_H, pInChI[0]->nNum_H_fixed, pStruct->num_atoms * sizeof(pStruct->fixed_H[0]));
857 : : }
858 : : else
859 : : {
860 : 0 : memset(pStruct->fixed_H, 0, pStruct->num_atoms * sizeof(pStruct->fixed_H[0])); /* djb-rwth: memset_s C11/Annex K variant? */
861 : : }
862 : :
863 : 0 : exit_function:
864 : :
865 : 0 : return ret;
866 : : }
867 : :
868 : :
869 : : /****************************************************************************/
870 : 0 : int FillOutCMP2FHINCHI(StrFromINChI* pStruct,
871 : : inp_ATOM* at2,
872 : : VAL_AT* pVA,
873 : : INChI* pInChI[],
874 : : CMP2FHINCHI* pc2i)
875 : : {
876 : 0 : int ret = 0, i, j;
877 [ # # # # : 0 : int bFixHRevrsExists = pInChI[1] && pInChI[1]->nNumberOfAtoms > 0 && !pInChI[1]->bDeleted;
# # ]
878 : 0 : inp_ATOM* at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
879 [ # # # # ]: 0 : pStruct->pOne_norm_data[1]->at) ? pStruct->pOne_norm_data[1]->at : NULL;
880 : 0 : S_CHAR* num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed ? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
881 : : /* atom number in structure that produced original InChI is atom number in all inp_ATOM *atoms */
882 : : /* atom number in structure that produced restored InChI is in nAtomRevrs[]: */
883 : 0 : AT_NUMB* nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
884 [ # # # # ]: 0 : S_CHAR* pnMobHInChI = (pInChI[1] && pInChI[1]->nNum_H) ? pInChI[1]->nNum_H :
885 [ # # # # ]: 0 : (pInChI[0] && pInChI[0]->nNum_H) ? pInChI[0]->nNum_H : NULL;
886 [ # # ]: 0 : S_CHAR* pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H) ?
887 [ # # ]: 0 : pStruct->pOneINChI[1]->nNum_H :
888 [ # # ]: 0 : (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H) ?
889 [ # # ]: 0 : pStruct->pOneINChI[0]->nNum_H : NULL;
890 : : int nNumTgHInChI, nNumTgMInChI, nNumTgHRevrs, nNumTgMRevrs;
891 : 0 : memset(pc2i, 0, sizeof(*pc2i)); /* djb-rwth: memset_s C11/Annex K variant? */
892 : 0 : pc2i->nNumTgInChI = pStruct->ti.num_t_groups;
893 : 0 : pc2i->nNumTgRevrs = pStruct->One_ti.num_t_groups;
894 : 0 : pc2i->bHasDifference |= pc2i->nNumTgInChI != pc2i->nNumTgRevrs;
895 : :
896 : 0 : pc2i->nNumRemHInChI = pStruct->nNumRemovedProtonsMobHInChI;
897 : 0 : pc2i->nNumRemHRevrs = pStruct->One_ti.tni.nNumRemovedProtons;
898 : 0 : pc2i->bHasDifference |= pc2i->nNumRemHInChI != pc2i->nNumRemHRevrs;
899 : :
900 : 0 : pc2i->bFixedHLayerExistsRevrs = bFixHRevrsExists;
901 : 0 : pc2i->bHasDifference |= !bFixHRevrsExists;
902 : :
903 [ # # # # ]: 0 : for (i = 0; i < pStruct->ti.num_t_groups && i < pStruct->One_ti.num_t_groups; i++)
904 : : {
905 : 0 : nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
906 : 0 : nNumTgMInChI = pStruct->ti.t_group[i].num[1];
907 : 0 : nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
908 : 0 : nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
909 : :
910 : 0 : pc2i->bHasDifference |= nNumTgHInChI != nNumTgHRevrs;
911 : 0 : pc2i->bHasDifference |= nNumTgMInChI != nNumTgMRevrs;
912 : :
913 : 0 : if (pStruct->ti.t_group[i].nNumEndpoints ==
914 [ # # ]: 0 : pStruct->One_ti.t_group[i].nNumEndpoints)
915 : : {
916 : :
917 [ # # ]: 0 : if (nNumTgHInChI != nNumTgHRevrs)
918 : : {
919 : 0 : pc2i->nNumTgDiffH++;
920 : : }
921 [ # # ]: 0 : if (nNumTgMInChI != nNumTgMRevrs)
922 : : {
923 : 0 : pc2i->nNumTgDiffMinus++;
924 : : }
925 : : }
926 : 0 : pc2i->bHasDifference |= pStruct->ti.t_group[i].nNumEndpoints !=
927 : 0 : pStruct->One_ti.t_group[i].nNumEndpoints;
928 : :
929 : 0 : pc2i->nNumTgHInChI += nNumTgHInChI;
930 : 0 : pc2i->nNumTgMInChI += nNumTgMInChI;
931 : 0 : pc2i->nNumTgHRevrs += nNumTgHRevrs;
932 : 0 : pc2i->nNumTgMRevrs += nNumTgMRevrs;
933 : : }
934 [ # # ]: 0 : for (; i < pStruct->ti.num_t_groups; i++)
935 : : {
936 : 0 : nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
937 : 0 : nNumTgMInChI = pStruct->ti.t_group[i].num[1];
938 : 0 : pc2i->nNumTgHInChI += nNumTgHInChI;
939 : 0 : pc2i->nNumTgMInChI += nNumTgMInChI;
940 : 0 : pc2i->bHasDifference |= 1;
941 : : }
942 [ # # ]: 0 : for (; i < pStruct->One_ti.num_t_groups; i++)
943 : : {
944 : 0 : nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
945 : 0 : nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
946 : 0 : pc2i->nNumTgHRevrs += nNumTgHRevrs;
947 : 0 : pc2i->nNumTgMRevrs += nNumTgMRevrs;
948 : 0 : pc2i->bHasDifference |= 1;
949 : : }
950 [ # # ]: 0 : for (i = j = 0; i < pStruct->num_atoms; i++)
951 : : {
952 : : /* i = original InChI canonical number - 1 */
953 : : /* k = atom number from InChI created out of restored Fixed-H structure */
954 : 0 : int iCanonRevrs = nAtno2CanonRevrs[i];
955 : 0 : int endptInChI = pStruct->endpoint[i]; /* endpoint in InChI */
956 [ # # ]: 0 : int endptRevrs = at_Mobile_H_Revrs ? at_Mobile_H_Revrs[i].endpoint : 0;
957 : 0 : int nFixHInChI = pStruct->fixed_H[i];
958 [ # # ]: 0 : int nFixHRevrs = num_Fixed_H_Revrs ? num_Fixed_H_Revrs[iCanonRevrs] : 0;
959 [ # # ]: 0 : int nMobHInChI = pnMobHInChI ? pnMobHInChI[i] : 0;
960 [ # # ]: 0 : int nMobHRevrs = pnMobHRevrs ? pnMobHRevrs[iCanonRevrs] : 0;
961 [ # # ]: 0 : if ( /*(!endptInChI || !endptRevrs) &&*/ (nFixHInChI != nFixHRevrs) ||
962 [ # # # # ]: 0 : (!endptInChI != !endptRevrs) || nMobHInChI != nMobHRevrs)
963 : : {
964 : : /* in InChI or reversed InChI atom[i] is not tautomeric */
965 : : /* and number of fixed-H on the atom[i] differs */
966 [ # # ]: 0 : if (j >= MAX_DIFF_FIXH)
967 : : {
968 : 0 : ret = RI_ERR_PROGR;
969 : 0 : goto exit_function;
970 : : }
971 : 0 : pc2i->c2at[j].endptInChI = endptInChI;
972 : 0 : pc2i->c2at[j].endptRevrs = endptRevrs;
973 : 0 : pc2i->bHasDifference |= !endptInChI != !endptRevrs;
974 : 0 : pc2i->c2at[j].atomNumber = i;
975 : 0 : pc2i->c2at[j].nValElectr = pVA[i].cNumValenceElectrons;
976 : 0 : pc2i->c2at[j].nPeriodNum = pVA[i].cPeriodicRowNumber;
977 : 0 : pc2i->c2at[j].nFixHInChI = nFixHInChI;
978 : 0 : pc2i->c2at[j].nFixHRevrs = nFixHRevrs;
979 : 0 : pc2i->bHasDifference |= nFixHInChI != nFixHRevrs;
980 [ # # # # ]: 0 : pc2i->c2at[j].nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H[i] :
981 [ # # # # ]: 0 : pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H[i] : 0;
982 [ # # # # ]: 0 : pc2i->c2at[j].nMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H) ?
983 : 0 : pStruct->pOneINChI[1]->nNum_H[iCanonRevrs] :
984 [ # # # # ]: 0 : (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H) ?
985 : 0 : pStruct->pOneINChI[0]->nNum_H[iCanonRevrs] : 0;
986 [ # # # # : 0 : pc2i->nNumDiffMobH += (nMobHInChI != nMobHRevrs && !endptRevrs && !endptInChI);
# # ]
987 : 0 : pc2i->bHasDifference |= nMobHInChI != nMobHRevrs;
988 : 0 : pc2i->c2at[j].nNumHRevrs = at2[i].num_H;
989 : 0 : pc2i->c2at[j].nAtChargeRevrs = at2[i].charge;
990 : 0 : j++;
991 : : }
992 : 0 : pc2i->nNumEndpInChI += (endptInChI != 0);
993 : 0 : pc2i->nNumEndpRevrs += (endptRevrs != 0);
994 : :
995 [ # # ]: 0 : if (!pVA[i].cMetal)
996 : : {
997 : 0 : pc2i->nChargeFixHRevrsNonMetal += at2[i].charge;
998 [ # # ]: 0 : pc2i->nChargeMobHRevrsNonMetal += at_Mobile_H_Revrs ? at_Mobile_H_Revrs[i].charge : 0;
999 : : }
1000 : :
1001 : : /*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
1002 : : }
1003 [ # # ]: 0 : pc2i->nChargeFixHInChI = pInChI[0] ? pInChI[0]->nTotalCharge : 0;
1004 [ # # ]: 0 : pc2i->nChargeMobHInChI = pInChI[1] ? pInChI[1]->nTotalCharge : 0;
1005 : :
1006 [ # # ]: 0 : pc2i->nChargeMobHRevrs = pStruct->pOneINChI[1] ? pStruct->pOneINChI[1]->nTotalCharge :
1007 [ # # ]: 0 : pStruct->pOneINChI[0] ? pStruct->pOneINChI[0]->nTotalCharge : 0;
1008 [ # # ]: 0 : pc2i->nChargeFixHRevrs = pStruct->pOneINChI[0] ? pStruct->pOneINChI[0]->nTotalCharge : 0;
1009 : :
1010 : 0 : pc2i->bHasDifference |= pc2i->nChargeFixHInChI != pc2i->nChargeFixHRevrs;
1011 : 0 : pc2i->bHasDifference |= pc2i->nChargeMobHInChI != pc2i->nChargeMobHRevrs;
1012 : :
1013 : 0 : exit_function:
1014 : 0 : pc2i->len_c2at = j;
1015 : :
1016 : 0 : return ret;
1017 : : }
1018 : :
1019 : :
1020 : : /****************************************************************************/
1021 : 0 : int FillOutCMP2MHINCHI(StrFromINChI* pStruct,
1022 : : ALL_TC_GROUPS* pTCGroups,
1023 : : inp_ATOM* at2,
1024 : : VAL_AT* pVA,
1025 : : INChI* pInChI[],
1026 : : CMP2MHINCHI* pc2i)
1027 : : {
1028 : 0 : int ret = 0, i, j, iat;
1029 [ # # # # : 0 : int bFixHRevrsExists = pInChI[1] && pInChI[1]->nNumberOfAtoms > 0 && !pInChI[1]->bDeleted;
# # ]
1030 : 0 : inp_ATOM* at_Mobile_H_Revrs = (pStruct->pOne_norm_data[0] &&
1031 [ # # # # ]: 0 : pStruct->pOne_norm_data[0]->at) ? pStruct->pOne_norm_data[0]->at : NULL;
1032 : : /* atom number in structure that produced original InChI is atom number in all inp_ATOM *atoms */
1033 : : /* atom number in structure that produced restored InChI is in nAtomRevrs[]: */
1034 : 0 : AT_NUMB* nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
1035 : 0 : AT_NUMB* nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
1036 [ # # # # ]: 0 : S_CHAR* pnMobHInChI = (pInChI[0] && pInChI[0]->nNum_H) ? pInChI[0]->nNum_H : NULL;
1037 [ # # ]: 0 : S_CHAR* pnMobHRevrs = (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H) ?
1038 [ # # ]: 0 : pStruct->pOneINChI[0]->nNum_H : NULL;
1039 : : int nNumTgHInChI, nNumTgMInChI, nNumTgHRevrs, nNumTgMRevrs;
1040 : 0 : memset(pc2i, 0, sizeof(*pc2i)); /* djb-rwth: memset_s C11/Annex K variant? */
1041 : 0 : pc2i->nNumTgInChI = pStruct->ti.num_t_groups;
1042 : 0 : pc2i->nNumTgRevrs = pStruct->One_ti.num_t_groups;
1043 : 0 : pc2i->bHasDifference |= pc2i->nNumTgInChI != pc2i->nNumTgRevrs;
1044 : :
1045 : 0 : pc2i->nNumRemHInChI = pStruct->nNumRemovedProtonsMobHInChI;
1046 : 0 : pc2i->nNumRemHRevrs = pStruct->One_ti.tni.nNumRemovedProtons;
1047 : : /*pc2i->bHasDifference |= pc2i->nNumRemHInChI != pc2i->nNumRemHRevrs;*/
1048 : :
1049 : 0 : pc2i->bFixedHLayerExistsRevrs = bFixHRevrsExists;
1050 : : /*pc2i->bHasDifference |= !bFixHRevrsExists;*/
1051 : :
1052 [ # # ]: 0 : for (i = 0; i < pStruct->ti.num_t_groups; i++)
1053 : : {
1054 : 0 : int jFst = pStruct->ti.t_group[i].nFirstEndpointAtNoPos;
1055 : 0 : int jNum = pStruct->ti.t_group[i].nNumEndpoints;
1056 : : int is_N, is_O;
1057 [ # # ]: 0 : for (j = 0; j < jNum; j++)
1058 : : {
1059 : 0 : iat = pStruct->ti.nEndpointAtomNumber[jFst + j];
1060 [ # # # # ]: 0 : is_N = pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1;
1061 : 0 : is_O = pVA[iat].cNumValenceElectrons == 6;
1062 [ # # ]: 0 : if (is_N + is_O != 1)
1063 : : {
1064 : 0 : return RI_ERR_SYNTAX;
1065 : : }
1066 : 0 : pc2i->nNumTgNInChI += is_N;
1067 : 0 : pc2i->nNumTgOInChI += is_O;
1068 [ # # ]: 0 : if (at2[iat].chem_bonds_valence == at2[iat].valence)
1069 : : {
1070 : : /* donor */
1071 [ # # ]: 0 : if (is_N)
1072 : : {
1073 : : /* N */
1074 [ # # # # ]: 0 : pc2i->nNumTgNHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
1075 [ # # # # ]: 0 : pc2i->nNumTgNH2InChI += at2[iat].charge == 0 && at2[iat].num_H == 2;
1076 [ # # # # ]: 0 : pc2i->nNumTgNMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
1077 [ # # # # ]: 0 : pc2i->nNumTgNHMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 1;
1078 : : }
1079 : : else
1080 : : {
1081 : : /* O, S, Se, Te */
1082 [ # # # # ]: 0 : pc2i->nNumTgOHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
1083 [ # # # # ]: 0 : pc2i->nNumTgOMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
1084 : : }
1085 : : }
1086 : : else
1087 : : {
1088 [ # # ]: 0 : if (at2[iat].chem_bonds_valence == at2[iat].valence + 1)
1089 : : {
1090 : : /* donor */
1091 [ # # ]: 0 : if (is_N)
1092 : : {
1093 : : /* N */
1094 [ # # # # ]: 0 : pc2i->nNumTgDBNHInChI += at2[iat].charge == 0 && at2[iat].num_H == 1;
1095 [ # # # # ]: 0 : pc2i->nNumTgDBNMinusInChI += at2[iat].charge == -1 && at2[iat].num_H == 0;
1096 [ # # # # ]: 0 : pc2i->nNumTgDBNInChI += at2[iat].charge == 0 && at2[iat].num_H == 0;
1097 : : }
1098 : : else
1099 : : {
1100 : : /* O, S, Se, Te */
1101 [ # # # # ]: 0 : pc2i->nNumTgDBOInChI += at2[iat].charge == 0 && at2[iat].num_H == 0;
1102 : : }
1103 : : }
1104 : : }
1105 : : }
1106 : : }
1107 [ # # ]: 0 : for (i = 0; i < pStruct->One_ti.num_t_groups; i++)
1108 : : {
1109 : 0 : int jFst = pStruct->One_ti.t_group[i].nFirstEndpointAtNoPos;
1110 : 0 : int jNum = pStruct->One_ti.t_group[i].nNumEndpoints;
1111 : : int is_N, is_O;
1112 [ # # ]: 0 : for (j = 0; j < jNum; j++)
1113 : : {
1114 : 0 : iat = nCanon2AtnoRevrs[(int)pStruct->One_ti.nEndpointAtomNumber[jFst + j]];
1115 [ # # # # ]: 0 : is_N = pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1;
1116 : 0 : is_O = pVA[iat].cNumValenceElectrons == 6;
1117 [ # # ]: 0 : if (is_N + is_O != 1)
1118 : : {
1119 : 0 : return RI_ERR_PROGR;
1120 : : }
1121 : 0 : pc2i->nNumTgNRevrs += is_N;
1122 : 0 : pc2i->nNumTgORevrs += is_O;
1123 [ # # ]: 0 : if (at2[iat].chem_bonds_valence == at2[iat].valence)
1124 : : {
1125 : : /* donor */
1126 [ # # ]: 0 : if (is_N)
1127 : : {
1128 : : /* N */
1129 [ # # # # ]: 0 : pc2i->nNumTgNHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
1130 [ # # # # ]: 0 : pc2i->nNumTgNH2Revrs += at2[iat].charge == 0 && at2[iat].num_H == 2;
1131 [ # # # # ]: 0 : pc2i->nNumTgNMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
1132 [ # # # # ]: 0 : pc2i->nNumTgNHMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 1;
1133 : : }
1134 : : else
1135 : : {
1136 : : /* O, S, Se, Te */
1137 [ # # # # ]: 0 : pc2i->nNumTgOHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
1138 [ # # # # ]: 0 : pc2i->nNumTgOMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
1139 : : }
1140 : : }
1141 : : else
1142 : : {
1143 [ # # ]: 0 : if (at2[iat].chem_bonds_valence == at2[iat].valence + 1)
1144 : : {
1145 : : /* donor */
1146 [ # # ]: 0 : if (is_N)
1147 : : {
1148 : : /* N */
1149 [ # # # # ]: 0 : pc2i->nNumTgDBNHRevrs += at2[iat].charge == 0 && at2[iat].num_H == 1;
1150 [ # # # # ]: 0 : pc2i->nNumTgDBNMinusRevrs += at2[iat].charge == -1 && at2[iat].num_H == 0;
1151 [ # # # # ]: 0 : pc2i->nNumTgDBNRevrs += at2[iat].charge == 0 && at2[iat].num_H == 0;
1152 : : }
1153 : : else
1154 : : {
1155 : : /* O, S, Se, Te */
1156 [ # # # # ]: 0 : pc2i->nNumTgDBORevrs += at2[iat].charge == 0 && at2[iat].num_H == 0;
1157 : : }
1158 : : }
1159 : : }
1160 : : }
1161 : : }
1162 : :
1163 [ # # # # ]: 0 : for (i = 0; i < pStruct->ti.num_t_groups && i < pStruct->One_ti.num_t_groups; i++)
1164 : : {
1165 : 0 : nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
1166 : 0 : nNumTgMInChI = pStruct->ti.t_group[i].num[1];
1167 : 0 : nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
1168 : 0 : nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
1169 : :
1170 : 0 : pc2i->bHasDifference |= nNumTgHInChI != nNumTgHRevrs;
1171 : 0 : pc2i->bHasDifference |= nNumTgMInChI != nNumTgMRevrs;
1172 : :
1173 : 0 : if (pStruct->ti.t_group[i].nNumEndpoints ==
1174 [ # # ]: 0 : pStruct->One_ti.t_group[i].nNumEndpoints)
1175 : : {
1176 : :
1177 [ # # ]: 0 : if (nNumTgHInChI != nNumTgHRevrs)
1178 : : {
1179 : 0 : pc2i->nNumTgDiffH++;
1180 : : }
1181 [ # # ]: 0 : if (nNumTgMInChI != nNumTgMRevrs)
1182 : : {
1183 : 0 : pc2i->nNumTgDiffMinus++;
1184 : : }
1185 : : }
1186 : 0 : pc2i->bHasDifference |= pStruct->ti.t_group[i].nNumEndpoints !=
1187 : 0 : pStruct->One_ti.t_group[i].nNumEndpoints;
1188 : :
1189 : 0 : pc2i->nNumTgHInChI += nNumTgHInChI;
1190 : 0 : pc2i->nNumTgMInChI += nNumTgMInChI;
1191 : 0 : pc2i->nNumTgHRevrs += nNumTgHRevrs;
1192 : 0 : pc2i->nNumTgMRevrs += nNumTgMRevrs;
1193 : : }
1194 [ # # ]: 0 : for (; i < pStruct->ti.num_t_groups; i++)
1195 : : {
1196 : 0 : nNumTgHInChI = pStruct->ti.t_group[i].num[0] - pStruct->ti.t_group[i].num[1];
1197 : 0 : nNumTgMInChI = pStruct->ti.t_group[i].num[1];
1198 : 0 : pc2i->nNumTgHInChI += nNumTgHInChI;
1199 : 0 : pc2i->nNumTgMInChI += nNumTgMInChI;
1200 : 0 : pc2i->bHasDifference |= 1;
1201 : : }
1202 [ # # ]: 0 : for (; i < pStruct->One_ti.num_t_groups; i++)
1203 : : {
1204 : 0 : nNumTgHRevrs = pStruct->One_ti.t_group[i].num[0] - pStruct->One_ti.t_group[i].num[1];
1205 : 0 : nNumTgMRevrs = pStruct->One_ti.t_group[i].num[1];
1206 : 0 : pc2i->nNumTgHRevrs += nNumTgHRevrs;
1207 : 0 : pc2i->nNumTgMRevrs += nNumTgMRevrs;
1208 : 0 : pc2i->bHasDifference |= 1;
1209 : : }
1210 [ # # ]: 0 : for (i = j = 0; i < pStruct->num_atoms; i++)
1211 : : {
1212 : : /* i = original InChI canonical number - 1 */
1213 : : /* k = atom number from InChI created out of restored Fixed-H structure */
1214 : 0 : int iCanonRevrs = nAtno2CanonRevrs[i];
1215 : 0 : int endptInChI = at2[i].endpoint; /* endpoint in InChI */
1216 [ # # ]: 0 : int endptRevrs = at_Mobile_H_Revrs ? at_Mobile_H_Revrs[i].endpoint : 0;
1217 [ # # ]: 0 : int nMobHInChI = pnMobHInChI ? pnMobHInChI[i] : 0;
1218 [ # # ]: 0 : int nMobHRevrs = pnMobHRevrs ? pnMobHRevrs[iCanonRevrs] : 0;
1219 [ # # # # ]: 0 : if ((!endptInChI != !endptRevrs) || nMobHInChI != nMobHRevrs)
1220 : : {
1221 : : /* in InChI or reversed InChI atom[i] is not tautomeric */
1222 : : /* and number of fixed-H on the atom[i] differs */
1223 [ # # ]: 0 : if (j >= MAX_DIFF_FIXH)
1224 : : {
1225 : 0 : ret = RI_ERR_PROGR;
1226 : 0 : goto exit_function;
1227 : : }
1228 : 0 : pc2i->c2at[j].endptInChI = endptInChI;
1229 : 0 : pc2i->c2at[j].endptRevrs = endptRevrs;
1230 : 0 : pc2i->bHasDifference |= !endptInChI != !endptRevrs;
1231 : 0 : pc2i->c2at[j].atomNumber = i;
1232 : 0 : pc2i->c2at[j].nValElectr = pVA[i].cNumValenceElectrons;
1233 : 0 : pc2i->c2at[j].nPeriodNum = pVA[i].cPeriodicRowNumber;
1234 [ # # # # ]: 0 : pc2i->c2at[j].nMobHInChI = pInChI[1] && pInChI[1]->nNum_H ? pInChI[1]->nNum_H[i] :
1235 [ # # # # ]: 0 : pInChI[0] && pInChI[0]->nNum_H ? pInChI[0]->nNum_H[i] : 0;
1236 [ # # # # ]: 0 : pc2i->c2at[j].nMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H) ?
1237 : 0 : pStruct->pOneINChI[1]->nNum_H[iCanonRevrs] :
1238 [ # # # # ]: 0 : (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H) ?
1239 : 0 : pStruct->pOneINChI[0]->nNum_H[iCanonRevrs] : 0;
1240 : :
1241 [ # # # # : 0 : pc2i->nNumDiffMobH += (nMobHInChI != nMobHRevrs && !endptRevrs && !endptInChI);
# # ]
1242 : 0 : pc2i->bHasDifference |= (nMobHInChI != nMobHRevrs);
1243 : 0 : pc2i->c2at[j].nNumHRevrs = at2[i].num_H;
1244 : 0 : pc2i->c2at[j].nAtChargeRevrs = at2[i].charge;
1245 : 0 : j++;
1246 : : }
1247 : 0 : pc2i->nNumEndpInChI += (endptInChI != 0);
1248 : 0 : pc2i->nNumEndpRevrs += (endptRevrs != 0);
1249 : :
1250 [ # # ]: 0 : if (!pVA[i].cMetal)
1251 : : {
1252 [ # # # # ]: 0 : pc2i->nChargeMobHRevrsNonMetal += (at_Mobile_H_Revrs && !at_Mobile_H_Revrs[i].endpoint) ? at_Mobile_H_Revrs[i].charge : 0;
1253 : : }
1254 : :
1255 : :
1256 : : /*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
1257 : : }
1258 : 0 : pc2i->nChargeMobHRevrsNonMetal += pTCGroups->tgroup_charge;
1259 : :
1260 [ # # ]: 0 : pc2i->nChargeMobHInChI = pInChI[0] ? pInChI[0]->nTotalCharge : 0;
1261 : :
1262 [ # # ]: 0 : pc2i->nChargeMobHRevrs = pStruct->pOneINChI[0] ? pStruct->pOneINChI[0]->nTotalCharge : 0;
1263 : :
1264 : 0 : pc2i->bHasDifference |= pc2i->nChargeMobHInChI != pc2i->nChargeMobHRevrs;
1265 : :
1266 : 0 : exit_function:
1267 : 0 : pc2i->len_c2at = j;
1268 : :
1269 : 0 : return ret;
1270 : : }
1271 : :
1272 : :
1273 : : /****************************************************************************/
1274 : 0 : int NormalizeAndCompare(CANON_GLOBALS* pCG,
1275 : : INCHI_CLOCK* ic,
1276 : : ICHICONST INPUT_PARMS* ip,
1277 : : STRUCT_DATA* sd,
1278 : : BN_STRUCT* pBNS,
1279 : : BN_DATA* pBD,
1280 : : StrFromINChI* pStruct,
1281 : : inp_ATOM* at,
1282 : : inp_ATOM* at2,
1283 : : inp_ATOM* at3,
1284 : : VAL_AT* pVA,
1285 : : ALL_TC_GROUPS* pTCGroups,
1286 : : INChI* pInChI[],
1287 : : long num_inp,
1288 : : int bHasSomeFixedH,
1289 : : int* pnNumRunBNS,
1290 : : int* pnTotalDelta,
1291 : : int forbidden_edge_mask,
1292 : : int forbidden_stereo_edge_mask)
1293 : : {
1294 : : int i;
1295 : : int err;
1296 : : ICR icr, icr2;
1297 : 0 : int num_norm_endpoints, num_endpoints, num_norm_t_groups, ret = 0; /* djb-rwth: ignoring LLVM warning: variables used; removing redundant variables */
1298 : : #if ( bRELEASE_VERSION == 0 )
1299 : : #ifndef TARGET_API_LIB
1300 : : const char* szCurHdr = (ip->pSdfValue && ip->pSdfValue[0]) ? ip->pSdfValue : "???";
1301 : : int iComponent = pTCGroups->iComponent;
1302 : : #endif
1303 : : #endif
1304 : 0 : T_GROUP_INFO* t_group_info = NULL;
1305 : 0 : inp_ATOM* at_norm = NULL; /* normalized */
1306 : 0 : inp_ATOM* at_prep = NULL; /* preprocessed */
1307 : : INCHI_MODE cmpInChI, cmpInChI2;
1308 : : int nDeltaPrev, nDeltaCur;
1309 : : int iOrigInChI, iRevrInChI;
1310 : :
1311 : :
1312 : : /***********************************************************/
1313 : : /* normalize and create one component InChI */
1314 : : /***********************************************************/
1315 : 0 : ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1316 : : &t_group_info, &at_norm, &at_prep);
1317 [ # # ]: 0 : if (ret < 0)
1318 : : {
1319 : : #if ( bRELEASE_VERSION == 0 )
1320 : : #ifndef TARGET_API_LIB
1321 : : fprintf(stdout, "\nERROR in MakeOneInchi-1: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
1322 : : szCurHdr ? szCurHdr : "???", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F', ret);
1323 : : #endif
1324 : : #endif
1325 : 0 : goto exit_function;
1326 : : }
1327 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
1328 : : {
1329 : : /* these indexes are used to compare Mobile-H InChI */
1330 [ # # # # : 0 : iOrigInChI = (pInChI[1] && pInChI[1]->nNumberOfAtoms && !pInChI[1]->bDeleted) ? 1 : 0;
# # ]
1331 [ # # # # : 0 : iRevrInChI = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted) ? 1 : 0;
# # ]
1332 : : }
1333 : : else
1334 : : {
1335 : 0 : iOrigInChI = 0;
1336 : 0 : iRevrInChI = 0;
1337 : : }
1338 : :
1339 : : /* Intercept and correct non-polymer Zz to Zy if applicable */
1340 [ # # # # ]: 0 : if (pStruct->n_zy && pStruct->n_pzz)
1341 : : {
1342 [ # # ]: 0 : if (pStruct->pOneINChI[iRevrInChI]->szHillFormula)
1343 : : {
1344 : : INCHI_IOS_STRING temp_string_container;
1345 : 0 : INCHI_IOS_STRING* strbuf = &temp_string_container;
1346 : 0 : int len0 = strlen(pStruct->pOneINChI[iRevrInChI]->szHillFormula);
1347 [ # # ]: 0 : if (inchi_strbuf_init(strbuf, len0 + 1, len0 + 1) > 0)
1348 : : {
1349 : 0 : inchi_strbuf_printf(strbuf, "%-s", pStruct->pOneINChI[iRevrInChI]->szHillFormula);
1350 : : }
1351 : 0 : MergeZzInHillFormula(strbuf);
1352 [ # # ]: 0 : if (strbuf->nUsedLength > len0 + 1)
1353 : : {
1354 : : char* ctmp; /* djb-rwth: supplementary variable */
1355 : 0 : ctmp = (char*)inchi_realloc(pStruct->pOneINChI[iRevrInChI]->szHillFormula, (long long)strbuf->nUsedLength + 1); /* djb-rwth: cast operator added */
1356 [ # # ]: 0 : if (ctmp != NULL) /* djb-rwth: NULL pointer must not be assigned to pStruct->pOneINChI[iRevrInChI]->szHillFormula */
1357 : 0 : pStruct->pOneINChI[iRevrInChI]->szHillFormula = ctmp;
1358 : : }
1359 : 0 : strcpy(pStruct->pOneINChI[iRevrInChI]->szHillFormula, strbuf->pStr);
1360 : 0 : inchi_strbuf_close(strbuf);
1361 : : }
1362 : : }
1363 : :
1364 : :
1365 : : /************************************************************/
1366 : : /* compare */
1367 : : /************************************************************/
1368 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr(pStruct)))
1369 : : {
1370 : 0 : goto exit_function;
1371 : : }
1372 : 0 : cmpInChI = CompareReversedINChI2(pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *a2*/, &icr, &err);
1373 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1374 : : {
1375 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1376 : 0 : goto exit_function;
1377 : : }
1378 [ # # ]: 0 : if (err)
1379 : : {
1380 : 0 : ret = RI_ERR_ALLOC;
1381 : 0 : goto exit_function;
1382 : : }
1383 : : /********** InChI from restored structure has LESS hydrogen atoms ******************************/
1384 [ # # # # : 0 : if ((cmpInChI & IDIF_LESS_H) && at_prep && 0 < (nDeltaCur = icr.tot_num_H2 - icr.tot_num_H1))
# # ]
1385 : : {
1386 : : do
1387 : : {
1388 : 0 : ret = FixLessHydrogenInFormula(pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups,
1389 : : pnNumRunBNS, pnTotalDelta, forbidden_edge_mask);
1390 [ # # ]: 0 : if (ret < 0)
1391 : : {
1392 : 0 : goto exit_function;
1393 : : }
1394 [ # # ]: 0 : if (ret)
1395 : : {
1396 : : /* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
1397 : 0 : ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1398 : : &t_group_info, &at_norm, &at_prep);
1399 [ # # ]: 0 : if (ret < 0)
1400 : : {
1401 : : #if ( bRELEASE_VERSION == 0 )
1402 : : #ifndef TARGET_API_LIB
1403 : : fprintf(stdout, "\nERROR in MakeOneInchi-2: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
1404 : : szCurHdr ? szCurHdr : "???", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F', ret);
1405 : : #endif
1406 : : #endif
1407 : 0 : goto exit_function;
1408 : : }
1409 : : /* compare new InChI to the original InChI */
1410 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
1411 : : {
1412 [ # # # # : 0 : iRevrInChI = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted) ? 1 : 0;
# # ]
1413 : : }
1414 : : else
1415 : : {
1416 : 0 : iRevrInChI = 0;
1417 : : }
1418 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr(pStruct)))
1419 : : {
1420 : 0 : goto exit_function;
1421 : : }
1422 : 0 : cmpInChI = CompareReversedINChI2(pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err);
1423 : 0 : nDeltaPrev = nDeltaCur;
1424 : 0 : nDeltaCur = icr.tot_num_H2 - icr.tot_num_H1;
1425 : : }
1426 : : else
1427 : : {
1428 : 0 : break;
1429 : : }
1430 [ # # # # : 0 : } while ((cmpInChI & IDIF_LESS_H) && at_prep && nDeltaCur && nDeltaCur < nDeltaPrev);
# # # # ]
1431 : : }
1432 : : /********** InChI from restored structure has MORE hydrogen atoms ******************************/
1433 [ # # # # : 0 : if ((cmpInChI & IDIF_MORE_H) && at_prep && 0 < (nDeltaCur = icr.tot_num_H1 - icr.tot_num_H2))
# # ]
1434 : : {
1435 : : do
1436 : : {
1437 : 0 : ret = FixMoreHydrogenInFormula(pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups,
1438 : : pnNumRunBNS, pnTotalDelta, forbidden_edge_mask);
1439 [ # # ]: 0 : if (ret < 0)
1440 : : {
1441 : 0 : goto exit_function;
1442 : : }
1443 [ # # ]: 0 : if (ret)
1444 : : {
1445 : : /* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
1446 : 0 : ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1447 : : &t_group_info, &at_norm, &at_prep);
1448 [ # # ]: 0 : if (ret < 0)
1449 : : {
1450 : : #if ( bRELEASE_VERSION == 0 )
1451 : : #ifndef TARGET_API_LIB
1452 : : fprintf(stdout, "\nERROR in MakeOneInchi-3: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
1453 : : szCurHdr ? szCurHdr : "???", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F', ret);
1454 : : #endif
1455 : : #endif
1456 : 0 : goto exit_function;
1457 : : }
1458 : : /* compare new InChI to the original InChI */
1459 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
1460 : : {
1461 [ # # # # : 0 : iRevrInChI = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted) ? 1 : 0;
# # ]
1462 : : }
1463 : : else
1464 : : {
1465 : 0 : iRevrInChI = 0;
1466 : : }
1467 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr(pStruct)))
1468 : : {
1469 : 0 : goto exit_function;
1470 : : }
1471 : 0 : cmpInChI = CompareReversedINChI2(pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err);
1472 : 0 : nDeltaPrev = nDeltaCur;
1473 : 0 : nDeltaCur = icr.tot_num_H1 - icr.tot_num_H2;
1474 : : }
1475 : : else
1476 : : {
1477 : 0 : break;
1478 : : }
1479 [ # # # # : 0 : } while ((cmpInChI & IDIF_MORE_H) && at_prep && nDeltaCur && nDeltaCur < nDeltaPrev);
# # # # ]
1480 : : }
1481 : : /***************** Fix non-taut atoms normalized to tautomeric endpoints ***********************/
1482 [ # # # # : 0 : if ((cmpInChI & IDIF_EXTRA_TG_ENDP) && at_norm && 0 < (nDeltaCur = icr.num_endp_in1_only))
# # ]
1483 : : {
1484 : : do
1485 : : {
1486 : 0 : ret = FixRemoveExtraTautEndpoints(pBNS, pBD, pStruct, at, at2, at_prep, at_norm, pVA, pTCGroups, &icr,
1487 : : pnNumRunBNS, pnTotalDelta, forbidden_edge_mask);
1488 [ # # ]: 0 : if (ret < 0)
1489 : : {
1490 : 0 : goto exit_function;
1491 : : }
1492 [ # # ]: 0 : if (ret)
1493 : : {
1494 : : /* Probably success. The changes are in pBNS. Create new InChI out of the new restored structure */
1495 : 0 : ret = MakeOneInChIOutOfStrFromINChI2(pCG, ic, ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1496 : : &t_group_info, &at_norm, &at_prep);
1497 [ # # ]: 0 : if (ret < 0)
1498 : : {
1499 : : #if ( bRELEASE_VERSION == 0 )
1500 : : #ifndef TARGET_API_LIB
1501 : : fprintf(stdout, "\nERROR in MakeOneInchi-4: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
1502 : : szCurHdr ? szCurHdr : "???", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F', ret);
1503 : : #endif
1504 : : #endif
1505 : 0 : goto exit_function;
1506 : : }
1507 : : /* compare new InChI to the original InChI */
1508 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
1509 : : {
1510 [ # # # # : 0 : iRevrInChI = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted) ? 1 : 0;
# # ]
1511 : : }
1512 : : else
1513 : : {
1514 : 0 : iRevrInChI = 0;
1515 : : }
1516 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON && (ret = FillOutExtraFixedHDataRestr(pStruct)))
1517 : : {
1518 : 0 : goto exit_function;
1519 : : }
1520 : 0 : cmpInChI = CompareReversedINChI2(pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL, &icr, &err);
1521 : 0 : nDeltaPrev = nDeltaCur;
1522 : 0 : nDeltaCur = icr.num_endp_in1_only;
1523 : : }
1524 : : else
1525 : : {
1526 : 0 : break;
1527 : : }
1528 [ # # # # : 0 : } while ((cmpInChI & IDIF_EXTRA_TG_ENDP) && at_norm && nDeltaCur && nDeltaCur < nDeltaPrev);
# # # # ]
1529 : : }
1530 : : /************************ case of Fixed-H ******************************************************/
1531 : :
1532 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_NON)
1533 : : {
1534 : 0 : int num_tries = 0;
1535 : : do
1536 : : {
1537 [ # # ]: 0 : if (0 > (ret = FixFixedHRestoredStructure(pCG, ic, ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
1538 : : &t_group_info, &at_norm, &at_prep, pInChI,
1539 : : num_inp, bHasSomeFixedH, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
1540 : : forbidden_stereo_edge_mask)))
1541 : : {
1542 : 0 : goto exit_function;
1543 : : }
1544 [ # # # # ]: 0 : } while (num_tries++ < 2 && ret > 0);
1545 : : }
1546 : : /************************ case of Fixed-H ******************************************************/
1547 [ # # ]: 0 : if (pStruct->bMobileH == TAUT_YES)
1548 : : {
1549 [ # # ]: 0 : if (0 > (ret = FixMobileHRestoredStructure(pCG, ic, ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
1550 : : &t_group_info, &at_norm, &at_prep, pInChI,
1551 : : num_inp, bHasSomeFixedH, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
1552 : : forbidden_stereo_edge_mask)))
1553 : : {
1554 : 0 : goto exit_function;
1555 : : }
1556 : : }
1557 : : /**********************************************************************************************/
1558 : : /* stereo */
1559 : 0 : cmpInChI = CompareReversedINChI2(pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *a2*/, &icr, &err);
1560 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1561 : : {
1562 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1563 : 0 : goto exit_function;
1564 : : }
1565 [ # # ]: 0 : if (err)
1566 : : {
1567 : 0 : ret = RI_ERR_ALLOC;
1568 : 0 : goto exit_function;
1569 : : }
1570 : 0 : cmpInChI2 = 0;
1571 : 0 : memset(&icr2, 0, sizeof(icr2)); /* djb-rwth: memset_s C11/Annex K variant? */
1572 [ # # # # ]: 0 : if (iRevrInChI || iOrigInChI)
1573 : : {
1574 : : /* additional mobile-H compare in case of Fixed-H */
1575 : 0 : cmpInChI2 = CompareReversedINChI2(pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *a2*/, &icr2, &err);
1576 [ # # ]: 0 : if (cmpInChI & IDIF_PROBLEM)
1577 : : {
1578 : 0 : ret = RI_ERR_PROGR; /* severe restore problem */
1579 : 0 : goto exit_function;
1580 : : }
1581 [ # # ]: 0 : if (err)
1582 : : {
1583 : 0 : ret = RI_ERR_ALLOC;
1584 : 0 : goto exit_function;
1585 : : }
1586 : : }
1587 : 0 : ret = FixRestoredStructureStereo(pCG, ic,
1588 : : cmpInChI, &icr, cmpInChI2, &icr2,
1589 : : ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups,
1590 : : &t_group_info, &at_norm, &at_prep, pInChI,
1591 : : num_inp, pnNumRunBNS, pnTotalDelta, forbidden_edge_mask,
1592 : : forbidden_stereo_edge_mask);
1593 : :
1594 [ # # ]: 0 : if (ret < 0)
1595 : : {
1596 : 0 : goto exit_function;
1597 : : }
1598 : : #if ( FIX_ADD_PROTON_FOR_ADP == 1 )
1599 : : /************************ check and fix ADP by adding a proton (dummy) *************************/
1600 : : if (cmpInChI && pTCGroups->num_tgroups && pBNS->tot_st_cap > pBNS->tot_st_flow)
1601 : : {
1602 : : ret = FixAddProtonForADP(pBNS, pBD, pStruct, at, at2, at_prep, pVA, pTCGroups, &icr,
1603 : : pnNumRunBNS, pnTotalDelta, forbidden_edge_mask);
1604 : : if (ret < 0)
1605 : : {
1606 : : goto exit_function;
1607 : : }
1608 : : }
1609 : : #endif
1610 : : /* moved to MakeOneInChIOutOfStrFromINChI():
1611 : : pStruct->nNumRemovedProtons = (pStruct->iMobileH == TAUT_YES)? pStruct->One_ti.tni.nNumRemovedProtons : 0;
1612 : : */
1613 : :
1614 : : /* count endpoints */
1615 : 0 : num_endpoints = 0;
1616 : 0 : num_norm_endpoints = 0;
1617 : 0 : num_norm_t_groups = 0;
1618 : : /* djb-rwth: removing redundant code */
1619 : 0 : at_norm = pStruct->pOne_norm_data[0]->at;
1620 [ # # ]: 0 : for (i = 0; i < pTCGroups->num_tgroups; i++)
1621 : : {
1622 : 0 : num_endpoints += pTCGroups->pTCG[i].num_edges;
1623 : : /* djb-rwth: removing redundant code */
1624 : : }
1625 : :
1626 [ # # ]: 0 : if (t_group_info)
1627 : : {
1628 : : /* after canonicalization, t_group_info->t_group[i].num[0] = number of H */
1629 : : /* t_group_info->t_group[i].num[1] = number of (-) */
1630 [ # # ]: 0 : for (i = 0; i < t_group_info->num_t_groups; i++)
1631 : : {
1632 [ # # ]: 0 : if (t_group_info->t_group[i].num[0])
1633 : : {
1634 : 0 : num_norm_t_groups++;
1635 : 0 : num_norm_endpoints += t_group_info->t_group[i].nNumEndpoints;
1636 : : /* djb-rwth: removing redundant code */
1637 : : }
1638 : : }
1639 : : }
1640 : : #if ( bRELEASE_VERSION == 0 )
1641 : : #ifndef TARGET_API_LIB
1642 : : if (num_norm_t_groups != pTCGroups->num_tgroups || num_norm_endpoints != num_endpoints)
1643 : : {
1644 : : /* need aggressive (de)protonation */
1645 : : /* pStruct->bExtract |= EXTRACT_STRUCT_NUMBER; */
1646 : : fprintf(stdout, "NORMCOMP: %s comp=%d %c%c: InChI/NormRvrs NumTg=%d/%d NumEndp=%d/%d\n",
1647 : : (*ip).pSdfValue, (*pTCGroups).iComponent,
1648 : : pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F',
1649 : : pTCGroups->num_tgroups, num_norm_t_groups,
1650 : : num_endpoints, num_norm_endpoints);
1651 : : }
1652 : : #endif
1653 : : #endif
1654 : :
1655 : 0 : exit_function:
1656 : :
1657 [ # # ]: 0 : for (i = 0; i < TAUT_NUM; i++)
1658 : : {
1659 : 0 : Free_INChI(&pStruct->pOneINChI[i]);
1660 : 0 : Free_INChI_Aux(&pStruct->pOneINChI_Aux[i]);
1661 : 0 : FreeInpAtomData(pStruct->pOne_norm_data[i]);
1662 [ # # ]: 0 : if (pStruct->pOne_norm_data[i])
1663 : : {
1664 [ # # ]: 0 : inchi_free(pStruct->pOne_norm_data[i]);
1665 : 0 : pStruct->pOne_norm_data[i] = NULL;
1666 : : }
1667 : : }
1668 : :
1669 : 0 : free_t_group_info(&pStruct->One_ti);
1670 : :
1671 : 0 : return ret;
1672 : : }
1673 : :
1674 : :
1675 : : /****************************************************************************
1676 : : Find A=X< where all bonds to X except A=X are marked as stereogenic;
1677 : : temporary allow stereobonds change and make A=X bonds single */
1678 : 0 : int CheckAndRefixStereobonds(BN_STRUCT* pBNS, BN_DATA* pBD, StrFromINChI* pStruct,
1679 : : inp_ATOM* at, inp_ATOM* at2, VAL_AT* pVA, ALL_TC_GROUPS* pTCGroups,
1680 : : int* pnNumRunBNS, int* pnTotalDelta, int forbidden_edge_mask)
1681 : : {
1682 : 0 : int forbidden_edge_stereo = BNS_EDGE_FORBIDDEN_MASK;
1683 : 0 : int inv_forbidden_edge_stereo = ~forbidden_edge_stereo;
1684 : :
1685 : : int i, k, ne, j1, j2, num_wrong, num_fixed;
1686 : : int ret2, retBNS, ret;
1687 : 0 : int num_at = pStruct->num_atoms;
1688 : 0 : int num_deleted_H = pStruct->num_deleted_H;
1689 : 0 : int len_at = num_at + num_deleted_H;
1690 : : EDGE_LIST FixedEdges, WrongEdges, CarbonChargeEdges;
1691 : :
1692 : : BNS_EDGE* pEdge;
1693 : : Vertex v1, v2;
1694 : : BNS_VERTEX* pv1, * pv2;
1695 : :
1696 : 0 : ret = 0;
1697 : :
1698 : : /* to simplify, prepare new at[] from pBNS */
1699 : 0 : memcpy(at2, at, len_at * sizeof(at2[0]));
1700 : 0 : pStruct->at = at2;
1701 : 0 : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
1702 : 0 : pStruct->at = at;
1703 [ # # ]: 0 : if (ret2 < 0)
1704 : : {
1705 : 0 : return ret;
1706 : : }
1707 : :
1708 : 0 : num_wrong = 0;
1709 : : /* find wrong double bonds */
1710 [ # # ]: 0 : for (i = 0; i < num_at; i++)
1711 : : {
1712 [ # # ]: 0 : if (at2[i].valence == 3 &&
1713 [ # # ]: 0 : at2[i].chem_bonds_valence - at2[i].valence == 1 &&
1714 [ # # # # : 0 : at2[i].sb_parity[0] && at2[i].sb_parity[1] && !at2[i].sb_parity[2] &&
# # ]
1715 [ # # ]: 0 : (at2[i].bond_type[j1 = (int)at2[i].sb_ord[0]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
1716 [ # # # # ]: 0 : (at2[i].bond_type[j2 = (int)at2[i].sb_ord[1]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
1717 : : j1 != j2)
1718 : : {
1719 : :
1720 : 0 : num_wrong++;
1721 : : }
1722 : : }
1723 [ # # ]: 0 : if (!num_wrong)
1724 : : {
1725 : 0 : return 0;
1726 : : }
1727 : 0 : num_fixed = 0;
1728 [ # # ]: 0 : for (i = 0; i < pBNS->num_bonds; i++)
1729 : : {
1730 : 0 : pEdge = pBNS->edge + i;
1731 [ # # ]: 0 : if (pEdge->forbidden & forbidden_edge_stereo)
1732 : : {
1733 : 0 : num_fixed++;
1734 : : }
1735 : : }
1736 : :
1737 : : /* there may be no fixed stereo bonds at all, see #87607 */
1738 : 0 : AllocEdgeList(&CarbonChargeEdges, EDGE_LIST_CLEAR);
1739 : 0 : AllocEdgeList(&FixedEdges, EDGE_LIST_CLEAR);
1740 : 0 : AllocEdgeList(&WrongEdges, EDGE_LIST_CLEAR);
1741 : :
1742 : : /* do not goto exit_function before reaching this point: EdgeLists have not been initiated */
1743 : :
1744 [ # # ]: 0 : if (0 > (ret = ForbidCarbonChargeEdges(pBNS, pTCGroups, &CarbonChargeEdges, forbidden_edge_mask)))
1745 : : {
1746 : 0 : goto exit_function;
1747 : : }
1748 [ # # # # ]: 0 : if ((ret = AllocEdgeList(&FixedEdges, num_fixed)) ||
1749 : 0 : (ret = AllocEdgeList(&WrongEdges, num_wrong)))
1750 : : {
1751 : 0 : goto exit_function;
1752 : : }
1753 : : /* collect wrong double bonds and set flow=0 */
1754 [ # # # # ]: 0 : for (i = 0; i < num_at && WrongEdges.num_edges < num_wrong; i++)
1755 : : {
1756 [ # # ]: 0 : if (at2[i].valence == 3 &&
1757 [ # # ]: 0 : at2[i].chem_bonds_valence - at2[i].valence == 1 &&
1758 [ # # # # : 0 : at2[i].sb_parity[0] && at2[i].sb_parity[1] && !at2[i].sb_parity[2] &&
# # ]
1759 [ # # ]: 0 : (at2[i].bond_type[j1 = (int)at2[i].sb_ord[0]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
1760 [ # # # # ]: 0 : (at2[i].bond_type[j2 = (int)at2[i].sb_ord[1]] & BOND_TYPE_MASK) == BOND_TYPE_SINGLE &&
1761 : : j1 != j2)
1762 : : {
1763 [ # # # # ]: 0 : switch (j1 + j2)
1764 : : {
1765 : 0 : case 1: /* 0, 1 */
1766 : 0 : k = 2;
1767 : 0 : break;
1768 : 0 : case 2: /* 0, 2 */
1769 : 0 : k = 1;
1770 : 0 : break;
1771 : 0 : case 3: /* 1, 2 */
1772 : 0 : k = 0;
1773 : 0 : break;
1774 : 0 : default:
1775 : 0 : ret = RI_ERR_PROGR;
1776 : 0 : goto exit_function;
1777 : : }
1778 : 0 : ne = pBNS->vert[i].iedge[k];
1779 : 0 : pEdge = pBNS->edge + ne;
1780 : 0 : v1 = pEdge->neighbor1;
1781 : 0 : v2 = pEdge->neighbor12 ^ v1;
1782 : 0 : pv1 = pBNS->vert + v1;
1783 : 0 : pv2 = pBNS->vert + v2;
1784 : :
1785 [ # # ]: 0 : if (!pEdge->flow)
1786 : : {
1787 : 0 : ret = RI_ERR_PROGR;
1788 : 0 : goto exit_function;
1789 : : }
1790 : 0 : pEdge->flow--;
1791 : 0 : pEdge->forbidden |= forbidden_edge_mask;
1792 : 0 : pv1->st_edge.flow--;
1793 : 0 : pv2->st_edge.flow--;
1794 : 0 : pBNS->tot_st_flow -= 2;
1795 [ # # ]: 0 : if ((ret = AddToEdgeList(&WrongEdges, ne, 0))) /* djb-rwth: addressing LLVM warning */
1796 : : {
1797 : 0 : goto exit_function;
1798 : : }
1799 : : }
1800 : : }
1801 : : /* remove forbidden mark from stereo bonds (unfix stereo bonds) */
1802 [ # # # # ]: 0 : for (i = 0; i < pBNS->num_bonds && FixedEdges.num_edges < num_fixed; i++)
1803 : : {
1804 : 0 : pEdge = pBNS->edge + i;
1805 [ # # ]: 0 : if (pEdge->forbidden & forbidden_edge_stereo)
1806 : : {
1807 : 0 : pEdge->forbidden &= inv_forbidden_edge_stereo;
1808 : 0 : FixedEdges.pnEdges[FixedEdges.num_edges++] = i;
1809 : : }
1810 : : }
1811 : : /* Run BNS to move charges and rearrange bond orders */
1812 : 0 : retBNS = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
1813 : 0 : (*pnNumRunBNS)++;
1814 [ # # ]: 0 : if (retBNS < 0)
1815 : : {
1816 : 0 : goto exit_function;
1817 : : }
1818 : : else
1819 : : {
1820 [ # # ]: 0 : if (retBNS > 0)
1821 : : {
1822 : 0 : *pnTotalDelta += retBNS;
1823 : : }
1824 : : }
1825 : : /* remove forbidden_edge_mask and set forbidden_edge_stereo */
1826 : 0 : RemoveForbiddenEdgeMask(pBNS, &WrongEdges, forbidden_edge_mask);
1827 : : /* allow carbon charges to change */
1828 : 0 : RemoveForbiddenEdgeMask(pBNS, &CarbonChargeEdges, forbidden_edge_mask);
1829 : : /* fix previously unfixed stereo bonds */
1830 : 0 : SetForbiddenEdgeMask(pBNS, &FixedEdges, forbidden_edge_stereo);
1831 : : /* Run BNS again in case not all edge flows are maximal */
1832 : 0 : ret2 = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
1833 : 0 : (*pnNumRunBNS)++;
1834 [ # # ]: 0 : if (ret2 < 0)
1835 : : {
1836 : 0 : goto exit_function;
1837 : : }
1838 : : else
1839 : : {
1840 [ # # ]: 0 : if (ret2 > 0)
1841 : : {
1842 : 0 : *pnTotalDelta += retBNS;
1843 : : }
1844 : : }
1845 : 0 : ret = retBNS;
1846 : :
1847 : 0 : exit_function:
1848 : :
1849 : 0 : AllocEdgeList(&CarbonChargeEdges, EDGE_LIST_FREE);
1850 : 0 : AllocEdgeList(&FixedEdges, EDGE_LIST_FREE);
1851 : 0 : AllocEdgeList(&WrongEdges, EDGE_LIST_FREE);
1852 : :
1853 : 0 : return ret;
1854 : : }
1855 : :
1856 : :
1857 : : /****************************************************************************
1858 : : Find and eliminate false Mobile-H groups: Cl(=O)3(-O(-)) => Cl(-)(=O)4
1859 : : ****************************************************************************/
1860 : 0 : int MoveChargeToRemoveCenerpoints(BN_STRUCT* pBNS,
1861 : : BN_DATA* pBD,
1862 : : StrFromINChI* pStruct,
1863 : : inp_ATOM* at,
1864 : : inp_ATOM* at2,
1865 : : VAL_AT* pVA,
1866 : : ALL_TC_GROUPS* pTCGroups,
1867 : : int* pnNumRunBNS,
1868 : : int* pnTotalDelta,
1869 : : int forbidden_edge_mask)
1870 : : {
1871 : : int i, j, neigh, num_success; /* djb-rwth: removing redundant variables */
1872 : : int num_donors, num_acceptors, bond_type, num_donors_O, num_acceptors_O, is_centerpoint_N, num_known_endpoints, num_wrong_neigh;
1873 : : int ret2, ret_forbid_edges, ret, delta;
1874 : 0 : int num_at = pStruct->num_atoms;
1875 : 0 : int num_deleted_H = pStruct->num_deleted_H;
1876 : 0 : int len_at = num_at + num_deleted_H;
1877 : 0 : int forbidden_edge_test = BNS_EDGE_FORBIDDEN_TEST;
1878 [ # # # # : 0 : int bPossiblyIgnore = pStruct->charge >= 0 && (!pTCGroups->num_tgroups || (pStruct->iMobileH == TAUT_NON && pStruct->ti.num_t_groups)); /* djb-rwth: addressing LLVM warning */
# # # # ]
1879 : : S_CHAR MobileChargeNeigh[MAXVAL], DoubleBondAcceptors[MAXVAL], DoubleBondNotONeigh[MAXVAL];
1880 : : int numMobileChargeNeigh, numDoubleBondAcceptors, numDoubleBondNotONeigh; /* djb-rwth: removing redundant variables */
1881 : : EDGE_LIST ChargeListAllExcept_DB_O;
1882 : :
1883 : :
1884 : : BNS_EDGE* pEdgeMinus, * pe;
1885 : : Vertex v1m, v2m;
1886 : : BNS_VERTEX* pv1m, * pv2m;
1887 : : /* djb-rwth: removing redundant code */
1888 : 0 : num_success = 0;
1889 : :
1890 : : /* count O(+)H, N(+)H */
1891 : :
1892 : : /*
1893 : : if ( pStruct->charge >= 0 && (!pTCGroups->num_tgroups || pStruct->iMobileH == TAUT_NON && pStruct->ti.num_t_groups) ) {
1894 : : goto exit_function;
1895 : : }
1896 : : */
1897 [ # # ]: 0 : if ((ret = AllocEdgeList(&ChargeListAllExcept_DB_O, EDGE_LIST_CLEAR))) /* djb-rwth: addressing LLVM warning */
1898 : : {
1899 : 0 : goto exit_function;
1900 : : }
1901 : :
1902 : :
1903 : : /* to simplify, prepare new at[] from pBNS */
1904 : 0 : memcpy(at2, at, len_at * sizeof(at2[0]));
1905 : 0 : pStruct->at = at2;
1906 : 0 : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
1907 : 0 : pStruct->at = at;
1908 [ # # ]: 0 : if (ret2 < 0)
1909 : : {
1910 : 0 : ret = ret2;
1911 : 0 : goto exit_function;
1912 : : }
1913 : : #if ( FIND_RING_SYSTEMS == 1 )
1914 : 0 : ret2 = MarkRingSystemsInp(at2, num_at, 0);
1915 [ # # ]: 0 : if (ret2 < 0)
1916 : : {
1917 : 0 : ret = ret2;
1918 : 0 : goto exit_function;
1919 : : }
1920 : : #endif
1921 : : /* mark bonds that cannot be tautomeric; do not forget to remove the marks later */
1922 : 0 : ret_forbid_edges = SetForbiddenEdges(pBNS, at2, num_at, forbidden_edge_test, 0, NULL);
1923 [ # # ]: 0 : if (ret_forbid_edges < 0)
1924 : : {
1925 : 0 : ret = ret_forbid_edges;
1926 : 0 : goto exit_function;
1927 : : }
1928 : :
1929 [ # # ]: 0 : for (i = 0; i < num_at; i++)
1930 : : {
1931 [ # # ]: 0 : if (pVA[i].cNumValenceElectrons != 4 && /* not C, Si, Ge */
1932 [ # # # # : 0 : !(pVA[i].nTautGroupEdge || (pStruct->iMobileH == TAUT_NON && pStruct->endpoint && pStruct->endpoint[i])) &&
# # # # ]
1933 [ # # # # : 0 : !at2[i].num_H && !at2[i].charge && at2[i].valence >= 2 &&
# # ]
1934 [ # # # # ]: 0 : at2[i].valence < at2[i].chem_bonds_valence &&
1935 : 0 : is_centerpoint_elem(at2[i].el_number)) /* djb-rwth: addressing LLVM warning */
1936 : : {
1937 : :
1938 [ # # # # : 0 : is_centerpoint_N = (pVA[i].cNumValenceElectrons == 5 && (pVA[i].cPeriodicRowNumber == 1 || pVA[i].cMetal));
# # ]
1939 : : /* look at the neighbors */
1940 : 0 : numMobileChargeNeigh = numDoubleBondAcceptors = numDoubleBondNotONeigh = num_donors = num_acceptors = 0;
1941 : 0 : num_donors_O = num_acceptors_O = 0;
1942 : 0 : num_known_endpoints = num_wrong_neigh = 0;
1943 [ # # ]: 0 : for (j = 0; j < at2[i].valence; j++) /* djb-rwth: removing redundant code */
1944 : : {
1945 : 0 : neigh = at2[i].neighbor[j];
1946 [ # # # # : 0 : if ((at2[neigh].endpoint || (pStruct->iMobileH == TAUT_NON && pStruct->endpoint && pStruct->endpoint[neigh])) || at2[neigh].charge > 0) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
1947 : : {
1948 : 0 : num_known_endpoints++;
1949 : 0 : continue;
1950 : : }
1951 [ # # ]: 0 : if (pBNS->edge[pBNS->vert[i].iedge[j]].forbidden & forbidden_edge_test)
1952 : : {
1953 : 0 : continue;
1954 : : }
1955 : 0 : bond_type = at2[i].bond_type[j] & BOND_TYPE_MASK;
1956 [ # # ]: 0 : if (bond_type > BOND_TYPE_DOUBLE)
1957 : : {
1958 : 0 : num_wrong_neigh++;
1959 : 0 : continue;
1960 : : }
1961 [ # # # # ]: 0 : if (at2[neigh].num_H && bond_type == BOND_TYPE_SINGLE)
1962 : : {
1963 : 0 : break; /* not this case */
1964 : : }
1965 [ # # ]: 0 : if (at2[neigh].chem_bonds_valence - at2[neigh].charge
1966 : 0 : != get_endpoint_valence(at2[neigh].el_number))
1967 : : {
1968 [ # # # # ]: 0 : if (bond_type == BOND_TYPE_DOUBLE && pVA[neigh].cNumValenceElectrons != 6)
1969 : : {
1970 : 0 : DoubleBondNotONeigh[numDoubleBondNotONeigh++] = j;
1971 : : }
1972 : 0 : continue;
1973 : : }
1974 [ # # # # ]: 0 : if (at2[neigh].charge == -1 && bond_type == BOND_TYPE_SINGLE &&
1975 [ # # # # ]: 0 : (pVA[neigh].nCMinusGroupEdge < 1 || pBNS->edge[pVA[neigh].nCMinusGroupEdge - 1].flow != 1))
1976 : : {
1977 : : break;
1978 : : }
1979 [ # # # ]: 0 : switch (bond_type)
1980 : : {
1981 : 0 : case BOND_TYPE_SINGLE:
1982 [ # # # # ]: 0 : if (at2[neigh].charge != -1 || pVA[neigh].nCMinusGroupEdge <= 0)
1983 : : {
1984 : 0 : num_wrong_neigh++;
1985 : 0 : continue;
1986 : : }
1987 : 0 : num_donors++;
1988 [ # # # # ]: 0 : num_donors_O += (pVA[neigh].cNumValenceElectrons == 6 && pVA[neigh].cPeriodicRowNumber <= 4);
1989 : 0 : MobileChargeNeigh[numMobileChargeNeigh++] = j;
1990 : 0 : break;
1991 : 0 : case BOND_TYPE_DOUBLE:
1992 [ # # ]: 0 : if (at2[neigh].charge)
1993 : : {
1994 : 0 : num_wrong_neigh++;
1995 : 0 : continue;
1996 : : }
1997 : 0 : DoubleBondAcceptors[numDoubleBondAcceptors++] = j;
1998 : 0 : num_acceptors++;
1999 [ # # # # ]: 0 : num_acceptors_O += (pVA[neigh].cNumValenceElectrons == 6 && pVA[neigh].cPeriodicRowNumber <= 4);
2000 : : }
2001 : : }
2002 [ # # # # : 0 : if (j != at2[i].valence || !num_donors || !num_acceptors)
# # ]
2003 : : {
2004 : 0 : continue;
2005 : : }
2006 : : /* special case NOn(-) */
2007 [ # # # # : 0 : if (is_centerpoint_N && (num_donors == num_donors_O) && (num_acceptors == num_acceptors_O))
# # ]
2008 : : {
2009 : 0 : continue;
2010 : : }
2011 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON && num_donors == numDoubleBondNotONeigh)
2012 : 0 : {
2013 : : /* fix all charges except on =O */
2014 : : Vertex vPathStart, vPathEnd;
2015 : : int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
2016 : 0 : int k, e, num_MovedCharges = 0;
2017 : :
2018 [ # # ]: 0 : if (!ChargeListAllExcept_DB_O.num_edges)
2019 : : {
2020 : : /* djb-rwth: removing redundant code */
2021 [ # # ]: 0 : for (k = 0; k < num_at; k++)
2022 : : {
2023 [ # # # # ]: 0 : if (!((1 == at2[k].valence && pBNS->edge[pBNS->vert[k].iedge[0]].flow &&
2024 [ # # ]: 0 : !pBNS->edge[pBNS->vert[k].iedge[0]].forbidden &&
2025 [ # # # # ]: 0 : !((e = pVA[k].nCMinusGroupEdge - 1) >= 0 && pBNS->edge[e].flow) &&
2026 [ # # # # ]: 0 : !((e = pVA[k].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[e].flow) &&
2027 : : /* 0 == at2[k].charge && */
2028 [ # # # # ]: 0 : pVA[k].cNumValenceElectrons == 6 && !pVA[k].cMetal &&
2029 [ # # # # ]: 0 : (pStruct->endpoint && pStruct->endpoint[k])) ||
2030 [ # # # # ]: 0 : (pStruct->fixed_H && pStruct->fixed_H[k]))) /* djb-rwth: addressing LLVM warnings */
2031 : : /* djb-rwth: removing redundant code */
2032 [ # # # # ]: 0 : if ((e = pVA[k].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[e].flow &&
2033 [ # # # # ]: 0 : !pBNS->edge[e].forbidden &&
2034 : 0 : (ret = AddToEdgeList(&ChargeListAllExcept_DB_O, e, 64)))
2035 : : {
2036 : 0 : goto exit_function;
2037 : : }
2038 [ # # ]: 0 : if ((e = pVA[k].nCPlusGroupEdge - 1) >= 0 &&
2039 [ # # # # ]: 0 : !pBNS->edge[e].forbidden &&
2040 : 0 : (ret = AddToEdgeList(&ChargeListAllExcept_DB_O, e, 64)))
2041 : : {
2042 : 0 : goto exit_function;
2043 : : }
2044 : : }
2045 : : }
2046 : : /* fix double bonds to non-O neighbors connected by double bonds;
2047 : : we will try to make these bons single */
2048 [ # # ]: 0 : for (k = 0; k < numDoubleBondNotONeigh; k++)
2049 : : {
2050 : 0 : e = pBNS->vert[i].iedge[(int)DoubleBondNotONeigh[k]];
2051 [ # # # # ]: 0 : if (!pBNS->edge[e].forbidden &&
2052 : 0 : (ret = AddToEdgeList(&ChargeListAllExcept_DB_O, e, 64)))
2053 : : {
2054 : 0 : goto exit_function;
2055 : : }
2056 : : }
2057 : : /* attempt to make DoubleBondNotONeigh[] single */
2058 : 0 : SetForbiddenEdgeMask(pBNS, &ChargeListAllExcept_DB_O, forbidden_edge_mask);
2059 [ # # # # ]: 0 : for (k = 0; k < numDoubleBondNotONeigh && num_MovedCharges < numMobileChargeNeigh; k++)
2060 : : {
2061 : 0 : pe = pBNS->edge + pBNS->vert[i].iedge[(int)DoubleBondNotONeigh[k]];
2062 : 0 : delta = 1;
2063 [ # # ]: 0 : if (pe->flow != delta)
2064 : 0 : continue;
2065 : 0 : pv1m = pBNS->vert + (v1m = pe->neighbor1);
2066 : 0 : pv2m = pBNS->vert + (v2m = pe->neighbor12 ^ v1m);
2067 : 0 : pv1m->st_edge.flow -= delta;
2068 : 0 : pv2m->st_edge.flow -= delta;
2069 : 0 : pe->flow -= delta;
2070 : 0 : pBNS->tot_st_flow -= 2 * delta;
2071 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2072 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
2073 [ # # ]: 0 : if (ret < 0)
2074 : : {
2075 : 0 : goto exit_function;
2076 : : }
2077 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1m && vPathStart == v2m) ||
# # ]
2078 [ # # # # ]: 0 : (vPathEnd == v2m && vPathStart == v1m)) &&
2079 [ # # ]: 0 : nDeltaCharge == 0 /* (-) moving from one to another atom*/) /* djb-rwth: addressing LLVM warnings */
2080 : : {
2081 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2082 : 0 : (*pnNumRunBNS)++;
2083 [ # # ]: 0 : if (ret < 0)
2084 : : {
2085 : 0 : goto exit_function;
2086 : : }
2087 : : else
2088 : : {
2089 [ # # ]: 0 : if (ret == 1)
2090 : : {
2091 : 0 : *pnTotalDelta += ret;
2092 : 0 : num_MovedCharges++;
2093 : : }
2094 : : else
2095 : : {
2096 : 0 : ret = RI_ERR_PROGR;
2097 : 0 : goto exit_function;
2098 : : }
2099 : : }
2100 : : }
2101 : : else
2102 : : {
2103 : : /* djb-rwth: removing redundant code */
2104 : 0 : pv1m->st_edge.flow += delta;
2105 : 0 : pv2m->st_edge.flow += delta;
2106 : 0 : pe->flow += delta;
2107 : 0 : pBNS->tot_st_flow += 2 * delta;
2108 : : }
2109 : : }
2110 : 0 : RemoveForbiddenEdgeMask(pBNS, &ChargeListAllExcept_DB_O, forbidden_edge_mask);
2111 : : }
2112 : : else
2113 : : {
2114 [ # # # # : 0 : if (!bPossiblyIgnore || (!num_known_endpoints && !num_wrong_neigh && (num_acceptors_O + num_donors_O >= 3))) /* djb-rwth: addressing LLVM warning */
# # # # ]
2115 : : {
2116 : : /* remove negative charges from the neighbors */
2117 : 0 : pBNS->vert[i].st_edge.cap += num_donors; /* enough to make all bonds to donors double */
2118 : 0 : pBNS->tot_st_cap += num_donors;
2119 : 0 : pVA[i].cInitCharge -= num_donors; /* work no matter what are known charge/valence */
2120 [ # # ]: 0 : for (j = 0; j < numMobileChargeNeigh; j++)
2121 : : {
2122 : 0 : neigh = at2[i].neighbor[(int)MobileChargeNeigh[j]];
2123 : 0 : pEdgeMinus = pBNS->edge + ((long long)pVA[neigh].nCMinusGroupEdge - 1); /* djb-rwth: cast operator added */
2124 : 0 : v1m = pEdgeMinus->neighbor1;
2125 : 0 : v2m = pEdgeMinus->neighbor12 ^ v1m;
2126 : 0 : pv1m = pBNS->vert + v1m;
2127 : 0 : pv2m = pBNS->vert + v2m;
2128 : 0 : delta = pEdgeMinus->flow;
2129 : 0 : pv1m->st_edge.flow -= delta;
2130 : 0 : pv2m->st_edge.flow -= delta;
2131 [ # # ]: 0 : if (IS_BNS_VT_C_GR(pv1m->type))
2132 : : {
2133 : : /* irreversible change to ChargeStruct */
2134 : 0 : pv1m->st_edge.cap -= delta;
2135 : : }
2136 : : else
2137 : : {
2138 [ # # ]: 0 : if (IS_BNS_VT_C_GR(pv2m->type))
2139 : : {
2140 : : /* irreversible change to ChargeStruct */
2141 : 0 : pv2m->st_edge.cap -= delta;
2142 : : }
2143 : : else
2144 : : {
2145 : 0 : ret = RI_ERR_PROGR;
2146 : 0 : goto exit_function;
2147 : : }
2148 : : }
2149 : 0 : pBNS->tot_st_cap -= delta;
2150 : 0 : pBNS->tot_st_flow -= 2 * delta;
2151 : 0 : pEdgeMinus->flow -= delta;
2152 : : }
2153 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2154 : 0 : (*pnNumRunBNS)++;
2155 [ # # ]: 0 : if (ret < 0)
2156 : : {
2157 : 0 : goto exit_function;
2158 : : }
2159 : : else
2160 [ # # ]: 0 : if (ret == num_donors)
2161 : : {
2162 : 0 : *pnTotalDelta += ret;
2163 : 0 : num_success++;
2164 : : /*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
2165 : : }
2166 : : else
2167 : : {
2168 : 0 : ret = RI_ERR_PROGR;
2169 : 0 : goto exit_function;
2170 : : }
2171 : : }
2172 : : }
2173 : : }
2174 : : }
2175 [ # # ]: 0 : if (ret_forbid_edges)
2176 : : {
2177 : : /* remove the marks */
2178 : 0 : RemoveForbiddenBondFlowBits(pBNS, forbidden_edge_test);
2179 : : }
2180 : 0 : ret = num_success;
2181 : :
2182 : 0 : exit_function:
2183 : :
2184 : 0 : AllocEdgeList(&ChargeListAllExcept_DB_O, EDGE_LIST_FREE);
2185 : :
2186 : 0 : return ret;
2187 : : }
2188 : :
2189 : :
2190 : : /****************************************************************************
2191 : : Find and eliminate cases when Mobile H endpoint has radical on it
2192 : : (typical for wrong P(VI)(=O)3OH
2193 : : ****************************************************************************/
2194 : 0 : int MakeSingleBondsMetal2ChargedHeteroat(BN_STRUCT* pBNS,
2195 : : BN_DATA* pBD,
2196 : : StrFromINChI* pStruct,
2197 : : inp_ATOM* at,
2198 : : inp_ATOM* at2,
2199 : : VAL_AT* pVA,
2200 : : ALL_TC_GROUPS* pTCGroups,
2201 : : int* pnNumRunBNS,
2202 : : int* pnTotalDelta,
2203 : : int forbidden_edge_mask)
2204 : : {
2205 : : int i;
2206 : :
2207 : : int ret2, ret, pass;
2208 : 0 : int num_at = pStruct->num_atoms;
2209 : 0 : int num_deleted_H = pStruct->num_deleted_H;
2210 : 0 : int len_at = num_at + num_deleted_H;
2211 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
2212 : :
2213 : : int j, k;
2214 : : int cur_num_edges;
2215 : : BNS_EDGE* e;
2216 : : Vertex v1, v2;
2217 : :
2218 : : EdgeIndex* pFixedEdges;
2219 : : int nNumEdgesToFix;
2220 : :
2221 : 0 : ret = 0;
2222 : :
2223 : : /* to simplify, prepare new at[] from pBNS */
2224 : 0 : memcpy(at2, at, len_at * sizeof(at2[0]));
2225 : 0 : pStruct->at = at2;
2226 : 0 : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2227 : 0 : pStruct->at = at;
2228 [ # # ]: 0 : if (ret2 < 0)
2229 : : {
2230 : 0 : ret = ret2;
2231 : 0 : goto exit_function;
2232 : : }
2233 : :
2234 : 0 : pFixedEdges = NULL;
2235 : :
2236 : 0 : nNumEdgesToFix = 0; /* cpunt nNumEdgesToFix only when pass==0 */
2237 : 0 : cur_num_edges = 0; /* count cur_num_edges only when pass==1; at the end they must be equal */
2238 [ # # ]: 0 : for (pass = 0; pass < 2; pass++)
2239 : : {
2240 [ # # ]: 0 : if (pass)
2241 : : {
2242 : : /* 2nd pass: allocate edge storage */
2243 [ # # ]: 0 : if (!nNumEdgesToFix)
2244 : : {
2245 : 0 : break; /* nothing to do */
2246 : : }
2247 : 0 : pFixedEdges = (EdgeIndex*)inchi_malloc(nNumEdgesToFix * sizeof(pFixedEdges[0]));
2248 [ # # ]: 0 : if (!pFixedEdges)
2249 : : {
2250 : 0 : ret = RI_ERR_ALLOC;
2251 : 0 : goto exit_function;
2252 : : }
2253 : : }
2254 [ # # ]: 0 : for (i = 0; i < num_at; i++)
2255 : : {
2256 : : int neigh;
2257 [ # # ]: 0 : if (pVA[i].cMetal)
2258 : : {
2259 [ # # ]: 0 : for (j = 0; j < at2[i].valence; j++)
2260 : : {
2261 : 0 : neigh = at2[i].neighbor[j];
2262 [ # # ]: 0 : if (pVA[neigh].cNumValenceElectrons == 4 &&
2263 [ # # ]: 0 : pVA[neigh].cPeriodicRowNumber == 1)
2264 : : {
2265 : 0 : continue; /* ignore carbon */
2266 : : }
2267 [ # # # # ]: 0 : if (at2[i].bond_type[j] > BOND_TYPE_SINGLE && at2[neigh].charge &&
2268 [ # # # # ]: 0 : !pVA[neigh].cMetal && pVA[neigh].cnListIndex > 0)
2269 : : {
2270 [ # # ]: 0 : int cnBits = at2[neigh].charge > 0 ? MAKE_CN_BITS(cn_bits_N, cn_bits_P, 0, 0) :
2271 : : MAKE_CN_BITS(cn_bits_N, cn_bits_M, 0, 0);
2272 : 0 : int atBits = cnList[pVA[neigh].cnListIndex - 1].bits;
2273 [ # # ]: 0 : for (k = 0; k < MAX_NUM_CN_BITS - 1; k++, atBits >>= cn_bits_shift)
2274 : : {
2275 : : /* ??? */
2276 [ # # ]: 0 : if ((atBits & cnBits) == cnBits)
2277 : : {
2278 : 0 : break;
2279 : : }
2280 : : }
2281 [ # # ]: 0 : if (k == MAX_NUM_CN_BITS - 1)
2282 : : {
2283 : 0 : continue;
2284 : : }
2285 [ # # ]: 0 : if (pass == 0)
2286 : : {
2287 : 0 : nNumEdgesToFix++;
2288 : : }
2289 : : else
2290 : : {
2291 : 0 : pFixedEdges[cur_num_edges++] = pBNS->vert[i].iedge[j];
2292 : : }
2293 : : }
2294 : : }
2295 : : }
2296 : : }
2297 : : }
2298 : :
2299 : : /* restore the initial structures */
2300 : 0 : memcpy(at2, at, ((long long)num_at + (long long)num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2301 : :
2302 [ # # # # ]: 0 : if (nNumEdgesToFix && pFixedEdges)
2303 : : {
2304 [ # # ]: 0 : if (nNumEdgesToFix != cur_num_edges)
2305 : : {
2306 : 0 : ret = RI_ERR_PROGR;
2307 : 0 : goto pre_exit_function; /* djb-rwth: fixing coverity ID #499637 */
2308 : : }
2309 : : /* change edge flow, fix the edges, and run BNS */
2310 [ # # ]: 0 : for (i = 0; i < nNumEdgesToFix; i++)
2311 : : {
2312 : 0 : e = pBNS->edge + pFixedEdges[i];
2313 : 0 : v1 = e->neighbor1;
2314 : 0 : v2 = e->neighbor12 ^ v1;
2315 : 0 : e->flow--;
2316 : 0 : e->forbidden |= forbidden_edge_mask;
2317 : 0 : pBNS->vert[v1].st_edge.flow--;
2318 : 0 : pBNS->vert[v2].st_edge.flow--;
2319 : 0 : pBNS->tot_st_flow -= 2;
2320 : 0 : (*pnTotalDelta) -= 2;
2321 : : }
2322 : : /* Run BNS allowing to change any charges */
2323 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2324 : 0 : (*pnNumRunBNS)++;
2325 [ # # ]: 0 : if (ret < 0)
2326 : : {
2327 : 0 : goto pre_exit_function; /* djb-rwth: fixing coverity ID #499637 */
2328 : : }
2329 : : else
2330 : : {
2331 : 0 : (*pnTotalDelta) += ret;
2332 : : }
2333 : : /* unfix the edges */
2334 [ # # ]: 0 : for (i = 0; i < nNumEdgesToFix; i++)
2335 : : {
2336 : 0 : e = pBNS->edge + pFixedEdges[i];
2337 : 0 : e->forbidden &= inv_forbidden_edge_mask;
2338 : : }
2339 [ # # ]: 0 : if (ret < 2 * nNumEdgesToFix)
2340 : : {
2341 : : /* not all fixes succeeded */
2342 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2343 : 0 : (*pnNumRunBNS)++;
2344 [ # # ]: 0 : if (ret < 0)
2345 : : {
2346 : 0 : goto pre_exit_function; /* djb-rwth: fixing coverity ID #499637 */
2347 : : }
2348 : : else
2349 : : {
2350 : 0 : (*pnTotalDelta) += ret;
2351 : : }
2352 : : }
2353 : : }
2354 : :
2355 : 0 : pre_exit_function:
2356 [ # # ]: 0 : if (pFixedEdges)
2357 : : {
2358 [ # # ]: 0 : inchi_free(pFixedEdges);
2359 : 0 : pFixedEdges = NULL;
2360 : : }
2361 : :
2362 : 0 : exit_function:
2363 : 0 : return ret;
2364 : : }
2365 : :
2366 : :
2367 : :
2368 : : /**************************************************************************/
2369 : : /* In Reconnected structure change 'salt bonds' to 'coordination bonds */
2370 : : /* for example, M-O-C= -> M(+)-O(-)-C= */
2371 : : /* Defect: instead of NH2-C=O(+)-M it will restore NH2(+)=C-O(-)-M(+) */
2372 : : /* However, in this release metal-organic compounds do not get much care */
2373 : 0 : int SaltBondsToCoordBonds(BN_STRUCT* pBNS,
2374 : : BN_DATA* pBD,
2375 : : StrFromINChI* pStruct,
2376 : : inp_ATOM* at,
2377 : : inp_ATOM* at2,
2378 : : VAL_AT* pVA,
2379 : : ALL_TC_GROUPS* pTCGroups,
2380 : : int* pnNumRunBNS,
2381 : : int* pnTotalDelta,
2382 : : int forbidden_edge_mask)
2383 : : {
2384 : : int i;
2385 : :
2386 : : int ret2, ret, cur_success;
2387 : 0 : int num_at = pStruct->num_atoms;
2388 : 0 : int num_edges = pBNS->num_bonds + 2 * pBNS->num_atoms;
2389 : 0 : int num_deleted_H = pStruct->num_deleted_H;
2390 : 0 : int len_at = num_at + num_deleted_H;
2391 : 0 : int inv_forbidden_edge_mask = ~forbidden_edge_mask;
2392 : : EDGE_LIST AllChargeEdges;
2393 : :
2394 : : int j, k, n;
2395 : : BNS_EDGE* pe, * pePlusMetal, * peMinusO;
2396 : : BNS_VERTEX* pv1, * pv2, * pvO, * pvM;
2397 : : Vertex v1, v2, vPlusMinus;
2398 : :
2399 : : EdgeIndex ie, iePlusMetal, ieMinusO;
2400 : :
2401 : : Vertex vPathStart, vPathEnd;
2402 : : int delta, nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
2403 : :
2404 : 0 : ret = 0;
2405 : 0 : cur_success = 0;
2406 : 0 : AllocEdgeList(&AllChargeEdges, EDGE_LIST_CLEAR);
2407 : :
2408 [ # # # # : 0 : if (pStruct->iInchiRec == INCHI_BAS || !pStruct->pSrm->bMetalAddFlower || pStruct->pSrm->nMetalMinBondOrder)
# # ]
2409 : : {
2410 : 0 : goto exit_function;
2411 : : }
2412 : :
2413 : : /* to simplify, prepare new at[] from pBNS */
2414 : 0 : memcpy(at2, at, len_at * sizeof(at2[0]));
2415 : 0 : pStruct->at = at2;
2416 : 0 : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2417 : 0 : pStruct->at = at;
2418 [ # # ]: 0 : if (ret2 < 0)
2419 : : {
2420 : 0 : ret = ret2;
2421 : 0 : goto exit_function;
2422 : : }
2423 [ # # ]: 0 : for (i = 0; i < num_at; i++)
2424 : : {
2425 [ # # ]: 0 : if (bIsMetalSalt(at2, i))
2426 : : {
2427 [ # # ]: 0 : if (!AllChargeEdges.num_edges)
2428 : : {
2429 : : /*--------- one-time action: fix all bonds, charges, taut. group edges ------------*/
2430 [ # # ]: 0 : for (j = 0; j < num_at; j++)
2431 : : {
2432 : : /* all bonds */
2433 [ # # ]: 0 : for (k = 0; k < at2[j].valence; k++)
2434 : : {
2435 : 0 : n = at2[j].neighbor[k];
2436 [ # # # # : 0 : if (n < j && !pBNS->edge[ie = pBNS->vert[j].iedge[k]].forbidden &&
# # ]
2437 : 0 : (ret = AddToEdgeList(&AllChargeEdges, ie, num_edges)))
2438 : : {
2439 : 0 : goto exit_function;
2440 : : }
2441 : : }
2442 : : /* charge edges */
2443 [ # # # # : 0 : if ((ie = pVA[j].nCMinusGroupEdge - 1) >= 0 && !pBNS->edge[ie].forbidden &&
# # ]
2444 : 0 : (ret = AddToEdgeList(&AllChargeEdges, ie, num_edges)))
2445 : : {
2446 : 0 : goto exit_function;
2447 : : }
2448 [ # # # # : 0 : if ((ie = pVA[j].nCPlusGroupEdge - 1) >= 0 && !pBNS->edge[ie].forbidden &&
# # ]
2449 : 0 : (ret = AddToEdgeList(&AllChargeEdges, ie, num_edges)))
2450 : : {
2451 : 0 : goto exit_function;
2452 : : }
2453 : : }
2454 : : /* taut group edges */
2455 [ # # ]: 0 : for (j = 0; j < pTCGroups->num_tgroups; j++)
2456 : : {
2457 : 0 : pv1 = pBNS->vert + (v1 = pTCGroups->pTCG[j].nVertexNumber); /* t-group vertex */ /* djb-rwth: ignoring LLVM warning: see comment below */
2458 [ # # ]: 0 : for (k = 0; k < pv1->num_adj_edges; k++)
2459 : : {
2460 : : /* ie, pe - tautomeric atom edge; pv2 - endpoint vertex */
2461 : : /* Note: pe, pv2, v1 are not used here; they are to show how to traverse t-group */
2462 : 0 : pv2 = pBNS->vert + (pe = pBNS->edge + (ie = pv1->iedge[k]))->neighbor1; /* djb-rwth: ignoring LLVM warning: see comment above */
2463 [ # # ]: 0 : if ((ret = AddToEdgeList(&AllChargeEdges, ie, num_edges))) /* djb-rwth: addressing LLVM warning */
2464 : : {
2465 : 0 : goto exit_function;
2466 : : }
2467 : : }
2468 : : }
2469 : : /*---------------------------------------------------------------*/
2470 : : }
2471 : : /* replace all single bonds to neutral neighbors with zero-order bonds
2472 : : allow neighbor charge change to (-1) and metal atom charge increment +1 */
2473 [ # # ]: 0 : for (k = 0; k < at2[i].valence; k++)
2474 : : {
2475 : 0 : n = at2[i].neighbor[k];
2476 : 0 : pe = pBNS->edge + pBNS->vert[i].iedge[k];
2477 [ # # # # ]: 0 : if (at2[n].charge || at2[i].bond_type[k] != BOND_TYPE_SINGLE)
2478 : : {
2479 : 0 : continue;
2480 : : }
2481 : 0 : iePlusMetal = pVA[i].nCPlusGroupEdge - 1;
2482 : 0 : ieMinusO = pVA[n].nCMinusGroupEdge - 1;
2483 : :
2484 [ # # # # : 0 : if (pe->flow != 1 || pe->forbidden || iePlusMetal < 0)
# # ]
2485 : : {
2486 : 0 : continue;
2487 : : }
2488 : 0 : pePlusMetal = pBNS->edge + iePlusMetal;
2489 [ # # ]: 0 : if (pePlusMetal->flow <= 0)
2490 : : {
2491 : 0 : continue; /* to add (+) to metal this flow must be decremented */
2492 : : }
2493 [ # # ]: 0 : if (ieMinusO >= 0)
2494 : : {
2495 : : /* usually does not happen */
2496 : 0 : peMinusO = pBNS->edge + ieMinusO;
2497 : :
2498 [ # # # # : 0 : if (peMinusO->flow || pePlusMetal->forbidden || peMinusO->forbidden)
# # ]
2499 : : {
2500 : 0 : continue;
2501 : : }
2502 : :
2503 : : /* decrement bond order to 0 */
2504 : 0 : delta = 1;
2505 : 0 : pv1 = pBNS->vert + (v1 = pe->neighbor1);
2506 : 0 : pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
2507 : :
2508 : 0 : pe->flow -= delta;
2509 : 0 : pv1->st_edge.flow -= delta;
2510 : 0 : pv2->st_edge.flow -= delta;
2511 : 0 : pBNS->tot_st_flow -= 2 * delta;
2512 : :
2513 : 0 : SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask);
2514 : 0 : pePlusMetal->forbidden &= inv_forbidden_edge_mask;
2515 : 0 : peMinusO->forbidden &= inv_forbidden_edge_mask;
2516 : :
2517 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2518 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
2519 : :
2520 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) ||
# # ]
2521 [ # # # # ]: 0 : (vPathEnd == v2 && vPathStart == v1)) /*&& nDeltaCharge > 0*/) /* djb-rwth: addressing LLVM warnings */
2522 : : {
2523 : : /* (+)charge was just moved, no change in number of charges */
2524 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2525 [ # # ]: 0 : if (ret > 0)
2526 : : {
2527 : 0 : (*pnNumRunBNS)++;
2528 : 0 : cur_success++; /* 01 */
2529 : : }
2530 : : }
2531 : : else
2532 : : {
2533 : 0 : pe->flow += delta; /* roll back */
2534 : 0 : pv1->st_edge.flow += delta;
2535 : 0 : pv2->st_edge.flow += delta;
2536 : 0 : pBNS->tot_st_flow += 2 * delta;
2537 : : }
2538 : 0 : RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask);
2539 : : }
2540 : : else
2541 : : {
2542 [ # # ]: 0 : if (NO_VERTEX != (vPlusMinus = GetPlusMinusVertex(pBNS, pTCGroups, 1, 1)))
2543 : : {
2544 : : /* manually add (-) charge to O and (+) charge to metal */
2545 : : /* decrement bond order to 0 */
2546 : : /*---------------------------------------------------------------------------*/
2547 : : /* */
2548 : : /* (+/-)* (+/-) Result: */
2549 : : /* | || */
2550 : : /* | || - Added (+) to M */
2551 : : /* (+)super (+)super - Incremented bond M-O */
2552 : : /* || | */
2553 : : /* || => | To make this attachment H, */
2554 : : /* (Y) (Y) increment */
2555 : : /* | || pTCGroups->pTCG[itg].tg_num_H */
2556 : : /* | || */
2557 : : /* (+)metal (+)hetero Technical details: */
2558 : : /* \\ \ increase capacities of */
2559 : : /* M M(+) edges to (+/-) otherwise */
2560 : : /* | || flow may not be able to */
2561 : : /* -O* -O-O increase */
2562 : : /* */
2563 : : /* After that change M=O bond order from 2 to 0 */
2564 : : /*---------------------------------------------------------------------------*/
2565 : : int i1, j1, k1;
2566 : 0 : delta = 1;
2567 : 0 : pvO = pBNS->vert + n;
2568 : 0 : pvM = pBNS->vert + i;
2569 : : /* Increment st_edge.cap on (+/-) vertex */
2570 : 0 : pBNS->vert[vPlusMinus].st_edge.cap += delta;
2571 : : /* Increment st_edge.cap on O */
2572 : 0 : pvO->st_edge.cap += delta;
2573 : : /* increment cap on M-O edge */
2574 : 0 : pe->cap += delta;
2575 : : /* total cap count */
2576 : 0 : pBNS->tot_st_cap += 2 * delta;
2577 : :
2578 : 0 : v1 = vPlusMinus;
2579 : 0 : v2 = n; /* atom O */
2580 : :
2581 : : /* increase capacities of edges to Y */
2582 [ # # ]: 0 : for (i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1++)
2583 : : {
2584 : 0 : j1 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
2585 [ # # ]: 0 : for (k1 = 0; k1 < pBNS->vert[j1].num_adj_edges; k1++)
2586 : : {
2587 : 0 : pBNS->edge[pBNS->vert[j1].iedge[k1]].cap += delta;
2588 : : }
2589 : : }
2590 : 0 : SetForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask);
2591 : 0 : pePlusMetal->forbidden &= inv_forbidden_edge_mask;
2592 : 0 : pe->forbidden &= inv_forbidden_edge_mask;
2593 : :
2594 : 0 : ret = RunBnsTestOnce(pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
2595 : : &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms);
2596 : 0 : cur_success = 0;
2597 [ # # # # : 0 : if (ret == 1 && ((vPathEnd == v1 && vPathStart == v2) ||
# # ]
2598 [ # # # # ]: 0 : (vPathEnd == v2 && vPathStart == v1)) /*&& nDeltaCharge == 1*/) /* djb-rwth: addressing LLVM warnings */
2599 : : {
2600 : : /* Added (+)charge to -N< => nDeltaCharge == 1 */
2601 : : /* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
2602 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2603 [ # # ]: 0 : if (ret > 0)
2604 : : {
2605 : 0 : (*pnNumRunBNS)++;
2606 : 0 : cur_success++; /* 01 */
2607 : : }
2608 : : }
2609 [ # # ]: 0 : if (cur_success)
2610 : : {
2611 : : /* set bond M=O order = 0 */
2612 [ # # ]: 0 : if (pe->flow != 2 * delta)
2613 : : {
2614 : 0 : ret = RI_ERR_PROGR;
2615 : 0 : goto exit_function;
2616 : : }
2617 : : /* reduce pe bond order by 2*delta */
2618 : 0 : pe->flow -= 2 * delta;
2619 : 0 : pvO->st_edge.cap -= 2 * delta;
2620 : 0 : pvO->st_edge.flow -= 2 * delta;
2621 : 0 : pvM->st_edge.flow -= 2 * delta;
2622 : 0 : pvM->st_edge.cap -= 2 * delta;
2623 : 0 : pBNS->tot_st_cap -= 3 * delta;
2624 : 0 : pBNS->tot_st_flow -= 4 * delta;
2625 : : /* fix M-O bond order to zero */
2626 : 0 : pe->cap -= 2 * delta;
2627 : : /* add fixed (-) charge to O */
2628 : 0 : pVA[n].cInitCharge -= delta;
2629 : : }
2630 : : else
2631 : : {
2632 : : /* failed */
2633 : 0 : pBNS->vert[vPlusMinus].st_edge.cap -= delta;
2634 : 0 : pvO->st_edge.cap -= delta;
2635 : : /*pTCGroups->pTCG[itg].edges_cap -= delta;*/ /* ???bug??? - commented out 2006-03-22 */
2636 : 0 : pBNS->tot_st_cap -= 2 * delta;
2637 : : /* decrease capacities of edges to Y */
2638 [ # # ]: 0 : for (i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1++)
2639 : : {
2640 : 0 : j1 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
2641 [ # # ]: 0 : for (k1 = 0; k1 < pBNS->vert[j1].num_adj_edges; k1++)
2642 : : {
2643 : 0 : pBNS->edge[pBNS->vert[j1].iedge[k1]].cap -= delta;
2644 : : }
2645 : : }
2646 : : }
2647 : 0 : RemoveForbiddenEdgeMask(pBNS, &AllChargeEdges, forbidden_edge_mask);
2648 : : }
2649 : : }
2650 : : }
2651 : : }
2652 : : }
2653 : :
2654 : 0 : exit_function:
2655 : :
2656 : 0 : AllocEdgeList(&AllChargeEdges, EDGE_LIST_FREE);
2657 : :
2658 : 0 : return ret;
2659 : : }
2660 : :
2661 : :
2662 : : #if ( KEEP_METAL_EDGE_FLOW == 1 )
2663 : :
2664 : :
2665 : : /****************************************************************************/
2666 : : int ForbidMetalCarbonEdges(BN_STRUCT* pBNS,
2667 : : inp_ATOM* at,
2668 : : int num_at,
2669 : : VAL_AT* pVA,
2670 : : ALL_TC_GROUPS* pTCGroups,
2671 : : EDGE_LIST* pMetalCarbonEdges,
2672 : : int forbidden_edge_mask)
2673 : : {
2674 : :
2675 : : int i, j, neigh, nNumEdgeMetalCarbon = 0, pass = 0, ret = 0;
2676 : : BNS_VERTEX* pVert, * pNeigh;
2677 : : BNS_EDGE* pEdge;
2678 : :
2679 : : /* count carbon-metal edges */
2680 : :
2681 : : if (pTCGroups->num_metal_atoms)
2682 : : {
2683 : : fill_ForbiddenEdgesMetalCarbon:
2684 : : for (i = 0; i < num_at; i++)
2685 : : {
2686 : : if (pVA[i].cMetal && pVA[i].cNumBondsToMetal)
2687 : : {
2688 : : pVert = pBNS->vert + i;
2689 : : for (j = 0; j < pVert->num_adj_edges; j++)
2690 : : {
2691 : : pEdge = pBNS->edge + pVert->iedge[j];
2692 : : neigh = pEdge->neighbor12 ^ i;
2693 : : pNeigh = pBNS->vert + neigh;
2694 : : if (!IS_BNS_VT_ATOM(pNeigh->type))
2695 : : continue;
2696 : : if (at[neigh].endpoint)
2697 : : continue;
2698 : : if (pVA[neigh].cNumValenceElectrons == 4 && pVA[neigh].cPeriodicRowNumber == 1 &&
2699 : : pNeigh->st_edge.cap >= at[neigh].valence + 1)
2700 : : {
2701 : : if (pass)
2702 : : {
2703 : : if (ret = AddToEdgeList(pMetalCarbonEdges, pVert->iedge[j], 0))
2704 : : {
2705 : : goto exit_function;
2706 : : }
2707 : : pEdge->forbidden |= forbidden_edge_mask;
2708 : : }
2709 : : else
2710 : : {
2711 : : nNumEdgeMetalCarbon++;
2712 : : }
2713 : : }
2714 : : }
2715 : : }
2716 : : }
2717 : : if (!pass && nNumEdgeMetalCarbon)
2718 : : {
2719 : : if (ret = AllocEdgeList(pMetalCarbonEdges, nNumEdgeMetalCarbon))
2720 : : {
2721 : : goto exit_function;
2722 : : }
2723 : : pass++;
2724 : : goto fill_ForbiddenEdgesMetalCarbon;
2725 : : }
2726 : : }
2727 : :
2728 : : exit_function:
2729 : :
2730 : : return ret;
2731 : : }
2732 : :
2733 : :
2734 : : #endif
2735 : :
2736 : :
2737 : : /****************************************************************************
2738 : : Restore bonds & charges
2739 : : *****************************************************************************/
2740 : 0 : int RunBnsRestore1(CANON_GLOBALS* pCG,
2741 : : INCHI_CLOCK* ic,
2742 : : ICHICONST INPUT_PARMS* ip,
2743 : : STRUCT_DATA* sd,
2744 : : BN_STRUCT* pBNS,
2745 : : BN_DATA* pBD,
2746 : : StrFromINChI* pStruct,
2747 : : VAL_AT* pVA,
2748 : : ALL_TC_GROUPS* pTCGroups,
2749 : : INChI* pInChI[],
2750 : : long num_inp,
2751 : : int bHasSomeFixedH)
2752 : : {
2753 : 0 : int nNumRunBNS = 0;
2754 : :
2755 : : EDGE_LIST CarbonChargeEdges, MetalCarbonEdges, Nplus2BondsEdges;
2756 : :
2757 : 0 : int nTotalDelta = 0, ret = 0; /* djb-rwth: removing redundant variables */
2758 : 0 : inp_ATOM* at = pStruct->at;
2759 : 0 : inp_ATOM* at2 = NULL; /* restored structure */
2760 : 0 : inp_ATOM* at3 = NULL; /* structure for calculating one InChI */
2761 : 0 : int num_at = pStruct->num_atoms;
2762 : 0 : int num_deleted_H = pStruct->num_deleted_H;
2763 : : #ifdef _DEBUG
2764 : : int ret2;
2765 : : #endif
2766 : :
2767 : : #if ( KEEP_METAL_EDGE_FLOW == 1 )
2768 : : BNS_VERTEX* pVert, * pNeigh;
2769 : : int j, neigh;
2770 : : #endif
2771 : :
2772 : : /* Edge lists initialization */
2773 : 0 : AllocEdgeList(&CarbonChargeEdges, EDGE_LIST_CLEAR);
2774 : 0 : AllocEdgeList(&MetalCarbonEdges, EDGE_LIST_CLEAR);
2775 : 0 : AllocEdgeList(&Nplus2BondsEdges, EDGE_LIST_CLEAR);
2776 : :
2777 [ # # # # ]: 0 : if (pStruct->iMobileH == TAUT_NON &&
2778 : 0 : (ret = FillOutExtraFixedHDataInChI(pStruct, pInChI)))
2779 : : {
2780 : 0 : goto exit_function;
2781 : : }
2782 : :
2783 [ # # # # : 0 : if ((!at2 && !(at2 = (inp_ATOM*)inchi_malloc(((long long)num_at + (long long)num_deleted_H) * sizeof(at2[0])))) ||
# # ]
2784 [ # # ]: 0 : (!at3 && !(at3 = (inp_ATOM*)inchi_malloc(((long long)num_at + (long long)num_deleted_H) * sizeof(at3[0]))))) /* djb-rwth: cast operators added; addressing LLVM warning */
2785 : : {
2786 [ # # ]: 0 : inchi_free(at2);
2787 [ # # ]: 0 : inchi_free(at3);
2788 : 0 : return RI_ERR_ALLOC;
2789 : : }
2790 : :
2791 [ # # ]: 0 : if (0 > (ret = ForbidCarbonChargeEdges(pBNS, pTCGroups, &CarbonChargeEdges, BNS_EDGE_FORBIDDEN_TEMP)))
2792 : : {
2793 : 0 : goto exit_function;
2794 : : }
2795 : :
2796 : : #if ( KEEP_METAL_EDGE_FLOW == 1 )
2797 : : /* count edges of -C(IV)< carbons connected to metals */
2798 : : if (0 > (ret = ForbidMetalCarbonEdges(pBNS, at, num_at, pVA, pTCGroups, &MetalCarbonEdges, BNS_EDGE_FORBIDDEN_TEMP)))
2799 : : {
2800 : : goto exit_function;
2801 : : }
2802 : : #endif
2803 [ # # ]: 0 : if (0 > (ret = ForbidNintrogenPlus2BondsInSmallRings(pBNS, at, num_at, pVA, 6,
2804 : : pTCGroups, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP)))
2805 : : {
2806 : 0 : goto exit_function;
2807 : : }
2808 : :
2809 : : /*********** Run BNS #1: no charge on carbons and =N= ***************/
2810 [ # # ]: 0 : if (Nplus2BondsEdges.num_edges)
2811 : : {
2812 : : /* Run BNS leaving carbon charges unchanged */
2813 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2814 : 0 : nNumRunBNS++;
2815 [ # # ]: 0 : if (ret < 0)
2816 : : {
2817 : 0 : goto exit_function;
2818 : : }
2819 : : else
2820 : : {
2821 : 0 : nTotalDelta += ret;
2822 : : }
2823 : 0 : RemoveForbiddenEdgeMask(pBNS, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP);
2824 : 0 : AllocEdgeList(&Nplus2BondsEdges, EDGE_LIST_FREE);
2825 : : }
2826 : : #ifdef _DEBUG
2827 : : /* debug only */
2828 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2829 : : pStruct->at = at2;
2830 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2831 : : pStruct->at = at;
2832 : : #endif
2833 : : /*************************** extend min ring size to 8 ****************************/
2834 [ # # ]: 0 : if (0 > (ret = ForbidNintrogenPlus2BondsInSmallRings(pBNS, at, num_at, pVA, 8,
2835 : : pTCGroups, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP)))
2836 : : {
2837 : 0 : goto exit_function;
2838 : : }
2839 [ # # ]: 0 : if (Nplus2BondsEdges.num_edges)
2840 : : {
2841 : : /* Run BNS leaving carbon charges unchanged */
2842 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2843 : 0 : nNumRunBNS++;
2844 [ # # ]: 0 : if (ret < 0)
2845 : : {
2846 : 0 : goto exit_function;
2847 : : }
2848 : : else
2849 : : {
2850 : 0 : nTotalDelta += ret;
2851 : : }
2852 : 0 : RemoveForbiddenEdgeMask(pBNS, &Nplus2BondsEdges, BNS_EDGE_FORBIDDEN_TEMP);
2853 : 0 : AllocEdgeList(&Nplus2BondsEdges, EDGE_LIST_FREE);
2854 : : }
2855 : : #ifdef _DEBUG
2856 : : /* debug only */
2857 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2858 : : pStruct->at = at2;
2859 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2860 : : pStruct->at = at;
2861 : : #endif
2862 : : /*******************************************************************/
2863 [ # # ]: 0 : if (CarbonChargeEdges.num_edges > 0)
2864 : : {
2865 : : /* Run BNS leaving carbon charges unchanged */
2866 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2867 : 0 : nNumRunBNS++;
2868 [ # # ]: 0 : if (ret < 0)
2869 : : {
2870 : 0 : goto exit_function;
2871 : : }
2872 : : else
2873 : : {
2874 : 0 : nTotalDelta += ret;
2875 : : }
2876 : 0 : RemoveForbiddenEdgeMask(pBNS, &CarbonChargeEdges, BNS_EDGE_FORBIDDEN_TEMP);
2877 : 0 : AllocEdgeList(&CarbonChargeEdges, EDGE_LIST_FREE);
2878 : : }
2879 : : #ifdef _DEBUG
2880 : : /* debug only */
2881 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2882 : : pStruct->at = at2;
2883 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2884 : : pStruct->at = at;
2885 : : #endif
2886 : : /*******************************************************************/
2887 [ # # ]: 0 : if (MetalCarbonEdges.num_edges > 0)
2888 : : {
2889 : : /* Run BNS leaving carbon charges unchanged */
2890 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2891 : 0 : nNumRunBNS++;
2892 [ # # ]: 0 : if (ret < 0)
2893 : : {
2894 : 0 : goto exit_function;
2895 : : }
2896 : : else
2897 : : {
2898 : 0 : nTotalDelta += ret;
2899 : : }
2900 : 0 : RemoveForbiddenEdgeMask(pBNS, &MetalCarbonEdges, BNS_EDGE_FORBIDDEN_TEMP);
2901 : 0 : AllocEdgeList(&MetalCarbonEdges, EDGE_LIST_FREE);
2902 : : }
2903 : : /*******************************************************************/
2904 : : /* Run BNS allowing to change any charges */
2905 : 0 : ret = RunBnsRestoreOnce(pBNS, pBD, pVA, pTCGroups);
2906 : 0 : nNumRunBNS++;
2907 [ # # ]: 0 : if (ret < 0)
2908 : : {
2909 : 0 : goto exit_function;
2910 : : }
2911 : : else
2912 : : {
2913 : 0 : nTotalDelta += ret;
2914 : : }
2915 : : #ifdef _DEBUG
2916 : : /* debug only */
2917 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2918 : : pStruct->at = at2;
2919 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2920 : : pStruct->at = at;
2921 : : #endif
2922 : :
2923 : : #if ( BNS_RAD_SEARCH == 1 )
2924 : : /****************************************************************************/
2925 : : /* move unfulfilled 'radicals' from ChargeStruct to atoms */
2926 : : /* and set change charges of affected atoms to fit total charge */
2927 : 0 : ret = MoveRadToAtomsAddCharges(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups, BNS_EDGE_FORBIDDEN_TEMP);
2928 [ # # ]: 0 : if (ret < 0)
2929 : : {
2930 : 0 : goto exit_function;
2931 : : }
2932 : : #endif
2933 : : /**************************************************************/
2934 : : /**************************************************************/
2935 : : /***** fix restore inconsistencies *****/
2936 : : /**************************************************************/
2937 : : /**************************************************************/
2938 : : #ifdef _DEBUG
2939 : : /* debug only */
2940 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2941 : : pStruct->at = at2;
2942 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2943 : : pStruct->at = at;
2944 : : #endif
2945 : :
2946 : : /* rearrange (+) and (-) edges flow so that there is no (+)flow=0 and (-)flow=1 */
2947 : 0 : ret = RearrangePlusMinusEdgesFlow(pBNS, pBD, pVA, pTCGroups, BNS_EDGE_FORBIDDEN_TEMP);
2948 [ # # ]: 0 : if (ret < 0)
2949 : : {
2950 : 0 : goto exit_function;
2951 : : }
2952 : :
2953 : : /*****************************************************************/
2954 : : /* Increment zero order metal bonds to heteroatoms */
2955 : : /*****************************************************************/
2956 : 0 : ret = IncrementZeroOrderBondsToHeteroat(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
2957 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
2958 [ # # ]: 0 : if (ret < 0)
2959 : : {
2960 : 0 : goto exit_function;
2961 : : }
2962 : :
2963 : : #ifdef _DEBUG
2964 : : /* debug only */
2965 : : memcpy(at2, at, ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H) * sizeof(at2[0])); /* djb-rwth: cast operators added */
2966 : : pStruct->at = at2;
2967 : : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
2968 : : pStruct->at = at;
2969 : : #endif
2970 : :
2971 : : #if (MOVE_CHARGES_FROM_HETEREO_TO_METAL == 1 )
2972 : : /*****************************************************************/
2973 : : /* move charges from heteroatoms to metal atoms */
2974 : : /*****************************************************************/
2975 : : ret = MoveChargeFromHeteroatomsToMetals(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
2976 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
2977 : : if (ret < 0)
2978 : : {
2979 : : goto exit_function;
2980 : : }
2981 : : #endif
2982 : : /***********************************************************************
2983 : : NH2 NH2
2984 : : \ \
2985 : : C==S(+)- => C(+)-S- where NH2 are not tautomeric
2986 : : / /
2987 : : NH2 NH2
2988 : : ************************************************************************/
2989 : 0 : ret = MovePlusFromS2DiaminoCarbon(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
2990 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
2991 [ # # ]: 0 : if (ret < 0)
2992 : : {
2993 : 0 : goto exit_function;
2994 : : }
2995 : : /*****************************************************************/
2996 : : /* Avoid charge separation on heteroatoms */
2997 : : /*****************************************************************/
2998 : 0 : ret = EliminateChargeSeparationOnHeteroatoms(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
2999 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP, 0);
3000 [ # # ]: 0 : if (ret < 0)
3001 : : {
3002 : 0 : goto exit_function;
3003 : : }
3004 [ # # ]: 0 : if (ret)
3005 : : {
3006 : : /*charge separation remains; allow changes of stereobonds in a ring and try again */
3007 : 0 : ret = EliminateChargeSeparationOnHeteroatoms(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3008 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP,
3009 : : BNS_EDGE_FORBIDDEN_MASK);
3010 [ # # ]: 0 : if (ret < 0)
3011 : : {
3012 : 0 : goto exit_function;
3013 : : }
3014 : : }
3015 : : /*****************************************************************/
3016 : : /* convert N#N(+)-N= into N(-)=N(+)=N- */
3017 : : /*****************************************************************/
3018 : 0 : ret = RestoreNNNgroup(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3019 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3020 [ # # ]: 0 : if (ret < 0)
3021 : : {
3022 : 0 : goto exit_function;
3023 : : }
3024 : : /*****************************************************************/
3025 : : /* convert Metal(q)-N(-)-O(-) Metal(q-2)-N=O (local change) */
3026 : : /*****************************************************************/
3027 : 0 : ret = FixMetal_Nminus_Ominus(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3028 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3029 [ # # ]: 0 : if (ret < 0)
3030 : : {
3031 : 0 : goto exit_function;
3032 : : }
3033 : : /*****************************************************************/
3034 : : /* convert N(-)=C= into N#C- - */
3035 : : /*****************************************************************/
3036 : 0 : ret = RestoreCyanoGroup(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3037 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3038 [ # # ]: 0 : if (ret < 0)
3039 : : {
3040 : 0 : goto exit_function;
3041 : : }
3042 : : /*****************************************************************/
3043 : : /* convert C(+)#N(+)- into C(-)#N(+)- */
3044 : : /*****************************************************************/
3045 : 0 : ret = RestoreIsoCyanoGroup(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3046 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3047 [ # # ]: 0 : if (ret < 0)
3048 : : {
3049 : 0 : goto exit_function;
3050 : : }
3051 : : /*****************************************************************/
3052 : : /* eliminate =N(V)= if possible */
3053 : : /* | */
3054 : : /*****************************************************************/
3055 : 0 : ret = EliminateNitrogen5Val3Bonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3056 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3057 [ # # ]: 0 : if (ret < 0)
3058 : : {
3059 : 0 : goto exit_function;
3060 : : }
3061 : :
3062 : : /*****************************************************************/
3063 : : /* | | */
3064 : : /* convert -S- to =S= if possible */
3065 : : /* | | */
3066 : : /*****************************************************************/
3067 : 0 : ret = Convert_SIV_to_SVI(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3068 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3069 [ # # ]: 0 : if (ret < 0)
3070 : : {
3071 : 0 : goto exit_function;
3072 : : }
3073 : :
3074 : : /*****************************************************************/
3075 : : /* =N(+)=O =N-O(-) */
3076 : : /* convert => if possible */
3077 : : /* Metal(q) Metal(q+2) */
3078 : : /*****************************************************************/
3079 : 0 : ret = PlusFromDB_N_DB_O_to_Metal(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3080 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3081 [ # # ]: 0 : if (ret < 0)
3082 : : {
3083 : 0 : goto exit_function;
3084 : : }
3085 : :
3086 : : /*****************************************************************/
3087 : : /* forbidden edges prevents required in InChI tautomerism */
3088 : : /* incorrectly restored mobile H mix separate tautomeric groups */
3089 : : /* because an edge may not become forbidden */
3090 : : /* note: removes this 'forbidden_edge' bit from ALL edges */
3091 : : /*****************************************************************/
3092 : 0 : ret = MoveMobileHToAvoidFixedBonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3093 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3094 : :
3095 [ # # ]: 0 : if (ret < 0)
3096 : : {
3097 : 0 : goto exit_function;
3098 : : }
3099 : : /**************************************************************************/
3100 : : /* 2. Mobile H endpoint has radical on it (typical for wrong P(VI)(=O)3OH */
3101 : : /* djb-rwth: removing redundant code */
3102 [ # # ]: 0 : if (pStruct->iMobileH == TAUT_NON)
3103 : : {
3104 : 0 : ret = RemoveRadFromMobileHEndpointFixH(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3105 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3106 : : }
3107 : : else
3108 : : {
3109 : 0 : ret = RemoveRadFromMobileHEndpoint(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3110 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3111 : : }
3112 [ # # ]: 0 : if (ret < 0)
3113 : : {
3114 : 0 : goto exit_function;
3115 : : }
3116 : : /* djb-rwth: removing redundant code */
3117 : : /**************************************************************/
3118 : : /* make bonds between a charged heteroatom and a metal single */
3119 : 0 : ret = MakeSingleBondsMetal2ChargedHeteroat(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3120 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3121 [ # # ]: 0 : if (ret < 0)
3122 : : {
3123 : 0 : goto exit_function;
3124 : : }
3125 : : /**************************************************************/
3126 : : /* move (+) charges to >N- and other centerpoints */
3127 : 0 : ret = MoveChargeToMakeCenerpoints(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3128 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3129 [ # # ]: 0 : if (ret < 0)
3130 : : {
3131 : 0 : goto exit_function;
3132 : : }
3133 : :
3134 : : /**************************************************************************/
3135 : : /* Find and eliminate false Mobile-H groups: Cl(=O)3(-O(-)) => Cl(-)(=O)4 */
3136 : 0 : ret = MoveChargeToRemoveCenerpoints(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3137 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3138 [ # # ]: 0 : if (ret < 0)
3139 : : {
3140 : 0 : goto exit_function;
3141 : : }
3142 : : /**************************************************************************/
3143 : : /* Find A=X< where all bonds to X except A=X are marked as stereogenic */
3144 : : /* make bonds A=X single */
3145 : 0 : ret = CheckAndRefixStereobonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3146 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3147 [ # # ]: 0 : if (ret < 0)
3148 : : {
3149 : 0 : goto exit_function;
3150 : : }
3151 : : /**************************************************************************/
3152 : : /* In Reconnected structure change 'salt bonds' to 'coordination bonds */
3153 : : /* for example, M-O-C= -> M(+)-O(-)-C= */
3154 : : /* Defect: instead of NH2-C=O(+)-M it will restore NH2(+)=C-O(-)-M(+) */
3155 : : /* However, in this release metal-organic compounds do not get much care */
3156 : 0 : ret = SaltBondsToCoordBonds(pBNS, pBD, pStruct, at, at2, pVA, pTCGroups,
3157 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP);
3158 [ # # ]: 0 : if (ret < 0)
3159 : : {
3160 : 0 : goto exit_function;
3161 : : }
3162 : : /**************************************************************************/
3163 : : /* Normalize the structure and compare t-groups and stereobonds */
3164 : 0 : ret = NormalizeAndCompare(pCG, ic, ip, sd, pBNS, pBD, pStruct, at, at2, at3, pVA, pTCGroups, pInChI, num_inp, bHasSomeFixedH,
3165 : : &nNumRunBNS, &nTotalDelta, BNS_EDGE_FORBIDDEN_TEMP, BNS_EDGE_FORBIDDEN_MASK);
3166 [ # # ]: 0 : if (ret < 0)
3167 : : {
3168 : 0 : goto exit_function;
3169 : : }
3170 : : /**************************************************************************/
3171 : : /* Create InChI out of the restored structure */
3172 : :
3173 : :
3174 : : /*ret = nTotalDelta;*/
3175 : :
3176 : 0 : exit_function:
3177 : :
3178 : 0 : pStruct->at = at;
3179 : 0 : pStruct->at2 = at2;
3180 : 0 : at2 = NULL;
3181 : 0 : AllocEdgeList(&CarbonChargeEdges, EDGE_LIST_FREE);
3182 : 0 : AllocEdgeList(&MetalCarbonEdges, EDGE_LIST_FREE);
3183 : 0 : AllocEdgeList(&Nplus2BondsEdges, EDGE_LIST_FREE);
3184 [ # # ]: 0 : if (at2)
3185 : : {
3186 [ # # ]: 0 : inchi_free(at2);
3187 : : }
3188 [ # # ]: 0 : if (at3)
3189 : : {
3190 [ # # ]: 0 : inchi_free(at3);
3191 : : }
3192 : :
3193 : 0 : return ret;
3194 : : }
3195 : :
3196 : :
3197 : : /****************************************************************************/
3198 : 0 : int RestoreAtomMakeBNS(INCHI_CLOCK* ic, CANON_GLOBALS* pCG,
3199 : : ICHICONST INPUT_PARMS* ip,
3200 : : STRUCT_DATA* sd,
3201 : : StrFromINChI* pStruct,
3202 : : int iComponent,
3203 : : int iAtNoOffset,
3204 : : INChI* pInChI[],
3205 : : const char* szCurHdr,
3206 : : long num_inp,
3207 : : int bHasSomeFixedH)
3208 : : {
3209 : 0 : int i, j, ret = 0, ret2;
3210 : : /*int nDelta, nTotalDelta;*/
3211 : 0 : VAL_AT* pVA = NULL;
3212 : : VAL_AT va1;
3213 : 0 : int num_at = pStruct->num_atoms;
3214 : 0 : inp_ATOM* at = pStruct->at;
3215 : : ALL_TC_GROUPS TCGroups;
3216 : 0 : ALL_TC_GROUPS* pTCGroups = &TCGroups;
3217 : 0 : int nAddEdges2eachAtom = 2, nAddVertices = 0;
3218 : :
3219 : : BFS_Q bfsq;
3220 : :
3221 : : /* BNS creation */
3222 : 0 : BN_STRUCT* pBNS = NULL;
3223 : 0 : BN_DATA* pBD = NULL;
3224 : 0 : int nNum_changed_bonds = 0;
3225 : 0 : int bTreatMoreAtomsAsMetals = 0, bSecondPassNewMetals = 0;
3226 : 0 : int nMaxAddAtoms = 2, nMaxAddEdges = 2, max_altp = BN_MAX_ALTP;
3227 : :
3228 : 0 : memset(pTCGroups, 0, sizeof(pTCGroups[0])); /* djb-rwth: memset_s C11/Annex K variant? */
3229 [ # # ]: 0 : for (i = 0; i < NUM_TCGROUP_TYPES; i++)
3230 : : {
3231 : 0 : pTCGroups->nGroup[i] = TCG_None; /* unassigned */
3232 : : }
3233 : 0 : pTCGroups->iComponent = iComponent;
3234 : 0 : pTCGroups->iAtNoOffset = iAtNoOffset;
3235 : :
3236 [ # # ]: 0 : if (num_at == 1)
3237 : : {
3238 : : /* single atom -- no bonds to restore */
3239 : 0 : inp_ATOM* at2 = (inp_ATOM*)inchi_malloc(sizeof(at2[0]) * ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H)); /* djb-rwth: cast operators added */
3240 : 0 : inp_ATOM* at3 = (inp_ATOM*)inchi_malloc(sizeof(at3[0]) * ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H)); /* djb-rwth: cast operators added */
3241 : 0 : pStruct->at2 = at2;
3242 : 0 : at[0].charge = pInChI[0]->nTotalCharge;
3243 [ # # ]: 0 : if (at2)
3244 : : {
3245 : 0 : memcpy(at2, at, sizeof(at2[0]) * ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H)); /* djb-rwth: cast operators added */
3246 : : }
3247 [ # # # # ]: 0 : if (!at2 || !at3)
3248 : : {
3249 [ # # # # ]: 0 : if (at3) inchi_free(at3);
3250 : 0 : return RI_ERR_ALLOC;
3251 : : }
3252 : 0 : ret = MakeOneInChIOutOfStrFromINChI(pCG, ic, ip, sd, pStruct, pStruct->at2, at3, pTCGroups);
3253 : : /* clean up */
3254 [ # # ]: 0 : for (i = 0; i < TAUT_NUM; i++)
3255 : : {
3256 : 0 : Free_INChI(&pStruct->pOneINChI[i]);
3257 : 0 : Free_INChI_Aux(&pStruct->pOneINChI_Aux[i]);
3258 : 0 : FreeInpAtomData(pStruct->pOne_norm_data[i]);
3259 [ # # ]: 0 : if (pStruct->pOne_norm_data[i])
3260 : : {
3261 [ # # ]: 0 : inchi_free(pStruct->pOne_norm_data[i]);
3262 : 0 : pStruct->pOne_norm_data[i] = NULL;
3263 : : }
3264 : : }
3265 : : /* djb-rwth: fixing oss-fuzz issue #69602 */
3266 : : /* free_t_group_info(&pStruct->One_ti); */
3267 [ # # ]: 0 : inchi_free(at3);
3268 : :
3269 : 0 : return ret;
3270 : : }
3271 : :
3272 : 0 : AllocBfsQueue(&bfsq, BFS_Q_CLEAR, 0);
3273 [ # # ]: 0 : if (!(pVA = (VAL_AT*)inchi_calloc(num_at, sizeof(pVA[0]))))
3274 : : {
3275 : 0 : ret = RI_ERR_ALLOC;
3276 : 0 : goto exit_function;
3277 : : }
3278 : 0 : pStruct->pVA = pVA;
3279 : 0 : memset(&va1, 0, sizeof(va1)); /* djb-rwth: memset_s C11/Annex K variant? */
3280 : 0 : pTCGroups->total_charge = pInChI[0]->nTotalCharge;
3281 [ # # ]: 0 : if (0 > (ret = AllocBfsQueue(&bfsq, num_at, 0 /* min ring size undefined */)))
3282 : : {
3283 : 0 : goto exit_function;
3284 : : }
3285 : 0 : pStruct->pbfsq = &bfsq;
3286 : :
3287 [ # # # # : 0 : if (pStruct->iMobileH == TAUT_NON && pInChI[1] && pInChI[1]->nNumberOfAtoms > 1 &&
# # # # ]
3288 : 0 : (ret = FillOutpStructEndpointFromInChI(pInChI[1], &pStruct->endpoint)))
3289 : : {
3290 : 0 : goto exit_function;
3291 : : }
3292 : :
3293 : : /* mark metal atoms; find min ring sizes for atoms that have 2 bonds */
3294 [ # # ]: 0 : for (i = 0; i < num_at; i++)
3295 : : {
3296 : 0 : pVA[i].cNumValenceElectrons = get_sp_element_type(at[i].el_number, &j);
3297 : 0 : pVA[i].cPeriodicRowNumber = j;
3298 : 0 : pVA[i].cPeriodicNumber = at[i].el_number;
3299 : 0 : pVA[i].cNumValenceElectrons--; /* = -1 d- and f- metals, 0 for H, 1 for Na, 2 for Mg,.. = (ATYPE_Xx-1) */
3300 : :
3301 [ # # ]: 0 : if (is_el_a_metal(at[i].el_number))
3302 : : {
3303 [ # # ]: 0 : if (pStruct->pSrm->bStereoRemovesMetalFlag)
3304 : : {
3305 : : /* treat metal as non-metal if it is stereogenic or has a stereobond */
3306 [ # # # # ]: 0 : pVA[i].cMetal = !(at[i].p_parity || at[i].sb_parity[0]);
3307 : : }
3308 : : else
3309 : : {
3310 : 0 : pVA[i].cMetal = 1;
3311 : : }
3312 : : }
3313 [ # # # # ]: 0 : if (at[i].valence == 2 && !at[i].num_H)
3314 : : {
3315 : 0 : pVA[i].cMinRingSize = is_bond_in_Nmax_memb_ring(at, i, 0, bfsq.q, bfsq.nAtomLevel,
3316 : : bfsq.cSource, 99 /* max ring size */);
3317 : : }
3318 : : else
3319 : : {
3320 : 0 : pVA[i].cMinRingSize = 0;
3321 : : }
3322 : : }
3323 : : /* AllocBfsQueue( &bfsq, BFS_Q_FREE, 0 ); */
3324 : :
3325 : 0 : repeat_for_new_metals:
3326 : : /* set valences for the first time; find ChargeValence structures for each atom */
3327 [ # # ]: 0 : for (i = 0; i < num_at; i++)
3328 : : {
3329 : : /* get additional fictitious atoms information */
3330 : 0 : pVA[i].cInitFreeValences = 0;
3331 : :
3332 : 0 : ret = GetAtomRestoreInfo(pCG, at, i, pVA, pStruct->pSrm, pStruct->bMobileH, pStruct->endpoint);
3333 : :
3334 [ # # ]: 0 : if (ret < 0)
3335 : : {
3336 : 0 : goto exit_function;
3337 : : }
3338 [ # # # # : 0 : if (ret == TREAT_ATOM_AS_METAL && !bSecondPassNewMetals && !pVA[i].cMetal)
# # ]
3339 : : {
3340 [ # # ]: 0 : if (pStruct->pSrm->bStereoRemovesMetalFlag)
3341 : : {
3342 : : /* treat metal as non-metal if it is stereogenic or has a stereobond */
3343 [ # # # # ]: 0 : pVA[i].cMetal = !(at[i].p_parity || at[i].sb_parity[0]);
3344 : : }
3345 : : else
3346 : : {
3347 : 0 : pVA[i].cMetal = 1;
3348 : : }
3349 [ # # ]: 0 : if (pVA[i].cMetal)
3350 : : {
3351 : 0 : bTreatMoreAtomsAsMetals++;
3352 : : }
3353 : : }
3354 : 0 : pTCGroups->charge_on_atoms += pVA[i].cInitCharge;
3355 : : }
3356 [ # # # # ]: 0 : if (bTreatMoreAtomsAsMetals && !bSecondPassNewMetals)
3357 : : {
3358 [ # # ]: 0 : for (i = 0; i < num_at; i++)
3359 : : {
3360 : : /* clear all members of pVA[i] except two */
3361 : 0 : pTCGroups->charge_on_atoms -= pVA[i].cInitCharge;
3362 : 0 : va1.cMetal = pVA[i].cMetal;
3363 : 0 : va1.cMinRingSize = pVA[i].cMinRingSize;
3364 : 0 : va1.cNumValenceElectrons = pVA[i].cNumValenceElectrons;
3365 : 0 : va1.cPeriodicRowNumber = pVA[i].cPeriodicRowNumber;
3366 : 0 : va1.cPeriodicNumber = pVA[i].cPeriodicNumber;
3367 : 0 : pVA[i] = va1;
3368 : : }
3369 : 0 : bSecondPassNewMetals = 1;
3370 : 0 : goto repeat_for_new_metals;
3371 : : }
3372 : :
3373 : : /* count atoms, bonds, additional edges and vertices in ChargeValence structures and t-groups */
3374 : 0 : ret = nCountBnsSizes(at, num_at, nAddEdges2eachAtom, nAddVertices, &pStruct->ti,
3375 : : pVA, pStruct->pSrm, pTCGroups);
3376 [ # # ]: 0 : if (ret < 0)
3377 : : {
3378 : 0 : goto exit_function;
3379 : : }
3380 : :
3381 : : /* find and count groups; add counts of all other vertices to be created */
3382 : 0 : ret = nAddSuperCGroups(pTCGroups);
3383 [ # # ]: 0 : if (ret < 0)
3384 : : {
3385 : 0 : goto exit_function;
3386 : : }
3387 : :
3388 : : /* create the BNS and fill it with all real atoms */
3389 : 0 : pBNS = AllocateAndInitTCGBnStruct(pStruct, pVA, pTCGroups,
3390 : : nMaxAddAtoms, nMaxAddEdges, max_altp, &nNum_changed_bonds);
3391 [ # # ]: 0 : if (!pBNS)
3392 : : {
3393 : 0 : ret = BNS_OUT_OF_RAM;
3394 : 0 : goto exit_function;
3395 : : }
3396 : : /* add t-groups to the BNS */
3397 : 0 : ret = AddTGroups2TCGBnStruct(pBNS, pStruct, pVA, pTCGroups, nMaxAddEdges);
3398 [ # # ]: 0 : if (ret < 0)
3399 : : {
3400 : 0 : goto exit_function;
3401 : : }
3402 : :
3403 : : /* add c-groups to the BNS; adjust charges */
3404 : 0 : ret = AddCGroups2TCGBnStruct(pBNS, pStruct, pVA, pTCGroups, nMaxAddEdges);
3405 [ # # ]: 0 : if (ret < 0)
3406 : : {
3407 : 0 : goto exit_function;
3408 : : }
3409 : :
3410 : 0 : pBNS->ulTimeOutTime = NULL; /* v. 1.05 */
3411 : 0 : pBNS->ic = ic; /* v. 1.05 */
3412 : :
3413 : : /* allocate BNData */
3414 : 0 : pBD = AllocateAndInitBnData(pBNS->max_vertices + pBNS->max_vertices / 2);
3415 [ # # ]: 0 : if (!pBD)
3416 : : {
3417 : 0 : ret = BNS_OUT_OF_RAM;
3418 : 0 : goto exit_function;
3419 : : }
3420 : 0 : CheckBnsConsistency(pStruct, pBNS, pVA, pTCGroups, 0);
3421 : :
3422 : : /* restore bonds & charges */
3423 : 0 : ret = RunBnsRestore1(pCG, ic, ip, sd, pBNS, pBD, pStruct, pVA, pTCGroups, pInChI, num_inp, bHasSomeFixedH);
3424 [ # # ]: 0 : if (ret < 0)
3425 : : {
3426 : 0 : goto exit_function;
3427 : : }
3428 : :
3429 : 0 : ret = CheckBnsConsistency(pStruct, pBNS, pVA, pTCGroups, 1);
3430 : : #if ( bRELEASE_VERSION == 0 )
3431 : : #ifndef TARGET_API_LIB
3432 : : if (ret)
3433 : : {
3434 : : fprintf(stdout, "Msg for: %ld %s comp=%d %c%c\n", num_inp, (szCurHdr && szCurHdr[0]) ? szCurHdr : "", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F');
3435 : : }
3436 : : if (pStruct->iMobileH == TAUT_YES && pStruct->nNumRemovedProtons)
3437 : : {
3438 : : fprintf(stdout, "REMOVED_PROTONS%+d %ld %s\n", pStruct->nNumRemovedProtons, num_inp, (szCurHdr && szCurHdr[0]) ? szCurHdr : "");
3439 : : /*pStruct->bExtract |= EXTRACT_STRUCT_NUMBER;*/
3440 : : }
3441 : : if (pStruct->bExtract & EXTRACT_STRUCT_NUMBER)
3442 : : {
3443 : : fprintf(stdout, "EXTRACT: %ld: %s\n", num_inp, (szCurHdr && szCurHdr[0]) ? szCurHdr : "");
3444 : : }
3445 : : #endif
3446 : : #endif
3447 : : { /* create the final structure in pStruct->at2 */
3448 : 0 : inp_ATOM* at_tmp = pStruct->at;
3449 : 0 : pStruct->at = pStruct->at2;
3450 : 0 : memcpy(pStruct->at, at_tmp, sizeof(pStruct->at[0]) * ((long long)pStruct->num_atoms + (long long)pStruct->num_deleted_H)); /* djb-rwth: cast operators added */
3451 : 0 : ret2 = CopyBnsToAtom(pStruct, pBNS, pVA, pTCGroups, 1);
3452 : 0 : pStruct->at2 = pStruct->at;
3453 : 0 : pStruct->at = at_tmp;
3454 [ # # ]: 0 : if (ret2 < 0)
3455 : : {
3456 : 0 : ret = ret2;
3457 : : }
3458 : : }
3459 : :
3460 : 0 : exit_function:
3461 : :
3462 : 0 : pStruct->pbfsq = NULL;
3463 : 0 : AllocBfsQueue(&bfsq, BFS_Q_FREE, 0);
3464 : :
3465 : 0 : pBD = DeAllocateBnData(pBD); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3466 : 0 : pBNS = DeAllocateBnStruct(pBNS); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3467 : : /*
3468 : : if ( pVA ) inchi_free( pVA );
3469 : : */
3470 [ # # # # ]: 0 : if (pTCGroups->pTCG) inchi_free(pTCGroups->pTCG);
3471 : :
3472 : 0 : return ret;
3473 : : }
3474 : :
3475 : :
3476 : : /****************************************************************************/
3477 : 0 : int OneInChI2Atom(INCHI_CLOCK* ic,
3478 : : CANON_GLOBALS* pCG,
3479 : : ICHICONST INPUT_PARMS* ip_inp,
3480 : : STRUCT_DATA* sd,
3481 : : const char* szCurHdr,
3482 : : long num_inp,
3483 : : StrFromINChI* pStruct,
3484 : : int iComponent,
3485 : : int iAtNoOffset,
3486 : : int bHasSomeFixedH,
3487 : : INChI* pInChI[])
3488 : : {
3489 : : int ret;
3490 : : INPUT_PARMS* ip, ip_loc;
3491 : :
3492 : 0 : ip_loc = *ip_inp;
3493 : 0 : ip = &ip_loc;
3494 : :
3495 : 0 : sd->pStrErrStruct[0] = '\0';
3496 : 0 : ret = RestoreAtomConnectionsSetStereo(pStruct, iComponent, iAtNoOffset, pInChI[0], pInChI[1]);
3497 [ # # ]: 0 : if (ret < 0)
3498 : : {
3499 : 0 : goto exit_function;
3500 : : }
3501 : 0 : ret = SetStereoBondTypesFrom0DStereo(pStruct, pInChI[0]);
3502 [ # # ]: 0 : if (ret < 0)
3503 : : {
3504 : 0 : goto exit_function;
3505 : : }
3506 : 0 : ret = ReconcileAllCmlBondParities(pStruct->at, pStruct->num_atoms, 0);
3507 [ # # ]: 0 : if (ret < 0)
3508 : : {
3509 : 0 : goto exit_function;
3510 : : }
3511 : :
3512 : : /* main InChI restore function */
3513 : 0 : ret = RestoreAtomMakeBNS(ic, pCG, ip, sd, pStruct, iComponent, iAtNoOffset, pInChI, szCurHdr, num_inp, bHasSomeFixedH);
3514 : :
3515 : : #ifndef COMPILE_ANSI_ONLY
3516 : : if ((pStruct->num_inp_actual > 0 ? pStruct->num_inp_actual : num_inp) >= ip->first_struct_number &&
3517 : : ((/*ret > 0 &&*/ ip->bDisplayIfRestoreWarnings) && pStruct->pXYZ))
3518 : : {
3519 : : inchiTime ulTStart;
3520 : : InchiTimeGet(&ulTStart);
3521 : : DisplayRestoredComponent(pCG, pStruct, iComponent, iAtNoOffset, pInChI[0], szCurHdr);
3522 : : sd->ulStructTime -= InchiTimeElapsed(ic, &ulTStart); /* subtract display time */
3523 : : }
3524 : : #endif
3525 : :
3526 [ # # ]: 0 : if (ret < 0)
3527 : : {
3528 : 0 : goto exit_function;
3529 : : }
3530 [ # # # # : 0 : if ((pStruct->num_inp_actual ? pStruct->num_inp_actual : num_inp) >= ip->first_struct_number && ret >= 0)
# # ]
3531 : : {
3532 : : /* remove t-group markings and increment zero-order bonds,
3533 : : otherwise MakeInChIOutOfStrFromINChI2() woild fail */
3534 : : /* --- moved to MakeInChIOutOfStrFromINChI2 ---
3535 : : IncrZeroBondsAndClearEndpts(pStruct->at2, pStruct->num_atoms, iComponent+1);
3536 : : CopySt2At( pStruct->at2, pStruct->st, pStruct->num_atoms );
3537 : : */
3538 : : /* include all restored structure features in pStruct->at2 */
3539 : : /* make full InChI out of pStruct->at2, pStruct->num_atoms */
3540 : : /***************************************************************************************/
3541 : : /* !!! pStruct->One_InChI etc. were removed at the exit from NormalizeAndCompare() !!! */
3542 : : /***************************************************************************************/
3543 [ # # # # : 0 : if (bHasSomeFixedH && pStruct->iInchiRec == INCHI_REC && pStruct->iMobileH == TAUT_YES &&
# # ]
3544 [ # # # # ]: 0 : !pStruct->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC))
3545 : : {
3546 : : /* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
3547 : 0 : ip->nMode |= REQ_MODE_BASIC;
3548 : : }
3549 : :
3550 : 0 : ret = MakeInChIOutOfStrFromINChI2(ic, pCG, ip, sd, pStruct, iComponent, iAtNoOffset, num_inp);
3551 : :
3552 : : if (ret >= 0)
3553 : : {
3554 : : ;
3555 : : }
3556 : : #if ( bRELEASE_VERSION == 0 )
3557 : : #ifndef TARGET_API_LIB
3558 : : else
3559 : : {
3560 : : fprintf(stdout, "\nERROR in MakeInChI-1: %ld %s Comp:%d %c%c Err:%d\n", num_inp,
3561 : : szCurHdr ? szCurHdr : "???", iComponent, pStruct->iInchiRec ? 'R' : 'D', pStruct->iMobileH ? 'M' : 'F', ret);
3562 : : }
3563 : : #endif
3564 : : #endif
3565 : : }
3566 : :
3567 : 0 : exit_function:
3568 : :
3569 : 0 : return ret;
3570 : : }
3571 : :
3572 : :
3573 : : /****************************************************************************/
3574 : 0 : int MakeProtonComponent(StrFromINChI* pStruct, int iComponent, int num_prot)
3575 : : {
3576 : 0 : inp_ATOM* at = NULL;
3577 : : int i;
3578 : :
3579 [ # # ]: 0 : if (num_prot <= 0)
3580 : : {
3581 : 0 : return 0;
3582 : : }
3583 : : /* allocate */
3584 : 0 : pStruct->at = (inp_ATOM*)inchi_calloc(num_prot, sizeof(pStruct->at[0]));
3585 : 0 : pStruct->at2 = (inp_ATOM*)inchi_calloc(num_prot, sizeof(pStruct->at2[0]));
3586 [ # # # # ]: 0 : if (!pStruct->at || !pStruct->at2)
3587 : : {
3588 : 0 : return 0;
3589 : : }
3590 : : /* create protons */
3591 : 0 : at = pStruct->at;
3592 : : /* fill out proton atom info */
3593 [ # # ]: 0 : for (i = 0; i < num_prot; i++)
3594 : : {
3595 : 0 : strcpy(at[i].elname, "H");
3596 : 0 : at[i].el_number = EL_NUMBER_H;
3597 : 0 : at[i].orig_at_number = i + 1;
3598 : : /*
3599 : : at[i].orig_compt_at_numb = i + 1;
3600 : : at[i].component = i + 1;
3601 : : */
3602 : 0 : at[i].charge = 1;
3603 : : }
3604 : 0 : memcpy(pStruct->at2, at, num_prot * sizeof(pStruct->at2[0]));
3605 : 0 : pStruct->bDeleted = 0;
3606 : 0 : pStruct->num_atoms = num_prot;
3607 : 0 : pStruct->bMobileH = TAUT_YES;
3608 : 0 : pStruct->iMobileH = TAUT_YES;
3609 : :
3610 : 0 : return num_prot;
3611 : : }
3612 : :
3613 : :
3614 : : /****************************************************************************/
3615 : 0 : int AddRemProtonsInRestrStruct(INCHI_CLOCK* ic,
3616 : : CANON_GLOBALS* pCG,
3617 : : ICHICONST INPUT_PARMS* ip_inp,
3618 : : STRUCT_DATA* sd, long num_inp,
3619 : : int bHasSomeFixedH,
3620 : : StrFromINChI* pStruct,
3621 : : int num_components,
3622 : : StrFromINChI* pStructR,
3623 : : int num_componentsR,
3624 : : NUM_H* nProtonsToBeRemovedByNormFromRevrs,
3625 : : int* recmet_change_balance)
3626 : : {
3627 : : /* on entry and exit, all at[i].num_H do not include isotopic H and explicit terminal H are connected */
3628 : 0 : int iComp, q, ret = 0;
3629 : : int num_atoms, num_deleted_H, num_tg, num_changed, num_deleted_components; /* djb-rwth: removing redundant variables */
3630 : : inp_ATOM* at;
3631 : : INPUT_PARMS* ip, ip_loc;
3632 : 0 : int num_prot = *nProtonsToBeRemovedByNormFromRevrs;
3633 : 0 : int delta_recmet_prot, num_prot_prev, bAccumulateChanges = 0, nNumProtAddedByRevrs;
3634 : : INChI_Aux* pINChI_Aux;
3635 : : INCHI_MODE bNormalizationFlags;
3636 : : int nChargeRevrs, nChargeInChI;
3637 : :
3638 [ # # ]: 0 : if (!num_prot)
3639 : : {
3640 : 0 : return 0;
3641 : : }
3642 : 0 : delta_recmet_prot = 0;
3643 : 0 : num_changed = 0;
3644 : 0 : num_deleted_components = 0;
3645 : 0 : ip_loc = *ip_inp;
3646 : 0 : ip = &ip_loc;
3647 : : /*----------------------------------------------------------------------------------
3648 : : nLink < 0 && num_componentsR > 0 => This is a Disconnected structure component; it is
3649 : : same as already processed reconnected one
3650 : : Do no preicess it
3651 : :
3652 : : nLink > 0 && num_componentsR > 0 => This is a Disconnected structure component;
3653 : : (should not happen) It it is a result of (nLink-1)th Reconeected
3654 : : component disconnection (NOT IMPLEMENTED YET)
3655 : :
3656 : : nLink = 0 => Process this component. It is either a reconnected
3657 : : component, or a result of a disconnection (for now)
3658 : :
3659 : : nLink > 0 && num_componentsR = 0 => This is a Reconnected component that is same as
3660 : : a disconnected one that will not be processed.
3661 : : Process and save charge delta.
3662 : : -----------------------------------------------------------------------------------*/
3663 : :
3664 [ # # # # ]: 0 : for (iComp = 0; iComp < num_components && num_prot; iComp++)
3665 : : {
3666 : 0 : bAccumulateChanges = 0;
3667 [ # # # # ]: 0 : if (pStruct[iComp].nLink < 0 && num_componentsR > 0)
3668 : : {
3669 : : /* check */
3670 : 0 : q = -(pStruct[iComp].nLink + 1);
3671 [ # # # # : 0 : if (!pStructR || !num_componentsR || q >= num_componentsR || pStructR[q].nLink != (iComp + 1))
# # # # ]
3672 : : {
3673 : 0 : ret = RI_ERR_PROGR;
3674 : 0 : goto exit_function;
3675 : : }
3676 : 0 : continue; /* Disconnected structure component has already been processed as a Reconnected one */
3677 : : }
3678 : :
3679 : 0 : at = pStruct[iComp].at2;
3680 : 0 : num_atoms = pStruct[iComp].num_atoms;
3681 : 0 : num_deleted_H = pStruct[iComp].num_deleted_H; /* djb-rwth: removing redundant code */
3682 [ # # # # ]: 0 : bAccumulateChanges = (pStruct[iComp].nLink > 0 && !num_componentsR);
3683 : 0 : nChargeRevrs = pStruct[iComp].nChargeRevrs;
3684 : 0 : nChargeInChI = pStruct[iComp].nChargeInChI;
3685 : 0 : num_deleted_components += (0 != pStruct[iComp].bDeleted);
3686 [ # # # # ]: 0 : if (!at || !num_atoms)
3687 : : {
3688 : 0 : continue;
3689 : : }
3690 : : /* find whether it is a reconnected structure */
3691 : 0 : q = bRevInchiComponentExists(pStruct + iComp, INCHI_REC, TAUT_YES, 0) ? INCHI_REC : INCHI_BAS;
3692 : : /*
3693 : : q = pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC] &&
3694 : : pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES] &&
3695 : : pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES]->nNumberOfAtoms? INCHI_REC : INCHI_BAS;
3696 : : */
3697 : 0 : pINChI_Aux = pStruct[iComp].RevInChI.pINChI_Aux[q][0][TAUT_YES]; /* 0 = 1st component in RevInChI */
3698 : : /*nNumProtAddedByRevrs = pINChI_Aux->nNumRemovedProtons;*/
3699 : 0 : nNumProtAddedByRevrs = -pStruct[iComp].nNumRemovedProtonsByRevrs;
3700 : 0 : bNormalizationFlags = pINChI_Aux->bNormalizationFlags;
3701 : 0 : num_tg = pINChI_Aux->nNumberOfTGroups;
3702 : :
3703 : :
3704 : : /* disconnect all explicit H and add the number of implicit iso H and all explicit terminal H to the number of implicit H */
3705 [ # # ]: 0 : if (0 > (ret = DisconnectedConnectedH(at, num_atoms, num_deleted_H)))
3706 : : {
3707 : 0 : goto exit_function;
3708 : : }
3709 : 0 : num_prot_prev = num_prot;
3710 : 0 : ret = AddRemoveProtonsRestr(at, num_atoms, &num_prot, nNumProtAddedByRevrs,
3711 : : bNormalizationFlags, num_tg, nChargeRevrs, nChargeInChI);
3712 : :
3713 : 0 : pStruct[iComp].bPostProcessed = ret;
3714 : 0 : num_changed += (ret > 0);
3715 [ # # ]: 0 : if (ret < 0)
3716 : : {
3717 : 0 : goto exit_function;
3718 : : }
3719 [ # # ]: 0 : if (ret > 0)
3720 : : {
3721 : : /* recalculate InChI; it will reconnect at */
3722 : 0 : StrFromINChI* pStruct1 = pStruct + iComp;
3723 : 0 : INCHI_MODE nMode = ip->nMode;
3724 : 0 : FreeAllINChIArrays(pStruct1->RevInChI.pINChI,
3725 : 0 : pStruct1->RevInChI.pINChI_Aux,
3726 : 0 : pStruct1->RevInChI.num_components);
3727 : :
3728 [ # # # # : 0 : if (bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
# # ]
3729 [ # # # # ]: 0 : !pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC))
3730 : : {
3731 : : /* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
3732 : 0 : ip->nMode |= REQ_MODE_BASIC;
3733 : : }
3734 : : /* calls ConnectDisconnectedH(...): subtracts number of implicit iso H from implicit H */
3735 : :
3736 : 0 : ret = MakeInChIOutOfStrFromINChI2(ic, pCG, ip, sd, pStruct1, 0, 0, num_inp);
3737 : :
3738 : 0 : ip->nMode = nMode;
3739 [ # # ]: 0 : if (ret < 0)
3740 : : {
3741 : 0 : goto exit_function;
3742 : : }
3743 : : }
3744 : : else
3745 : : {
3746 : : /* reconnect disconnected terminal H and subtracts number of implicit iso H from implicit H */
3747 [ # # ]: 0 : if (0 > (ret = ConnectDisconnectedH(at, num_atoms, num_deleted_H)))
3748 : : {
3749 : 0 : goto exit_function;
3750 : : }
3751 : : }
3752 [ # # # # ]: 0 : if (bAccumulateChanges && recmet_change_balance)
3753 : : {
3754 : : /* processed Reconnected layer component that is also present in Disconnected layer */
3755 : 0 : delta_recmet_prot += num_prot - num_prot_prev;
3756 : : }
3757 : : }
3758 : :
3759 : 0 : iComp = num_components - 1;
3760 [ # # # # : 0 : if (!bHasSomeFixedH && num_prot > 0 && 1 == num_deleted_components && iComp >= 0 && pStruct[iComp].bDeleted)
# # # # #
# ]
3761 : : {
3762 : : /* add bare protons to the deleted Mobile-H component; undelete the component */
3763 : 0 : num_prot_prev = num_prot;
3764 [ # # ]: 0 : if (!MakeProtonComponent(pStruct + iComp, iComp, num_prot))
3765 : : {
3766 : 0 : goto exit_function;
3767 : : }
3768 : : else
3769 : : {
3770 : : /* recalculate InChI; it will reconnect at */
3771 : 0 : StrFromINChI* pStruct1 = pStruct + iComp;
3772 : 0 : INCHI_MODE nMode = ip->nMode;
3773 : 0 : num_changed++;
3774 : 0 : num_prot = 0;
3775 : 0 : FreeAllINChIArrays(pStruct1->RevInChI.pINChI,
3776 : 0 : pStruct1->RevInChI.pINChI_Aux,
3777 : 0 : pStruct1->RevInChI.num_components);
3778 : :
3779 [ # # # # : 0 : if (bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
# # ]
3780 [ # # # # ]: 0 : !pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC))
3781 : : {
3782 : : /* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
3783 : 0 : ip->nMode |= REQ_MODE_BASIC;
3784 : : }
3785 : : /* Although MakeInChIOutOfStrFromINChI2() calls ConnectDisconnectedH(...) */
3786 : : /* to subtracts number of implicit iso H from implicit H */
3787 : : /* this CANNOT have any effect on the deleted H component */
3788 : :
3789 : 0 : ret = MakeInChIOutOfStrFromINChI2(ic, pCG, ip, sd, pStruct1, 0, 0, num_inp);
3790 : :
3791 : 0 : ip->nMode = nMode;
3792 [ # # ]: 0 : if (ret < 0)
3793 : : {
3794 : 0 : goto exit_function;
3795 : : }
3796 [ # # # # ]: 0 : if (bAccumulateChanges && recmet_change_balance)
3797 : : {
3798 : : /* processed Reconnected layer component that is also present in Disconnected layer */
3799 : 0 : delta_recmet_prot += num_prot - num_prot_prev;
3800 : : }
3801 : : }
3802 : : }
3803 : 0 : *nProtonsToBeRemovedByNormFromRevrs = num_prot;
3804 [ # # ]: 0 : if (recmet_change_balance)
3805 : : {
3806 : 0 : *recmet_change_balance = delta_recmet_prot;
3807 : : }
3808 : :
3809 : 0 : exit_function:
3810 : :
3811 [ # # ]: 0 : return ret < 0 ? ret : num_changed;
3812 : : }
3813 : :
3814 : :
3815 : : /****************************************************************************/
3816 : 0 : int AddRemIsoProtonsInRestrStruct(INCHI_CLOCK* ic,
3817 : : CANON_GLOBALS* pCG,
3818 : : ICHICONST INPUT_PARMS* ip_inp,
3819 : : STRUCT_DATA* sd,
3820 : : long num_inp,
3821 : : int bHasSomeFixedH,
3822 : : StrFromINChI* pStruct,
3823 : : int num_components,
3824 : : StrFromINChI* pStructR,
3825 : : int num_componentsR,
3826 : : NUM_H pProtonBalance[],
3827 : : NUM_H recmet_change_balance[])
3828 : : {
3829 : : /* on entry and exit, all at[i].num_H do not include isotopic H and explicit terminal H are connected */
3830 : 0 : int iComp, q, k, ret = 0, bNotEmpty;
3831 : : int num_atoms, num_deleted_H, num_tg, num_changed; /* djb-rwth: removing redundant variables */
3832 : : inp_ATOM* at;
3833 : : NUM_H num_prot[NUM_H_ISOTOPES], delta_recmet_prot[NUM_H_ISOTOPES], num_prot_prev[NUM_H_ISOTOPES];
3834 : : int bAccumulateChanges;
3835 : : INChI_Aux* pINChI_Aux;
3836 : : /* djb-rwth: removing redundant variables */
3837 : : INPUT_PARMS* ip, ip_loc;
3838 : :
3839 : 0 : ip_loc = *ip_inp;
3840 : 0 : ip = &ip_loc;
3841 : :
3842 : 0 : memcpy(num_prot, pProtonBalance, sizeof(num_prot));
3843 [ # # ]: 0 : for (bNotEmpty = 0, k = 0; k < NUM_H_ISOTOPES; k++)
3844 : : {
3845 : 0 : bNotEmpty |= num_prot[k];
3846 : : }
3847 [ # # ]: 0 : if (!bNotEmpty)
3848 : : {
3849 : 0 : return 0;
3850 : : }
3851 : 0 : memset(delta_recmet_prot, 0, sizeof(delta_recmet_prot)); /* djb-rwth: memset_s C11/Annex K variant? */
3852 : 0 : num_changed = 0;
3853 : : /*----------------------------------------------------------------------------------
3854 : : nLink < 0 && num_componentsR > 0 => This is a Disconnected structure component; it is
3855 : : same as already processed reconnected one
3856 : : Do no process it
3857 : :
3858 : : nLink > 0 && num_componentsR > 0 => This is a Disconnected structure component;
3859 : : (should not happen) It it is a result of (nLink-1)th Reconeected
3860 : : component disconnection (NOT IMPLEMENTED YET)
3861 : :
3862 : : nLink = 0 => Process this component. It is either a reconnected
3863 : : component, or a result of a disconnection (for now)
3864 : :
3865 : : nLink > 0 && num_componentsR = 0 => This is a Reconnected component that is same as
3866 : : a disconnected one that will not be processed.
3867 : : Process and save charge delta.
3868 : : -----------------------------------------------------------------------------------*/
3869 : :
3870 [ # # ]: 0 : for (iComp = 0; iComp < num_components && num_prot; iComp++) /* djb-rwth: the condition will always evaluate to true only if pProtonBalance is not NULL */
3871 : : {
3872 : : /* djb-rwth: removing redundant code */
3873 [ # # # # ]: 0 : if (pStruct[iComp].nLink < 0 && num_componentsR > 0)
3874 : : {
3875 : : /* check */
3876 : 0 : q = -(pStruct[iComp].nLink + 1);
3877 [ # # # # : 0 : if (!pStructR || !num_componentsR || q >= num_componentsR || pStructR[q].nLink != (iComp + 1))
# # # # ]
3878 : : {
3879 : 0 : ret = RI_ERR_PROGR;
3880 : 0 : goto exit_function;
3881 : : }
3882 : 0 : continue; /* Disconnected structure component has already been processed as a Reconnected one */
3883 : : }
3884 : :
3885 : 0 : at = pStruct[iComp].at2;
3886 : 0 : num_atoms = pStruct[iComp].num_atoms;
3887 : 0 : num_deleted_H = pStruct[iComp].num_deleted_H; /* djb-rwth: removing redundant code */
3888 [ # # # # ]: 0 : bAccumulateChanges = (pStruct[iComp].nLink > 0 && !num_componentsR);
3889 : :
3890 [ # # # # ]: 0 : if (!at || !num_atoms)
3891 : : {
3892 : 0 : continue;
3893 : : }
3894 : : /* find whether it is a reconnected structure */
3895 : 0 : q = pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC] &&
3896 [ # # ]: 0 : pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES] &&
3897 [ # # # # ]: 0 : pStruct[iComp].RevInChI.pINChI_Aux[INCHI_REC][0][TAUT_YES]->nNumberOfAtoms ? INCHI_REC : INCHI_BAS;
3898 : :
3899 : 0 : pINChI_Aux = pStruct[iComp].RevInChI.pINChI_Aux[q][0][TAUT_YES]; /* 0 = 1st component in RevInChI */
3900 : : /* djb-rwth: removing redundant code */
3901 : 0 : num_tg = pINChI_Aux->nNumberOfTGroups;
3902 : 0 : memcpy(num_prot_prev, num_prot, sizeof(num_prot_prev));
3903 : :
3904 : : /* pass CONNECTED explicit H to AddRemoveIsoProtonsRestr() for isotopic H addition */
3905 : 0 : ret = AddRemoveIsoProtonsRestr(at, num_atoms, num_prot, num_tg);
3906 : :
3907 : 0 : pStruct[iComp].bPostProcessed |= ret;
3908 : 0 : num_changed += (ret > 0);
3909 [ # # ]: 0 : if (ret < 0)
3910 : : {
3911 : 0 : goto exit_function;
3912 : : }
3913 [ # # ]: 0 : if (ret > 0)
3914 : : {
3915 : 0 : StrFromINChI* pStruct1 = pStruct + iComp;
3916 : 0 : INCHI_MODE nMode = ip->nMode;
3917 : : /* recalculate InChI; MakeInChIOutOfStrFromINChI2() will reconnect explicit H */
3918 : : /* disconnect all explicit H and add the number of implicit iso H and all explicit terminal H to the number of implicit H */
3919 [ # # ]: 0 : if (0 > (ret = DisconnectedConnectedH(at, num_atoms, num_deleted_H)))
3920 : : {
3921 : 0 : goto exit_function;
3922 : : }
3923 : 0 : FreeAllINChIArrays(pStruct1->RevInChI.pINChI,
3924 : 0 : pStruct1->RevInChI.pINChI_Aux,
3925 : 0 : pStruct1->RevInChI.num_components);
3926 [ # # # # : 0 : if (bHasSomeFixedH && pStruct1->iInchiRec == INCHI_REC && pStruct1->iMobileH == TAUT_YES &&
# # ]
3927 [ # # # # ]: 0 : !pStruct1->bFixedHExists && !(ip->nMode & REQ_MODE_BASIC))
3928 : : {
3929 : : /* reconnected components without Fixed-H layer may produce 'tautomeric' fragments like Cl(-) */
3930 : 0 : ip->nMode |= REQ_MODE_BASIC;
3931 : : }
3932 : : /* input: disconnected explicit H, output: connected explicit H */
3933 : 0 : ret = MakeInChIOutOfStrFromINChI2(ic, pCG, ip, sd, pStruct1, 0, 0, num_inp);
3934 : 0 : ip->nMode = nMode;
3935 [ # # ]: 0 : if (ret < 0)
3936 : : {
3937 : 0 : goto exit_function;
3938 : : }
3939 : : }
3940 : : /* the following was commented out 2007-08-28 by DT. Reason: it's a bug since H must be already connected */
3941 : : /* else {
3942 : : if ( 0 > ( ret = ConnectDisconnectedH( at, num_atoms, num_deleted_H ) ) ) {
3943 : : goto exit_function;
3944 : : }
3945 : : } */
3946 [ # # ]: 0 : if (bAccumulateChanges)
3947 : : {
3948 : : /* processed Reconnected layer component that is also present in Disconnected layer */
3949 [ # # ]: 0 : for (k = 0; k < NUM_H_ISOTOPES; k++)
3950 : : {
3951 : 0 : delta_recmet_prot[k] += num_prot[k] - num_prot_prev[k];
3952 : : }
3953 : : }
3954 : : }
3955 : :
3956 : 0 : memcpy(pProtonBalance, num_prot, sizeof(num_prot));
3957 [ # # ]: 0 : if (recmet_change_balance)
3958 : : {
3959 : 0 : memcpy(recmet_change_balance, delta_recmet_prot, sizeof(delta_recmet_prot));
3960 : : }
3961 : :
3962 : 0 : exit_function:
3963 : :
3964 [ # # ]: 0 : return ret < 0 ? ret : num_changed;
3965 : : }
3966 : :
3967 : : #endif
|