Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <ctype.h>
9 : : #include <math.h>
10 : : #include <stdbool.h>
11 : : #include <limits.h>
12 : :
13 : : #include "mode.h"
14 : : #include "ichinorm.h" /* @nnuk */
15 : : #include "strutil.h"
16 : : #include "molecular_inorganics_data.h"
17 : : #include "ichister.h"
18 : : #include "ichi_io.h"
19 : : #include "ichimain.h"
20 : : #include "ichidrp.h" /* @nnuk */
21 : :
22 : : #include "bcf_s.h"
23 : :
24 : : /* Added fix to remove_ion_pairs() -- 2010-03-17 DT */
25 : : #define FIX_P_IV_Plus_O_Minus
26 : :
27 : : #ifndef COMPILE_ALL_CPP
28 : : #ifdef __cplusplus
29 : : extern "C"
30 : : {
31 : : #endif
32 : : #endif
33 : :
34 : : /* Defined in ichisort.c, prototype in ichicomn.h */
35 : : int insertions_sort_AT_RANK(AT_RANK *base, int num);
36 : :
37 : : #ifndef COMPILE_ALL_CPP
38 : : #ifdef __cplusplus
39 : : }
40 : : #endif
41 : : #endif
42 : :
43 : : typedef struct tagTreeAtom
44 : : {
45 : : AT_NUMB neighbor[MAXVAL]; /* positions (from 0) of the neighbors in the inp_ATOM array */
46 : : S_CHAR valence; /* number of bonds = number of neighbors */
47 : : AT_NUMB nRingSystem;
48 : : AT_NUMB nBlockSystem;
49 : : S_CHAR bCutVertex;
50 : : } tre_ATOM;
51 : :
52 : : /* Local prototypes */
53 : :
54 : : int cmp_iso_atw_diff_component_no(const void *a1, const void *a2);
55 : : int cmp_components(const void *a1, const void *a2);
56 : : /* int mark_one_struct_component( inp_ATOM* at,
57 : : int j,
58 : : AT_NUMB *mark,
59 : : AT_NUMB num_disconnected_components );
60 : : */
61 : : INChI_Stereo *Alloc_INChI_Stereo(int num_at, int num_bonds);
62 : : static int is_only_HDT_neighbors(const inp_ATOM* at, int num_atoms, int metal_idx);
63 : : int RemoveInpAtBond(inp_ATOM *at, int iat, int k);
64 : : int DisconnectInpAtBond(inp_ATOM *at,
65 : : AT_NUMB *nOldCompNumber,
66 : : int iat,
67 : : int neigh_ord);
68 : : int move_explicit_Hcation(inp_ATOM *at,
69 : : int num_at,
70 : : int iat,
71 : : int iat_H,
72 : : int bInAllComponents);
73 : : int DisconnectOneLigand(inp_ATOM *at,
74 : : AT_NUMB *nOldCompNumber,
75 : : S_CHAR *bMetal,
76 : : char *elnumber_Heteroat,
77 : : int num_halogens,
78 : : int num_atoms,
79 : : int iMetal,
80 : : int jLigand,
81 : : INCHI_MODE *bTautFlagsDone);
82 : : int bIsAmmoniumSalt(inp_ATOM *at,
83 : : int i,
84 : : int *piO,
85 : : int *pk,
86 : : S_CHAR *num_explicit_H);
87 : : int DisconnectAmmoniumSalt(inp_ATOM *at,
88 : : int i,
89 : : int iO,
90 : : int k,
91 : : S_CHAR *num_explicit_H);
92 : : /*int bIsMetalSalt( inp_ATOM *at, int i ); - moved to strutil,h */
93 : : int DisconnectMetalSalt(inp_ATOM *at, int i);
94 : : int bIsMetalToDisconnect(inp_ATOM *at, int i, int bCheckMetalValence);
95 : : int get_iat_number(int el_number);
96 : : int tot_unsat(int unsat[]);
97 : : int max_unsat(int unsat[]);
98 : : double dist3D(inp_ATOM *at1, inp_ATOM *at2);
99 : : double dist2D(inp_ATOM *at1, inp_ATOM *at2);
100 : : double dist_from_segm(double x, double y,
101 : : double x1, double y1,
102 : : double x2, double y2);
103 : : int segments_intersect(double x11, double y11,
104 : : double x12, double y12, /* segment #1 */
105 : : double x21, double y21,
106 : : double x22, double y22);
107 : : double GetMinDistDistribution(inp_ATOM *at,
108 : : int num_at,
109 : : int iat,
110 : : int iat_H,
111 : : int bInAllComponents,
112 : : double min_dist[],
113 : : int num_segm);
114 : : int nFindOneOM(inp_ATOM *at,
115 : : int at_no,
116 : : int ord_OM[],
117 : : int num_OM);
118 : : int the_only_doublet_neigh(inp_ATOM *at, int i1, int *ineigh1, int *ineigh2);
119 : : int fix_non_uniform_drawn_oxoanions(int num_atoms, inp_ATOM *at, int *num_changes);
120 : : int fix_non_uniform_drawn_amidiniums(int num_atoms, inp_ATOM *at, int *num_changes);
121 : :
122 : : void add_bond_if_unseen(subgraf_pathfinder *spf,
123 : : int node0, int node,
124 : : int *nbonds, int **bonds);
125 : :
126 : : /****************************************************************************/
127 : : #ifndef NUMH
128 : : #define NUM_ISO_H(AT, N) (AT[N].num_iso_H[0] + AT[N].num_iso_H[1] + AT[N].num_iso_H[2])
129 : : #define NUMH(AT, N) (AT[N].num_H + NUM_ISO_H(AT, N))
130 : : #endif
131 : : /****************************************************************************/
132 : :
133 : : /****************************************************************************/
134 : 0 : int cmp_iso_atw_diff_component_no(const void *a1, const void *a2)
135 : : {
136 : 0 : int ret = (int)((const inp_ATOM *)a1)->iso_atw_diff - (int)((const inp_ATOM *)a2)->iso_atw_diff;
137 [ # # ]: 0 : if (!ret) /* make the sort stable */
138 : : {
139 : 0 : ret = (int)((const inp_ATOM *)a1)->component - (int)((const inp_ATOM *)a2)->component;
140 : : }
141 : :
142 : 0 : return ret;
143 : : }
144 : :
145 : : /****************************************************************************/
146 : 0 : int the_only_doublet_neigh(inp_ATOM *at,
147 : : int i1,
148 : : int *ineigh1,
149 : : int *ineigh2)
150 : : {
151 : 0 : int i, neigh1, num_rad1 = 0, num_rad2 = 0;
152 : :
153 : 0 : inp_ATOM *a = at + i1, *b;
154 [ # # ]: 0 : if (RADICAL_DOUBLET != a->radical)
155 : : {
156 : 0 : return -1;
157 : : }
158 [ # # ]: 0 : for (i = 0; i < a->valence; i++)
159 : : {
160 : 0 : b = at + ((int)a->neighbor[i]); /* djb-rwth: removing redundant code */
161 [ # # ]: 0 : if (RADICAL_DOUBLET == b->radical)
162 : : {
163 : 0 : num_rad1++;
164 : 0 : *ineigh1 = i;
165 : : }
166 : : }
167 : :
168 [ # # ]: 0 : if (1 == num_rad1)
169 : : {
170 : 0 : a = at + (neigh1 = (int)a->neighbor[*ineigh1]);
171 [ # # ]: 0 : for (i = 0; i < a->valence; i++)
172 : : {
173 : 0 : b = at + (int)a->neighbor[i];
174 [ # # ]: 0 : if (RADICAL_DOUBLET == b->radical)
175 : : {
176 : 0 : num_rad2++;
177 : 0 : *ineigh2 = i;
178 : : }
179 : : }
180 : :
181 [ # # ]: 0 : if (1 == num_rad2)
182 : : {
183 : 0 : return neigh1;
184 : : }
185 : : }
186 : :
187 : 0 : return -1;
188 : : }
189 : :
190 : : /****************************************************************************
191 : : Correct non-uniformly drawn oxoanions
192 : : ****************************************************************************/
193 : 122 : int fix_non_uniform_drawn_oxoanions(int num_atoms,
194 : : inp_ATOM *at,
195 : : int *num_changes)
196 : : {
197 : : /* For central halogen, apply the following
198 : : correction rules:
199 : :
200 : : O O(-)
201 : : || |
202 : : O=Hal(-)=O ===> O=Hal=O
203 : : || ||
204 : : O O
205 : :
206 : : (perchlorate, etc.)
207 : :
208 : :
209 : : O O(-)
210 : : || |
211 : : Hal(-)=O ===> Hal=O
212 : : || ||
213 : : O O
214 : :
215 : : (chlorate, etc.)
216 : :
217 : : O O(-)
218 : : || |
219 : : Hal(-)=O ===> Hal=O
220 : :
221 : :
222 : : (chlorite, etc.)
223 : :
224 : : Hal(-)=O ===> Hal-O(-)
225 : :
226 : :
227 : : (hypochlorite, etc.)
228 : :
229 : :
230 : :
231 : : For halcogenes (S, Se, Te)
232 : : Y Y(-)
233 : : || |
234 : : RnX(-) ===> RnX
235 : :
236 : : if:
237 : : 1) (X = S, Y = O) || (X = Se, Y = S, O) || (X = Te, Y = O, S, Se)
238 : : 2) valence of X exceeds 6, in initially drawn form
239 : :
240 : :
241 : : So the following is corrected:
242 : :
243 : : O O(-)
244 : : || |
245 : : O=S(-)-R ===> O=S-R
246 : : || ||
247 : : O O
248 : :
249 : : Or
250 : :
251 : : O O-
252 : : || |
253 : : F5Te(-) ===> F5Te
254 : :
255 : : but the following remains unchanged:
256 : :
257 : :
258 : : O
259 : : ||
260 : : O=S(-)-R
261 : :
262 : :
263 : : The central atom (of IUPAC Group 16-17) is shown as negative but it contains double bond(s)
264 : : to terminal atom of greater electronegativity (of Group 16).
265 : : The central atom is halcogen (S,Se,Te) in highest oxidation state or halogen.
266 : :
267 : : Fix:
268 : : move negative charge to terminal atom and change double bond to a single one.
269 : :
270 : : Eligible central atom Eligible terminal atom at double bond's end
271 : : Cl O
272 : : Br O
273 : : I O
274 : : [At S,Se,Te]
275 : : S O
276 : : Se O,S
277 : : Te O, S, Se
278 : :
279 : : Comments:
280 : : 1. Central atoms of Groups 13-15 are not considered.
281 : : 2. Pauling electronegativities are:
282 : : F(3.98) > O(3.44) > Cl (3.16) > N (3.04) > Br(2.96) > I(2.66) > S(2.58) > Se(2.55) > At (2.2) > Te(2.1)
283 : :
284 : :
285 : : */
286 : :
287 : : /* constants for element numbers */
288 : : enum elems
289 : : {
290 : : dNone,
291 : : dCl = 17,
292 : : dBr = 35,
293 : : dI = 53,
294 : : dAt = 85,
295 : : dO = 8,
296 : : dS = 16,
297 : : dSe = 34,
298 : : dTe = 52,
299 : : dP = 15,
300 : : dC = 6,
301 : : dN = 7
302 : : };
303 : :
304 : : static U_CHAR allowed_elnums_center_halogen[] = {dCl, dBr, dI, dAt};
305 : : static U_CHAR allowed_elnums_center_halcogen[] = {dS, dSe, dTe};
306 : :
307 : : int en_center;
308 : : int i, j, k;
309 : :
310 [ + + ]: 929 : for (i = 0; i < num_atoms; i++)
311 : : {
312 : : /* Find appropriate central atom. This center should be: ...*/
313 : :
314 : : /* charged exactly (-1) ... */
315 [ + + ]: 807 : if (at[i].charge != -1)
316 : : {
317 : 783 : continue;
318 : : }
319 : 24 : en_center = at[i].el_number;
320 : : /* from eligible element list ... */
321 [ + - ]: 24 : if (!memchr(allowed_elnums_center_halogen, en_center, sizeof(allowed_elnums_center_halogen)))
322 : : {
323 : : /* central atom is not not halogen; check if it is halcogen */
324 [ - + ]: 24 : if (memchr(allowed_elnums_center_halcogen, en_center, sizeof(allowed_elnums_center_halcogen)))
325 : : {
326 [ # # ]: 0 : if (at[i].chem_bonds_valence < 7)
327 : : {
328 : : /* central atom is anionic halcogen, but not in the highest oxidation state */
329 : 0 : continue;
330 : : }
331 : : }
332 : : else
333 : : {
334 : 24 : continue;
335 : : }
336 : : }
337 : :
338 : : /* OK, found central halogen or eligible central halcogen. */
339 : :
340 : : /* non-radical... */
341 [ # # # # ]: 0 : if (at[i].radical && (at[i].radical != RADICAL_SINGLET))
342 : : {
343 : 0 : continue;
344 : : }
345 : :
346 : : /* Center found, now examine the adjacent terminals... */
347 : : {
348 : 0 : int en_term, kk = 0, jj = 0, min_en = 999, iso = 0, min_iso = 999;
349 : 0 : jj = -1;
350 [ # # ]: 0 : for (k = 0; k < at[i].valence; k++)
351 : : {
352 : 0 : j = at[i].neighbor[k];
353 : :
354 : : /* Terminal should be: ... */
355 : :
356 : : /* terminal... */
357 [ # # ]: 0 : if (at[j].valence != 1)
358 : : {
359 : 0 : continue;
360 : : }
361 : : /* double-bonded ... */
362 [ # # ]: 0 : if (at[i].bond_type[k] != BOND_TYPE_DOUBLE)
363 : : {
364 : 0 : continue;
365 : : }
366 : : /* zero-charged ... */
367 [ # # ]: 0 : if (at[j].charge != 0)
368 : : {
369 : 0 : continue;
370 : : }
371 : : /* non-radical */
372 [ # # # # ]: 0 : if (at[j].radical && (at[j].radical != RADICAL_SINGLET))
373 : : {
374 : 0 : continue;
375 : : }
376 : : /* of eligible elements list ... */
377 : 0 : en_term = at[j].el_number;
378 [ # # # # : 0 : switch (en_term)
# ]
379 : : {
380 : 0 : case dO:
381 : 0 : break;
382 : 0 : case dS:
383 [ # # # # : 0 : if ((en_center == dSe) || (en_center == dAt) || (en_center == dTe))
# # ]
384 : : break;
385 : 0 : continue;
386 : 0 : case dSe:
387 [ # # # # ]: 0 : if ((en_center == dAt) || (en_center == dTe))
388 : : break;
389 : 0 : continue;
390 : 0 : case dTe:
391 [ # # ]: 0 : if (en_center == dAt)
392 : 0 : break;
393 : 0 : continue;
394 : 0 : default:
395 : 0 : continue;
396 : : }
397 : :
398 : : /* From several candidates, select one with less el. number (==more electronegative). */
399 [ # # ]: 0 : if (en_term < min_en)
400 : : {
401 : 0 : min_en = en_term;
402 : 0 : kk = k;
403 : 0 : jj = j;
404 [ # # ]: 0 : min_iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
405 : 0 : continue;
406 : : }
407 : : /* From same-element candidates, select one with less isotopic mass (arbitrary choice). */
408 [ # # ]: 0 : else if (en_term == min_en)
409 : : {
410 [ # # ]: 0 : iso = at[j].iso_atw_diff > 0 ? at[i].iso_atw_diff - 1 : at[i].iso_atw_diff;
411 [ # # ]: 0 : if (iso < min_iso)
412 : : {
413 : 0 : min_iso = iso;
414 : 0 : kk = k;
415 : 0 : jj = j;
416 : 0 : continue;
417 : : }
418 : : }
419 : : } /* end of checking nbrs. */
420 : :
421 : : /* If OK, apply changes. */
422 [ # # ]: 0 : if (jj >= 0)
423 : : {
424 : 0 : at[i].charge = 0;
425 : 0 : at[jj].charge = -1;
426 : 0 : at[i].bond_type[kk] = BOND_TYPE_SINGLE;
427 : 0 : at[jj].bond_type[0] = BOND_TYPE_SINGLE;
428 : 0 : at[i].bond_stereo[kk] = at[jj].bond_stereo[0] = 0;
429 : 0 : at[i].chem_bonds_valence--;
430 : 0 : at[jj].chem_bonds_valence--;
431 : 0 : (*num_changes)++;
432 : : }
433 : : }
434 : : } /* end of search for candidate centers. */
435 : :
436 : 122 : return 0;
437 : : }
438 : :
439 : : /****************************************************************************
440 : : Correct non-uniformly drawn amidinium cations.
441 : : ****************************************************************************/
442 : 122 : int fix_non_uniform_drawn_amidiniums(int num_atoms,
443 : : inp_ATOM *at,
444 : : int *num_changes)
445 : :
446 : : {
447 : : /* Amidines include carboxamidines RC(=NR)NR2,
448 : : sulfinamidines RS(=NR)NR2 and phosphinamidines, R2P(=NR)NR2.
449 : :
450 : :
451 : : NR NR
452 : : | |
453 : : R"-Y-NHR' ===> R"-Y=N(+)HR'
454 : : (+)
455 : :
456 : :
457 : : Y = C, S, P
458 : :
459 : :
460 : : Fix:
461 : : move positive charge to nitrogen and change single bond to a double one.
462 : :
463 : :
464 : : Comment:
465 : : Fix is applied only if at least one of R's at N is hydrogen
466 : : (otherwise we have just a '+' delocalization which is already recognized).
467 : :
468 : :
469 : : */
470 : :
471 : : /* constants for element numbers */
472 : : enum elems
473 : : {
474 : : dNone,
475 : : dCl = 17,
476 : : dBr = 35,
477 : : dI = 53,
478 : : dAt = 85,
479 : : dO = 8,
480 : : dS = 16,
481 : : dSe = 34,
482 : : dTe = 52,
483 : : dP = 15,
484 : : dC = 6,
485 : : dN = 7
486 : : };
487 : :
488 : : static U_CHAR allowed_elnums_center[] = {dC, dS, dP};
489 : : int en_center;
490 : : int i, j, k, jj, kk, k1;
491 : 122 : int mismatch = 0, nuH = 0, nuN = 0, nitrogens[MAXVAL];
492 : :
493 [ + + ]: 929 : for (i = 0; i < num_atoms; i++)
494 : : {
495 : : /* Find appropriate central atom. This center should be: ...*/
496 : :
497 : : /* charged exactly (+1) ... */
498 [ + + ]: 807 : if (at[i].charge != 1)
499 : : {
500 : 797 : continue;
501 : : }
502 : 10 : en_center = at[i].el_number;
503 : : /* from eligible element list ... */
504 [ + - ]: 10 : if (!memchr(allowed_elnums_center, en_center, sizeof(allowed_elnums_center)))
505 : : {
506 : 10 : continue;
507 : : }
508 : : /* has exactly 3 neighbours connected by single bonds*/
509 [ # # ]: 0 : if (at[i].valence != 3)
510 : : {
511 : 0 : continue;
512 : : }
513 [ # # ]: 0 : if (at[i].chem_bonds_valence != 3)
514 : : {
515 : 0 : continue;
516 : : }
517 : :
518 : : /* non-radical. */
519 [ # # # # ]: 0 : if (at[i].radical && (at[i].radical != RADICAL_SINGLET))
520 : : {
521 : 0 : continue;
522 : : }
523 : :
524 : : /* NB: center must have neutral neighbours, two of them are aliphatic N's of which at least one bears H. */
525 : 0 : mismatch = nuH = nuN = kk = 0; /* djb-rwth: removing redundant code */
526 : 0 : memset(nitrogens, 0, sizeof(nitrogens)); /* djb-rwth: memset_s C11/Annex K variant? */
527 : 0 : jj = -1;
528 [ # # ]: 0 : for (k = 0; k < at[i].valence; k++)
529 : : {
530 : 0 : j = at[i].neighbor[k];
531 : :
532 [ # # ]: 0 : if (at[j].charge != 0)
533 : : {
534 : 0 : mismatch = 1;
535 : 0 : break;
536 : : }
537 [ # # ]: 0 : if (at[j].el_number == dN)
538 : : {
539 [ # # # # ]: 0 : if ((at[j].valence > 3) || (at[j].chem_bonds_valence > 3))
540 : : {
541 : 0 : mismatch = 1;
542 : 0 : break;
543 : : }
544 : 0 : nuH += NUMH(at, j);
545 : 0 : nuN++;
546 [ # # ]: 0 : if (jj < 0)
547 : : {
548 : 0 : jj = j;
549 : 0 : kk = k;
550 : : }
551 : : }
552 : : }
553 : :
554 : : /* If OK, apply changes. */
555 [ # # ]: 0 : if (mismatch)
556 : : {
557 : 0 : continue;
558 : : }
559 [ # # ]: 0 : if (nuN != 2)
560 : : {
561 : 0 : continue;
562 : : }
563 [ # # ]: 0 : if (nuH < 1)
564 : : {
565 : 0 : continue;
566 : : }
567 [ # # ]: 0 : if (jj >= 0)
568 : : {
569 : 0 : at[i].charge = 0;
570 : 0 : at[jj].charge = 1;
571 : 0 : at[i].bond_type[kk] = BOND_TYPE_DOUBLE;
572 [ # # # # ]: 0 : for (k1 = 0; k1 < at[jj].valence && i != at[jj].neighbor[k1]; k1++)
573 : : ;
574 : 0 : at[jj].bond_type[k1] = BOND_TYPE_DOUBLE;
575 : 0 : at[i].chem_bonds_valence++;
576 : 0 : at[jj].chem_bonds_valence++;
577 : : /* NB: do nothing with wedge stereo bonds (retain wedge) */
578 : :
579 : 0 : (*num_changes)++;
580 : : }
581 : : } /* end of search for candidate centers. */
582 : :
583 : 122 : return 0;
584 : : }
585 : :
586 : : /****************************************************************************/
587 : 122 : int fix_odd_things(int num_atoms,
588 : : inp_ATOM *at,
589 : : int bFixBug,
590 : : int bFixNonUniformDraw)
591 : : {
592 : : /* N;P;As;Sb;O;S;Se;Te;C;Si */
593 : : static const U_CHAR en[] = {
594 : : EL_NUMBER_N,
595 : : EL_NUMBER_P,
596 : : EL_NUMBER_AS,
597 : : EL_NUMBER_SB,
598 : : EL_NUMBER_O,
599 : : EL_NUMBER_S,
600 : : EL_NUMBER_SE,
601 : : EL_NUMBER_TE};
602 : : static int ne = sizeof(en) / sizeof(en[0]);
603 : :
604 : : #define FIRST_NEIGHB2 4
605 : : #define FIRST_CENTER2 5
606 : :
607 : 122 : int i1, i2, k1, k2, c = -1, num_changes = 0;
608 : : /* djb-rwth: removing redundant variables */
609 : :
610 [ + - ]: 122 : if (bFixNonUniformDraw)
611 : : {
612 : : int ret1; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
613 : 122 : ret1 = fix_non_uniform_drawn_oxoanions(num_atoms, at, &num_changes); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
614 : 122 : ret1 = fix_non_uniform_drawn_amidiniums(num_atoms, at, &num_changes); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
615 : : }
616 : :
617 : : /* H(-)-X -> H-X(-); H(+)-X -> H-X(+) */
618 [ + + ]: 929 : for (i1 = 0; i1 < num_atoms; i1++)
619 : : {
620 [ + + ]: 807 : if (1 == at[i1].valence &&
621 [ + + ]: 356 : 1 == abs(at[i1].charge) &&
622 [ - + - - ]: 14 : (0 == at[i1].radical || RADICAL_SINGLET == at[i1].radical) &&
623 [ + - ]: 14 : BOND_TYPE_SINGLE == at[i1].bond_type[0] &&
624 [ - + - - ]: 14 : EL_NUMBER_H == at[i1].el_number && EL_NUMBER_H != at[i2 = (int)at[i1].neighbor[0]].el_number &&
625 [ # # # # ]: 0 : !NUMH(at, i1) && !NUMH(at, i2))
626 : : {
627 : 0 : at[i2].charge += at[i1].charge;
628 : 0 : at[i1].charge = 0;
629 : : }
630 : : }
631 : :
632 : : /* replace XHm(-)--Y==XHn(+) with XHm==Y--XHn, (n>=0 ,m>=0, X=N,P,As,Sb,O,S,Se,Te) */
633 [ + + ]: 929 : for (i1 = 0; i1 < num_atoms; i1++)
634 : : {
635 [ + + ]: 807 : if (1 != at[i1].charge ||
636 [ - + - - ]: 10 : (at[i1].radical && RADICAL_SINGLET != at[i1].radical) ||
637 [ - + ]: 10 : at[i1].chem_bonds_valence == at[i1].valence ||
638 [ # # ]: 0 : !memchr(en, at[i1].el_number, ne) ||
639 [ # # ]: 0 : get_el_valence(at[i1].el_number, at[i1].charge, 0) != at[i1].chem_bonds_valence + NUMH(at, i1)) /* djb-rwth: addressing LLVM warning */
640 : : {
641 : 807 : continue;
642 : : }
643 : :
644 : : /* found a candidate at[i1] for X in XHn(+) */
645 [ # # ]: 0 : if (1 == at[i1].valence &&
646 [ # # ]: 0 : BOND_TYPE_DOUBLE == at[i1].bond_type[0])
647 : : {
648 : 0 : c = (int)at[i1].neighbor[0];
649 [ # # ]: 0 : for (k2 = 0; k2 < at[c].valence; k2++)
650 : : {
651 : 0 : i2 = at[c].neighbor[k2];
652 [ # # ]: 0 : if (1 == at[i2].valence &&
653 [ # # ]: 0 : -1 == at[i2].charge &&
654 [ # # ]: 0 : at[i2].el_number == at[i1].el_number && /* exact match */
655 [ # # # # ]: 0 : (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
656 [ # # ]: 0 : BOND_TYPE_SINGLE == at[i2].bond_type[0] &&
657 : : /*memchr(en, at[i2].el_number, ne) &&*/
658 [ # # ]: 0 : get_el_valence(at[i2].el_number, at[i2].charge, 0) == at[i2].chem_bonds_valence + NUMH(at, i2))
659 : : {
660 : : /* found both X(-) and X(+); change bonds and remove charges */
661 [ # # # # ]: 0 : for (k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1++)
662 : : ;
663 : 0 : at[i1].charge = at[i2].charge = 0;
664 : 0 : at[i1].bond_type[0] = at[c].bond_type[k1] = BOND_TYPE_SINGLE;
665 : 0 : at[i1].chem_bonds_valence--;
666 : 0 : at[i2].bond_type[0] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
667 : 0 : at[i2].chem_bonds_valence++;
668 : 0 : num_changes++;
669 : 0 : break;
670 : : }
671 : : }
672 : : }
673 : : else
674 : : {
675 : : /* explicit H case: detect H-neighbors and Y */
676 : : int ineigh, neigh, i1_c, i2_c, num_H_i1, num_H_i2;
677 [ # # ]: 0 : for (ineigh = 0, num_H_i1 = 0, i1_c = -1; ineigh < at[i1].valence; ineigh++)
678 : : {
679 : 0 : neigh = at[i1].neighbor[ineigh];
680 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_H)
681 : : {
682 [ # # ]: 0 : if (at[neigh].chem_bonds_valence == 1 &&
683 [ # # # # ]: 0 : (0 == at[neigh].radical || RADICAL_SINGLET == at[neigh].radical))
684 : : {
685 : 0 : num_H_i1++; /* found H-neighbor */
686 : : }
687 : : else
688 : : {
689 : : break; /* wrong neighbor */
690 : : }
691 : : }
692 [ # # ]: 0 : else if (at[i1].bond_type[ineigh] == BOND_TYPE_DOUBLE)
693 : : {
694 : : /* found a candidate for Y; bond must be double */
695 : 0 : i1_c = ineigh;
696 : 0 : c = neigh;
697 : : }
698 : : }
699 [ # # # # ]: 0 : if (i1_c < 0 || num_H_i1 + 1 != at[i1].valence)
700 : : {
701 : 0 : continue;
702 : : }
703 [ # # ]: 0 : for (k2 = 0; k2 < at[c].valence; k2++)
704 : : {
705 : 0 : i2 = at[c].neighbor[k2];
706 [ # # ]: 0 : if (-1 == at[i2].charge &&
707 [ # # ]: 0 : at[i2].el_number == at[i1].el_number && /* exact match */
708 [ # # # # ]: 0 : (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
709 [ # # ]: 0 : get_el_valence(at[i2].el_number, at[i2].charge, 0) == at[i2].chem_bonds_valence + NUMH(at, i2))
710 : : {
711 [ # # ]: 0 : for (ineigh = 0, num_H_i2 = 0, i2_c = -1; ineigh < at[i2].valence; ineigh++)
712 : : {
713 : 0 : neigh = at[i2].neighbor[ineigh];
714 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_H)
715 : : {
716 [ # # ]: 0 : if (at[neigh].chem_bonds_valence == 1 &&
717 [ # # # # ]: 0 : (0 == at[neigh].radical || RADICAL_SINGLET == at[neigh].radical))
718 : : {
719 : 0 : num_H_i2++; /* found H-neighbor */
720 : : }
721 : : else
722 : : {
723 : : break; /* wrong neighbor */
724 : : }
725 : : }
726 : : else
727 : : {
728 [ # # # # ]: 0 : if (c == neigh && at[i2].bond_type[ineigh] == BOND_TYPE_SINGLE)
729 : : {
730 : 0 : i2_c = ineigh; /* position of Y neighbor; bond must be single */
731 : : }
732 : : else
733 : : {
734 : : break;
735 : : }
736 : : }
737 : : }
738 [ # # ]: 0 : if (num_H_i2 + (i2_c >= 0) != at[i2].valence)
739 : : {
740 : 0 : continue;
741 : : }
742 : : /* found both X(-) and X(+); change bonds and remove charges */
743 [ # # # # ]: 0 : for (k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1++)
744 : : ;
745 [ # # # # ]: 0 : if ((i1_c >= 0) && (i2_c >= 0)) /* djb-rwth: fixing coverity ID #499537 */
746 : : {
747 : 0 : at[i1].charge = at[i2].charge = 0;
748 : 0 : at[i1].bond_type[i1_c] = at[c].bond_type[k1] = BOND_TYPE_SINGLE;
749 : 0 : at[i1].chem_bonds_valence--;
750 : 0 : at[i2].bond_type[i2_c] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
751 : 0 : at[i2].chem_bonds_valence++;
752 : 0 : num_changes++;
753 : 0 : break;
754 : : }
755 : : else
756 : : {
757 : 0 : continue;
758 : : }
759 : : }
760 : : } /* k2 */
761 : : }
762 : : }
763 : :
764 : : /* Replace
765 : :
766 : : X- X X=O,S,Se,Te -- terminal atoms (NEIGHB2)
767 : : \ | \ ||
768 : : >Y++ with >Y Y=S,Se,Te -- central cation (CENTER2)
769 : : / | / ||
770 : : X- X Y valence=4, original Y bond valence = 4
771 : :
772 : :
773 : : --- the following case of P is processed separately in remove_ion_pairs()
774 : : --- therefire, it has been disabled here, see #ifndef FIX_P_IV_Plus_O_Minus -- 2010-03-17 DT
775 : :
776 : : X- X X=O,S,Se,Te -- terminal atoms (NEIGHB2)
777 : : \ | \ ||
778 : : >P+ with >P
779 : : / | / |
780 : : X- X- Y valence=4, original Y bond valence = 4
781 : :
782 : : */
783 : :
784 [ + + ]: 929 : for (i1 = 0; i1 < num_atoms; i1++)
785 : : {
786 [ + + ]: 807 : if (1 == at[i1].valence &&
787 [ + + ]: 356 : -1 == at[i1].charge &&
788 [ - + - - ]: 14 : (0 == at[i1].radical || RADICAL_SINGLET == at[i1].radical) &&
789 [ + - ]: 14 : !NUMH(at, i1) &&
790 [ + - ]: 14 : BOND_TYPE_SINGLE == at[i1].bond_type[0] &&
791 [ + - ]: 14 : memchr(en + FIRST_NEIGHB2, at[i1].el_number, (long long)ne - FIRST_NEIGHB2)) /* djb-rwth: cast operator added */
792 : : {
793 : : int charge, i;
794 : : /* found a candidate for X */
795 : 14 : c = (int)at[i1].neighbor[0]; /* candidate for Y */
796 [ - + - - ]: 14 : if (((charge = 2) == at[c].charge && memchr(en + FIRST_CENTER2, at[c].el_number, (long long)ne - FIRST_CENTER2) /* djb-rwth: cast operator added */
797 : :
798 : : #ifndef FIX_P_IV_Plus_O_Minus
799 : : || (charge = 1) == at[c].charge && EL_NUMBER_P == at[c].el_number
800 : : #endif
801 : 0 : ) &&
802 [ # # ]: 0 : 4 == at[c].valence &&
803 [ # # # # ]: 0 : (0 == at[c].radical || RADICAL_SINGLET == at[c].radical) &&
804 [ # # ]: 0 : at[c].valence == at[c].chem_bonds_valence &&
805 [ # # ]: 0 : !NUMH(at, c))
806 : : {
807 : : ; /* accept */
808 : : }
809 : : else
810 : : {
811 : 14 : continue; /* ignore at[i1] */
812 : : }
813 [ # # ]: 0 : for (k2 = 0; k2 < at[c].valence; k2++)
814 : : {
815 : 0 : i2 = at[c].neighbor[k2];
816 [ # # ]: 0 : if (i2 == i1)
817 : : {
818 : 0 : continue;
819 : : }
820 [ # # ]: 0 : if (1 == at[i2].valence &&
821 [ # # ]: 0 : -1 == at[i2].charge &&
822 [ # # ]: 0 : memchr(en + FIRST_NEIGHB2, at[i2].el_number, (long long)ne - FIRST_NEIGHB2) && /* djb-rwth: cast operator added */
823 : : /*at[i2].el_number == at[i1].el_number &&*/ /* exact match */
824 [ # # # # ]: 0 : (0 == at[i2].radical || RADICAL_SINGLET == at[i2].radical) &&
825 [ # # ]: 0 : !NUMH(at, i2) &&
826 [ # # ]: 0 : BOND_TYPE_SINGLE == at[i2].bond_type[0])
827 : : {
828 : : /* found both X(-) and X(-); change bonds and remove charges */
829 [ # # # # ]: 0 : for (k1 = 0; k1 < at[c].valence && i1 != at[c].neighbor[k1]; k1++)
830 : : {
831 : : ;
832 : : }
833 [ # # ]: 0 : for (i = 0; i < charge; i++)
834 : : {
835 : : /* in case of P it does not matter which X atom is neutralized
836 : : because of tautomerism. However, neutral central atom is important
837 : : for the neutralization of the components */
838 [ # # # ]: 0 : switch (i)
839 : : {
840 : 0 : case 0:
841 : 0 : at[i1].charge++; /* = 0; changed 2010-03-17 DT*/
842 : 0 : at[i1].bond_type[0] = at[c].bond_type[k1] = BOND_TYPE_DOUBLE;
843 : 0 : at[i1].bond_stereo[0] = at[c].bond_stereo[k1] = 0;
844 : 0 : at[i1].chem_bonds_valence++;
845 : 0 : at[c].chem_bonds_valence++;
846 [ # # ]: 0 : if (bFixBug)
847 : 0 : at[c].charge--; /* added 2010-03-17 DT*/
848 : 0 : num_changes++;
849 : 0 : break;
850 : 0 : case 1:
851 : 0 : at[i2].charge++; /*= 0; changed 2010-03-17 DT*/
852 : 0 : at[i2].bond_type[0] = at[c].bond_type[k2] = BOND_TYPE_DOUBLE;
853 : 0 : at[i2].bond_stereo[0] = at[c].bond_stereo[k2] = 0;
854 : 0 : at[i2].chem_bonds_valence++;
855 : 0 : at[c].chem_bonds_valence++;
856 [ # # ]: 0 : if (bFixBug)
857 : 0 : at[c].charge--; /* added 2010-03-17 DT */
858 : 0 : num_changes++;
859 : 0 : break;
860 : : }
861 : : }
862 : :
863 : : /* -- removed -- 2010-03-17 DT
864 : : #if ( FIX_ODD_THINGS_REM_Plus_BUG == 1 )
865 : : at[c].charge -= charge;
866 : : #else
867 : : if ( bFixBug )
868 : : {
869 : : at[c].charge -= charge;
870 : : }
871 : : #endif
872 : : */
873 : 0 : break;
874 : : }
875 : : }
876 : : }
877 : : }
878 : :
879 : : /* A(doublet)-B(doublet) -> A=B (A and B have no other doublet neighbors) */
880 : : /* A(doublet)=B(doublet) -> A#B (A and B have no other doublet neighbors) */
881 [ + + ]: 929 : for (i1 = 0; i1 < num_atoms; i1++)
882 : : {
883 [ - + - - ]: 807 : if (RADICAL_DOUBLET == at[i1].radical &&
884 : 0 : 0 <= (i2 = the_only_doublet_neigh(at, i1, &k1, &k2)))
885 : : {
886 [ # # ]: 0 : if (at[i1].bond_type[k1] <= BOND_TYPE_DOUBLE)
887 : : {
888 : 0 : at[i1].bond_type[k1]++;
889 : 0 : at[i1].chem_bonds_valence++;
890 : 0 : at[i2].bond_type[k2]++;
891 : 0 : at[i2].chem_bonds_valence++;
892 : 0 : at[i1].radical = 0;
893 : 0 : at[i2].radical = 0;
894 : : }
895 : : }
896 : : }
897 : :
898 : : #if (REMOVE_ION_PAIRS_EARLY == 1)
899 : 122 : num_changes += remove_ion_pairs(num_atoms, at);
900 : : #endif
901 : :
902 : 122 : return num_changes;
903 : : }
904 : :
905 : : /****************************************************************************/
906 : 98 : int post_fix_odd_things(int num_atoms, inp_ATOM *at)
907 : : {
908 : 98 : int num_changes = 0;
909 : : /* currently does nothing */
910 : 98 : return num_changes;
911 : : }
912 : :
913 : : /****************************************************************************/
914 : 0 : int nFindOneOM(inp_ATOM *at, int at_no, int ord_OM[], int num_OM)
915 : : {
916 : : int i, n_OM, best_value, cur_value, diff; /* djb-rwth: removing redundant variables */
917 : : int num_best;
918 : :
919 [ # # ]: 0 : if (1 == num_OM)
920 : : {
921 : 0 : return ord_OM[0];
922 : : }
923 [ # # ]: 0 : if (1 > num_OM)
924 : : {
925 : 0 : return -1;
926 : : }
927 : :
928 : : /* select neighbors with min. number of bonds */
929 : 0 : num_best = 1;
930 : 0 : n_OM = (int)at[at_no].neighbor[ord_OM[0]];
931 : 0 : best_value = (int)at[n_OM].valence;
932 : : /* compare number of bonds; move indexes of the best neighbors to the first elements of ord_OM[] */
933 [ # # ]: 0 : for (i = 1; i < num_OM; i++)
934 : : {
935 : 0 : n_OM = at[at_no].neighbor[ord_OM[i]];
936 : 0 : cur_value = (int)at[n_OM].valence;
937 : 0 : diff = cur_value - best_value;
938 [ # # ]: 0 : if (diff < 0)
939 : : {
940 : : /* djb-rwth: removing redundant code */
941 : 0 : best_value = cur_value;
942 : 0 : ord_OM[0] = ord_OM[i];
943 : 0 : num_best = 1;
944 : : }
945 [ # # ]: 0 : else if (diff == 0)
946 : : { /* was '=', pointed by WDI */
947 : 0 : ord_OM[num_best++] = ord_OM[i];
948 : : }
949 : : }
950 : 0 : num_OM = num_best;
951 [ # # ]: 0 : if (1 == num_OM)
952 : : {
953 : 0 : return ord_OM[0];
954 : : }
955 : :
956 : : /* select neighbors with min. periodic numbers */
957 : 0 : num_best = 1;
958 : 0 : n_OM = (int)at[at_no].neighbor[ord_OM[0]];
959 : 0 : best_value = (int)at[n_OM].el_number;
960 : :
961 : : /* compare periodic numbers; move indexes of the best neighbors to the first elements of ord_OM[] */
962 [ # # ]: 0 : for (i = 1; i < num_OM; i++)
963 : : {
964 : 0 : n_OM = at[at_no].neighbor[ord_OM[i]];
965 : 0 : cur_value = (int)at[n_OM].el_number;
966 : 0 : diff = cur_value - best_value;
967 [ # # ]: 0 : if (diff < 0)
968 : : {
969 : : /* djb-rwth: removing redundant code */
970 : 0 : best_value = cur_value;
971 : 0 : ord_OM[0] = ord_OM[i];
972 : 0 : num_best = 1;
973 : : }
974 [ # # ]: 0 : else if (diff == 0)
975 : : { /* was '=', pointed by WDI */
976 : 0 : ord_OM[num_best++] = ord_OM[i];
977 : : }
978 : : }
979 : 0 : num_OM = num_best;
980 [ # # ]: 0 : if (1 == num_OM)
981 : : {
982 : 0 : return ord_OM[0];
983 : : }
984 : :
985 : : /* if neighbors are not terminal atoms then reject */
986 [ # # ]: 0 : if (1 < at[n_OM].valence)
987 : : {
988 : 0 : return -1;
989 : : }
990 : :
991 : : /* if neighbors are terminal atoms then the one without isotope or with lightest isotope */
992 : 0 : num_best = 1;
993 : 0 : n_OM = (int)at[at_no].neighbor[ord_OM[0]];
994 : 0 : best_value = (int)at[n_OM].iso_atw_diff;
995 : :
996 : : /* compare periodic numbers; move indexes of the best neighbors to the first elements of ord_OM[] */
997 [ # # ]: 0 : for (i = 1; i < num_OM; i++)
998 : : {
999 : 0 : n_OM = at[at_no].neighbor[ord_OM[i]];
1000 : 0 : cur_value = (int)at[n_OM].el_number;
1001 : 0 : diff = cur_value - best_value;
1002 [ # # # # : 0 : if ((!cur_value && best_value) || diff < 0)
# # ]
1003 : : {
1004 : : /* djb-rwth: removing redundant code */
1005 : 0 : best_value = cur_value;
1006 : 0 : ord_OM[0] = ord_OM[i];
1007 : 0 : num_best = 1;
1008 : : }
1009 [ # # ]: 0 : else if (diff == 0)
1010 : : {
1011 : : /* was '=', pointed by WDI */
1012 : 0 : ord_OM[num_best++] = ord_OM[i];
1013 : : }
1014 : : }
1015 : :
1016 : 0 : num_OM = num_best;
1017 [ # # ]: 0 : if (1 == num_OM)
1018 : : {
1019 : 0 : return ord_OM[0];
1020 : : }
1021 : :
1022 : : /* return any */
1023 : 0 : return ord_OM[0];
1024 : : }
1025 : :
1026 : : /****************************************************************************
1027 : : NB:
1028 : : the bonds are fixed in fix_special_bonds()
1029 : : ****************************************************************************/
1030 : 126 : int remove_ion_pairs(int num_atoms, inp_ATOM *at)
1031 : : {
1032 : 126 : int num_changes = 0;
1033 : : #define MAX_NEIGH 6
1034 : :
1035 : : int i, n, n2, i1, i2, i3, i4, type, chrg;
1036 : 126 : int num_C_II = 0, num_C_plus = 0, num_C_minus = 0, num_N_plus = 0, num_N_minus = 0, num_O_plus = 0, num_O_minus = 0, num_All;
1037 : :
1038 : : #ifdef FIX_P_IV_Plus_O_Minus
1039 : 126 : int num_P_IV_plus = 0; /* added 2010-03-17 DT */
1040 : : #endif
1041 : :
1042 : : inp_ATOM *a;
1043 : : /****** count candidates ********/
1044 [ + + ]: 958 : for (i = 0, a = at; i < num_atoms; i++, a++)
1045 : : {
1046 [ + + + + ]: 832 : if (1 == (chrg = a->charge) || -1 == chrg)
1047 : : {
1048 [ + + - + ]: 64 : switch (ion_el_group(a->el_number))
1049 : : {
1050 : 4 : case EL_NUMBER_C:
1051 [ - + ]: 4 : if (chrg > 0)
1052 : : {
1053 : 0 : num_C_plus++;
1054 : : }
1055 : : else
1056 : : {
1057 : 4 : num_C_minus++;
1058 : : }
1059 : 4 : break;
1060 : 20 : case EL_NUMBER_O:
1061 [ - + ]: 20 : if (chrg > 0)
1062 : : {
1063 : 0 : num_O_plus++;
1064 : : }
1065 : : else
1066 : : {
1067 : 20 : num_O_minus++;
1068 : : }
1069 : 20 : break;
1070 : 0 : case EL_NUMBER_N:
1071 [ # # ]: 0 : if (chrg > 0)
1072 : : {
1073 : 0 : num_N_plus++;
1074 : : }
1075 : : else
1076 : : {
1077 : 0 : num_N_minus++;
1078 : : }
1079 : : #ifdef FIX_P_IV_Plus_O_Minus
1080 [ # # ]: 0 : num_P_IV_plus += a->el_number != EL_NUMBER_N &&
1081 : 0 : chrg == 1 &&
1082 [ # # # # ]: 0 : a->valence == 4 &&
1083 [ # # ]: 0 : a->chem_bonds_valence == 4; /* added 2010-03-17 DT */
1084 : : #endif
1085 : 0 : break;
1086 : : }
1087 : : }
1088 [ + + + + : 896 : else if (!chrg && a->chem_bonds_valence + NUMH(a, 0) == 2 &&
- + ]
1089 [ - - ]: 104 : get_el_valence(a->el_number, 0, 0) == 4 &&
1090 : 0 : ion_el_group(a->el_number) == EL_NUMBER_C)
1091 : : {
1092 : 0 : num_C_II++;
1093 : : }
1094 : : }
1095 : :
1096 : 126 : num_All = num_C_II + num_C_plus + num_C_minus + num_N_plus + num_N_minus + num_O_plus + num_O_minus;
1097 : :
1098 : : /* do not add num_P_IV_plus ! -- 2010-03-17 DT */
1099 [ + + ]: 126 : if (!num_All)
1100 : : {
1101 : 112 : return 0;
1102 : : }
1103 : :
1104 : : /**************************************************************************/
1105 : : /*************************** Terminal ion pairs ***************************/
1106 : : /**************************************************************************/
1107 : :
1108 : : /*-------------------------------------------------------------------------
1109 : : Pair type 1 N=N,P,As,Sb; O=O,S,Se,Te
1110 : : ===========
1111 : :
1112 : : X X if X is another -O(-) then neutralize O(-)
1113 : : | | that has the smallest periodic table number
1114 : : O=N(+)-O(-) => O=N=O
1115 : : i n
1116 : : --------------------------------------------------------------------------*/
1117 : :
1118 [ + + ]: 266 : for (type = 1; type <= 18; type++)
1119 : : {
1120 [ + - + + ]: 252 : if ((!type || 1 == type))
1121 : : {
1122 [ + - - + : 14 : for (i = 0; i < num_atoms && 0 < num_N_plus && 0 < num_O_minus; i++)
- - ]
1123 : : {
1124 [ # # # # : 0 : if (1 == at[i].charge && 3 == nNoMetalNumBonds(at, i) &&
# # ]
1125 [ # # ]: 0 : 4 == nNoMetalBondsValence(at, i) &&
1126 : 0 : ion_el_group(at[i].el_number) == EL_NUMBER_N)
1127 : : {
1128 : 0 : int num_OM = 0, ord_OM[3]; /* -O(-) */
1129 : 0 : int num_O = 0; /* =O */
1130 : 0 : int num_O_other = 0;
1131 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1132 : : {
1133 : 0 : n = at[i].neighbor[i1];
1134 [ # # # # : 0 : if (1 == nNoMetalNumBonds(at, n) && 0 == num_of_H(at, n) &&
# # ]
1135 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O) /* djb-rwth: ignoring LLVM warning: variable used */
1136 : : {
1137 [ # # ]: 0 : if (BOND_TYPE_SINGLE == at[i].bond_type[i1] &&
1138 [ # # ]: 0 : -1 == at[n].charge)
1139 : : {
1140 : 0 : ord_OM[num_OM++] = i1;
1141 : : }
1142 [ # # ]: 0 : else if (BOND_TYPE_DOUBLE == at[n].bond_type[0] &&
1143 [ # # ]: 0 : 0 == at[n].charge)
1144 : : {
1145 : 0 : num_O++;
1146 : : }
1147 : : else
1148 : : {
1149 : 0 : num_O_other++;
1150 : : }
1151 : : }
1152 : : }
1153 [ # # # # : 0 : if (num_OM > 0 && num_O > 0 && !num_O_other &&
# # # # ]
1154 : 0 : 0 <= (i1 = nFindOneOM(at, i, ord_OM, num_OM)))
1155 : : {
1156 : : /* remove charges and increase bond order */
1157 : 0 : n = at[i].neighbor[i1];
1158 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1159 : 0 : at[i].bond_type[i1]++;
1160 : 0 : at[n].bond_type[i2]++;
1161 : 0 : at[i].chem_bonds_valence++;
1162 : 0 : at[n].chem_bonds_valence++;
1163 : 0 : at[i].charge--;
1164 : 0 : at[n].charge++;
1165 : 0 : at[i].radical = 0;
1166 : 0 : at[n].radical = 0;
1167 : 0 : num_changes++;
1168 : 0 : num_N_plus--;
1169 : 0 : num_O_minus--;
1170 : 0 : num_All -= 2;
1171 : : }
1172 : : }
1173 : : }
1174 : :
1175 : : #ifdef FIX_P_IV_Plus_O_Minus
1176 : :
1177 : : /*-------------------------------------------------------------------------
1178 : : Pair type 1a P=P,As,Sb; O=O,S,Se,Te -- added 2010-03-17
1179 : : =============
1180 : :
1181 : : X X if X, Y, or Z is another -O(-) then neutralize O(-)
1182 : : | | that has the smallest periodic table number
1183 : : Y-P(+)-O(-) => Y-P=O
1184 : : |i n |
1185 : : Z Z
1186 : :
1187 : : --------------------------------------------------------------------------*/
1188 : :
1189 [ + - - + : 14 : for (i = 0; i < num_atoms && 0 < num_P_IV_plus /*&& 0 < num_N_plus*/ && 0 < num_O_minus; i++)
- - ]
1190 : : {
1191 [ # # # # : 0 : if (1 == at[i].charge && 4 == nNoMetalNumBonds(at, i) &&
# # ]
1192 : 0 : 4 == nNoMetalBondsValence(at, i) &&
1193 [ # # # # ]: 0 : at[i].el_number != EL_NUMBER_N && ion_el_group(at[i].el_number) == EL_NUMBER_N)
1194 : : {
1195 : 0 : int num_OM = 0, ord_OM[4]; /* -O(-) */
1196 : : /*int num_O = 0;*/ /* =O */
1197 : : /* djb-rwth: removing redundant variables */
1198 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1199 : : {
1200 : 0 : n = at[i].neighbor[i1];
1201 [ # # # # : 0 : if (1 == nNoMetalNumBonds(at, n) && 0 == num_of_H(at, n) &&
# # ]
1202 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O) /* djb-rwth: ignoring LLVM warning: variable used */
1203 : : {
1204 [ # # ]: 0 : if (BOND_TYPE_SINGLE == at[i].bond_type[i1] &&
1205 [ # # ]: 0 : -1 == at[n].charge)
1206 : : {
1207 : 0 : ord_OM[num_OM++] = i1;
1208 : : /*
1209 : : }
1210 : : if ( BOND_TYPE_DOUBLE == at[n].bond_type[0] &&
1211 : : 0 == at[n].charge ) {
1212 : : num_O ++;
1213 : : */
1214 : : }
1215 : : /* djb-rwth: removing redundant code */
1216 : : }
1217 : : }
1218 [ # # # # ]: 0 : if (num_OM > 0 /*&& num_O > 0 && !num_O_other*/ &&
1219 : 0 : 0 <= (i1 = nFindOneOM(at, i, ord_OM, num_OM)))
1220 : : {
1221 : : /* remove charges and increase bond order */
1222 : 0 : n = at[i].neighbor[i1];
1223 : 0 : i2 = is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor;
1224 : 0 : at[i].bond_type[i1]++;
1225 : 0 : at[n].bond_type[i2]++;
1226 : 0 : at[i].chem_bonds_valence++;
1227 : 0 : at[n].chem_bonds_valence++;
1228 : 0 : at[i].charge--;
1229 : 0 : at[n].charge++;
1230 : 0 : at[i].radical = 0;
1231 : 0 : at[n].radical = 0;
1232 : 0 : num_changes++;
1233 : 0 : num_N_plus--;
1234 : 0 : num_O_minus--;
1235 : 0 : num_P_IV_plus--;
1236 : 0 : num_All -= 2;
1237 : : }
1238 : : }
1239 : : }
1240 : : #endif /* FIX_P_IV_Plus_O_Minus */
1241 : : }
1242 : :
1243 : : /*-------------------------------------------------------------------------
1244 : : Terminal pair types: 2,3,4,5,6,7,8,9 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
1245 : : ====================================
1246 : : type #
1247 : : 2 2: O=N-C(II)- => O=N#C- N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
1248 : : 3 9: O=O(+)-C(-)(III) => O=O=C(IV)
1249 : : 4 3: O(-)-N(+)(IV) => O=N(V) (input structure has at least 1 double bond)
1250 : : 5 4: O(-)-O(+)(III) => O=O(IV)
1251 : : 6 8: O(-)-O-C(+)(III) => O=O=C(IV)
1252 : : 7 5: N(-)=N(+)(IV) => N#N(V) allow terminal H on N(-)
1253 : : 8 6: N(-)=O(+)(III) => N#O-
1254 : : 9 7: N(-)=C(+)(III) => N#C-
1255 : : --------------------------------------------------------------------------*/
1256 : :
1257 [ + - + + : 252 : if (!type || (2 <= type && type <= 9)) /* djb-rwth: addressing LLVM warning */
+ + ]
1258 : : {
1259 [ + + + - ]: 824 : for (i = 0; i < num_atoms && 0 < num_All; i++)
1260 : : {
1261 [ + + + + : 824 : if (0 == at[i].charge && 1 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i) &&
+ + + - ]
1262 [ + - ]: 224 : 0 == num_of_H(at, i) &&
1263 [ + - ]: 224 : ion_el_group(at[i].el_number) == EL_NUMBER_O &&
1264 : 112 : 0 <= (i1 = nNoMetalNeighIndex(at, i)) &&
1265 [ + - ]: 112 : at[i].bond_type[i1] <= BOND_TYPE_TRIPLE)
1266 : : {
1267 : : /* terminal O= */
1268 : 112 : n = at[i].neighbor[i1];
1269 [ + - + + : 112 : if ((!type || type == 2) && 0 < num_C_II)
- + ]
1270 : : {
1271 : : /* avoid alternating bonds */
1272 [ # # # # ]: 0 : if (0 == at[n].charge &&
1273 [ # # # # ]: 0 : 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
1274 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1275 [ # # ]: 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N &&
1276 : 0 : 0 <= (i2 = nNoMetalOtherNeighIndex(at, n, i)) &&
1277 [ # # ]: 0 : at[n].bond_type[i2] <= BOND_TYPE_TRIPLE)
1278 : : {
1279 : : /* i2 = index of opposite to at[i] neighbor of at[n] */
1280 : : /*i2 = (at[n].neighbor[0] == i);*/
1281 : 0 : n2 = at[n].neighbor[i2];
1282 [ # # ]: 0 : if (0 == at[n2].charge &&
1283 [ # # # # : 0 : 2 == at[n2].valence && 2 == at[n2].chem_bonds_valence &&
# # ]
1284 [ # # ]: 0 : 0 == num_of_H(at, n2) &&
1285 : 0 : ion_el_group(at[n2].el_number) == EL_NUMBER_C)
1286 : : {
1287 : : /* i n n2 */
1288 : : /* found O=N-C(II)- */
1289 : : /* convert O=N-C(II)- => O=N#C- */
1290 : :
1291 : 0 : i3 = (at[n2].neighbor[0] != n); /* index of at[n] neighbor of n2 */
1292 : 0 : at[n].chem_bonds_valence = 5; /* N */
1293 : 0 : at[n2].chem_bonds_valence = 4; /* C */
1294 : 0 : at[n].bond_type[i2] = BOND_TYPE_TRIPLE;
1295 : 0 : at[n2].bond_type[i3] = BOND_TYPE_TRIPLE;
1296 : 0 : at[n2].radical = 0;
1297 : 0 : num_changes++;
1298 : 0 : num_C_II--;
1299 : 0 : num_All--;
1300 : 0 : continue;
1301 : : }
1302 : : }
1303 : : }
1304 : :
1305 [ + - + + : 112 : if ((!type || type == 3) && 0 < num_O_plus && 0 < num_C_minus)
- + - - ]
1306 : : {
1307 [ # # # # : 0 : if (1 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
# # # # ]
1308 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1309 [ # # ]: 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O &&
1310 : 0 : 0 <= (i2 = nNoMetalOtherNeighIndex(at, n, i)) &&
1311 [ # # ]: 0 : at[n].bond_type[i2] <= BOND_TYPE_TRIPLE)
1312 : : {
1313 : : /* found O=O(+)- */
1314 : : /* i2 = index of opposite to at[i] neighbor of at[n] */
1315 : : /*i2 = (at[n].neighbor[0] == i);*/
1316 : 0 : n2 = at[n].neighbor[i2];
1317 [ # # # # : 0 : if (-1 == at[n2].charge && 3 >= nNoMetalNumBonds(at, n2) && 3 == nNoMetalBondsValence(at, n2) + NUMH(at, n2) &&
# # # # ]
1318 : 0 : ion_el_group(at[n2].el_number) == EL_NUMBER_C)
1319 : : {
1320 : : /* i n n2 */
1321 : : /* found found O=O(+)-C(-)(III) */
1322 : : /* convert O=O(+)-C(-)(III) => O=O=C(IV) */
1323 : 0 : i3 = (at[n2].neighbor[0] != n); /* index of at[n] neighbor of n2 */
1324 : 0 : at[n].charge--;
1325 : 0 : at[n2].charge++;
1326 : 0 : at[n].chem_bonds_valence += 1; /* =O- => =O= */
1327 : 0 : at[n2].chem_bonds_valence += 1; /* -C => =C */
1328 : 0 : at[n].bond_type[i2] = BOND_TYPE_DOUBLE;
1329 : 0 : at[n2].bond_type[i3] = BOND_TYPE_DOUBLE;
1330 : 0 : num_changes++;
1331 : 0 : num_O_plus--;
1332 : 0 : num_C_minus--;
1333 : 0 : num_All -= 2;
1334 : 0 : continue;
1335 : : }
1336 : : }
1337 : : }
1338 : : }
1339 : :
1340 [ + + ]: 600 : else if (-1 == at[i].charge &&
1341 [ + + ]: 192 : 0 < num_O_minus + num_N_minus &&
1342 [ - + - - ]: 160 : 0 < num_N_plus + num_O_plus + num_C_plus &&
1343 [ # # # # ]: 0 : 1 == nNoMetalNumBonds(at, i) && 1 == nNoMetalBondsValence(at, i) &&
1344 [ # # ]: 0 : 0 == num_of_H(at, i) &&
1345 [ # # ]: 0 : ion_el_group(at[i].el_number) == EL_NUMBER_O &&
1346 : 0 : 0 <= (i1 = nNoMetalNeighIndex(at, i)) &&
1347 [ # # ]: 0 : at[i].bond_type[i1] <= BOND_TYPE_TRIPLE)
1348 : : {
1349 : : /* terminal O(-)- */
1350 : 0 : n = at[i].neighbor[i1];
1351 : :
1352 [ # # # # : 0 : if ((!type || type == 4) && 0 < num_O_minus && 0 < num_N_plus && /* O(-)-N(+)(IV) */
# # # # ]
1353 [ # # # # : 0 : 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 4 == nNoMetalBondsValence(at, n) &&
# # # # ]
1354 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1355 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N /* except >O(+)- */
1356 : : )
1357 : : {
1358 : : /* found O(-)-N(+)(IV) */
1359 : : /* convert O(-)-N(+)(IV) => O=N(V) */
1360 : :
1361 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor); /* index of at[i] neighbor of at[n] */
1362 : 0 : at[i].charge++;
1363 : 0 : at[n].charge--;
1364 : 0 : at[i].chem_bonds_valence++;
1365 : 0 : at[n].chem_bonds_valence++;
1366 : 0 : at[i].bond_type[i1]++;
1367 : 0 : at[n].bond_type[i2]++;
1368 : 0 : num_changes++;
1369 : 0 : num_O_minus--;
1370 : 0 : num_N_plus--;
1371 : 0 : num_All -= 2;
1372 : 0 : continue;
1373 : : }
1374 : :
1375 [ # # # # : 0 : if ((!type || type == 5) && 0 < num_O_minus && 0 < num_O_plus && /* O(-)-O(+)(III) */
# # # # ]
1376 [ # # # # : 0 : 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
# # # # ]
1377 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1378 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O /* except >O(+)- */
1379 : : )
1380 : : {
1381 : : /* found O(+)(III) */
1382 : : /* convert O(-)-O(+)(III) => O=O(IV) */
1383 : :
1384 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor); /* index of at[i] neighbor of at[n] */
1385 : 0 : at[i].charge++;
1386 : 0 : at[n].charge--;
1387 : 0 : at[i].chem_bonds_valence++;
1388 : 0 : at[n].chem_bonds_valence++;
1389 : 0 : at[i].bond_type[i1]++;
1390 : 0 : at[n].bond_type[i2]++;
1391 : 0 : num_changes++;
1392 : 0 : num_O_minus--;
1393 : 0 : num_O_plus--;
1394 : 0 : num_All -= 2;
1395 : 0 : continue;
1396 : : }
1397 : :
1398 : : /* i n n2 */
1399 [ # # # # : 0 : if ((!type || type == 6) && /* O(-)-O-C(+)(III) */
# # ]
1400 [ # # ]: 0 : 0 < num_O_minus && 0 < num_C_plus &&
1401 [ # # # # : 0 : 0 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 2 == nNoMetalBondsValence(at, n) &&
# # # # ]
1402 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1403 [ # # ]: 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O &&
1404 : 0 : 0 <= (i2 = nNoMetalOtherNeighIndex(at, n, i)) &&
1405 [ # # ]: 0 : at[n].bond_type[i2] <= BOND_TYPE_TRIPLE)
1406 : : {
1407 : : /* found O(-)-O- */
1408 : : /* i2 = index of opposite to at[i] neighbor of at[n] */
1409 : : /*i2 = (at[n].neighbor[0] == i);*/
1410 : 0 : n2 = at[n].neighbor[i2];
1411 [ # # # # ]: 0 : if (1 == at[n2].charge && 3 >= nNoMetalNumBonds(at, n2) &&
1412 [ # # # # ]: 0 : 3 == nNoMetalBondsValence(at, n2) + NUMH(at, n2) &&
1413 : 0 : ion_el_group(at[n2].el_number) == EL_NUMBER_C)
1414 : : {
1415 : : /* i n n2 */
1416 : : /* found O(-)-O-C(+)(III) */
1417 : : /* convert O(-)-O-C(+)(III) => O=O=C(IV) */
1418 : : /*i3 = (at[n2].neighbor[0] != n);*/ /* i3 = index of at[n] neighbor of at[n2] */
1419 : 0 : i3 = (int)(is_in_the_list(at[n2].neighbor, (AT_NUMB)n, at[n2].valence) - at[n2].neighbor);
1420 : : /*i4 = index of at[i] in the adjacency list of at[n] */
1421 : 0 : i4 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1422 : 0 : at[i].charge++;
1423 : 0 : at[n2].charge--;
1424 : 0 : at[i].chem_bonds_valence += 1; /* O- => O= */
1425 : 0 : at[n].chem_bonds_valence += 2; /* -O- => =O= */
1426 : 0 : at[n2].chem_bonds_valence += 1; /* -C => =C */
1427 : 0 : at[i].bond_type[i1] = BOND_TYPE_DOUBLE;
1428 : 0 : at[n].bond_type[i4] = BOND_TYPE_DOUBLE;
1429 : 0 : at[n].bond_type[i2] = BOND_TYPE_DOUBLE;
1430 : 0 : at[n2].bond_type[i3] = BOND_TYPE_DOUBLE;
1431 : 0 : num_changes++;
1432 : 0 : num_O_minus--;
1433 : 0 : num_C_plus--;
1434 : 0 : num_All -= 2;
1435 : 0 : continue;
1436 : : }
1437 : : }
1438 : : }
1439 [ + + - + : 600 : else if (-1 == at[i].charge && 0 < num_N_minus && 0 < num_N_plus + num_O_plus + num_C_plus &&
- - - - ]
1440 [ # # # # ]: 0 : 1 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i) + NUMH(at, i) &&
1441 : : /*0 == num_of_H( at, i ) &&*/
1442 [ # # ]: 0 : ion_el_group(at[i].el_number) == EL_NUMBER_N &&
1443 : 0 : 0 <= (i1 = nNoMetalNeighIndex(at, i)) &&
1444 [ # # ]: 0 : at[i].bond_type[i1] <= BOND_TYPE_TRIPLE)
1445 : : {
1446 : : /* terminal N(-)= */
1447 : 0 : n = at[i].neighbor[i1 = 0];
1448 [ # # # # : 0 : if ((!type || type == 7) && 0 < num_N_plus && /* N(-)=N(+)(IV) */
# # ]
1449 [ # # # # : 0 : 1 == at[n].charge && 3 >= nNoMetalNumBonds(at, n) && 4 == nNoMetalBondsValence(at, n) &&
# # # # ]
1450 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1451 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N)
1452 : : {
1453 : : /* found N(-)-N(+)(IV) */
1454 : : /* convert N(-)=N(+)(IV) => N#N(V) */
1455 : :
1456 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor); /* index of at[i] neighbor of at[n] */
1457 : 0 : at[i].charge++;
1458 : 0 : at[n].charge--;
1459 : 0 : at[i].chem_bonds_valence++;
1460 : 0 : at[n].chem_bonds_valence++;
1461 : 0 : at[i].bond_type[i1]++;
1462 : 0 : at[n].bond_type[i2]++;
1463 : 0 : num_changes++;
1464 : 0 : num_N_minus--;
1465 : 0 : num_N_plus--;
1466 : 0 : num_All -= 2;
1467 : 0 : continue;
1468 : : }
1469 [ # # # # : 0 : if ((!type || type == 8) && 0 < num_O_plus && /* N(-)=O(+)(III) */
# # ]
1470 [ # # # # : 0 : 1 == at[n].charge && 2 == nNoMetalNumBonds(at, n) && 3 == nNoMetalBondsValence(at, n) &&
# # # # ]
1471 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1472 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_O)
1473 : : {
1474 : : /* found N(-)-O(+)(III) */
1475 : : /* convert N(-)=O(+)(III) => N#O(IV)- */
1476 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor); /* index of at[i] neighbor of at[n] */
1477 : 0 : at[i].charge++;
1478 : 0 : at[n].charge--;
1479 : 0 : at[i].chem_bonds_valence++;
1480 : 0 : at[n].chem_bonds_valence++;
1481 : 0 : at[i].bond_type[i1]++;
1482 : 0 : at[n].bond_type[i2]++;
1483 : 0 : num_changes++;
1484 : 0 : num_N_minus--;
1485 : 0 : num_O_plus--;
1486 : 0 : num_All -= 2;
1487 : 0 : continue;
1488 : : }
1489 [ # # # # : 0 : if ((!type || type == 9) && 0 < num_C_plus && /* N(-)=C(+)(III) */
# # ]
1490 [ # # # # : 0 : 1 == at[n].charge && 2 == at[n].valence && 3 == at[n].chem_bonds_valence &&
# # # # ]
1491 [ # # ]: 0 : 0 == num_of_H(at, n) &&
1492 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1493 : : {
1494 : : /* found N(-)=C(+)(III) */
1495 : : /* convert N(-)=C(+)(III) => N#C(IV)- */
1496 : :
1497 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor); /* index of at[i] neighbor of at[n] */
1498 : 0 : at[i].charge++;
1499 : 0 : at[n].charge--;
1500 : 0 : at[i].chem_bonds_valence++;
1501 : 0 : at[n].chem_bonds_valence++;
1502 : 0 : at[i].bond_type[i1]++;
1503 : 0 : at[n].bond_type[i2]++;
1504 : 0 : num_changes++;
1505 : 0 : num_N_minus--;
1506 : 0 : num_C_plus--;
1507 : 0 : num_All -= 2;
1508 : 0 : continue;
1509 : : }
1510 : : }
1511 : : }
1512 : : }
1513 : :
1514 : : /**************************************************************************/
1515 : : /*********************** NON-Terminal ion pairs ***************************/
1516 : : /**************************************************************************/
1517 : : /*-------------------------------------------------------------------------
1518 : : Non-Terminal pair types: 10,11,12,13,14 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
1519 : : ========================================
1520 : :
1521 : : 10: N(+)(IV)-C(-)(III) => N(V)=C(IV) (N has 3 or 2 bonds)
1522 : : 11: N(+)(IV)=C(-)(III) => N(V)#C(IV) (N has 3 or 2 bonds)
1523 : : 12: N(+)(IV)-N(-)(II) => N(V)=N(III) (allow terminal H on N(-))
1524 : : 13: -O(+)-C(-)(III) => -O=C-
1525 : : 14: -O(+)=C(-)(III) => -O#C-
1526 : : 15: O(+)(III)-N(-)(II) => O(IV)=N(III) (allow terminal H on N(-))
1527 : : --------------------------------------------------------------------------*/
1528 : :
1529 [ + - + + : 252 : if (!type || (10 <= type && type <= 15)) /* djb-rwth: addressing LLVM warning */
+ + ]
1530 : : {
1531 [ + + + - ]: 618 : for (i = 0; i < num_atoms && 0 < num_All; i++)
1532 : : {
1533 [ + + ]: 534 : if (1 == at[i].charge &&
1534 [ - + - - : 60 : 0 < num_N_plus + num_O_plus && 0 < num_C_minus + num_N_minus &&
- - ]
1535 [ # # # # ]: 0 : 4 >= nNoMetalNumBonds(at, i) && 4 == nNoMetalBondsValence(at, i) &&
1536 [ # # ]: 0 : 0 == num_of_H(at, i) &&
1537 : 0 : ion_el_group(at[i].el_number) == EL_NUMBER_N)
1538 : : {
1539 : : /* found non-terminal N(+)(IV) */
1540 [ # # # # : 0 : if ((!type || 10 == type) && 0 < num_N_plus && 0 < num_C_minus)
# # # # ]
1541 : : {
1542 : 0 : int num_neigh = 0, pos_neigh = -1;
1543 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1544 : : {
1545 : 0 : n = at[i].neighbor[i1];
1546 [ # # # # : 0 : if (-1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence + NUMH(at, n) &&
# # ]
1547 : : /*0 == at[n].num_H &&*/
1548 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
1549 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1550 : : {
1551 : : /* found N(+)(IV)-C(-)(III); prepare conversion to N(V)=C(IV) */
1552 : 0 : num_neigh++;
1553 : 0 : pos_neigh = i1;
1554 : : }
1555 : : }
1556 : 0 : i1 = pos_neigh;
1557 [ # # ]: 0 : if (1 == num_neigh &&
1558 [ # # # # ]: 0 : at[i].bond_type[i1] <= BOND_TYPE_TRIPLE &&
1559 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1]) &&
1560 : 0 : !has_other_ion_neigh(at, n, i))
1561 : : {
1562 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1563 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1564 : 0 : at[i].charge--;
1565 : 0 : at[n].charge++;
1566 : 0 : at[i].chem_bonds_valence++;
1567 : 0 : at[n].chem_bonds_valence++;
1568 : 0 : at[i].bond_type[i1]++;
1569 : 0 : at[n].bond_type[i2]++;
1570 : 0 : num_changes++;
1571 : 0 : num_C_minus--;
1572 : 0 : num_N_plus--;
1573 : 0 : num_All -= 2;
1574 : 0 : continue;
1575 : : }
1576 : : }
1577 [ # # # # : 0 : if ((!type || 11 == type) && 0 < num_N_plus && 0 < num_C_minus)
# # # # ]
1578 : : {
1579 : 0 : int num_neigh = 0, pos_neigh = -1;
1580 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1581 : : {
1582 : 0 : n = at[i].neighbor[i1];
1583 [ # # # # : 0 : if (-1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence + NUMH(at, n) &&
# # ]
1584 : : /*0 == at[n].num_H &&*/
1585 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_DOUBLE &&
1586 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1587 : : {
1588 : : /* found N(+)(IV)=C(-)(III); prepare conversion to N(V)#C(IV) */
1589 : 0 : num_neigh++;
1590 : 0 : pos_neigh = i1;
1591 : : }
1592 : : }
1593 [ # # # # ]: 0 : if (1 == num_neigh &&
1594 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1 = pos_neigh]) &&
1595 : 0 : !has_other_ion_neigh(at, n, i))
1596 : : {
1597 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1598 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1599 : 0 : at[i].charge--;
1600 : 0 : at[n].charge++;
1601 : 0 : at[i].chem_bonds_valence++;
1602 : 0 : at[n].chem_bonds_valence++;
1603 : 0 : at[i].bond_type[i1]++;
1604 : 0 : at[n].bond_type[i2]++;
1605 : 0 : num_changes++;
1606 : 0 : num_C_minus--;
1607 : 0 : num_N_plus--;
1608 : 0 : num_All -= 2;
1609 : 0 : continue;
1610 : : }
1611 : : }
1612 [ # # # # : 0 : if (!type || (12 == type && 0 < num_N_plus && 0 < num_N_minus)) /* djb-rwth: addressing LLVM warning */
# # # # ]
1613 : : {
1614 : 0 : int num_neigh = 0, pos_neigh = -1;
1615 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1616 : : {
1617 : 0 : n = at[i].neighbor[i1];
1618 [ # # # # ]: 0 : if (-1 == at[n].charge && 2 >= nNoMetalNumBonds(at, n) &&
1619 [ # # ]: 0 : 2 == nNoMetalBondsValence(at, n) + NUMH(at, n) &&
1620 : : /*0 == num_of_H( at, n ) &&*/
1621 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
1622 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N)
1623 : : {
1624 : : /* found N(+)(IV)=N(-)(II); prepare conversion to N(V)#N(III) */
1625 : 0 : num_neigh++;
1626 : 0 : pos_neigh = i1;
1627 : : }
1628 : : }
1629 [ # # # # ]: 0 : if (1 == num_neigh &&
1630 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1 = pos_neigh]) &&
1631 : 0 : !has_other_ion_neigh(at, n, i))
1632 : : {
1633 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1634 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1635 : 0 : at[i].charge--;
1636 : 0 : at[n].charge++;
1637 : 0 : at[i].chem_bonds_valence++;
1638 : 0 : at[n].chem_bonds_valence++;
1639 : 0 : at[i].bond_type[i1]++;
1640 : 0 : at[n].bond_type[i2]++;
1641 : 0 : num_changes++;
1642 : 0 : num_N_minus--;
1643 : 0 : num_N_plus--;
1644 : 0 : num_All -= 2;
1645 : 0 : continue;
1646 : : }
1647 : : }
1648 : : }
1649 [ + + - + ]: 534 : else if (1 == at[i].charge &&
1650 [ # # # # ]: 0 : 0 < num_O_plus && 0 < num_C_minus + num_N_minus &&
1651 [ # # # # ]: 0 : 3 >= nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
1652 [ # # ]: 0 : 0 == num_of_H(at, i) &&
1653 : 0 : ion_el_group(at[i].el_number) == EL_NUMBER_O)
1654 : : {
1655 : : /* found non-terminal O(+)(III) */
1656 [ # # # # : 0 : if ((!type || 13 == type) && 0 < num_C_minus)
# # ]
1657 : : {
1658 : 0 : int num_neigh = 0, pos_neigh = -1;
1659 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1660 : : {
1661 : 0 : n = at[i].neighbor[i1];
1662 [ # # # # : 0 : if (-1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence + NUMH(at, n) &&
# # ]
1663 : : /*0 == at[n].num_H &&*/
1664 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
1665 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1666 : : {
1667 : : /* found O(+)(III)-C(-)(II); prepare conversion to O(IV)=C(IV) */
1668 : 0 : num_neigh++;
1669 : 0 : pos_neigh = i1;
1670 : : }
1671 : : }
1672 [ # # # # ]: 0 : if (1 == num_neigh &&
1673 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1 = pos_neigh]) &&
1674 : 0 : !has_other_ion_neigh(at, n, i))
1675 : : {
1676 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1677 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1678 : 0 : at[i].charge--;
1679 : 0 : at[n].charge++;
1680 : 0 : at[i].chem_bonds_valence++;
1681 : 0 : at[n].chem_bonds_valence++;
1682 : 0 : at[i].bond_type[i1]++;
1683 : 0 : at[n].bond_type[i2]++;
1684 : 0 : num_changes++;
1685 : 0 : num_C_minus--;
1686 : 0 : num_O_plus--;
1687 : 0 : num_All -= 2;
1688 : 0 : continue;
1689 : : }
1690 : : }
1691 [ # # # # : 0 : if ((!type || 14 == type) && 0 < num_C_minus)
# # ]
1692 : : {
1693 : 0 : int num_neigh = 0, pos_neigh = -1;
1694 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1695 : : {
1696 : 0 : n = at[i].neighbor[i1];
1697 [ # # # # : 0 : if (-1 == at[n].charge && 3 >= at[n].valence && 3 == at[n].chem_bonds_valence + NUMH(at, n) &&
# # ]
1698 : : /*0 == at[n].num_H &&*/
1699 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_DOUBLE &&
1700 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1701 : : {
1702 : : /* found O(+)(III)=C(-)(III); prepare conversion to O(IV)#C(IV) */
1703 : 0 : num_neigh++;
1704 : 0 : pos_neigh = i1;
1705 : : }
1706 : : }
1707 [ # # # # ]: 0 : if (1 == num_neigh &&
1708 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1 = pos_neigh]) &&
1709 : 0 : !has_other_ion_neigh(at, n, i))
1710 : : {
1711 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1712 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1713 : 0 : at[i].charge--;
1714 : 0 : at[n].charge++;
1715 : 0 : at[i].chem_bonds_valence++;
1716 : 0 : at[n].chem_bonds_valence++;
1717 : 0 : at[i].bond_type[i1]++;
1718 : 0 : at[n].bond_type[i2]++;
1719 : 0 : num_changes++;
1720 : 0 : num_C_minus--;
1721 : 0 : num_O_plus--;
1722 : 0 : num_All -= 2;
1723 : 0 : continue;
1724 : : }
1725 : : }
1726 [ # # # # : 0 : if ((!type || 15 == type) && 0 < num_N_minus)
# # ]
1727 : : {
1728 : 0 : int num_neigh = 0, pos_neigh = -1;
1729 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
1730 : : {
1731 : 0 : n = at[i].neighbor[i1];
1732 [ # # # # ]: 0 : if (-1 == at[n].charge && 2 >= nNoMetalNumBonds(at, n) &&
1733 [ # # ]: 0 : 2 == nNoMetalBondsValence(at, n) + NUMH(at, n) &&
1734 : : /*0 == num_of_H( at, n ) &&*/
1735 [ # # # # ]: 0 : at[i].bond_type[i1] == BOND_TYPE_SINGLE &&
1736 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N)
1737 : : {
1738 : : /* found O(+)(III)=N(-)(II); prepare conversion to O(IV)#N(III) */
1739 : 0 : num_neigh++;
1740 : 0 : pos_neigh = i1;
1741 : : }
1742 : : }
1743 [ # # # # ]: 0 : if (1 == num_neigh &&
1744 [ # # ]: 0 : !has_other_ion_neigh(at, i, n = at[i].neighbor[i1 = pos_neigh]) &&
1745 : 0 : !has_other_ion_neigh(at, n, i))
1746 : : {
1747 : : /*n = at[i].neighbor[i1=pos_neigh];*/
1748 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1749 : 0 : at[i].charge--;
1750 : 0 : at[n].charge++;
1751 : 0 : at[i].chem_bonds_valence++;
1752 : 0 : at[n].chem_bonds_valence++;
1753 : 0 : at[i].bond_type[i1]++;
1754 : 0 : at[n].bond_type[i2]++;
1755 : 0 : num_changes++;
1756 : 0 : num_N_minus--;
1757 : 0 : num_O_plus--;
1758 : 0 : num_All -= 2;
1759 : 0 : continue;
1760 : : }
1761 : : }
1762 : : }
1763 : : }
1764 : : }
1765 : :
1766 : : /**************************************************************************/
1767 : : /*********************** NON-Terminal ion triples *************************/
1768 : : /**************************************************************************/
1769 : : /*-------------------------------------------------------------------------
1770 : : Non-Terminal triple types: 16, 17, 18 N=N,P,As,Sb; O=O,S,Se,Te; C=C,Si
1771 : : ========================================
1772 : : 16: C(+)(III)-O-N(-)(II) => C(IV)=O=N(III) (allow terminal H on N(-))
1773 : : | |
1774 : : 17: C(+)(III)-N-C(-)(III) => C(IV)=N=C(IV)
1775 : :
1776 : : 18: C(-)(III)-N=C(+)(III) => C(IV)=N#C(IV) (may have two or no charges)
1777 : : C(IV)=N-C(II) => C(IV)=N#C(IV)
1778 : :
1779 : : */
1780 : :
1781 [ + - + + : 252 : if ((!type || 16 == type) && 0 < num_C_plus && 0 < num_N_minus)
- + - - ]
1782 : : {
1783 : : int m[2], j[2], k;
1784 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1785 : : {
1786 [ # # # # : 0 : if (0 == at[i].charge && 2 == nNoMetalNumBonds(at, i) && 2 == nNoMetalBondsValence(at, i) &&
# # # # ]
1787 : 0 : 0 == num_of_H(at, i) &&
1788 [ # # ]: 0 : 0 <= (j[0] = nNoMetalNeighIndex(at, i)) &&
1789 [ # # ]: 0 : at[m[0] = at[i].neighbor[j[0]]].charge &&
1790 [ # # ]: 0 : 0 <= (j[1] = nNoMetalOtherNeighIndex(at, i, m[0])) &&
1791 [ # # ]: 0 : 0 == at[m[0]].charge + at[m[1] = at[i].neighbor[j[1]]].charge &&
1792 [ # # # # ]: 0 : 5 >= nNoMetalBondsValence(at, m[0]) + nNoMetalBondsValence(at, m[1]) &&
1793 : : /*5 >= at[m[0]].chem_bonds_valence + at[m[1]].chem_bonds_valence &&*/
1794 : 0 : ion_el_group(at[i].el_number) == EL_NUMBER_O)
1795 : : {
1796 : : /* found non-terminal A(+)-O-B(-); chem_bond_val of A+B <= 5 */
1797 : 0 : int n_N = -1, n_C = -1, i_C = -1;
1798 [ # # ]: 0 : for (k = 0; k < 2; k++)
1799 : : {
1800 : 0 : n = m[k];
1801 [ # # # # : 0 : if (-1 == at[n].charge && 2 == nNoMetalNumBonds(at, n) + NUMH(at, n) &&
# # ]
1802 : : /*0 == num_of_H( at, n ) &&*/
1803 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_N)
1804 : : {
1805 : 0 : n_N = n;
1806 : : }
1807 [ # # # # : 0 : else if (1 == at[n].charge && 3 == at[n].chem_bonds_valence + NUMH(at, n) &&
# # ]
1808 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1809 : : {
1810 : 0 : n_C = n;
1811 : 0 : i_C = k;
1812 : : }
1813 : : }
1814 [ # # # # : 0 : if (n_C < 0 || n_N < 0 ||
# # ]
1815 [ # # ]: 0 : has_other_ion_in_sphere_2(at, n_C, n_N) ||
1816 : 0 : has_other_ion_in_sphere_2(at, n_N, n_C))
1817 : : {
1818 : 0 : continue;
1819 : : }
1820 : :
1821 : : /* C(+)(III)-O-N(-)(II) => C(IV)=O=N(III) */
1822 [ # # ]: 0 : for (k = 0; k < 2; k++)
1823 : : {
1824 [ # # ]: 0 : n = k ? n_C : n_N;
1825 [ # # ]: 0 : i1 = k ? j[i_C] : j[1 - i_C];
1826 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1827 : 0 : at[i].bond_type[i1]++;
1828 : 0 : at[n].bond_type[i2]++;
1829 : 0 : at[i].chem_bonds_valence++;
1830 : 0 : at[n].chem_bonds_valence++;
1831 [ # # ]: 0 : at[n].charge += (k ? -1 : 1);
1832 : : }
1833 : 0 : num_changes++;
1834 : 0 : num_N_minus--;
1835 : 0 : num_C_plus--;
1836 : 0 : num_All -= 2;
1837 : : }
1838 : : }
1839 : : }
1840 : :
1841 [ + - + + : 252 : if ((!type || 17 == type) && 0 < num_C_plus && 0 < num_C_minus)
- + - - ]
1842 : : {
1843 : : int m[3], c[3], j[3], k;
1844 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1845 : : {
1846 [ # # # # : 0 : if (0 == at[i].charge && 3 == nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
# # # # ]
1847 : 0 : 0 == num_of_H(at, i) &&
1848 [ # # ]: 0 : 0 <= (j[0] = nNoMetalNeighIndex(at, i)) &&
1849 [ # # ]: 0 : 0 <= (j[1] = nNoMetalOtherNeighIndex(at, i, m[0] = at[i].neighbor[j[0]])) &&
1850 [ # # ]: 0 : 0 <= (j[2] = nNoMetalOtherNeighIndex2(at, i, m[0], m[1] = at[i].neighbor[j[1]])) &&
1851 [ # # ]: 0 : 1 == !(c[0] = at[m[0]].charge) + !(c[1] = at[m[1]].charge) + !(c[2] = at[m[2] = at[i].neighbor[j[2]]].charge) &&
1852 [ # # ]: 0 : 0 == c[0] + c[1] + c[2] &&
1853 [ # # # # : 0 : 2 == (3 == (c[0] ? at[m[0]].chem_bonds_valence + NUMH(at, m[0]) : 0)) + (3 == (c[1] ? at[m[1]].chem_bonds_valence + NUMH(at, m[1]) : 0)) + (3 == (c[2] ? at[m[2]].chem_bonds_valence + NUMH(at, m[2]) : 0)) &&
# # # # #
# # # # #
# # ]
1854 : 0 : ion_el_group(at[i].el_number) == EL_NUMBER_N)
1855 : : {
1856 : : /* found non-terminal A(+)-O-B(-) */
1857 : 0 : int n_Cp = -1, n_Cm = -1, i_Cp = -1, i_Cm = -1; /* p = positive, m = negatice ion C */
1858 [ # # ]: 0 : for (k = 0; k < 3; k++)
1859 : : {
1860 [ # # ]: 0 : if (c[k])
1861 : : {
1862 : 0 : n = m[k];
1863 [ # # # # ]: 0 : if (-1 == at[n].charge &&
1864 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1865 : : {
1866 : 0 : n_Cm = n;
1867 : 0 : i_Cm = k;
1868 : : }
1869 [ # # # # ]: 0 : else if (1 == at[n].charge &&
1870 : 0 : ion_el_group(at[n].el_number) == EL_NUMBER_C)
1871 : : {
1872 : 0 : n_Cp = n;
1873 : 0 : i_Cp = k;
1874 : : }
1875 : : }
1876 : : }
1877 [ # # # # : 0 : if (n_Cp < 0 || n_Cm < 0 ||
# # ]
1878 [ # # ]: 0 : has_other_ion_in_sphere_2(at, n_Cp, n_Cm) ||
1879 : 0 : has_other_ion_in_sphere_2(at, n_Cm, n_Cp))
1880 : : {
1881 : 0 : continue;
1882 : : }
1883 : :
1884 : : /* | | */
1885 : : /* C(+)(III)-N-C(-)(III) => C(IV)=N=C(IV) */
1886 [ # # ]: 0 : for (k = 0; k < 2; k++)
1887 : : {
1888 [ # # ]: 0 : n = k ? n_Cp : n_Cm;
1889 [ # # ]: 0 : i1 = k ? j[i_Cp] : j[i_Cm];
1890 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1891 : 0 : at[i].bond_type[i1]++;
1892 : 0 : at[n].bond_type[i2]++;
1893 : 0 : at[i].chem_bonds_valence++;
1894 : 0 : at[n].chem_bonds_valence++;
1895 [ # # ]: 0 : at[n].charge += (k ? -1 : 1);
1896 : : }
1897 : 0 : num_changes++;
1898 : 0 : num_C_minus--;
1899 : 0 : num_C_plus--;
1900 : 0 : num_All -= 2;
1901 : : }
1902 : : }
1903 : : }
1904 : :
1905 [ + - + + : 252 : if ((!type || 18 == type) && ((0 < num_C_plus && 0 < num_C_minus) || 0 < num_C_II)) /* djb-rwth: addressing LLVM warning */
- + - - -
+ ]
1906 : : {
1907 : : int m[2], v[2], j[2], k;
1908 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1909 : : {
1910 [ # # # # : 0 : if (0 == at[i].charge && 2 == nNoMetalNumBonds(at, i) && 3 == nNoMetalBondsValence(at, i) &&
# # # # ]
1911 : 0 : 0 == num_of_H(at, i) &&
1912 [ # # ]: 0 : 0 <= (j[0] = nNoMetalNeighIndex(at, i)) &&
1913 [ # # ]: 0 : 0 <= (j[1] = nNoMetalOtherNeighIndex(at, i, m[0] = at[i].neighbor[j[0]])) &&
1914 [ # # ]: 0 : 0 == at[m[0]].charge + at[m[1] = at[i].neighbor[j[1]]].charge &&
1915 [ # # ]: 0 : 6 == (v[0] = at[m[0]].chem_bonds_valence + NUMH(at, m[0])) + (v[1] = at[m[1]].chem_bonds_valence + NUMH(at, m[1])) &&
1916 [ # # # # : 0 : 2 >= abs(v[0] - v[1]) &&
# # ]
1917 [ # # ]: 0 : ion_el_group(at[i].el_number) == EL_NUMBER_N &&
1918 [ # # ]: 0 : ion_el_group(at[m[0]].el_number) == EL_NUMBER_C &&
1919 : 0 : ion_el_group(at[m[1]].el_number) == EL_NUMBER_C)
1920 : : {
1921 : : /* n_Cm i n_Cp */
1922 : : /* found non-terminal C(-)(III)-N=C(+)(III) or C(IV)=N-C(II): Cm-N-Cp */
1923 : : /* convert to C(IV)=N#C(IV) */
1924 : 0 : int n_Cp = -1, n_Cm = -1, i_Cp = -1, i_Cm = -1; /* p = positive, m = negatice ion C */
1925 [ # # ]: 0 : for (k = 0; k < 2; k++)
1926 : : {
1927 : 0 : n = m[k];
1928 [ # # # # : 0 : if (v[k] == 4 || (v[k] == 3 && at[i].bond_type[j[k]] == BOND_TYPE_SINGLE)) /* djb-rwth: addressing LLVM warning */
# # ]
1929 : : {
1930 : 0 : n_Cm = n;
1931 : 0 : i_Cm = k;
1932 : : }
1933 [ # # # # : 0 : else if (v[k] == 2 || (v[k] == 3 && at[i].bond_type[j[k]] == BOND_TYPE_DOUBLE)) /* djb-rwth: addressing LLVM warning */
# # ]
1934 : : {
1935 : 0 : n_Cp = n;
1936 : 0 : i_Cp = k;
1937 : : }
1938 : : }
1939 [ # # # # : 0 : if (n_Cp < 0 || n_Cm < 0 || at[n_Cp].valence + NUMH(at, n_Cp) != 2)
# # ]
1940 : : {
1941 : 0 : continue; /* guarantees at[n_Cp].valence <= 2 */
1942 : : }
1943 [ # # # # ]: 0 : if (v[i_Cp] == 2 || !at[n_Cp].charge)
1944 : : {
1945 [ # # ]: 0 : if (at[n_Cp].valence == 2)
1946 : : {
1947 : : /* neighbor of at[n_Cp] opposite to at[i] */
1948 : 0 : k = at[n_Cp].neighbor[at[n_Cp].neighbor[0] == i];
1949 [ # # ]: 0 : if (ion_el_group(at[k].el_number) == EL_NUMBER_N)
1950 : : {
1951 : 0 : continue;
1952 : : }
1953 : : }
1954 : : }
1955 [ # # ]: 0 : else if (at[n_Cp].charge)
1956 : : {
1957 [ # # # # ]: 0 : if (has_other_ion_in_sphere_2(at, n_Cp, n_Cm) ||
1958 : 0 : has_other_ion_in_sphere_2(at, n_Cm, n_Cp))
1959 : : {
1960 : 0 : continue;
1961 : : }
1962 : : }
1963 : : else
1964 : : {
1965 : 0 : continue; /* unknown case */
1966 : : }
1967 : :
1968 : : /* */
1969 : : /* C(-)(III)-N=C(+)(III) => C(IV)=N#C(IV) */
1970 : : /* C(IV)=N-C(II) => C(IV)=N#C(IV) */
1971 [ # # ]: 0 : if (at[n_Cp].charge)
1972 : : {
1973 : 0 : num_C_minus--;
1974 : 0 : num_C_plus--;
1975 : 0 : num_All -= 2;
1976 : : }
1977 : : else
1978 : : {
1979 : 0 : num_C_II--;
1980 : 0 : num_All--;
1981 : : }
1982 : :
1983 [ # # ]: 0 : for (k = 0; k < 2; k++)
1984 : : {
1985 [ # # ]: 0 : n = k ? n_Cp : n_Cm;
1986 [ # # ]: 0 : i3 = k ? i_Cp : i_Cm; /* added to fix the bug */
1987 : : /*i1 = k? j[i_Cp] : j[i_Cm];*/ /* replaced with next line */
1988 : 0 : i1 = j[i3];
1989 [ # # ]: 0 : if (v[i3 /*was i1*/] < 4)
1990 : : {
1991 : : /* WDI found a bug here: bounds violation */
1992 : 0 : int delta = 4 - v[i3 /*was i1*/];
1993 : 0 : i2 = (int)(is_in_the_list(at[n].neighbor, (AT_NUMB)i, at[n].valence) - at[n].neighbor);
1994 : 0 : at[i].bond_type[i1] += delta;
1995 : 0 : at[n].bond_type[i2] += delta;
1996 : 0 : at[i].chem_bonds_valence += delta;
1997 : 0 : at[n].chem_bonds_valence += delta;
1998 : 0 : at[n].charge = 0;
1999 : 0 : at[n].radical = 0;
2000 : : }
2001 : : }
2002 : 0 : at[i].charge = 0;
2003 : 0 : at[i].radical = 0;
2004 : 0 : num_changes++;
2005 : : }
2006 : : }
2007 : : }
2008 : : }
2009 : :
2010 : 14 : return num_changes;
2011 : : }
2012 : :
2013 : : /*#if ( DISCONNECT_SALTS == 1 )*/ /* { */
2014 : :
2015 : : /****************************************************************************/
2016 : 80 : int RemoveInpAtBond(inp_ATOM *atom, int iat, int k)
2017 : : {
2018 : : int i, j, m, m2; /* djb-rwth: removing redundant variables */
2019 : 80 : inp_ATOM *at = atom + iat;
2020 : 80 : inp_ATOM *at2 = NULL;
2021 : 80 : int val = at->valence - 1;
2022 : :
2023 [ + - ]: 80 : if (val >= 0)
2024 : : {
2025 : 80 : int bond = at->bond_type[k];
2026 [ + + ]: 80 : if (bond > BOND_TYPE_TRIPLE)
2027 : 34 : bond = BOND_TYPE_SINGLE; /* added 08-06-2003 */
2028 : :
2029 : : /* update CML tetrahedral atom parity. */
2030 [ - + ]: 80 : if (at->p_parity)
2031 : : {
2032 [ # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_ATOM_NEIGH; m++)
2033 : : {
2034 [ # # ]: 0 : if (at->p_orig_at_num[m] == at->orig_at_number)
2035 : : {
2036 : 0 : at->p_parity = 0;
2037 : 0 : break; /* only 3 bonds are present; removing one bond removes stereo */
2038 : : }
2039 : : }
2040 [ # # ]: 0 : if (at->p_parity /* at->valence == MAX_NUM_STEREO_ATOM_NEIGH*/)
2041 : : {
2042 : : /* p_orig_at_num is a fixed size array of MAX_NUM_STEREO_ATOM_NEIGH (4) elements */
2043 [ # # # # ]: 0 : for (m = 0; m < at->valence && m < MAX_NUM_STEREO_ATOM_NEIGH; m++) /* djb-rwth: fixing GH PR #72 */
2044 : : {
2045 [ # # ]: 0 : if (atom[(int)at->neighbor[k]].orig_at_number == at->p_orig_at_num[m])
2046 : : {
2047 : 0 : break;
2048 : : }
2049 : : }
2050 [ # # # # ]: 0 : if (m < at->valence && m < MAX_NUM_STEREO_ATOM_NEIGH) /* djb-rwth: fixing GH PR #72 */
2051 : : {
2052 : 0 : at->p_orig_at_num[m] = at->orig_at_number;
2053 : : }
2054 : : else
2055 : : {
2056 : 0 : at->p_parity = 0; /* wrong neighbors: at->neighbor[k] is not in the list of a stereo neighbors */
2057 : : }
2058 : : }
2059 : : }
2060 : :
2061 : : /* update CML stereogenic bond parities; at this point no removed explicit H exist yet */
2062 [ - + ]: 80 : if (at->sb_parity[0])
2063 : : {
2064 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at->sb_parity[m];)
2065 : : {
2066 [ # # # # : 0 : if (k == at->sb_ord[m] || (k == at->sn_ord[m] && val < 2 && ATOM_PARITY_WELL_DEF(at->sb_parity[m]))) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
2067 : 0 : {
2068 : : /* !!! FLAW: does take into account removed H !!! */
2069 : : /* stereogenic bond is being removed OR */
2070 : : /* remove stereogenic bond because its only neighbor is being removed */
2071 : : int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
2072 : 0 : int len = get_opposite_sb_atom(atom, iat, at->sb_ord[m], &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord);
2073 [ # # ]: 0 : if (len)
2074 : : {
2075 : 0 : i = pinxt_sb_parity_ord;
2076 : 0 : at2 = atom + pnxt_atom;
2077 : : /* djb-rwth: removing redundant code */
2078 : : }
2079 : : else
2080 : : {
2081 : 0 : i = MAX_NUM_STEREO_BONDS;
2082 : : }
2083 : : /*
2084 : : at2 = atom + at->neighbor[ (int)at->sb_ord[m] ];
2085 : : for ( i = 0; i < MAX_NUM_STEREO_BONDS && at2->sb_parity[i]; i ++ )
2086 : : {
2087 : : if ( iat == at2->neighbor[ (int)at2->sb_ord[i] ] )
2088 : : break;
2089 : : }
2090 : : */
2091 [ # # # # ]: 0 : if (i < MAX_NUM_STEREO_BONDS && at2->sb_parity[i])
2092 : : {
2093 : 0 : m2 = i;
2094 : : /* remove bond parity from at */
2095 [ # # ]: 0 : if (m < MAX_NUM_STEREO_BONDS - 1)
2096 : : {
2097 : 0 : memmove(at->sb_parity + m, at->sb_parity + m + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m) * sizeof(at->sb_parity[0])); /* djb-rwth: cast operator added */
2098 : 0 : memmove(at->sb_ord + m, at->sb_ord + m + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m) * sizeof(at->sb_ord[0])); /* djb-rwth: cast operator added */
2099 : 0 : memmove(at->sn_ord + m, at->sn_ord + m + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m) * sizeof(at->sn_ord[0])); /* djb-rwth: cast operator added */
2100 : 0 : memmove(at->sn_orig_at_num + m, at->sn_orig_at_num + m + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m) * sizeof(at->sn_orig_at_num[0])); /* djb-rwth: cast operator added */
2101 : : }
2102 : 0 : at->sb_parity[MAX_NUM_STEREO_BONDS - 1] = 0;
2103 : 0 : at->sb_ord[MAX_NUM_STEREO_BONDS - 1] = 0;
2104 : 0 : at->sn_ord[MAX_NUM_STEREO_BONDS - 1] = 0;
2105 : 0 : at->sn_orig_at_num[MAX_NUM_STEREO_BONDS - 1] = 0;
2106 : : /* remove bond parity from at2 */
2107 [ # # ]: 0 : if (m2 < MAX_NUM_STEREO_BONDS - 1)
2108 : : {
2109 : 0 : memmove(at2->sb_parity + m2, at2->sb_parity + m2 + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m2) * sizeof(at2->sb_parity[0])); /* djb-rwth: cast operator added */
2110 : 0 : memmove(at2->sb_ord + m2, at2->sb_ord + m2 + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m2) * sizeof(at2->sb_ord[0])); /* djb-rwth: cast operator added */
2111 : 0 : memmove(at2->sn_ord + m2, at2->sn_ord + m2 + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m2) * sizeof(at2->sn_ord[0])); /* djb-rwth: cast operator added */
2112 : 0 : memmove(at2->sn_orig_at_num + m2, at2->sn_orig_at_num + m2 + 1, (MAX_NUM_STEREO_BONDS - 1 - (long long)m2) * sizeof(at2->sn_orig_at_num[0])); /* djb-rwth: cast operator added */
2113 : : }
2114 : 0 : at2->sb_parity[MAX_NUM_STEREO_BONDS - 1] = 0;
2115 : 0 : at2->sb_ord[MAX_NUM_STEREO_BONDS - 1] = 0;
2116 : 0 : at2->sn_ord[MAX_NUM_STEREO_BONDS - 1] = 0;
2117 : 0 : at2->sn_orig_at_num[MAX_NUM_STEREO_BONDS - 1] = 0;
2118 : : /* do not increment m here because the array elements have been shifted */
2119 : : }
2120 : : else
2121 : : {
2122 : 0 : m++; /* program error: inconsistent stereobond parity */
2123 : : }
2124 : : }
2125 [ # # ]: 0 : else if (k == at->sn_ord[m])
2126 : : {
2127 : : /* stereogenic bond neighbor is being removed; another neighbor remains */
2128 : : /* !!! FLAW: does take into account removed H !!! */
2129 [ # # ]: 0 : for (j = 0, i = -1; j < at->valence; j++)
2130 : : {
2131 [ # # # # ]: 0 : if (j != k && j != at->sb_ord[m])
2132 : : {
2133 : 0 : i = j;
2134 : 0 : break;
2135 : : }
2136 : : }
2137 : :
2138 : : /* i is the position of the neighbor that will become a new neighbor */
2139 : : /***************************************************************************
2140 : : * at->sb_parity[m] is the direction (EVEN=clockwise, ODD=counterclockwise)
2141 : : * from stereobond to the neighbor. If the neighbor is removed then
2142 : : * the parity should invert, otherwise it should be unchanged.
2143 : : ***************************************************************************/
2144 [ # # ]: 0 : if (i < 0)
2145 : : {
2146 : : /* no alternative neighbor is available */
2147 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(at->sb_parity[m]))
2148 : : {
2149 : : /* parity cannot be not well-defined anymore */
2150 : : int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
2151 : 0 : int len = get_opposite_sb_atom(atom, iat, at->sb_ord[m], &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord);
2152 [ # # ]: 0 : if (len > 0)
2153 : : {
2154 : 0 : atom[pnxt_atom].sb_parity[pinxt_sb_parity_ord] = at->sb_parity[m] = AB_PARITY_UNDF;
2155 : : }
2156 : : }
2157 : 0 : at->sn_ord[m] = -99; /* sb neighbor has been disconnected */
2158 : 0 : at->sb_ord[m] -= (at->sb_ord[m] > k); /* same as above */
2159 : 0 : at->sn_orig_at_num[m] = 0;
2160 : : }
2161 [ # # ]: 0 : else if (i < at->valence)
2162 : : {
2163 : : /* choose another stereogenic bond neighbor, its ord. number is i before bond removal */
2164 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF(at->sb_parity[m]))
2165 : : {
2166 : : /* ALL WRONG: 'move' previous stereo bond neighbor to the last position (pos. 2 out of 0,1,2) */
2167 : : /* the parity of the transpositions is (2 - at->sn_ord[m])%2 = at->sn_ord[m] % 2 */
2168 : : /* and replace the neighbor with another; the contribution to the parity is 1 */
2169 : :
2170 : : /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + at->sn_ord[m] + 1 ) % 2;*/
2171 : :
2172 : : /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + k + i +
2173 : : (i > k) + (i > at->sb_ord[m]) ) % 2;*/
2174 : : /*=== parity should be INVERTED ===*/
2175 : 0 : at->sb_parity[m] = 3 - at->sb_parity[m];
2176 : : }
2177 : 0 : at->sn_ord[m] = i - (i > k); /* ord. number shifted because preceding bond is removed */
2178 : 0 : at->sb_ord[m] -= (at->sb_ord[m] > k); /* same as above */
2179 : 0 : at->sn_orig_at_num[m] = atom[(int)at->neighbor[i]].orig_at_number;
2180 : : /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + 1 ) % 2;*/
2181 : : }
2182 : : else
2183 : : {
2184 : 0 : at->sb_parity[m] = 0; /* program error: inconsistent stereobond parity */
2185 : : }
2186 : 0 : m++;
2187 : : }
2188 : : else
2189 : : {
2190 : : /* removing another neighbor, k: first move it to the last position (pos. 2 out of 0,1,2) */
2191 [ # # # # ]: 0 : if (k < 2 && ATOM_PARITY_WELL_DEF(at->sb_parity[m]))
2192 : : {
2193 : : /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + k ) % 2;*/
2194 : : /*at->sb_parity[m] = 2 - ( at->sb_parity[m] + (at->sn_ord[m] > k) + (at->sb_ord[m] > k) ) % 2;*/
2195 : : ; /*==== Parity should remain UNCHANGED ===*/
2196 : : }
2197 [ # # ]: 0 : if (at->sb_ord[m] > k)
2198 : : {
2199 : 0 : at->sb_ord[m]--;
2200 : : }
2201 [ # # ]: 0 : if (at->sn_ord[m] > k)
2202 : : {
2203 : 0 : at->sn_ord[m]--;
2204 : : }
2205 : 0 : m++;
2206 : : }
2207 : : }
2208 : : }
2209 : :
2210 [ + + ]: 80 : if (k < val)
2211 : : {
2212 : 4 : memmove(at->neighbor + k, at->neighbor + k + 1, sizeof(at->neighbor[0]) * ((long long)val - (long long)k)); /* djb-rwth: cast operators added */
2213 : 4 : memmove(at->bond_stereo + k, at->bond_stereo + k + 1, sizeof(at->bond_stereo[0]) * ((long long)val - (long long)k)); /* djb-rwth: cast operators added */
2214 : 4 : memmove(at->bond_type + k, at->bond_type + k + 1, sizeof(at->bond_type[0]) * ((long long)val - (long long)k)); /* djb-rwth: cast operators added */
2215 : : }
2216 : :
2217 : 80 : at->neighbor[val] = 0;
2218 : 80 : at->bond_stereo[val] = 0;
2219 : 80 : at->bond_type[val] = 0;
2220 : 80 : at->valence = val;
2221 : 80 : at->chem_bonds_valence -= bond;
2222 : 80 : return 1;
2223 : : }
2224 : :
2225 : 0 : return 0;
2226 : : }
2227 : :
2228 : : /****************************************************************************/
2229 : 40 : int DisconnectInpAtBond(inp_ATOM *at,
2230 : : AT_NUMB *nOldCompNumber,
2231 : : int iat,
2232 : : int neigh_ord)
2233 : : {
2234 : 40 : int neigh, i, ret = 0;
2235 : : int component;
2236 : 40 : neigh = at[iat].neighbor[neigh_ord];
2237 : :
2238 [ + - ]: 100 : for (i = 0; i < at[neigh].valence; i++)
2239 : : {
2240 [ + + ]: 100 : if (iat == (int)at[neigh].neighbor[i])
2241 : : {
2242 : 40 : break;
2243 : : }
2244 : : }
2245 : :
2246 [ + - ]: 40 : if (i < at[neigh].valence)
2247 : : {
2248 : 40 : ret += RemoveInpAtBond(at, iat, neigh_ord);
2249 : 40 : ret += RemoveInpAtBond(at, neigh, i);
2250 [ + + + - ]: 40 : if (nOldCompNumber && ret)
2251 : : {
2252 [ + - ]: 15 : if ((component = at[iat].component)) /* djb-rwth: addressing LLVM warning */
2253 : : {
2254 : 15 : nOldCompNumber[component - 1] = 0;
2255 : : }
2256 [ + - ]: 15 : if ((component = at[neigh].component)) /* djb-rwth: addressing LLVM warning */
2257 : : {
2258 : 15 : nOldCompNumber[component - 1] = 0;
2259 : : }
2260 : : }
2261 : : }
2262 : :
2263 : 40 : return (ret == 2);
2264 : : }
2265 : :
2266 : : /****************************************************************************/
2267 : 1391 : int bIsAmmoniumSalt(inp_ATOM *at,
2268 : : int i,
2269 : : int *piO,
2270 : : int *pk,
2271 : : S_CHAR *num_explicit_H)
2272 : : {
2273 : : /* NH4(+charge)-O(-charge)-C -> NH3 + HO-C; any charge including 0, */
2274 : : /* any C except charged or radical F, Cl, Br, I */
2275 : :
2276 : 1391 : int num_H, num_non_iso_H, num_impl_iso_H, bDisconnect = 1;
2277 : 1391 : int j, val, neigh, iO = -1, iC, k = -1;
2278 : :
2279 [ + + ]: 1391 : if (at[i].el_number != EL_NUMBER_N)
2280 : : {
2281 : 1357 : return 0;
2282 : : }
2283 : :
2284 : : /* check for NH4-O-C... -> NH3 + HO-C... */
2285 : 34 : val = at[i].valence;
2286 : 34 : num_impl_iso_H = NUM_ISO_H(at, i);
2287 : 34 : num_non_iso_H = at[i].num_H;
2288 : 34 : num_H = num_non_iso_H + num_impl_iso_H;
2289 [ - + ]: 34 : if (val + num_H == 5)
2290 : : {
2291 : 0 : int num_O = 0;
2292 : 0 : memset(num_explicit_H, 0, (NUM_H_ISOTOPES + 1) * sizeof(num_explicit_H[0])); /* djb-rwth: memset_s C11/Annex K variant? */
2293 [ # # ]: 0 : for (j = 0; j < val; j++)
2294 : : { /* looking for O: H4N-O-C... */
2295 : 0 : neigh = at[i].neighbor[j];
2296 [ # # ]: 0 : if (at[neigh].num_H ||
2297 [ # # # # : 0 : (at[neigh].charge && (at[neigh].el_number != EL_NUMBER_O || at[neigh].charge + at[i].charge)) ||
# # ]
2298 [ # # # # ]: 0 : (at[neigh].radical && at[neigh].radical != RADICAL_SINGLET)) /* djb-rwth: addressing LLVM warnings */
2299 : : {
2300 : 0 : bDisconnect = 0;
2301 : 0 : break; /* reject */
2302 : : }
2303 [ # # # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_H && at[neigh].valence == 1 &&
2304 [ # # # # ]: 0 : !at[neigh].charge && !at[neigh].radical)
2305 : : {
2306 : 0 : num_H++; /* at this point at[].num_H does not include explicit H count */
2307 : 0 : num_non_iso_H += (0 == at[neigh].iso_atw_diff);
2308 : 0 : num_explicit_H[at[neigh].iso_atw_diff]++; /* explicit H on N */
2309 : : }
2310 [ # # # # : 0 : else if (at[neigh].el_number == EL_NUMBER_O && at[neigh].valence == 2 && !num_O)
# # ]
2311 : : {
2312 : 0 : num_O++; /* found O: N-O- */
2313 : 0 : iO = neigh;
2314 : 0 : k = j;
2315 : 0 : iC = at[iO].neighbor[at[iO].neighbor[0] == i];
2316 [ # # ]: 0 : if (at[iC].el_number != EL_NUMBER_C || /*
2317 : : at[iC].num_H ||
2318 : : at[iC].chem_bonds_valence != 4 || */
2319 [ # # ]: 0 : at[iC].charge ||
2320 [ # # # # ]: 0 : (at[iC].radical && at[iC].radical != RADICAL_SINGLET) /*||
2321 : : at[iC].valence == at[iC].chem_bonds_valence*/
2322 : : ) /* djb-rwth: addressing LLVM warning */
2323 : : {
2324 : 0 : bDisconnect = 0;
2325 : 0 : break; /* reject */
2326 : : }
2327 : : }
2328 [ # # ]: 0 : else if ((at[neigh].el_number == EL_NUMBER_F ||
2329 [ # # ]: 0 : at[neigh].el_number == EL_NUMBER_CL ||
2330 [ # # ]: 0 : at[neigh].el_number == EL_NUMBER_BR ||
2331 [ # # ]: 0 : at[neigh].el_number == EL_NUMBER_I) &&
2332 [ # # # # ]: 0 : at[neigh].valence == 1 && at[neigh].chem_bonds_valence == 1 &&
2333 [ # # # # : 0 : !at[neigh].charge && !NUMH(at, neigh) && !num_O)
# # ]
2334 : : {
2335 : 0 : num_O++; /* found O: N-O- */
2336 : 0 : iO = neigh;
2337 : 0 : k = j;
2338 : : /* djb-rwth: removing redundant code */
2339 : : }
2340 : : else
2341 : : {
2342 : 0 : bDisconnect = 0;
2343 : 0 : break; /* reject */
2344 : : }
2345 : : }
2346 [ # # # # : 0 : if (bDisconnect && (num_O != 1 || num_H != 4))
# # ]
2347 : : {
2348 : 0 : bDisconnect = 0; /* reject */
2349 : : }
2350 : : }
2351 : : else
2352 : : {
2353 : 34 : bDisconnect = 0;
2354 : : }
2355 [ - + ]: 34 : if (bDisconnect)
2356 : : {
2357 : 0 : *piO = iO;
2358 : 0 : *pk = k;
2359 : : }
2360 : :
2361 : 34 : return bDisconnect;
2362 : : }
2363 : :
2364 : : /****************************************************************************/
2365 : 0 : int DisconnectAmmoniumSalt(inp_ATOM *at,
2366 : : int iN,
2367 : : int iO,
2368 : : int k,
2369 : : S_CHAR *num_explicit_H)
2370 : : {
2371 : :
2372 : : /* disconnect NH4-O from O */
2373 : : /* Note: iO = at[iN].neighbor[k], at[iN] is N, at[iO].neighbor[0] is either N=at[iN] or C=at[iC] */
2374 : :
2375 : 0 : int nMove_H_iso_diff = -1; /* do not move explicit H */
2376 : : int j, neigh, iso_diff, neigh_pos;
2377 : 0 : int val = at[iN].valence;
2378 : :
2379 [ # # # # ]: 0 : if (at[iN].charge && !(at[iN].charge + at[iO].charge))
2380 : : {
2381 : 0 : at[iN].charge = at[iO].charge = 0; /* remove charges */
2382 : : }
2383 : :
2384 [ # # # # ]: 0 : neigh_pos = (at[iO].valence == 2) ? (at[iO].neighbor[1] == iN) : 0; /* position of at[iN] in the neigh list of iO */
2385 : : /* disconnect bond O-N */
2386 : 0 : RemoveInpAtBond(at, iO, neigh_pos);
2387 : 0 : RemoveInpAtBond(at, iN, k);
2388 : 0 : val--;
2389 : :
2390 : : /* move 1 H from NH4 to O- or Cl */
2391 : :
2392 : : /* find non-isotopic or the lightest isotopic H to move from N to O */
2393 [ # # ]: 0 : for (iso_diff = 0; iso_diff <= NUM_H_ISOTOPES; iso_diff++) /* djb-rwth: fixing GH PR #72 */
2394 : : {
2395 [ # # ]: 0 : if (!iso_diff)
2396 : : {
2397 : : /* find non-isotopic H */
2398 [ # # ]: 0 : if (at[iN].num_H)
2399 : : {
2400 : 0 : at[iN].num_H--; /* move non-isotopic implicit H */
2401 : 0 : at[iO].num_H++;
2402 : 0 : break;
2403 : : }
2404 [ # # ]: 0 : else if (num_explicit_H[0])
2405 : : {
2406 : 0 : nMove_H_iso_diff = 0; /* flag: move explicit non-isotopic H */
2407 : 0 : break;
2408 : : }
2409 : : }
2410 : : else
2411 : : {
2412 : : /* find isotopic H */
2413 : : /* num_iso_H has length NUM_H_ISOTOPES; do not access out-of-bounds */
2414 [ # # # # ]: 0 : if ((iso_diff < NUM_H_ISOTOPES) && at[iN].num_iso_H[iso_diff]) /* djb-rwth: fixing GH PR #72 */
2415 : : {
2416 : 0 : at[iN].num_iso_H[iso_diff]--; /* move implicit isotopic H, atw = 1 */
2417 : 0 : at[iO].num_iso_H[iso_diff]++;
2418 : 0 : break;
2419 : : }
2420 : : else
2421 : : {
2422 [ # # ]: 0 : if (num_explicit_H[iso_diff])
2423 : : {
2424 : 0 : nMove_H_iso_diff = iso_diff; /* flag: move explicit isotopic H, atw = 1 */
2425 : 0 : break;
2426 : : }
2427 : : }
2428 : : }
2429 : : }
2430 : :
2431 [ # # ]: 0 : if (nMove_H_iso_diff >= 0)
2432 : : {
2433 : : /* move explicit H, it is isotopic if nMove_H_iso_diff > 0 */
2434 : 0 : double dist2_H_O, min_dist2_H_O = -1.0;
2435 : 0 : int jH = -1, iH = -1;
2436 [ # # ]: 0 : for (j = 0; j < val; j++)
2437 : : { /* looking H in N-H such that H-O is shortest */
2438 : 0 : neigh = at[iN].neighbor[j];
2439 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_H &&
2440 [ # # ]: 0 : at[neigh].iso_atw_diff == nMove_H_iso_diff)
2441 : : {
2442 : 0 : dist2_H_O = (at[neigh].x - at[iO].x) * (at[neigh].x - at[iO].x) +
2443 : 0 : (at[neigh].y - at[iO].y) * (at[neigh].y - at[iO].y) +
2444 : 0 : (at[neigh].z - at[iO].z) * (at[neigh].z - at[iO].z);
2445 [ # # # # ]: 0 : if (min_dist2_H_O < 0.0 || min_dist2_H_O > dist2_H_O)
2446 : : {
2447 : 0 : min_dist2_H_O = dist2_H_O;
2448 : 0 : iH = neigh;
2449 : 0 : jH = j;
2450 : : }
2451 : : }
2452 : : }
2453 : :
2454 : : /* reconnect; bonds do not need changes except stereo */
2455 : 0 : neigh_pos = at[iO].valence;
2456 : 0 : at[iO].neighbor[neigh_pos] = iH;
2457 : 0 : at[iO].bond_stereo[neigh_pos] = 0;
2458 : 0 : at[iO].bond_type[neigh_pos] = at[iH].bond_type[0];
2459 : 0 : at[iO].chem_bonds_valence += at[iH].bond_type[0];
2460 : 0 : at[iO].valence++;
2461 : 0 : at[iH].neighbor[0] = iO;
2462 : 0 : at[iH].bond_stereo[0] = 0;
2463 : :
2464 : : /* disconnect H from N */
2465 : 0 : RemoveInpAtBond(at, iN, jH);
2466 : 0 : val--;
2467 [ # # ]: 0 : if (k > jH)
2468 : : {
2469 : 0 : k--;
2470 : : }
2471 : : }
2472 : :
2473 : 0 : return 1;
2474 : : }
2475 : :
2476 : : /****************************************************************************/
2477 : 1233 : int bIsMetalSalt(inp_ATOM *at, int i)
2478 : : {
2479 : : int type, val, k, iO, iC, j, neigh;
2480 : 1233 : int bDisconnect = 1;
2481 : :
2482 : : /* check for a metal atom:
2483 : : metal atom should be connected and be a metal */
2484 [ + - + + ]: 2466 : if (!(val = at[i].valence) ||
2485 : 1233 : !(type = get_el_type(at[i].el_number)) ||
2486 [ - + ]: 15 : !(type & IS_METAL))
2487 : : {
2488 : 1218 : bDisconnect = 0; /* reject */
2489 : : }
2490 [ - + ]: 15 : else if (at[i].num_H)
2491 : : /* metal atom should not have adjacent H or multiple bonds or radical */
2492 : : {
2493 : 0 : bDisconnect = 0; /* reject */
2494 : : }
2495 : : else
2496 : : {
2497 : : /* check valence */
2498 [ + + ]: 15 : if ((at[i].charge == 0 &&
2499 [ + - + - ]: 14 : (((type & 1) && val == get_el_valence(at[i].el_number, 0, 0)) ||
2500 [ + + + + ]: 14 : ((type & 2) && val == get_el_valence(at[i].el_number, 0, 1)))) ||
2501 [ - + ]: 13 : (at[i].charge > 0 &&
2502 [ # # # # ]: 0 : (type & 1) && val == get_el_valence(at[i].el_number, at[i].charge, 0))) /* djb-rwth: addressing LLVM warnings */
2503 : : {
2504 : : ; /* accept */
2505 : : }
2506 : : else
2507 : : {
2508 : 13 : bDisconnect = 0; /* reject */
2509 : : }
2510 : : }
2511 : :
2512 [ + + ]: 1233 : if (bDisconnect)
2513 : : {
2514 : : /*************************************************************************
2515 : : * | *
2516 : : * check M neighbors. Disconnect if all neighbors are M-O-C# or M-O-C= *
2517 : : * | *
2518 : : *************************************************************************/
2519 [ + + ]: 5 : for (k = 0; k < at[i].valence; k++)
2520 : : {
2521 : 4 : iO = at[i].neighbor[k];
2522 : : /* halogenide 2004-07-08 */
2523 [ + - ]: 4 : if ((at[iO].el_number == EL_NUMBER_F ||
2524 [ + + ]: 4 : at[iO].el_number == EL_NUMBER_CL ||
2525 [ + - ]: 1 : at[iO].el_number == EL_NUMBER_BR ||
2526 [ - + ]: 1 : at[iO].el_number == EL_NUMBER_I) &&
2527 [ + - + - ]: 3 : at[iO].valence == 1 && at[iO].chem_bonds_valence == 1 &&
2528 [ + - - + : 3 : !at[iO].charge && !(at[iO].radical && at[iO].radical != RADICAL_SINGLET) && !NUMH(at, iO))
- - + - ]
2529 : : {
2530 : : ; /* found */
2531 : : }
2532 : : else
2533 : : {
2534 : : /* -O-C= */
2535 [ - + ]: 1 : if (at[iO].el_number != EL_NUMBER_O ||
2536 [ # # ]: 0 : NUMH(at, iO) ||
2537 [ # # ]: 0 : at[iO].valence != 2 ||
2538 [ # # ]: 0 : at[iO].charge ||
2539 [ # # # # ]: 0 : (at[iO].radical && at[iO].radical != RADICAL_SINGLET) ||
2540 [ # # ]: 0 : at[iO].valence != at[iO].chem_bonds_valence) /* djb-rwth: addressing LLVM warning */
2541 : : {
2542 : 1 : bDisconnect = 0; /* reject */
2543 : 1 : break;
2544 : : }
2545 : 0 : iC = at[iO].neighbor[at[iO].neighbor[0] == i];
2546 [ # # ]: 0 : if (at[iC].el_number != EL_NUMBER_C ||
2547 [ # # ]: 0 : at[iC].num_H ||
2548 [ # # ]: 0 : at[iC].chem_bonds_valence != 4 ||
2549 [ # # ]: 0 : at[iC].charge ||
2550 [ # # # # ]: 0 : (at[iC].radical && at[iC].radical != RADICAL_SINGLET) ||
2551 [ # # ]: 0 : at[iC].valence == at[iC].chem_bonds_valence) /* djb-rwth: addressing LLVM warning */
2552 : : {
2553 : 0 : bDisconnect = 0; /* reject */
2554 : 0 : break;
2555 : : }
2556 [ # # ]: 0 : for (j = 0; j < at[iC].valence; j++)
2557 : : {
2558 : 0 : neigh = at[iC].neighbor[j];
2559 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_H)
2560 : : {
2561 : 0 : break;
2562 : : }
2563 : : }
2564 [ # # ]: 0 : if (j != at[iC].valence)
2565 : : {
2566 : 0 : bDisconnect = 0; /* reject */
2567 : 0 : break;
2568 : : }
2569 : : }
2570 : : }
2571 : : }
2572 : :
2573 : 1233 : return bDisconnect;
2574 : : }
2575 : :
2576 : : /****************************************************************************/
2577 : 0 : int DisconnectMetalSalt(inp_ATOM *at, int i)
2578 : : {
2579 : : int k, iO;
2580 : : /* disconnect metal atom or ion at[i] */
2581 : :
2582 [ # # ]: 0 : for (k = 0; k < at[i].valence; k++)
2583 : : {
2584 : 0 : iO = at[i].neighbor[k];
2585 [ # # ]: 0 : if (at[iO].valence == 2)
2586 : : {
2587 [ # # ]: 0 : if (at[iO].neighbor[0] == i)
2588 : : {
2589 : : /* assuming atom O always has 2 bonds */
2590 : : /* copy the remaining neighbor to the 0 position */
2591 : 0 : at[iO].neighbor[0] = at[iO].neighbor[1];
2592 : 0 : at[iO].bond_stereo[0] = at[iO].bond_stereo[1];
2593 : 0 : at[iO].bond_type[0] = at[iO].bond_type[1];
2594 : : }
2595 : : /* clear neighbor at position 1 */
2596 : 0 : at[iO].neighbor[1] = 0;
2597 : 0 : at[iO].bond_stereo[1] = 0;
2598 : 0 : at[iO].bond_type[1] = 0;
2599 : : }
2600 : : else
2601 : : {
2602 : : /* clear neighbor at position 1 */
2603 : 0 : at[iO].neighbor[0] = 0;
2604 : 0 : at[iO].bond_stereo[0] = 0;
2605 : 0 : at[iO].bond_type[0] = 0;
2606 : : }
2607 : :
2608 : : /* make O negatively charged */
2609 : 0 : at[iO].charge = -1;
2610 : :
2611 : : /* reduce O valence to account for the removed single bond */
2612 : 0 : at[iO].valence--;
2613 : 0 : at[iO].chem_bonds_valence--;
2614 : :
2615 : : /* clear metal neighbor (O) */
2616 : 0 : at[i].neighbor[k] = 0;
2617 : 0 : at[i].bond_stereo[k] = 0;
2618 : 0 : at[i].bond_type[k] = 0;
2619 : :
2620 : : /* add a positive charge to the metal */
2621 : 0 : at[i].charge++;
2622 : : }
2623 : :
2624 : : /* set metal valence to zero because it has been disconnected */
2625 : 0 : at[i].valence = 0;
2626 : 0 : at[i].chem_bonds_valence = 0;
2627 : :
2628 : 0 : return k;
2629 : : }
2630 : :
2631 : : /****************************************************************************/
2632 : 98 : int DisconnectSalts(ORIG_ATOM_DATA *orig_inp_data, int bDisconnect)
2633 : : {
2634 : : int i, k, iO, num_changes, val;
2635 : : S_CHAR num_explicit_H[NUM_H_ISOTOPES + 1];
2636 : 98 : inp_ATOM *at = orig_inp_data->at;
2637 : 98 : int num_at = orig_inp_data->num_inp_atoms;
2638 : :
2639 : : /* check each atom */
2640 [ + + ]: 747 : for (i = 0, num_changes = 0; i < num_at; i++)
2641 : : {
2642 : :
2643 [ + + ]: 649 : if (!(val = at[i].valence) || /* disconnected atom */
2644 [ + + ]: 601 : val != at[i].chem_bonds_valence || /* a bond has higher multiplicity than 1 */
2645 [ - + - - ]: 577 : (at[i].radical && at[i].radical != RADICAL_SINGLET) /* radical */) /* djb-rwth: addressing LLVM warning */
2646 : : {
2647 : 72 : continue; /* reject */
2648 : : }
2649 : :
2650 [ - + ]: 577 : if (bIsAmmoniumSalt(at, i, &iO, &k, num_explicit_H))
2651 : : {
2652 [ # # ]: 0 : if (bDisconnect)
2653 : : {
2654 : 0 : DisconnectAmmoniumSalt(at, i, iO, k, num_explicit_H);
2655 : 0 : orig_inp_data->num_inp_bonds--;
2656 : : }
2657 : :
2658 : : /* count disconnected atoms */
2659 : 0 : num_changes++;
2660 : : }
2661 [ - + ]: 577 : else if (bIsMetalSalt(at, i))
2662 : : {
2663 [ # # ]: 0 : if (bDisconnect)
2664 : : {
2665 : 0 : k = DisconnectMetalSalt(at, i);
2666 : 0 : orig_inp_data->num_inp_bonds -= k;
2667 : : }
2668 : 0 : num_changes++;
2669 : : }
2670 : : }
2671 : :
2672 : 98 : return num_changes;
2673 : : }
2674 : :
2675 : : /*****************************************************************************/
2676 : : /* Important: Salt disconnection is independent from coord. disconnection: */
2677 : : /* because different atoms are disconnected. */
2678 : : /* However, sal disconnection may need to be rerun after metal disconnection */
2679 : : /* because metal disconnection may make certain atoms be eligible for salt */
2680 : : /* disconnection */
2681 : : /*****************************************************************************/
2682 : 772 : int bIsMetalToDisconnect(inp_ATOM *at, int i, int bCheckMetalValence)
2683 : : {
2684 : : int type, at_valence, num_H;
2685 : :
2686 : : /*
2687 : : if ( !at[i].valence )
2688 : : */
2689 : :
2690 [ + + ]: 772 : if (!(type = get_el_type(at[i].el_number)) ||
2691 [ - + ]: 14 : !(type & IS_METAL))
2692 : : {
2693 : 758 : return 0;
2694 : : }
2695 : :
2696 : 14 : num_H = NUMH(at, i);
2697 : 14 : at_valence = num_H + at[i].chem_bonds_valence;
2698 : :
2699 [ - + ]: 14 : if (!at_valence)
2700 : : {
2701 : 0 : return 0; /* nothing to disconnect */
2702 : : }
2703 : :
2704 [ - + ]: 14 : if (bCheckMetalValence)
2705 : : {
2706 [ # # ]: 0 : if (abs(at[i].charge) > 1)
2707 : : {
2708 : 0 : return 1; /* multiple charges */
2709 : : }
2710 : :
2711 [ # # # # ]: 0 : for (i = 0; i < 2 && (i & type); i++)
2712 : : {
2713 [ # # ]: 0 : if (at_valence == get_el_valence( at[i].el_number, at[i].charge, i )) /* djb-rwth: fixing coverity ID #499532 -- unresolved issue -- revision required */
2714 : : {
2715 : 0 : return 2; /* atom has normal valence */
2716 : : }
2717 : : }
2718 : : }
2719 : :
2720 : 14 : return 1;
2721 : : }
2722 : :
2723 : : /****************************************************************************/
2724 : 122 : int bMayDisconnectMetals(ORIG_ATOM_DATA *orig_inp_data,
2725 : : int bCheckMetalValence,
2726 : : INCHI_MODE *bTautFlagsDone)
2727 : : {
2728 : 122 : int i, j, k, iO, num_changes, val, bRadOrMultBonds, num_impl_H = 0;
2729 : : S_CHAR num_explicit_H[NUM_H_ISOTOPES + 1];
2730 : 122 : inp_ATOM *at = orig_inp_data->at;
2731 : 122 : int num_at = orig_inp_data->num_inp_atoms;
2732 : 122 : int *nNumImplH = &orig_inp_data->bDisconnectCoord;
2733 : :
2734 : : /* check each atom */
2735 [ + + ]: 929 : for (i = 0, num_changes = 0; i < num_at; i++)
2736 : : {
2737 : :
2738 [ + + + + ]: 807 : if (!(val = at[i].valence) && !NUMH(at, i))
2739 : : {
2740 : 56 : continue; /* disconnected atom */
2741 : : }
2742 : :
2743 : 1480 : bRadOrMultBonds = (val == 0) ||
2744 [ + + + + ]: 1398 : (val != at[i].chem_bonds_valence) || /* a bond has higher multiplicity than 1 */
2745 [ - + - - ]: 647 : (at[i].radical && at[i].radical != RADICAL_SINGLET); /* radical */
2746 : :
2747 [ + + - + ]: 751 : if (!bRadOrMultBonds && bIsAmmoniumSalt(at, i, &iO, &k, num_explicit_H))
2748 : : {
2749 : : ;
2750 : : }
2751 [ + + + + ]: 751 : else if (!bRadOrMultBonds && bIsMetalSalt(at, i))
2752 : : {
2753 : : ;
2754 : : }
2755 [ + + ]: 750 : else if (1 == (j = bIsMetalToDisconnect(at, i, bCheckMetalValence)))
2756 : : {
2757 : 10 : num_impl_H += NUMH(at, i);
2758 : 10 : num_changes++;
2759 : : }
2760 [ - + - - ]: 740 : else if (2 == j && bTautFlagsDone)
2761 : : {
2762 : 0 : *bTautFlagsDone |= TG_FLAG_CHECK_VALENCE_COORD_DONE;
2763 : : }
2764 : : }
2765 : :
2766 [ + - ]: 122 : if (nNumImplH)
2767 : : {
2768 [ + + ]: 122 : *nNumImplH = num_changes ? num_impl_H + 1 : 0;
2769 : : }
2770 : :
2771 : 122 : return num_changes;
2772 : : }
2773 : :
2774 : : /****************************************************************************/
2775 : :
2776 : : #if (bRELEASE_VERSION == 0 && (EXTR_HAS_METAL_ATOM & (EXTR_MASK | EXTR_FLAG)))
2777 : :
2778 : : /****************************************************************************/
2779 : : int bHasMetalAtom(ORIG_ATOM_DATA *orig_inp_data)
2780 : : {
2781 : : int i;
2782 : : inp_ATOM *at;
2783 : :
2784 : : if (orig_inp_data && (at = orig_inp_data->at))
2785 : : {
2786 : : int num_at = orig_inp_data->num_inp_atoms;
2787 : : /* check each atom */
2788 : : for (i = 0; i < num_at; i++)
2789 : : {
2790 : : if (IS_METAL & get_el_type(at[i].el_number))
2791 : : {
2792 : : return 1;
2793 : : }
2794 : : }
2795 : : }
2796 : :
2797 : : return 0;
2798 : : }
2799 : : #endif
2800 : :
2801 : : /*****************************************************************************
2802 : : { "F", 19, 19, 18.998403220, 0 , 0, {{0,}, {0,}, {1,}, {2,}, {3,5}, },},
2803 : : { "Cl", 35, 35, 34.968852730, 0 , 0, {{0,}, {0,}, {1,3,5,7}, {2,4,6}, {3,5,}, },},
2804 : : { "Br", 80, 79, 78.918336100, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, },},
2805 : : { "I", 127, 127, 126.904500000, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, },},
2806 : : { "At", 210, 210, 209.987100000, 0 , 0, {{0,}, {0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, },},
2807 : : { "N", 14, 14, 14.003074000, 0 , 0, {{1,}, {2,}, {3,5}, {4,}, {3,}, },},
2808 : : { "P", 31, 31, 30.973762000, 0 , 0, {{1,3,5,7,}, {2,4,6,}, {3,5,}, {4,}, {3,}, },},
2809 : : { "As", 75, 75, 74.921594200, 0 , 0, {{0,}, {2,4,6,}, {3,5,}, {4,}, {3,}, },},
2810 : : { "Sb", 122, 121, 120.903800000, 0 , 0, {{1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, {3,}, },},
2811 : : { "O", 16, 16, 15.994914630, 0 , 0, {{0,}, {1,}, {2,}, {3,5,}, {4,}, },},
2812 : : { "S", 32, 32, 31.972070700, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6}, {3,5,}, {4,}, },},
2813 : : { "Se", 79, 80, 79.916519600, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {4,}, },},
2814 : : { "Te", 128, 130, 129.906200000, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, },},
2815 : : { "Po", 209, 209, 208.982400000, 0 , 0, {{0,}, {1,3,5,7,}, {2,4,6,}, {3,5,}, {2,4,}, },},
2816 : : { "B", 11, 11, 11.009300000, 0 , 0, {{3,}, {4,}, {3,}, {2,}, {1,}, },},
2817 : : *****************************************************************************/
2818 : :
2819 : : /****************************************************************************/
2820 : 4 : int DisconnectMetals(ORIG_ATOM_DATA *orig_inp_data,
2821 : : int bCheckMetalValence,
2822 : : INCHI_MODE *bTautFlagsDone)
2823 : : {
2824 : : int i, j, k, n, iO, num_changes, val, bRadOrMultBonds;
2825 : : int num_impl_H, num_at, err, num_disconnected;
2826 : : S_CHAR num_explicit_H[NUM_H_ISOTOPES + 1];
2827 : : static char elnumber_Heteroat[16] = {
2828 : : '\0',
2829 : : };
2830 : : static int num_halogens = 0;
2831 : : int num_halogens2;
2832 : :
2833 : 4 : inp_ATOM *at = NULL;
2834 : 4 : S_CHAR *bMetal = NULL;
2835 : 4 : inp_ATOM *atom = orig_inp_data->at;
2836 : 4 : int num_atoms = orig_inp_data->num_inp_atoms;
2837 : 4 : int nNumExplH = (orig_inp_data->bDisconnectCoord > 0) ? orig_inp_data->bDisconnectCoord - 1 : 0;
2838 : 4 : AT_NUMB *nOldCompNumber = orig_inp_data->nOldCompNumber;
2839 : :
2840 : 4 : err = 0;
2841 : 4 : num_impl_H = 0;
2842 : 4 : num_at = num_atoms;
2843 : 4 : num_disconnected = 0;
2844 : :
2845 [ + - ]: 4 : if (!(at = (inp_ATOM *)inchi_calloc((long long)num_at + (long long)nNumExplH, sizeof(at[0]))) || /* djb-rwth: cast operators added */
2846 [ - + ]: 4 : !(bMetal = (S_CHAR *)inchi_calloc((long long)num_at + (long long)nNumExplH, sizeof(bMetal[0])))) /* djb-rwth: cast operators added */
2847 : : {
2848 : 0 : err = 1;
2849 : 0 : goto exit_function;
2850 : : }
2851 : :
2852 [ + + ]: 4 : if (!num_halogens) /* if (!elnumber_Heteroat[0] ) */
2853 : : {
2854 : 3 : i = 0;
2855 : : /* halogens */
2856 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_F; /* 0 */
2857 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_CL;
2858 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_BR;
2859 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_I;
2860 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_AT; /* 4 */
2861 : 3 : num_halogens2 = i;
2862 : : /* other non-metal */
2863 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_N;
2864 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_P;
2865 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_AS;
2866 : : /*elnumber_Heteroat[i++] = EL_NUMBER_SB;*/ /* metal 10-28-2003 */
2867 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_O;
2868 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_S;
2869 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_SE;
2870 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_TE;
2871 : : /*elnumber_Heteroat[i++] = EL_NUMBER_PO;*/ /* metal 10-28-2003 */
2872 : 3 : elnumber_Heteroat[i++] = (char)EL_NUMBER_B;
2873 : 3 : elnumber_Heteroat[i++] = 0;
2874 : 3 : num_halogens = num_halogens2;
2875 : : }
2876 : :
2877 : 4 : memcpy(at, atom, num_atoms * sizeof(at[0]));
2878 : :
2879 : : /* check each atom, mark metals */
2880 [ + + ]: 26 : for (i = 0, k = 0, num_changes = 0; i < num_atoms; i++)
2881 : : {
2882 [ + + - + ]: 22 : if (!(val = at[i].valence) && !NUMH(at, i))
2883 : : {
2884 : 0 : continue; /* disconnected atom */
2885 : : }
2886 : 43 : bRadOrMultBonds = (val == 0) ||
2887 [ + + + + ]: 31 : (val != at[i].chem_bonds_valence) || /* a bond has higher multiplicity than 1 */
2888 [ - + - - ]: 9 : (at[i].radical && at[i].radical != RADICAL_SINGLET); /* radical */
2889 : :
2890 [ + + - + ]: 22 : if (!bRadOrMultBonds && bIsAmmoniumSalt(at, i, &iO, &k, num_explicit_H))
2891 : : {
2892 : : ;
2893 : : }
2894 [ + + - + ]: 22 : else if (!bRadOrMultBonds && bIsMetalSalt(at, i))
2895 : : {
2896 : : ;
2897 : : }
2898 [ + + ]: 22 : else if (1 == (j = bIsMetalToDisconnect(at, i, bCheckMetalValence)))
2899 : : {
2900 : 4 : num_impl_H += (k = NUMH(at, i));
2901 : 4 : bMetal[i] = 1 + k;
2902 : 4 : num_changes++;
2903 : : }
2904 [ - + - - ]: 18 : else if (2 == j && bTautFlagsDone)
2905 : : {
2906 : 0 : *bTautFlagsDone |= TG_FLAG_CHECK_VALENCE_COORD_DONE;
2907 : : }
2908 : : }
2909 : :
2910 [ - + ]: 4 : if (num_impl_H != nNumExplH)
2911 : : {
2912 : 0 : err = 2;
2913 : 0 : goto exit_function;
2914 : : }
2915 : :
2916 : : /* replace implicit H atoms with explicit H atoms */
2917 [ + + + + ]: 5 : for (i = 0; i < num_atoms && 0 < num_impl_H; i++)
2918 : : {
2919 [ - + ]: 1 : if (bMetal[i] <= 1)
2920 : : {
2921 : 0 : continue;
2922 : : }
2923 [ + + ]: 5 : for (k = 0; k < NUM_H_ISOTOPES + 1; k++)
2924 : : {
2925 [ + + ]: 4 : n = k ? at[i].num_iso_H[k - 1] : at[i].num_H;
2926 [ + + ]: 7 : for (j = 0; j < n; j++)
2927 : : {
2928 [ - + ]: 3 : if (num_at >= num_atoms + nNumExplH)
2929 : : {
2930 : 0 : err = 3;
2931 : 0 : goto exit_function;
2932 : : }
2933 : 3 : at[num_at].elname[0] = 'H';
2934 : 3 : at[num_at].el_number = get_periodic_table_number(at[num_at].elname);
2935 : 3 : at[num_at].iso_atw_diff = k;
2936 : 3 : at[num_at].component = at[i].component;
2937 : 3 : move_explicit_Hcation(at, num_at + 1, i, num_at, 1);
2938 : 3 : at[num_at].orig_at_number = num_at + 1;
2939 : 3 : num_at++;
2940 : 3 : num_impl_H--;
2941 : 3 : bMetal[i]--;
2942 [ - + ]: 3 : if (k)
2943 : : {
2944 : 0 : at[i].num_iso_H[k - 1]--;
2945 : : }
2946 : : else
2947 : : {
2948 : 3 : at[i].num_H--;
2949 : : }
2950 : : }
2951 : : }
2952 : :
2953 [ - + ]: 1 : if (bMetal[i] != 1)
2954 : : {
2955 : 0 : err = 4;
2956 : 0 : goto exit_function;
2957 : : }
2958 : : }
2959 : :
2960 [ - + ]: 4 : if (num_at != num_atoms + nNumExplH)
2961 : : {
2962 : 0 : err = 5;
2963 : 0 : goto exit_function;
2964 : : }
2965 : :
2966 : : /* disconnect metal - ligand bonds */
2967 [ + + ]: 26 : for (i = 0; i < num_atoms; i++)
2968 : : {
2969 [ + + ]: 22 : if (!bMetal[i])
2970 : : {
2971 : 18 : continue;
2972 : : }
2973 : :
2974 : : /* disconnect metal atom M
2975 : :
2976 : : Note: Defect in case of bridging ligands:
2977 : :
2978 : : M M M M M M(+)
2979 : : \ / will be transformed to , not to
2980 : : N(+) N(+) N(-)
2981 : : / \ / \ / \
2982 : : R R R R R R
2983 : :
2984 : : Non-bridging are OK:
2985 : :
2986 : : M R M(+) R
2987 : : \ / /
2988 : : N(+) ---> N
2989 : : / \ / \
2990 : : R R R R
2991 : :
2992 : : */
2993 : :
2994 [ + + ]: 19 : for (j = at[i].valence - 1; 0 <= j; j--)
2995 : : {
2996 [ + - + - ]: 15 : if (j < at[i].valence && !bMetal[(int)at[i].neighbor[j]])
2997 : : {
2998 : : /* do not break metal-metal bond here */
2999 : :
3000 : 15 : num_disconnected += DisconnectOneLigand(at,
3001 : : nOldCompNumber,
3002 : : bMetal,
3003 : : elnumber_Heteroat,
3004 : : num_halogens,
3005 : : num_atoms,
3006 : : i,
3007 : : j,
3008 : : bTautFlagsDone);
3009 : : }
3010 : : }
3011 : : }
3012 : :
3013 : : /* disconnect metal-metal bonds */
3014 [ + + ]: 26 : for (i = 0; i < num_atoms; i++)
3015 : : {
3016 [ + + ]: 22 : if (!bMetal[i])
3017 : : {
3018 : 18 : continue;
3019 : : }
3020 [ - + ]: 4 : for (j = at[i].valence - 1; 0 <= j; j--)
3021 : : {
3022 [ # # # # ]: 0 : if (j < at[i].valence && bMetal[(int)at[i].neighbor[j]])
3023 : : {
3024 : : /* break metal-metal bond here */
3025 : :
3026 : 0 : num_disconnected += DisconnectOneLigand(at,
3027 : : nOldCompNumber,
3028 : : bMetal,
3029 : : elnumber_Heteroat,
3030 : : num_halogens,
3031 : : num_atoms,
3032 : : i,
3033 : : j,
3034 : : bTautFlagsDone);
3035 : : }
3036 : : }
3037 : : }
3038 : :
3039 : 4 : exit_function:
3040 : :
3041 [ - + ]: 4 : if (!num_disconnected)
3042 : : {
3043 : 0 : err = 6;
3044 : : }
3045 [ + - - + ]: 4 : if (at && err)
3046 : : {
3047 [ # # ]: 0 : inchi_free(at);
3048 : 0 : at = NULL;
3049 : : }
3050 [ + - + - ]: 4 : if (atom && at)
3051 : : { /* changed if ( at ) to if ( atom && at ) 2004-04-03 */
3052 [ + - ]: 4 : inchi_free(atom);
3053 : 4 : atom = NULL;
3054 : : }
3055 [ + - ]: 4 : if (bMetal)
3056 [ + - ]: 4 : inchi_free(bMetal);
3057 : :
3058 [ + - ]: 4 : if (at)
3059 : : {
3060 : 4 : orig_inp_data->at = at;
3061 : 4 : orig_inp_data->num_inp_atoms = num_at;
3062 : : }
3063 : :
3064 [ - + ]: 4 : return err ? -err : num_disconnected;
3065 : : }
3066 : :
3067 : : /****************************************************************************/
3068 : 15 : int DisconnectOneLigand(inp_ATOM *at,
3069 : : AT_NUMB *nOldCompNumber,
3070 : : S_CHAR *bMetal,
3071 : : char *elnumber_Heteroat,
3072 : : int num_halogens,
3073 : : int num_atoms,
3074 : : int iMetal,
3075 : : int jLigand,
3076 : : INCHI_MODE *bTautFlagsDone)
3077 : : {
3078 : : int i, j, iLigand, neigh, val;
3079 : : int metal_neigh_ord[MAXVAL], num_neigh_arom_bonds[MAXVAL];
3080 : : int num_metal_neigh, num_disconnections;
3081 : : int num_del_arom_bonds, num_tot_arom_bonds, new_charge;
3082 : : char *p;
3083 : :
3084 : 15 : iLigand = at[iMetal].neighbor[jLigand];
3085 : 15 : num_metal_neigh = 0;
3086 : 15 : num_disconnections = 0;
3087 : 15 : num_del_arom_bonds = num_tot_arom_bonds = 0;
3088 : :
3089 : : /* find bonds to disconnect */
3090 [ + + ]: 52 : for (i = 0; i < at[iLigand].valence; i++)
3091 : : {
3092 : 37 : num_neigh_arom_bonds[i] = 0;
3093 : 37 : neigh = (int)at[iLigand].neighbor[i];
3094 [ + - + + ]: 37 : if (neigh < num_atoms && bMetal[neigh])
3095 : : {
3096 : 15 : metal_neigh_ord[num_metal_neigh++] = i;
3097 [ + + ]: 15 : if (at[iLigand].bond_type[i] > BOND_TYPE_TRIPLE)
3098 : : {
3099 : : /* aromatic bond */
3100 [ + + ]: 65 : for (j = 0; j < at[neigh].valence; j++)
3101 : : {
3102 : 55 : num_neigh_arom_bonds[i] += (at[neigh].bond_type[j] > BOND_TYPE_TRIPLE);
3103 : : }
3104 : 10 : num_del_arom_bonds++;
3105 : : }
3106 : : }
3107 : 37 : num_tot_arom_bonds += (at[iLigand].bond_type[i] > BOND_TYPE_TRIPLE);
3108 : : }
3109 : :
3110 : : /* Disconnect */
3111 [ + + ]: 15 : if (num_del_arom_bonds)
3112 : : {
3113 : : /* fix chem_valence of the ligand and its neighbors in case of disconnecting arom. bonds */
3114 : : /* because in this case special care should be taken of updating at[].chem_bonds_valence */
3115 [ + + ]: 20 : for (i = 0; i < num_metal_neigh; i++)
3116 : : {
3117 : 10 : j = metal_neigh_ord[i];
3118 [ + - ]: 10 : if (num_neigh_arom_bonds[j])
3119 : : {
3120 : 10 : neigh = at[iLigand].neighbor[j];
3121 : 10 : at[neigh].chem_bonds_valence -= num_neigh_arom_bonds[j] / 2 - (num_neigh_arom_bonds[j] - 1) / 2;
3122 : : }
3123 : : }
3124 : 10 : at[iLigand].chem_bonds_valence -= num_tot_arom_bonds / 2 - (num_tot_arom_bonds - num_del_arom_bonds) / 2;
3125 : : }
3126 : :
3127 : : /* disconnect in reverse order, otherwise the metal_neigh_ord[i]
3128 : : becomes invalid after the first disconnection
3129 : : */
3130 [ + + ]: 30 : for (i = num_metal_neigh - 1; 0 <= i; i--)
3131 : : {
3132 : 15 : num_disconnections += DisconnectInpAtBond(at,
3133 : : nOldCompNumber,
3134 : : iLigand,
3135 : : metal_neigh_ord[i]);
3136 : : }
3137 : :
3138 : : /* attempt to change ligand charge to make its valence 'natural' */
3139 : 15 : i = num_tot_arom_bonds - num_del_arom_bonds;
3140 [ - + - - : 15 : if ((i && i != 2 && i != 3) ||
- - ]
3141 [ - + - - ]: 15 : (at[iLigand].radical && at[iLigand].radical != RADICAL_SINGLET) ||
3142 [ + + ]: 15 : !(p = strchr(elnumber_Heteroat, at[iLigand].el_number))) /* djb-rwth: addressing LLVM warnings */
3143 : : {
3144 : 13 : goto exit_function; /* non-standard atom */
3145 : : }
3146 : :
3147 : 2 : val = at[iLigand].chem_bonds_valence + NUMH(at, iLigand);
3148 : 2 : new_charge = MAX_ATOMS; /* impossible value */
3149 : :
3150 [ - + ]: 2 : if (!val)
3151 : : {
3152 [ # # ]: 0 : if (p - elnumber_Heteroat < num_halogens)
3153 : : {
3154 : 0 : new_charge = -1;
3155 : : }
3156 : : }
3157 : : else
3158 : : {
3159 [ + - ]: 2 : for (i = -1; i <= 1; i++)
3160 : : {
3161 [ + - ]: 2 : if (val == get_el_valence(at[iLigand].el_number, i, 0))
3162 : : {
3163 : 2 : new_charge = i; /* found charge that fits chem. valence */
3164 : 2 : break;
3165 : : }
3166 : : }
3167 : : }
3168 : :
3169 [ - + ]: 2 : if (new_charge != MAX_ATOMS)
3170 : : {
3171 [ - + ]: 2 : if ((new_charge != at[iLigand].charge ||
3172 [ - - - - : 2 : (at[iLigand].radical && at[iLigand].radical != RADICAL_SINGLET)) &&
- + ]
3173 : : 1 == num_metal_neigh)
3174 : : {
3175 [ - + - - : 2 : if (1 == new_charge && 4 == val && 2 == at[iLigand].valence &&
- - ]
3176 [ # # ]: 0 : 4 == at[iLigand].chem_bonds_valence &&
3177 [ # # ]: 0 : at[iLigand].bond_type[0] == at[iLigand].bond_type[1])
3178 : : {
3179 : : ; /* do not add +1 charge to disconnected =N=, etc. 2004-10-27 */
3180 : : }
3181 : : else
3182 : : {
3183 [ + - + - ]: 2 : if (bTautFlagsDone && new_charge != at[iLigand].charge)
3184 : : {
3185 : 2 : *bTautFlagsDone |= TG_FLAG_MOVE_CHARGE_COORD_DONE;
3186 : : }
3187 : 2 : at[iMetal].charge -= new_charge - at[iLigand].charge;
3188 : 2 : at[iLigand].charge = new_charge;
3189 : : /*at[iLigand].radical = 0;*/
3190 : : }
3191 : : }
3192 : : }
3193 : :
3194 : 0 : exit_function:
3195 : :
3196 : 15 : return num_disconnections; /* ret;*/
3197 : : }
3198 : :
3199 : : /****************************************************************************/
3200 : 3 : double dist3D(inp_ATOM *at1, inp_ATOM *at2)
3201 : : {
3202 : 3 : double dx = at1->x - at2->x;
3203 : 3 : double dy = at1->y - at2->y;
3204 : 3 : double dz = at1->z - at2->z;
3205 : :
3206 : 3 : return sqrt(dx * dx + dy * dy + dz * dz);
3207 : : }
3208 : :
3209 : : /****************************************************************************/
3210 : : #define MIN_BOND_LENGTH (1.0e-6)
3211 : : #define MIN_COS (1.0e-6)
3212 : : #define MIN_BOND_LENGTH2 (MIN_BOND_LENGTH * MIN_BOND_LENGTH)
3213 : : #define MAX_BOND_LENGTH (1.0e30)
3214 : : /****************************************************************************/
3215 : :
3216 : : /****************************************************************************/
3217 : 3 : double GetMinDistDistribution(inp_ATOM *at,
3218 : : int num_at,
3219 : : int iat,
3220 : : int iat_H,
3221 : : int bInAllComponents,
3222 : : double min_dist[],
3223 : : int num_segm)
3224 : : {
3225 : : /* const double one_pi = 2.0*atan2(1.0 , 0.0 ); */
3226 : 3 : const double one_pi = 3.14159265358979323846; /* M_PI */
3227 : 3 : const double two_pi = 2.0 * one_pi;
3228 : 3 : const double f_step = two_pi / num_segm;
3229 : 3 : const double h_step = f_step / 2.0;
3230 : : int i, j, k, kk, ki, kn, n, num_bonds;
3231 : : double xi, yi, xn, yn, cross_prod_in, dot_prod_in, xni, yni, rni, tni, rmin;
3232 : 3 : double fi, fk, fn, ft = 0, rt = 0, rk, ri, rn, c, ave_bond_len;
3233 : :
3234 [ + + ]: 63 : for (i = 0; i < num_segm; i++)
3235 : : {
3236 : 60 : min_dist[i] = MAX_BOND_LENGTH; /* more than any distance */
3237 : : }
3238 : 3 : num_bonds = 0;
3239 : 3 : ave_bond_len = 0.0;
3240 : :
3241 [ + + ]: 12 : for (i = 0; i < num_at; i++)
3242 : : {
3243 [ + + + + : 9 : if (i != iat && i != iat_H &&
- + ]
3244 [ # # ]: 0 : (bInAllComponents || at[i].component == at[iat].component))
3245 : : {
3246 [ + + ]: 6 : for (j = 0; j < at[i].valence; j++)
3247 : : {
3248 : 3 : n = at[i].neighbor[j];
3249 [ - + - - : 3 : if ((n > i && n != iat) || n == iat_H)
- + ]
3250 : : {
3251 : 0 : continue;
3252 : : }
3253 : : #if (bRELEASE_VERSION != 1 && defined(_DEBUG))
3254 : : if (n == iat)
3255 : : {
3256 : : int stop = 1; /* <BRKPT> */
3257 : : }
3258 : : #endif
3259 : 3 : xi = at[i].x - at[iat].x; /* ri; i != iat */
3260 : 3 : yi = at[i].y - at[iat].y;
3261 : 3 : xn = at[n].x - at[iat].x; /* rn; possibly n == iat */
3262 : 3 : yn = at[n].y - at[iat].y;
3263 : 3 : cross_prod_in = xi * yn - xn * yi; /* ((r(i)-r(iat)) x (r(n)-r(iat)) */
3264 [ - + ]: 3 : if (cross_prod_in < -0.01 * MIN_BOND_LENGTH2)
3265 : : {
3266 : : /* make sure the r(i)->r(n) vector is counterclockwise around at[iat] */
3267 : 0 : inchi_swap((char *)&xi, (char *)&xn, sizeof(xi));
3268 : 0 : inchi_swap((char *)&yi, (char *)&yn, sizeof(yi));
3269 : : /* djb-rwth: removing redundant code */
3270 : : }
3271 : :
3272 : 3 : xni = xn - xi; /* r(n)->r(i) */
3273 : 3 : yni = yn - yi;
3274 : 3 : rni = xni * xni + yni * yni;
3275 [ - + ]: 3 : if (rni > 0.01 * MIN_BOND_LENGTH2)
3276 : : {
3277 : : /* vector length |ri->rn| is not too small */
3278 : : /* arrowhead of the vector r(t) = ri + (rn-ri)*t; 0 <= t <= 1 points to the bond ri->rn */
3279 : : /* r(tni) is perpendicular to the bond ri->rn so that min|r(t)| = r(tni) = |tni|*rni */
3280 : 0 : tni = -(xni * xi + yni * yi) / rni;
3281 : : /* find min. distance from n-i bond to at[iat] */
3282 [ # # ]: 0 : if (tni < 0.0)
3283 : : {
3284 : 0 : rmin = sqrt(xi * xi + yi * yi);
3285 : : }
3286 [ # # ]: 0 : else if (tni > 1.0)
3287 : : {
3288 : 0 : rmin = sqrt(xn * xn + yn * yn);
3289 : : }
3290 : : else
3291 : : {
3292 : 0 : rmin = sqrt(tni * tni * rni);
3293 : : }
3294 : 0 : ave_bond_len += sqrt(rni);
3295 : 0 : num_bonds++;
3296 : : }
3297 : : else
3298 : : {
3299 : : /* zero length i-n bond */
3300 : 3 : tni = 0.5; /* fake */
3301 : 3 : rmin = sqrt(xi * xi + yi * yi); /* arbitrarily choose one */
3302 : : }
3303 [ - + ]: 3 : if (rmin >= 0.1 * MIN_BOND_LENGTH)
3304 : : {
3305 : : /* at[iat] does not belong to at[i]-at[n] bond */
3306 : 0 : int bCalc_rt = 1;
3307 : 0 : fi = atan2(yi, xi);
3308 [ # # ]: 0 : fn = (n == iat) ? fi : atan2(yn, xn);
3309 [ # # ]: 0 : if (fi > fn)
3310 : : {
3311 : : /* make sure fn - fi >= 0 */
3312 : 0 : fn += two_pi;
3313 : : }
3314 [ # # ]: 0 : if (fi < 0.0)
3315 : : {
3316 : 0 : fi += two_pi;
3317 : 0 : fn += two_pi;
3318 : : }
3319 : 0 : ki = (int)floor((fi + h_step) / f_step); /* cast does not match function type */
3320 : 0 : kn = (int)floor((fn + h_step) / f_step);
3321 : :
3322 : : /* the bond may affect several segments */
3323 [ # # ]: 0 : for (k = ki; k <= kn; k++)
3324 : : {
3325 : 0 : kk = k % num_segm;
3326 [ # # ]: 0 : if (min_dist[kk] < rmin)
3327 : : {
3328 : 0 : continue;
3329 : : }
3330 [ # # ]: 0 : if (bCalc_rt)
3331 : : {
3332 [ # # ]: 0 : if (n == iat)
3333 : : {
3334 : 0 : ft = fi;
3335 : 0 : rt = rmin;
3336 : : }
3337 : : else
3338 : : {
3339 : : double xt, yt;
3340 : 0 : xt = xi + xni * tni;
3341 : 0 : yt = yi + yni * tni;
3342 : 0 : ft = atan2(yt, xt);
3343 : 0 : rt = sqrt(xt * xt + yt * yt);
3344 : : }
3345 : 0 : bCalc_rt = 0;
3346 : : }
3347 : 0 : fk = f_step * kk;
3348 : 0 : c = fabs(cos(fk - ft));
3349 [ # # ]: 0 : if (c < MIN_COS)
3350 : 0 : c = MIN_COS;
3351 : 0 : rk = rt / c;
3352 [ # # ]: 0 : if (min_dist[kk] > rk)
3353 : : {
3354 : 0 : min_dist[kk] = rk;
3355 : : }
3356 : : }
3357 : : }
3358 : : else
3359 : : {
3360 : : /* rmin < 0.1*MIN_BOND_LENGTH */
3361 : 3 : ri = xi * xi + yi * yi;
3362 : 3 : rn = xn * xn + yn * yn;
3363 [ - + - - ]: 3 : if (ri > MIN_BOND_LENGTH2 && rn > MIN_BOND_LENGTH2)
3364 : : {
3365 : 0 : dot_prod_in = xn * xi + yn * yi;
3366 : : /* a very short bond */
3367 [ # # ]: 0 : if (dot_prod_in > 0.01 * MIN_BOND_LENGTH2)
3368 : : {
3369 : : /* bond does not cross at[iat] */
3370 : 0 : double fyixi = atan2(yi, xi);
3371 [ # # ]: 0 : if (fyixi < 0.0)
3372 : 0 : fyixi += two_pi;
3373 : 0 : kk = (int)floor((fyixi + h_step) / f_step) % num_segm;
3374 [ # # ]: 0 : if (min_dist[kk] > rmin)
3375 : : {
3376 : 0 : min_dist[kk] = rmin;
3377 : : }
3378 : : }
3379 [ # # ]: 0 : else if (dot_prod_in < -0.01 * MIN_BOND_LENGTH2)
3380 : : {
3381 : : /* bond does cross at[iat] */
3382 : 0 : double fyixi = atan2(yi, xi);
3383 [ # # ]: 0 : if (fyixi < 0.0)
3384 : 0 : fyixi += two_pi;
3385 : 0 : kk = (int)floor((fyixi + h_step) / f_step) % num_segm;
3386 [ # # ]: 0 : if (min_dist[kk] > rmin)
3387 : : {
3388 : 0 : min_dist[kk] = rmin;
3389 : : }
3390 : 0 : fyixi += one_pi;
3391 : 0 : kk = (int)floor((fyixi + h_step) / f_step) % num_segm;
3392 [ # # ]: 0 : if (min_dist[kk] > rmin)
3393 : : {
3394 : 0 : min_dist[kk] = rmin;
3395 : : }
3396 : : }
3397 : : else
3398 : : {
3399 : : ; /* error, should not happen */
3400 : : }
3401 : : }
3402 [ + - + - ]: 3 : else if (ri <= MIN_BOND_LENGTH2 && rn <= MIN_BOND_LENGTH2)
3403 : : {
3404 : : /* a very short bond coincides with at[iat]; ignore */
3405 : : ;
3406 : : }
3407 : : else
3408 : : {
3409 : : /* one end of the bond coincides with at[iat] */
3410 [ # # ]: 0 : fi = ri > rn ? atan2(yi, xi) : atan2(yn, xn);
3411 [ # # ]: 0 : if (fi < 0.0)
3412 : 0 : fi += two_pi;
3413 : 0 : kk = (int)floor((fi + h_step) / f_step) % num_segm;
3414 [ # # ]: 0 : if (min_dist[kk] > rmin)
3415 : : {
3416 : 0 : min_dist[kk] = rmin;
3417 : : }
3418 : : }
3419 : : }
3420 : : }
3421 : : }
3422 : : }
3423 : :
3424 [ - + ]: 3 : if (num_bonds)
3425 : : {
3426 : 0 : return ave_bond_len / (double)num_bonds;
3427 : : }
3428 : : else
3429 : : {
3430 : 3 : return 0.0;
3431 : : }
3432 : : }
3433 : :
3434 : : /****************************************************************************/
3435 : 3 : int move_explicit_Hcation(inp_ATOM *at,
3436 : : int num_at,
3437 : : int iat,
3438 : : int iat_H,
3439 : : int bInAllComponents)
3440 : : {
3441 : :
3442 : : #define NUM_SEGM 20
3443 : :
3444 : : /* const double one_pi = 2.0*atan2(1.0 , 0.0 ); */
3445 : 3 : const double one_pi = 3.14159265358979323846; /* M_PI */
3446 : 3 : const double two_pi = 2.0 * one_pi;
3447 : 3 : const double f_step = two_pi / NUM_SEGM;
3448 : 3 : const double h_step = f_step / 2.0;
3449 : : double min_dist[NUM_SEGM];
3450 : 3 : int nB, i, k, kk, next, val = 0;
3451 : : double r, r0, xd, yd, zd, xr, yr, zr, ave_bond_len;
3452 : : /*double step = 4.0*atan(1.0)/NUM_SEGM;*/
3453 : : /* find at[iat] neighbors coordinates */
3454 : :
3455 : 3 : xd = yd = zd = 0.0;
3456 : :
3457 [ + + ]: 3 : if (at[iat].valence)
3458 : : {
3459 [ + + ]: 5 : for (i = 0, nB = 0, r = 0.0; i < at[iat].valence; i++)
3460 : : {
3461 : 3 : next = at[iat].neighbor[i];
3462 : 3 : xd += at[next].x;
3463 : 3 : yd += at[next].y;
3464 : 3 : zd += at[next].z;
3465 : 3 : r += dist3D(at + iat, at + next);
3466 : 3 : nB++;
3467 : : }
3468 : 2 : xd /= (double)nB;
3469 : 2 : yd /= (double)nB;
3470 : 2 : zd /= (double)nB;
3471 : 2 : r /= (double)nB;
3472 : 2 : r0 = sqrt((double)(xd - at[iat].x) * (xd - at[iat].x) + (double)(yd - at[iat].y) * (yd - at[iat].y));
3473 : : }
3474 : : else
3475 : : {
3476 [ - + ]: 1 : if (at[iat_H].valence)
3477 : : {
3478 : 0 : r = dist3D(at + iat_H, at + (int)at[iat_H].neighbor[0]);
3479 : : }
3480 : : else
3481 : : {
3482 : 1 : r = 0.0;
3483 : : }
3484 : 1 : r0 = 0.0;
3485 : : }
3486 : :
3487 : 3 : ave_bond_len = GetMinDistDistribution(at, num_at, iat, iat_H,
3488 : : bInAllComponents, min_dist,
3489 : : NUM_SEGM);
3490 : :
3491 [ + - - + ]: 3 : if (r < MIN_BOND_LENGTH && ave_bond_len > MIN_BOND_LENGTH)
3492 : : {
3493 : 0 : r = ave_bond_len; /* ave_bond_len = 0.0 may mean that it is 0D structure */
3494 : : }
3495 : :
3496 [ - + ]: 3 : if (r > MIN_BOND_LENGTH)
3497 : : {
3498 : : /* process non-zero bond lengths */
3499 : : double f;
3500 [ # # ]: 0 : if (10.0 * r0 < r)
3501 : : {
3502 : 0 : xr = -r; /* arbitrary */
3503 : 0 : yr = 0.0;
3504 : 0 : zr = 0.0;
3505 : : }
3506 : : else
3507 : : {
3508 : : /*
3509 : : if ( r0 < MIN_BOND_LENGTH ) {
3510 : : r0 = 1.0;
3511 : : }
3512 : : */
3513 : 0 : xr = r * (at[iat].x - xd) / r0;
3514 : 0 : yr = r * (at[iat].y - yd) / r0; /* length = r */
3515 : 0 : zr = r * (at[iat].z - zd) / r0;
3516 : :
3517 : : /* -- test: opposire direction --
3518 : : xr = -r * ( at[iat].x - xd )/r0;
3519 : : yr = -r * ( at[iat].y - yd )/r0;
3520 : : zr = -r * ( at[iat].z - zd )/r0;
3521 : : */
3522 [ # # ]: 0 : if (xr * xr + yr * yr < 0.04 * r * r)
3523 : : {
3524 : 0 : xr = -r;
3525 : 0 : yr = 0.0;
3526 : : }
3527 : : }
3528 : :
3529 : 0 : r = sqrt(xr * xr + yr * yr);
3530 : 0 : f = atan2(yr, xr);
3531 : :
3532 [ # # ]: 0 : if (f < 0.0)
3533 : : {
3534 : 0 : f += two_pi;
3535 : : }
3536 : :
3537 : 0 : kk = (int)floor((f + h_step) / f_step) % NUM_SEGM;
3538 : : /* cast does not match function type by design */
3539 : :
3540 [ # # ]: 0 : if (min_dist[kk] < 1.5 * r)
3541 : : {
3542 : 0 : double dist = 1.5 * r;
3543 : 0 : int start = -1, len = 0, start_max = -1, len_max = 0;
3544 : :
3545 : 0 : again:
3546 : : /* look for longest kk interval with min_dist[kk] >= dist */
3547 [ # # ]: 0 : for (k = 0, start = 0, len = 0, len_max = 0; k < 2 * NUM_SEGM; k++)
3548 : : {
3549 : 0 : kk = k % NUM_SEGM;
3550 [ # # ]: 0 : if (min_dist[kk] >= dist)
3551 : : {
3552 [ # # ]: 0 : if (!len++)
3553 : : {
3554 : 0 : start = k;
3555 : : }
3556 : : }
3557 : : else
3558 : : {
3559 [ # # ]: 0 : if (len > len_max)
3560 : : {
3561 : 0 : len_max = len;
3562 : 0 : start_max = start;
3563 : : }
3564 : 0 : len = 0;
3565 : : }
3566 : : }
3567 [ # # ]: 0 : if (!len_max)
3568 : : {
3569 [ # # ]: 0 : if (dist > 0.1 * r)
3570 : : {
3571 : 0 : dist *= 0.75;
3572 : 0 : goto again;
3573 : : }
3574 : : else
3575 : : {
3576 : 0 : goto done; /* do it anyway */
3577 : : }
3578 : : }
3579 : : else
3580 : : {
3581 : : /* found a good sector */
3582 : 0 : f = f_step * ((double)start_max + ((double)len_max - 1.0) / 2.0); /* djb-rwth: cast operators added */
3583 : 0 : r0 = dist / 1.5;
3584 : 0 : xr = r0 * cos(f);
3585 : 0 : yr = r0 * sin(f);
3586 : 0 : zr = zr / r * r0;
3587 : : }
3588 : : }
3589 : : }
3590 : : else
3591 : : {
3592 : 3 : xr = yr = zr = 0;
3593 : : }
3594 : :
3595 : 3 : done:
3596 [ - + ]: 3 : if (at[iat_H].valence)
3597 : : {
3598 : : /* disconnect H */
3599 : 0 : next = at[iat_H].neighbor[0];
3600 [ # # ]: 0 : for (i = 0; i < at[next].valence; i++)
3601 : : {
3602 [ # # ]: 0 : if (at[next].neighbor[i] == iat_H)
3603 : : {
3604 : 0 : RemoveInpAtBond(at, next, i);
3605 : 0 : i = 0; /* success */
3606 : 0 : break;
3607 : : }
3608 : : }
3609 : : }
3610 : : else
3611 : : {
3612 : : /* isolated H+ cation */
3613 : 3 : next = iat_H;
3614 : 3 : i = 0;
3615 : 3 : at[iat_H].valence = 1;
3616 : 3 : at[iat_H].chem_bonds_valence = 1;
3617 : 3 : at[iat_H].bond_type[0] = BOND_TYPE_SINGLE;
3618 : : }
3619 : :
3620 [ + - ]: 3 : if (0 == i /*i < at[next].valence*/)
3621 : : {
3622 : : /* move charge */
3623 [ - + - - ]: 3 : if (at[next].charge > 0 && at[iat].charge < 0)
3624 : : {
3625 : 0 : at[next].charge--;
3626 : 0 : at[iat].charge++;
3627 : : }
3628 : :
3629 : : /* connect H to at[iat] */
3630 : 3 : val = at[iat].valence;
3631 : :
3632 : : #pragma warning (push)
3633 : : #pragma warning (disable: 6386)
3634 [ + - ]: 3 : if (val < MAXVAL)
3635 : : {
3636 : 3 : at[iat].neighbor[val] = iat_H;
3637 : 3 : at[iat].bond_type[val] = at[iat_H].bond_type[0];
3638 : 3 : at[iat].bond_stereo[val] = 0;
3639 : 3 : at[iat].chem_bonds_valence += at[iat_H].bond_type[0];
3640 : 3 : at[iat].valence = val + 1;
3641 : : };
3642 : : #pragma warning(pop)
3643 : :
3644 : 3 : at[iat_H].component = at[iat].component;
3645 : 3 : at[iat_H].neighbor[0] = iat;
3646 : 3 : at[iat_H].bond_stereo[0] = 0; /* possible loss of stereo info */
3647 : 3 : at[iat_H].x = at[iat].x + xr;
3648 : 3 : at[iat_H].y = at[iat].y + yr;
3649 : 3 : at[iat_H].z = at[iat].z + zr;
3650 : :
3651 : 3 : return 1; /* success */
3652 : : }
3653 : :
3654 : 0 : return 0; /* failed */
3655 : : }
3656 : :
3657 : : /****************************************************************************/
3658 : 161 : int add_DT_to_num_H(int num_atoms, inp_ATOM *at)
3659 : : /* assume num_1H, num_D and num_T are not included in num_H */
3660 : : {
3661 : : int i, j;
3662 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
3663 : : {
3664 [ + + ]: 3240 : for (j = 0; j < NUM_H_ISOTOPES; j++)
3665 : : {
3666 : 2430 : at[i].num_H += at[i].num_iso_H[j];
3667 : : }
3668 : : }
3669 : 161 : return 0;
3670 : : }
3671 : :
3672 : : /****************************************************************************
3673 : : **@nnuk
3674 : : * @param at input atom array
3675 : : * @param num_atoms number of atoms
3676 : : * @param metal_idx index of the metal atom
3677 : : * @return 1 all neighbors are H/D/T
3678 : : * @return 0 at least one non-hydrogen neighbor is present
3679 : : ****************************************************************************/
3680 : 1 : static int is_only_HDT_neighbors(const inp_ATOM* at, int num_atoms, int metal_idx)
3681 : : {
3682 : : int v;
3683 : :
3684 [ + - + - : 1 : if (!at || metal_idx < 0 || metal_idx >= num_atoms)
- + ]
3685 : : {
3686 : 0 : return 0;
3687 : : }
3688 : :
3689 [ + - ]: 2 : for (v = 0; v < at[metal_idx].valence; v++)
3690 : : {
3691 : 2 : int nb = at[metal_idx].neighbor[v];
3692 : :
3693 [ + - - + ]: 2 : if (nb < 0 || nb >= num_atoms)
3694 : : {
3695 : 0 : continue;
3696 : : }
3697 : :
3698 [ + + - + ]: 2 : if (!(at[nb].elname[0] == 'H' && at[nb].elname[1] == '\0'))
3699 : : {
3700 : 1 : return 0;
3701 : : }
3702 : : }
3703 : :
3704 : 0 : return 1;
3705 : : }
3706 : :
3707 : : /****************************************************************************
3708 : : Return value: new number of atoms > 0 or -1=out of RAM
3709 : : ****************************************************************************/
3710 : 161 : int remove_terminal_HDT(int num_atoms, inp_ATOM *at, int bFixTermHChrg, const unsigned char* keep_explicit_HDT)
3711 : : {
3712 : : AT_NUMB *new_ord;
3713 : : inp_ATOM *new_at;
3714 : : char *p;
3715 : : static const char szHDT[] = "HDT";
3716 : : static const int kMax = sizeof(szHDT); /* = 4 */
3717 : 161 : int ret = -1;
3718 : 161 : int num_hydrogens = 0, num_H = 0; /* number of terminal H, D, T */
3719 : : int i, j, k, n, m;
3720 : : int val;
3721 : : AT_RANK new_HydrogenAt_order[NUM_H_ISOTOPES + 1];
3722 : : AT_RANK new_OtherNeigh_order[MAXVAL];
3723 : : S_CHAR old_trans[MAX_NUM_STEREO_BONDS];
3724 : :
3725 : : int num_OtherNeigh, num_HydrogenAt;
3726 : :
3727 : 161 : new_ord = (AT_NUMB *)inchi_calloc(num_atoms, sizeof(new_ord[0])); /* changed malloc to calloc 9-11-2003 */
3728 : 161 : new_at = (inp_ATOM *)inchi_malloc(sizeof(new_at[0]) * num_atoms);
3729 [ + - - + ]: 161 : if (!new_ord || !new_at)
3730 : : {
3731 : 0 : goto exit_function;
3732 : : }
3733 : :
3734 : : /* move H. D, T to the end of the list of atoms */
3735 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
3736 : : {
3737 : 810 : at[i].component = i; /* temporarily save original numbering */
3738 : : /* get k = temp. hydrogen isotope/non-hydrogen atom type: */
3739 : : /* k=0:H, k=2:D, k=3:T, k=4=kMax: not a hydrogen */
3740 [ + + ]: 1449 : k = at[i].elname[1] ? kMax : (p = (char *)strchr(szHDT, at[i].elname[0])) ? (int)(p - szHDT)
3741 [ + + ]: 639 : : kMax;
3742 : : /* set hydrogen isotope atw differences */
3743 : : /* Notes: k-value of isotopic H is incremented to correct iso_atw_diff value later. */
3744 : : /* 1H isotope cannot be detected here. */
3745 [ + - - + ]: 810 : if (k == ATW_H || k == ATW_H + 1)
3746 : : {
3747 : : /* D or T, k = 1 or 2 */
3748 : 0 : at[i].elname[0] = 'H'; /* hydrogen isotope */
3749 : 0 : at[i].iso_atw_diff = ++k; /* increment k to make k = iso_atw_diff ( 2 for D, 3 for T ) */
3750 : : }
3751 [ + + + + : 810 : num_H += (k != kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 && !NUMH(at, i));
+ - + - ]
3752 : : }
3753 : :
3754 : : /* special case: HD, HT, DT, HH: the only non-isotopic H or
3755 : : * the lightest isotopic H out of two is removed
3756 : : * to become implicit (make the heavier H the "central atom").
3757 : : * Note: This must be consistent with MOL_FMT_to_atom()
3758 : : * treatment of isotopic Hn aliases.
3759 : : */
3760 [ - + - - ]: 161 : if (2 == num_H && 2 == num_atoms &&
3761 [ # # # # : 0 : !NUMH(at, 0) && !NUMH(at, 1) &&
# # ]
3762 : 0 : (!keep_explicit_HDT ||
3763 [ # # ]: 0 : (!keep_explicit_HDT[0] &&
3764 [ # # ]: 0 : !keep_explicit_HDT[1])))
3765 : : {
3766 : :
3767 [ # # ]: 0 : if (at[0].iso_atw_diff >= at[1].iso_atw_diff)
3768 : : {
3769 : 0 : new_ord[0] = 0;
3770 : 0 : new_ord[1] = 1;
3771 : : }
3772 : : else
3773 : : {
3774 : 0 : new_ord[0] = 1;
3775 : 0 : new_ord[1] = 0;
3776 : : }
3777 [ # # ]: 0 : if (at[new_ord[1]].charge)
3778 : : {
3779 : 0 : at[new_ord[0]].charge += at[new_ord[1]].charge;
3780 : 0 : at[new_ord[1]].charge = 0;
3781 : : }
3782 : 0 : new_at[new_ord[0]] = at[0];
3783 : 0 : new_at[new_ord[1]] = at[1];
3784 : 0 : num_hydrogens = 1;
3785 : : }
3786 : : else
3787 : : {
3788 : : /* general case except H-H */
3789 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
3790 : : {
3791 [ + + + + ]: 916 : k = (at[i].elname[1] || NUMH(at, i)) ? kMax : (at[i].elname[0] == 'H') ? at[i].iso_atw_diff
3792 [ + + ]: 106 : : kMax;
3793 : 810 : n = (int)at[i].neighbor[0];
3794 [ + + + + : 810 : if (k < kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 &&
+ - + + ]
3795 [ - + + - ]: 3 : (!keep_explicit_HDT || !keep_explicit_HDT[i]) &&
3796 : : /* the order of comparison is important */
3797 : 1 : ((n > i) /* at[n] has not been encountered yet*/ ||
3798 [ + - + - ]: 2 : (int)new_ord[n] < num_atoms - num_hydrogens) /* at[n] might have been encountered; it has not been moved */ &&
3799 [ - + ]: 2 : (!is_el_a_metal(at[n].el_number) || is_only_HDT_neighbors(at, num_atoms, n))/*@nnuk*/)
3800 : : {
3801 : : /* found an explicit terminal hydrogen */
3802 : 0 : num_hydrogens++;
3803 [ # # # # : 0 : if (k == 0 && ATW_H <= at[i].iso_atw_diff && at[i].iso_atw_diff < ATW_H + NUM_H_ISOTOPES)
# # ]
3804 : : {
3805 : 0 : k = at[i].iso_atw_diff; /* H isotope has already been marked above or elsewhere */ /* djb-rwth: ignoring LLVM warning: variable used */
3806 : : }
3807 [ # # ]: 0 : if (at[i].charge)
3808 : : {
3809 : : /* transfer charge from the hydrogen */
3810 : 0 : at[n].charge += at[i].charge;
3811 : 0 : at[i].charge = 0;
3812 [ # # ]: 0 : if (bFixTermHChrg)
3813 : : {
3814 : : /* Fixed bug (July 6, 2008 IPl) :
3815 : : if terminal H was charged (not neutralized before call of remove_terminal_HDT)
3816 : : and had an ordering number > than that of heavy-atom neighbour, then
3817 : : charge on neighbour atom was not adjusted (though charge on H was removed). */
3818 [ # # ]: 0 : if (i > n)
3819 : : /* new_at[new_ord[n]] has been created and filled already */
3820 : 0 : new_at[new_ord[n]].charge = at[n].charge;
3821 : : }
3822 : : }
3823 : 0 : new_ord[i] = num_atoms - num_hydrogens; /* move hydrogens to the end of the list */
3824 : : }
3825 : : else
3826 : : {
3827 : : /* atom is not an explicit terminal hydrogen */
3828 : 810 : new_ord[i] = i - num_hydrogens; /* adjust non-hydrogens positions */
3829 : : }
3830 : :
3831 : : /* copy atom to the new position */
3832 : 810 : new_at[new_ord[i]] = at[i];
3833 : : } /* i */
3834 : : } /* general case except H-H */
3835 : :
3836 [ - + ]: 161 : if (num_hydrogens)
3837 : : {
3838 : 0 : int num_others = num_atoms - num_hydrogens; /* atoms which are not terminal H, D, T */
3839 [ # # ]: 0 : if (num_hydrogens > 1)
3840 : : {
3841 : : /* sort hydrogen isotopes in ascending order, */
3842 : : /* orig, numbers being the secondary sorting key */
3843 : 0 : qsort(new_at + num_others, num_hydrogens, sizeof(new_at[0]), cmp_iso_atw_diff_component_no);
3844 : : }
3845 : : /* save new numbering of hydrogen atoms using temporarily saved orig numbering */
3846 [ # # ]: 0 : for (i = num_others; i < num_atoms; i++)
3847 : : {
3848 : 0 : new_ord[(int)new_at[i].component] = i;
3849 : : }
3850 : :
3851 : : /* renumber neighbors according to new_ord[] and detach terminal hydrogens */
3852 [ # # ]: 0 : for (i = 0; i < num_others; i++)
3853 : : {
3854 : 0 : memset(new_HydrogenAt_order, 0, sizeof(new_HydrogenAt_order)); /* djb-rwth: memset_s C11/Annex K variant? */
3855 : 0 : memset(new_OtherNeigh_order, 0, sizeof(new_OtherNeigh_order)); /* djb-rwth: memset_s C11/Annex K variant? */
3856 : 0 : num_OtherNeigh = 0;
3857 : 0 : num_HydrogenAt = 0;
3858 : 0 : num_H = 0;
3859 : :
3860 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m++)
3861 : : {
3862 : 0 : old_trans[m] = 2 - (new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m])) % 2;
3863 : : }
3864 : :
3865 [ # # ]: 0 : for (k = val = 0; k < new_at[i].valence; k++) /* djb-rwth: removing redundant variables/code */
3866 : : {
3867 [ # # ]: 0 : if (num_others <= (n = new_ord[new_at[i].neighbor[k]]))
3868 : : {
3869 : : /* discovered neighbor = disconnected explicit hydrogen
3870 : : * i = new atom new_at[i] ordering number
3871 : : * n = new number of the explicit H
3872 : : * k = ordering number of the explicit H in new_at[i] adjacency list
3873 : : */
3874 [ # # # # ]: 0 : if (0 < new_at[n].iso_atw_diff && new_at[n].iso_atw_diff < ATW_H + NUM_H_ISOTOPES)
3875 : : {
3876 : : /* make explicit isotopic H implicit */
3877 : 0 : new_at[i].num_iso_H[new_at[n].iso_atw_diff - 1]++; /* isotopic H */
3878 : 0 : num_HydrogenAt += !new_HydrogenAt_order[new_at[n].iso_atw_diff];
3879 : 0 : new_HydrogenAt_order[new_at[n].iso_atw_diff] = k + 1;
3880 : : }
3881 : : else
3882 : : {
3883 : : /* make explicit non-isotopic H implicit */
3884 : 0 : new_at[i].num_H++; /* non-isotopic H */
3885 : 0 : num_HydrogenAt += !num_H;
3886 : 0 : num_H++;
3887 : 0 : new_HydrogenAt_order[0] = k + 1;
3888 : : }
3889 : : /* decrement chem. bonds valence because one bond is removed */
3890 [ # # ]: 0 : new_at[i].chem_bonds_valence = inchi_max(0, new_at[i].chem_bonds_valence - 1);
3891 : 0 : new_at[n].neighbor[0] = i; /* update removed hydrogen neighbor number */
3892 [ # # ]: 0 : if (new_at[i].sb_parity[0])
3893 : : {
3894 : : /* if the removed H is an SB neighbor then mark it as removed */
3895 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m++)
3896 : : {
3897 [ # # ]: 0 : if (k == (int)new_at[i].sn_ord[m])
3898 : : {
3899 : 0 : new_at[i].sn_ord[m] = -(new_at[n].iso_atw_diff + 1);
3900 : : /* means the SB neighbor has been removed; (-4)=H, (-3)=1H, (-2)=D, (-1)=T */
3901 : : }
3902 : : }
3903 : : }
3904 : : }
3905 : : else
3906 : : {
3907 : : /* discovered a regular (not an explicit H) neighbor */
3908 [ # # ]: 0 : if (new_at[i].sb_parity[0])
3909 : : {
3910 [ # # ]: 0 : if (num_OtherNeigh < MAX_NUM_STEREO_BONDS)
3911 : : {
3912 : 0 : new_OtherNeigh_order[num_OtherNeigh] = k + 1;
3913 : : }
3914 : 0 : num_OtherNeigh++; /* increment outside of if() to detect overflow */
3915 [ # # ]: 0 : if (val != k)
3916 : : {
3917 : : /* store new stereobond and sb-neighbor ordering numbers */
3918 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m++)
3919 : : {
3920 [ # # ]: 0 : if (k == (int)new_at[i].sb_ord[m])
3921 : 0 : new_at[i].sb_ord[m] = val;
3922 [ # # ]: 0 : else if (k == (int)new_at[i].sn_ord[m])
3923 : 0 : new_at[i].sn_ord[m] = val;
3924 : : }
3925 : : }
3926 : : }
3927 : 0 : new_at[i].neighbor[val] = new_ord[new_at[i].neighbor[k]];
3928 : 0 : new_at[i].bond_type[val] = new_at[i].bond_type[k];
3929 : 0 : new_at[i].bond_stereo[val] = new_at[i].bond_stereo[k];
3930 : 0 : val++;
3931 : : }
3932 : : }
3933 [ # # # # ]: 0 : if (new_at[i].valence > val && new_at[i].sb_parity[0])
3934 : : {
3935 [ # # # # ]: 0 : if (num_HydrogenAt == new_at[i].valence - val && num_HydrogenAt + num_OtherNeigh <= MAXVAL)
3936 : : {
3937 : : /* recalculate parity so that it would describe neighbor sequence H,1H,D,T,neigh[0],neigh[1]... */
3938 : 0 : memmove(new_OtherNeigh_order + num_HydrogenAt, new_OtherNeigh_order, num_OtherNeigh * sizeof(new_OtherNeigh_order[0]));
3939 [ # # ]: 0 : for (k = 0, j = 1; k <= NUM_H_ISOTOPES; k++)
3940 : : {
3941 [ # # # # : 0 : if (new_HydrogenAt_order[k] && (num_HydrogenAt - j < MAXVAL) && (num_HydrogenAt - j >= 0)) /* djb-rwth: fixing buffer overruns */
# # ]
3942 : : {
3943 : 0 : new_OtherNeigh_order[num_HydrogenAt - j] = new_HydrogenAt_order[k];
3944 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m++)
3945 : : {
3946 [ # # ]: 0 : if ((int)new_at[i].sn_ord[m] == -(k + 1))
3947 : : {
3948 : 0 : new_at[i].sn_ord[m] = -j;
3949 : : /* negative means explicit H isotope ord are
3950 : : (contiguously) in front of the adjacency list */
3951 : : }
3952 : : }
3953 : 0 : j++;
3954 : : }
3955 : : }
3956 : : /* at this point new_OtherNeigh_order[] contains
3957 : : incremented old ordering numbers in new order */
3958 : 0 : k = insertions_sort_AT_RANK(new_OtherNeigh_order, num_HydrogenAt + num_OtherNeigh); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3959 : : /* djb-rwth: removing redundant code */
3960 : : /*if ( k ) {*/
3961 : : /*
3962 : : for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
3963 : : if ( PARITY_WELL_DEF(new_at[i].sb_parity[m]) ) {
3964 : : if ( old_trans[m] != 2 - (4 + new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m]))%2 ) {
3965 : : new_at[i].sb_parity[m] = 3 - new_at[i].sb_parity[m];
3966 : : }
3967 : : }
3968 : : }
3969 : : */
3970 : : /*}*/
3971 : : }
3972 : : }
3973 : 0 : new_at[i].valence = val;
3974 : : }
3975 : 0 : memcpy(at, new_at, sizeof(at[0]) * num_atoms);
3976 : 0 : ret = num_others;
3977 : : }
3978 : : else
3979 : : {
3980 : 161 : ret = num_atoms;
3981 : : }
3982 : :
3983 : 161 : exit_function:
3984 : :
3985 [ + - ]: 161 : if (new_ord)
3986 : : {
3987 [ + - ]: 161 : inchi_free(new_ord);
3988 : : }
3989 [ + - ]: 161 : if (new_at)
3990 : : {
3991 [ + - ]: 161 : inchi_free(new_at);
3992 : : }
3993 : :
3994 : 161 : return ret;
3995 : : }
3996 : :
3997 : : /*#endif*/ /* } DISCONNECT_SALTS */
3998 : :
3999 : : typedef enum tagIonAtomType
4000 : : {
4001 : : IAT_H = 0,
4002 : : IAT_C,
4003 : : IAT_N,
4004 : : IAT_P,
4005 : : IAT_O,
4006 : : IAT_S,
4007 : : IAT_Se,
4008 : : IAT_Te,
4009 : : IAT_F,
4010 : : IAT_Cl,
4011 : : IAT_Br,
4012 : : IAT_I,
4013 : : IAT_MAX = 12
4014 : : } ION_ATOM_TYPE;
4015 : :
4016 : : /****************************************************************************/
4017 : 807 : int get_iat_number(int el_number)
4018 : : {
4019 [ + + + + : 807 : switch (el_number)
+ + + + +
+ + + + ]
4020 : : {
4021 : 3 : case EL_NUMBER_H:
4022 : 3 : return IAT_H;
4023 : 471 : case EL_NUMBER_C:
4024 : 471 : return IAT_C;
4025 : 18 : case EL_NUMBER_N:
4026 : 18 : return IAT_N;
4027 : 1 : case EL_NUMBER_P:
4028 : 1 : return IAT_P;
4029 : 123 : case EL_NUMBER_O:
4030 : 123 : return IAT_O;
4031 : 3 : case EL_NUMBER_S:
4032 : 3 : return IAT_S;
4033 : 1 : case EL_NUMBER_SE:
4034 : 1 : return IAT_Se;
4035 : 1 : case EL_NUMBER_TE:
4036 : 1 : return IAT_Te;
4037 : 11 : case EL_NUMBER_F:
4038 : 11 : return IAT_F;
4039 : 90 : case EL_NUMBER_CL:
4040 : 90 : return IAT_Cl;
4041 : 18 : case EL_NUMBER_BR:
4042 : 18 : return IAT_Br;
4043 : 1 : case EL_NUMBER_I:
4044 : 1 : return IAT_I;
4045 : 66 : default:
4046 : 66 : return -1;
4047 : : }
4048 : : }
4049 : :
4050 : : /*****************************************************************************
4051 : : * (@nnuk : Nauman Ullah Khan)
4052 : : * Array only to be used for molecular inorganics. It is seperate from the ElData
4053 : : * array in util.c file. The need for duplicate array arrives as in molecular inorganics
4054 : : * we need a change in metal type. Some changes include an upgrade from lower metal
4055 : : * type to higher metal type (meaning : more valences of an atom can be used).
4056 : : * Some changes include a degradation from higher metal type to a lower metal type
4057 : : * where fewer number of valences for an atom are used. Due to these changes there
4058 : : * is an urge to have a duplicate array so that the current functionality does
4059 : : * not get affected.
4060 : : *
4061 : : * (Summary) : Type of the element has changed from METAL -> MolInOrg.
4062 : : ******************************************************************************/
4063 : :
4064 : : /****************************************************************************
4065 : : * (@nnuk : Nauman Ullah Khan)
4066 : : * Function retrieves the valence values from the MolecularInoragnicsArray
4067 : : ****************************************************************************/
4068 : 26 : int getElValenceforMolecularInorganics(int nPeriodicNum, int charge, int val_num)
4069 : : {
4070 [ + - + - : 26 : if (charge < MIN_ATOM_CHARGE || charge > MAX_ATOM_CHARGE || val_num >= MAX_NUM_VALENCES)
- + ]
4071 : : {
4072 : 0 : return 0;
4073 : : }
4074 : :
4075 [ + - ]: 26 : return (int) MolecularInorganicsArray[nPeriodicNum > 1 ? nPeriodicNum + 1 : 0].cValence[NEUTRAL_STATE + charge][val_num];
4076 : : }
4077 : :
4078 : : /****************************************************************************
4079 : : * (@nnuk : Nauman Ullah Khan)
4080 : : * Function retrieves the element type value from the MolecularInorganicsArray
4081 : : ****************************************************************************/
4082 : 17 : int getElTypeforMolecularInorganics(int nPeriodicNum)
4083 : : {
4084 : 17 : return MolecularInorganicsArray[nPeriodicNum + 1].nType;
4085 : : }
4086 : :
4087 : : /*****************************************************************************
4088 : : * (@nnuk : Nauman Ullah Khan)
4089 : : * Function check for molecular inorganics if a metal atom has to be disconnected
4090 : : * or not.
4091 : : ******************************************************************************/
4092 : 17 : int MolecularInorganicsIsMetalToDisconnect(inp_ATOM *at, int atom_idx)
4093 : : {
4094 : :
4095 : : int at_valence, num_H;
4096 : 17 : int type = getElTypeforMolecularInorganics(at[atom_idx].el_number);
4097 : : int j;
4098 : :
4099 : : /* Calculate the actual valence of the atom
4100 : : * It means that the total bounding capacity
4101 : : * of the atom has to be taken into account
4102 : : * which will further get equated within the
4103 : : * elements array to a metal atom(neutral or an ion) */
4104 : 17 : num_H = NUMH(at, atom_idx);
4105 : 17 : at_valence = num_H + at[atom_idx].chem_bonds_valence;
4106 : :
4107 [ + - - + ]: 17 : if (!at_valence || (abs(at[atom_idx].charge) > 1))
4108 : : {
4109 : 0 : return 0; /* Isolated metal atom or Atom has multiple charges */
4110 : : }
4111 : :
4112 : : /* Check if the valence matches a known normal valence */
4113 [ + + ]: 33 : for (j = 0; j < 4; j++)
4114 : : {
4115 : 31 : const int bitmask = (1 << j); /* Create bitmask for the j-th bit */
4116 : 31 : const bool is_valence_state_valid = (bitmask & type) != 0; /* Check if the j-th valence state is allowed */
4117 : :
4118 [ + + + + ]: 31 : if (is_valence_state_valid && at_valence == getElValenceforMolecularInorganics(at[atom_idx].el_number, at[atom_idx].charge, j))
4119 : : {
4120 : 15 : return 1; /* Atom has normal valence follows disconnection logic if applicable */
4121 : : }
4122 : : }
4123 : :
4124 : : /* Default: Valence greater than usual or the atom is isolated hence no disconnection */
4125 : 2 : return 0;
4126 : : }
4127 : :
4128 : : /*****************************************************************************
4129 : : * (@nnuk : Nauman Ullah Khan)
4130 : : * Function to retrieve binary values for MolecularInorganicsPreprocessing
4131 : : * Binary values are retrieved from the disconnection array "binaryArrayMolecularInorganics"
4132 : : * "1" means that the bond between atom and the neighbouring atom has to be
4133 : : * disconnected whereas, "0" means the bond has to be kept.
4134 : : ******************************************************************************/
4135 : :
4136 : 22 : int shouldBondBeCut(int atom1, int atom2)
4137 : : {
4138 : : int index1, index2, binaryValue;
4139 : :
4140 : : /* Bounds-check the 1-based periodic numbers before indexing the
4141 : : * NUM_ELEMENTS x NUM_ELEMENTS table. An out-of-range value (e.g. a
4142 : : * pseudo-atom with el_number 0, or a number beyond the table) would
4143 : : * otherwise read out of bounds. Default to 0 = keep the bond. */
4144 [ + - + - : 22 : if (atom1 < 1 || atom1 > NUM_ELEMENTS || atom2 < 1 || atom2 > NUM_ELEMENTS)
+ - - + ]
4145 : : {
4146 : 0 : return 0;
4147 : : }
4148 : :
4149 : : /* Get the indices corresponding to the atomic numbers */
4150 : 22 : index1 = atom1 - 1;
4151 : 22 : index2 = atom2 - 1;
4152 : :
4153 : : /* Retrieve the binary value from the binary array */
4154 : 22 : binaryValue = binaryArrayMolecularInorganics[index1][index2];
4155 : :
4156 : : /* Output for debugging purposes */
4157 : : /*printf("Electronegativity binary value between the atom and it's neighbour is: %d\n", binaryValue); */
4158 : :
4159 : 22 : return binaryValue;
4160 : : }
4161 : :
4162 : : /*****************************************************************************
4163 : : * (@nnuk : Nauman Ullah Khan)
4164 : : * Function to update the neighboring list of the atom for MolecularInorganicsPreprocessing.
4165 : : ******************************************************************************/
4166 : :
4167 : 34 : void updateNeighborListMolecularInorganics(inp_ATOM *at, int atom_idx, int neighbor_idx)
4168 : : {
4169 : :
4170 : 34 : int valence = at[atom_idx].valence;
4171 : : int i, j;
4172 : :
4173 [ + + ]: 55 : for (i = 0; i < valence; i++)
4174 : : {
4175 [ - + ]: 21 : if (at[atom_idx].neighbor[i] == neighbor_idx)
4176 : : {
4177 : : /* Shift remaining neighbors to fill the gap */
4178 [ # # ]: 0 : for (j = i; j < valence - 1; j++)
4179 : : {
4180 : 0 : at[atom_idx].neighbor[j] = at[atom_idx].neighbor[j + 1];
4181 : : }
4182 : 0 : at[atom_idx].valence--; /* Reduce the valence (number of neighbors) */
4183 : :
4184 : 0 : break;
4185 : : }
4186 : : }
4187 : 34 : }
4188 : :
4189 : : /*****************************************************************************
4190 : : * Convert coordinative (type 9) bonds into normal single bonds.
4191 : : *
4192 : : * A coordinative bond is the zero-order, charge-separated equivalent of a
4193 : : * single bond: the two bonded atoms carry equal and opposite formal charges
4194 : : * (e.g. M(+) ... L(-)). Realizing it as a single bond turns the donated lone
4195 : : * pair into the shared bonding pair, so the +/- charges cancel. This routine
4196 : : * performs that change in place: every COORDINATIVE_BOND becomes
4197 : : * BOND_TYPE_SINGLE and, when the two atoms carry opposite-sign charges, each is
4198 : : * moved one step toward neutral (one charge pair neutralized per bond).
4199 : : *
4200 : : * Only type-9 bonds are touched. A plain single bond is left alone even when
4201 : : * its endpoints carry opposite formal charges: there the charges are an
4202 : : * intrinsic part of the single-bond Lewis structure, not the zero-order
4203 : : * artifact of a dative bond, so cancelling them would corrupt a self-consistent
4204 : : * depiction (and leave the atoms at unusual valences).
4205 : : *
4206 : : * Each undirected bond is processed exactly once, from its lower-indexed
4207 : : * endpoint (the j > i guard), so a multiply-charged pair (e.g. M(2+)-L(2-))
4208 : : * cannot have its charges cancelled once from each stored half-bond.
4209 : : *****************************************************************************/
4210 : 24 : static void ConvertCoordinativeBondsToSingle(inp_ATOM *at, int num_atoms)
4211 : : {
4212 : : int i, k, k2, j;
4213 : :
4214 [ + + ]: 182 : for (i = 0; i < num_atoms; i++)
4215 : : {
4216 [ + + ]: 436 : for (k = 0; k < at[i].valence; k++)
4217 : : {
4218 : 278 : j = at[i].neighbor[k];
4219 [ + - - + ]: 278 : if (j < 0 || j >= num_atoms)
4220 : : {
4221 : 0 : continue;
4222 : : }
4223 : :
4224 : : /* Visit each undirected bond once, from the lower-indexed atom, so
4225 : : * a multiply-charged pair cannot be neutralized once from each end. */
4226 [ + + ]: 278 : if (j <= i)
4227 : : {
4228 : 139 : continue;
4229 : : }
4230 : :
4231 : : /* Only coordinative (type 9) bonds are converted; plain single
4232 : : * bonds keep their intrinsic formal charges untouched. */
4233 [ + + ]: 139 : if (at[i].bond_type[k] != COORDINATIVE_BOND)
4234 : : {
4235 : 133 : continue;
4236 : : }
4237 : :
4238 : : /* Realize the bond as single on both endpoints so the rest of the
4239 : : * pipeline sees a plain single bond from either atom. */
4240 : 6 : at[i].bond_type[k] = BOND_TYPE_SINGLE;
4241 : :
4242 [ + - ]: 10 : for (k2 = 0; k2 < at[j].valence; k2++)
4243 : : {
4244 [ + + ]: 10 : if (at[j].neighbor[k2] == i)
4245 : : {
4246 : 6 : at[j].bond_type[k2] = BOND_TYPE_SINGLE;
4247 : 6 : break;
4248 : : }
4249 : : }
4250 : :
4251 : : /* Cancel the paired +/- charges: the lone pair becomes the bonding
4252 : : * pair, so each atom moves one unit toward neutral. */
4253 [ - + - - ]: 6 : if (at[i].charge > 0 && at[j].charge < 0)
4254 : : {
4255 : 0 : at[i].charge--;
4256 : 0 : at[j].charge++;
4257 : : }
4258 [ + + - + ]: 6 : else if (at[i].charge < 0 && at[j].charge > 0)
4259 : : {
4260 : 0 : at[i].charge++;
4261 : 0 : at[j].charge--;
4262 : : }
4263 : : }
4264 : : }
4265 : 24 : }
4266 : :
4267 : : /*****************************************************************************
4268 : : * @nnuk
4269 : : * Determine whether an element is a Group 1 or Group 2 metal.
4270 : : *
4271 : : * Hydrogen is excluded because it is not treated as a metal by the
4272 : : * Molecular Inorganics preprocessing.
4273 : : *
4274 : : * @param el_number number in the periodic table
4275 : : *
4276 : : * @return 1 or 0
4277 : : *****************************************************************************/
4278 : 42 : static int MolecularInorganicsIsGroup1or2Metal(int el_number)
4279 : : {
4280 [ + + ]: 42 : switch (el_number)
4281 : : {
4282 : : /* Group 1 */
4283 : 26 : case 3: /* Li */
4284 : : case 11: /* Na */
4285 : : case 19: /* K */
4286 : : case 37: /* Rb */
4287 : : case 55: /* Cs */
4288 : : case 87: /* Fr */
4289 : :
4290 : : /* Group 2 */
4291 : : case 4: /* Be */
4292 : : case 12: /* Mg */
4293 : : case 20: /* Ca */
4294 : : case 38: /* Sr */
4295 : : case 56: /* Ba */
4296 : : case 88: /* Ra */
4297 : 26 : return 1;
4298 : :
4299 : 16 : default:
4300 : 16 : return 0;
4301 : : }
4302 : : }
4303 : :
4304 : : /*****************************************************************************
4305 : : * @nnuk
4306 : : * @brief Count C, N, and O atoms in the metal's perceived ring system.
4307 : : *
4308 : : * Implements the chelate-ring criterion from the 2026-07-16 Molecular
4309 : : * Inorganics decision tree. Group 1 and Group 2 metals are excluded and
4310 : : * therefore return zero.
4311 : : *
4312 : : * @param at Input atom array
4313 : : * @param num_at atom number
4314 : : * @param metal_idx index of the metal atom
4315 : : *
4316 : : * @return Number of C, N, and O atoms in the same ring system, or zero when
4317 : : * the metal is in Group 1 or Group 2 or is not part of a ring system.
4318 : : *****************************************************************************/
4319 : 25 : static int MolecularInorganicsCountRingCNOAtoms(const inp_ATOM* at, int num_at, int metal_idx)
4320 : : {
4321 : : int atom_idx;
4322 : 25 : int ring_cno_count = 0;
4323 : : AT_NUMB ring_id;
4324 : :
4325 [ + + + - ]: 25 : if (!MolecularInorganicsIsGroup1or2Metal(at[metal_idx].el_number) && at[metal_idx].nRingSystem)
4326 : : {
4327 : 8 : ring_id = at[metal_idx].nRingSystem;
4328 : :
4329 [ + + ]: 90 : for (atom_idx = 0; atom_idx < num_at; atom_idx++)
4330 : : {
4331 [ + + ]: 82 : if (at[atom_idx].nRingSystem == ring_id &&
4332 [ + + ]: 38 : (at[atom_idx].el_number == 6 || /* C */
4333 [ + - ]: 16 : at[atom_idx].el_number == 7 || /* N */
4334 [ + + ]: 16 : at[atom_idx].el_number == 8)) /* O */
4335 : : {
4336 : 30 : ring_cno_count++;
4337 : : }
4338 : : }
4339 : : }
4340 : :
4341 : 25 : return ring_cno_count;
4342 : : }
4343 : :
4344 : :
4345 : : /*****************************************************************************
4346 : : * @nnuk
4347 : : * Determine whether an input bond has stereochemical direction information
4348 : : * stored on either endpoint of the bond.
4349 : : *
4350 : : * @param at input atom array
4351 : : * @param atom_idx index of the atom
4352 : : * @param bond_pos bond position
4353 : : *
4354 : : * @return if bond has stereo or not
4355 : : *****************************************************************************/
4356 : 25 : static int MolecularInorganicsBondHasStereo(const inp_ATOM* at, int atom_idx, int bond_pos)
4357 : : {
4358 : : int neigh_pos;
4359 : : int neighbor_idx;
4360 : : int bond_has_stereo;
4361 : :
4362 : 25 : neighbor_idx = at[atom_idx].neighbor[bond_pos];
4363 : 25 : bond_has_stereo = (at[atom_idx].bond_stereo[bond_pos] != 0);
4364 : :
4365 [ + - + - ]: 38 : for (neigh_pos = 0; !bond_has_stereo && neigh_pos < at[neighbor_idx].valence; neigh_pos++)
4366 : : {
4367 [ + + ]: 38 : if (at[neighbor_idx].neighbor[neigh_pos] == atom_idx)
4368 : : {
4369 : 25 : bond_has_stereo = (at[neighbor_idx].bond_stereo[neigh_pos] != 0);
4370 : 25 : break;
4371 : : }
4372 : : }
4373 : :
4374 : 25 : return bond_has_stereo;
4375 : : }
4376 : :
4377 : : /*****************************************************************************
4378 : : * (@nnuk :: Nauman Ullah Khan)
4379 : : * @brief Function to preprocess molecular inorganics structures by disconnecting metal bonds and
4380 : : * handling salts + ammonium salts.
4381 : : *
4382 : : * This function processes a given molecular structure, identifies metal atoms,
4383 : : * and performs bond disconnections based on electronegativity differences,
4384 : : * coordination number and valence. After metal disconnections,
4385 : : * it also checks for ammonium salt patterns and disconnects them where applicable.
4386 : : *
4387 : : * @param orig_at_data Pointer to the original atom data structure.
4388 : : * @param ip Pointer to the input parameters structure.
4389 : : * @return Number of successful disconnections or -1 on error.
4390 : : *****************************************************************************/
4391 : :
4392 : 24 : int MolecularInorganicsPreprocessing(ORIG_ATOM_DATA *orig_at_data, INPUT_PARMS *ip)
4393 : : {
4394 : 24 : int ret_code = 0;
4395 : :
4396 [ + - + - : 24 : if (!ip || !orig_at_data || !orig_at_data->at)
- + ]
4397 : : {
4398 : 0 : return -1;
4399 : : }
4400 : :
4401 [ - + ]: 24 : if (!ip->bMolecularInorganics)
4402 : : {
4403 : 0 : return -1;
4404 : : }
4405 : :
4406 : : /* Pointer to the array of input atoms from the original atom data structure */
4407 : 24 : inp_ATOM *at = orig_at_data->at;
4408 : :
4409 : : /* Total number of input atoms present in the molecular structure */
4410 : 24 : int num_at = orig_at_data->num_inp_atoms;
4411 : :
4412 : : /* Pointer to the array storing the old component numbers for each atom, used for tracking connectivity */
4413 : 24 : AT_NUMB *nOldCompNumber = orig_at_data->nOldCompNumber;
4414 : :
4415 : : /* Track number of disconnections */
4416 : 24 : int num_disconnected = 0;
4417 : :
4418 : : /* variables declared */
4419 : : int i, j, n, k;
4420 : : int binaryValue;
4421 : : int disconnectDecision;
4422 : : int neigh_pos;
4423 : : int neighbor_idx;
4424 : : int num_metals;
4425 : : int all_metal_atoms_terminal;
4426 : : int has_single_bond_to_metal;
4427 : : int keep_all_metal_bonds;
4428 : :
4429 : : /* memory allocation */
4430 : 24 : S_CHAR* dfs_visited = (S_CHAR*)inchi_calloc(num_at, sizeof(S_CHAR));
4431 : 24 : int* dfs_stack = (int*)inchi_malloc(num_at * sizeof(int));
4432 : :
4433 [ + - - + ]: 24 : if (!dfs_visited || !dfs_stack)
4434 : : {
4435 : 0 : ret_code = -1;
4436 : 0 : goto cleanup;
4437 : : }
4438 : :
4439 : : /* Before disconnection, invoke ammonium salt functions */
4440 [ + + ]: 182 : for (j = 0; j < num_at; j++)
4441 : : {
4442 : : int piO, pk;
4443 : : S_CHAR num_explicit_H[NUM_H_ISOTOPES + 1];
4444 : :
4445 [ - + ]: 158 : if (bIsAmmoniumSalt(at, j, &piO, &pk, num_explicit_H))
4446 : : {
4447 : 0 : DisconnectAmmoniumSalt(at, j, piO, pk, num_explicit_H);
4448 : : }
4449 : : }
4450 : :
4451 : : /*
4452 : : * Detect ring systems before the charge-separated bond pass so that a
4453 : : * qualifying metal-containing chelate ring is not disconnected before
4454 : : * the chelate protection rule can be applied.
4455 : : */
4456 : 24 : MarkRingSystemsInp(at, num_at, 0);
4457 : :
4458 : : /* Disconnect charge-separated metal-ligand bonds, preserving the drawn
4459 : : * formal charges. A metal and ligand carrying opposite formal charges
4460 : : * across a single (type 1) or coordinative (type 9) bond depict an ionic
4461 : : * interaction (e.g. M(2+) ... L(2-)) and must split into the drawn ions
4462 : : * regardless of the metal's nominal valence or the presence of other
4463 : : * metals in the same component - the heuristics in the disconnection loop
4464 : : * below would otherwise keep these bonds connected. DisconnectInpAtBond
4465 : : * also decrements valence and chem_bonds_valence on both atoms (a type-9
4466 : : * bond counts as single), so no charge is added or removed here: each ion
4467 : : * keeps exactly the charge drawn in the input. Higher-order bonds (e.g. a
4468 : : * drawn M=O double bond) are genuine covalent bonds and are left intact.
4469 : : *
4470 : : *
4471 : : * An exception is made for non-Group-1/2 metals that belong to a ring
4472 : : * containing at least three carbon, nitrogen, or oxygen atoms. Such bonds
4473 : : * form part of a qualifying chelate ring and must remain connected.*/
4474 [ + + ]: 182 : for (i = 0; i < num_at; i++)
4475 : : {
4476 [ + + ]: 444 : for (k = 0; k < at[i].valence; )
4477 : : {
4478 : : int metal_idx;
4479 : 286 : int ring_cno_count = 0;
4480 : :
4481 : 286 : j = at[i].neighbor[k];
4482 : :
4483 : : /* Process each undirected bond once, from its lower-indexed atom,
4484 : : * and only charge-separated metal/non-metal single or coordinative
4485 : : * bonds. */
4486 [ + + + - ]: 286 : if (j <= i || j >= num_at ||
4487 [ + + ]: 147 : (at[i].bond_type[k] != COORDINATIVE_BOND &&
4488 [ + + + + ]: 251 : at[i].bond_type[k] != BOND_TYPE_SINGLE) ||
4489 : 117 : is_el_a_metal(at[i].el_number) ==
4490 : 117 : is_el_a_metal(at[j].el_number) ||
4491 [ + + - + ]: 51 : !((at[i].charge > 0 && at[j].charge < 0) ||
4492 [ + + + + ]: 44 : (at[i].charge < 0 && at[j].charge > 0)))
4493 : : {
4494 : 278 : k++;
4495 : 278 : continue;
4496 : : }
4497 : :
4498 [ + + ]: 8 : metal_idx = is_el_a_metal(at[i].el_number) ? i : j;
4499 : :
4500 : : /*
4501 : : * Deliberately apply the chelate-ring protection in this preliminary
4502 : : * charge-separated bond pass. Without this check, an explicitly charged
4503 : : * chelate of a non-Group-1/2 metal could be disconnected before the main
4504 : : * decision-tree pass evaluates whether its metal bonds must be retained.
4505 : : *
4506 : : * The ring criterion follows the 2026-07-16 Molecular Inorganics decision
4507 : : * tree: the metal-containing ring system must contain at least three atoms
4508 : : * selected from C, N, and O.
4509 : : */
4510 : 8 : ring_cno_count = MolecularInorganicsCountRingCNOAtoms(at, num_at, metal_idx);
4511 : :
4512 [ - + ]: 8 : if (ring_cno_count >= 3)
4513 : : {
4514 : 0 : k++;
4515 : 0 : continue;
4516 : : }
4517 : :
4518 : 8 : DisconnectInpAtBond(at, nOldCompNumber, i, k);
4519 : 8 : num_disconnected++;
4520 : 8 : ip->bMolecularInorganicsReconnectedInChI = 1;
4521 : : }
4522 : : }
4523 : :
4524 : : /* Realize the remaining (uncharged) coordinative (type 9) bonds as single
4525 : : * bonds, so the rest of the pipeline treats them like the equivalent
4526 : : * single-bonded structure.
4527 : : */
4528 : 24 : ConvertCoordinativeBondsToSingle(at, num_at);
4529 : :
4530 : : /*
4531 : : * Re-perceive ring systems after the charge-separated bond disconnections,
4532 : : * because those graph changes may alter the ring membership used by the
4533 : : * main Molecular Inorganics decision-tree evaluation.
4534 : : */
4535 : 24 : MarkRingSystemsInp(at, num_at, 0);
4536 : :
4537 : : /* Compute the number of metals and whether every metal is terminal. */
4538 : 24 : num_metals = 0;
4539 : 24 : all_metal_atoms_terminal = 1;
4540 : :
4541 [ + + ]: 182 : for (i = 0; i < num_at; i++)
4542 : : {
4543 [ + + ]: 158 : if (is_el_a_metal(at[i].el_number))
4544 : : {
4545 : 26 : num_metals++;
4546 : :
4547 [ + + - + ]: 26 : if (at[i].valence != 1 || at[i].bond_type[0] != BOND_TYPE_SINGLE)
4548 : : {
4549 : 22 : all_metal_atoms_terminal = 0;
4550 : : }
4551 : : }
4552 : : }
4553 : :
4554 [ + + ]: 24 : if (!num_metals)
4555 : : {
4556 : 2 : goto cleanup;
4557 : : }
4558 : :
4559 : : /* Check whether at least one single bond remains attached to a metal. */
4560 : 22 : has_single_bond_to_metal = 0;
4561 : :
4562 [ + + + + ]: 92 : for (i = 0; i < num_at && !has_single_bond_to_metal; i++)
4563 : : {
4564 [ + + ]: 70 : if (!is_el_a_metal(at[i].el_number))
4565 : : {
4566 : 47 : continue;
4567 : : }
4568 : :
4569 [ + + ]: 23 : for (n = 0; n < at[i].valence; n++)
4570 : : {
4571 [ + - ]: 14 : if (at[i].bond_type[n] == BOND_TYPE_SINGLE)
4572 : : {
4573 : 14 : has_single_bond_to_metal = 1;
4574 : 14 : break;
4575 : : }
4576 : : }
4577 : : }
4578 : :
4579 [ + + ]: 22 : if (!has_single_bond_to_metal)
4580 : : {
4581 : 8 : goto cleanup;
4582 : : }
4583 : :
4584 : : /* Evaluate the complete decision tree before changing any remaining
4585 : : * metal-ligand bond. If one bond must be retained, all remaining bonds to
4586 : : * metal atoms are retained. */
4587 : 14 : keep_all_metal_bonds = 0;
4588 : :
4589 [ + + + + ]: 82 : for (i = 0; i < num_at && !keep_all_metal_bonds; i++)
4590 : : {
4591 : 68 : int ring_cno_count = 0;
4592 : : int current_metal_is_group_1_or_2;
4593 : :
4594 [ + + ]: 68 : if (!is_el_a_metal(at[i].el_number))
4595 : : {
4596 : 51 : continue;
4597 : : }
4598 : :
4599 : 17 : current_metal_is_group_1_or_2 = MolecularInorganicsIsGroup1or2Metal(at[i].el_number);
4600 : :
4601 : : /*
4602 : : * Count C, N, and O atoms in the same ring system as the metal.
4603 : : * Group 1 and Group 2 metals are excluded from chelate protection.
4604 : : */
4605 : 17 : ring_cno_count = MolecularInorganicsCountRingCNOAtoms(at, num_at, i);
4606 : :
4607 : 17 : disconnectDecision = MolecularInorganicsIsMetalToDisconnect(at, i);
4608 : :
4609 [ + + ]: 35 : for (n = 0; n < at[i].valence; n++)
4610 : : {
4611 : 25 : int bond_has_stereo = 0;
4612 : 25 : int bond_links_to_other_metal = 0;
4613 : : int dfs_stack_size;
4614 : :
4615 : 25 : neighbor_idx = at[i].neighbor[n];
4616 : :
4617 [ + - - + ]: 25 : if (neighbor_idx < 0 || neighbor_idx >= num_at)
4618 : : {
4619 : 0 : continue;
4620 : : }
4621 : :
4622 : 25 : bond_has_stereo = MolecularInorganicsBondHasStereo(at, i, n);
4623 : :
4624 : : /* The actual bond must be a non-stereogenic single bond. */
4625 [ + + - + ]: 25 : if (at[i].bond_type[n] != BOND_TYPE_SINGLE || bond_has_stereo)
4626 : : {
4627 : 1 : keep_all_metal_bonds = 1;
4628 : 1 : break;
4629 : : }
4630 : :
4631 [ + + ]: 24 : if (disconnectDecision != 1)
4632 : : {
4633 : 2 : keep_all_metal_bonds = 1;
4634 : 2 : break;
4635 : : }
4636 : :
4637 : : /* The bonded atom pair must satisfy the binary disconnection table. */
4638 : 22 : binaryValue = shouldBondBeCut(at[i].el_number, at[neighbor_idx].el_number);
4639 : :
4640 [ + + ]: 22 : if (binaryValue != 1)
4641 : : {
4642 : 2 : keep_all_metal_bonds = 1;
4643 : 2 : break;
4644 : : }
4645 : :
4646 : : /* Determine whether the actual bond is part of a path from this
4647 : : * metal atom to another metal atom. The current metal is excluded
4648 : : * from the traversal so that only paths starting through this bond
4649 : : * are considered. */
4650 : 20 : memset(dfs_visited, 0, num_at * sizeof(*dfs_visited));
4651 : 20 : dfs_stack_size = 0;
4652 : 20 : dfs_visited[i] = 1;
4653 : 20 : dfs_visited[neighbor_idx] = 1;
4654 : 20 : dfs_stack[dfs_stack_size++] = neighbor_idx;
4655 : :
4656 [ + + + - ]: 118 : while (dfs_stack_size && !bond_links_to_other_metal)
4657 : : {
4658 : 106 : int current_atom = dfs_stack[--dfs_stack_size];
4659 : :
4660 [ + + ]: 106 : if (is_el_a_metal(at[current_atom].el_number))
4661 : : {
4662 : 8 : bond_links_to_other_metal = 1;
4663 : 8 : break;
4664 : : }
4665 : :
4666 [ + + ]: 312 : for (neigh_pos = 0; neigh_pos < at[current_atom].valence; neigh_pos++)
4667 : : {
4668 : 214 : int neighbor_atom = at[current_atom].neighbor[neigh_pos];
4669 : :
4670 [ + - + - : 214 : if (neighbor_atom < 0 || neighbor_atom >= num_at || dfs_visited[neighbor_atom])
+ + ]
4671 : : {
4672 : 111 : continue;
4673 : : }
4674 : :
4675 : 103 : dfs_visited[neighbor_atom] = 1;
4676 : 103 : dfs_stack[dfs_stack_size++] = neighbor_atom;
4677 : : }
4678 : : }
4679 : :
4680 : : /*
4681 : : * Retain a linkage to another metal unless:
4682 : : * 1) all metal atoms are terminal, or
4683 : : * 2) the current metal belongs to Group 1 or Group 2.
4684 : : */
4685 [ + + + + : 20 : if (bond_links_to_other_metal && !all_metal_atoms_terminal && !current_metal_is_group_1_or_2)
- + ]
4686 : : {
4687 : 0 : keep_all_metal_bonds = 1;
4688 : 0 : break;
4689 : : }
4690 : :
4691 : : /*
4692 : : * Protect a qualifying chelate ring. Group 1 and Group 2 metals return
4693 : : * zero from MolecularInorganicsCountRingCNOAtoms().
4694 : : */
4695 [ + + ]: 20 : if (ring_cno_count >= 3)
4696 : : {
4697 : 2 : keep_all_metal_bonds = 1;
4698 : 2 : break;
4699 : : }
4700 : : }
4701 : : }
4702 : :
4703 [ + + ]: 14 : if (keep_all_metal_bonds)
4704 : : {
4705 : 7 : ip->bMolecularInorganicsReconnectedInChI = 1;
4706 : 7 : goto cleanup;
4707 : : }
4708 : :
4709 : : /* All remaining metal bonds satisfy the complete decision tree and may be
4710 : : * disconnected.
4711 : : **/
4712 [ + + ]: 59 : for (i = 0; i < num_at; i++)
4713 : : {
4714 [ + + ]: 52 : if (!is_el_a_metal(at[i].el_number))
4715 : : {
4716 : 42 : continue;
4717 : : }
4718 : :
4719 [ + + ]: 27 : for (n = at[i].valence - 1; n >= 0; n--)
4720 : : {
4721 : 17 : neighbor_idx = at[i].neighbor[n];
4722 : :
4723 [ + - - + ]: 17 : if (neighbor_idx < 0 || neighbor_idx >= num_at)
4724 : : {
4725 : 0 : continue;
4726 : : }
4727 : :
4728 : 17 : DisconnectInpAtBond(at, nOldCompNumber, i, n);
4729 : :
4730 : : /* Updating the metal as well as neighbor list */
4731 : 17 : updateNeighborListMolecularInorganics(at, i, neighbor_idx);
4732 : 17 : updateNeighborListMolecularInorganics(at, neighbor_idx, i);
4733 : :
4734 : 17 : at[i].charge += 1; /* Metal atom loses an electron -> +1 charge */
4735 : 17 : at[neighbor_idx].charge -= 1; /* Neighbor atom gains an electron -> -1 charge */
4736 : :
4737 : 17 : num_disconnected++;
4738 : : }
4739 : : }
4740 : :
4741 : 7 : cleanup:
4742 [ + - + - ]: 24 : if (dfs_visited) inchi_free(dfs_visited);
4743 [ + - + - ]: 24 : if (dfs_stack) inchi_free(dfs_stack);
4744 : :
4745 [ - + ]: 24 : return (ret_code < 0) ? ret_code : num_disconnected;
4746 : : }
4747 : :
4748 : : #if (READ_INCHI_STRING == 1)
4749 : :
4750 : : /****************************************************************************/
4751 : 0 : int bHeteroAtomMayHaveXchgIsoH(inp_ATOM *atom, int iat)
4752 : : {
4753 : 0 : inp_ATOM *at = atom + iat, *at2;
4754 : 0 : int j, val, is_H = 0, num_H, iat_numb, bAccept; /* djb-rwth: removing redundant variables */
4755 : :
4756 [ # # ]: 0 : if (0 > (iat_numb = get_iat_number(at->el_number)))
4757 : : {
4758 : 0 : return 0;
4759 : : }
4760 : :
4761 [ # # # # : 0 : if (abs(at->charge) > 1 || (at->radical && RADICAL_SINGLET != at->radical)) /* djb-rwth: addressing LLVM warning */
# # ]
4762 : : {
4763 : 0 : return 0;
4764 : : }
4765 : :
4766 : 0 : val = -1;
4767 [ # # # # : 0 : switch (iat_numb)
# ]
4768 : : {
4769 : 0 : case IAT_N:
4770 : : case IAT_P:
4771 : : /* djb-rwth: removing redundant code */
4772 : 0 : val = 3 + at->charge;
4773 : 0 : break;
4774 : :
4775 : 0 : case IAT_O:
4776 : : case IAT_S:
4777 : : case IAT_Se:
4778 : : case IAT_Te:
4779 : : /* djb-rwth: removing redundant code */
4780 : 0 : val = 2 + at->charge;
4781 : 0 : break;
4782 : :
4783 : 0 : case IAT_F:
4784 : : case IAT_Cl:
4785 : : case IAT_Br:
4786 : : case IAT_I:
4787 [ # # ]: 0 : if (at->charge == 0)
4788 : : {
4789 : : /* djb-rwth: removing redundant code */
4790 : 0 : val = 1;
4791 : : }
4792 : 0 : break;
4793 : :
4794 : 0 : case IAT_H:
4795 [ # # ]: 0 : if (at->valence == 0 &&
4796 [ # # ]: 0 : at->charge == 1)
4797 : : {
4798 : 0 : is_H = 1; /* isolated proton */
4799 : 0 : val = 0;
4800 : : }
4801 : : }
4802 [ # # ]: 0 : if (val < 0)
4803 : : {
4804 : 0 : return 0;
4805 : : }
4806 : 0 : num_H = NUMH(at, 0);
4807 [ # # ]: 0 : if (val != at->chem_bonds_valence + num_H)
4808 : : {
4809 : 0 : return 0;
4810 : : }
4811 [ # # ]: 0 : if (is_H)
4812 : : {
4813 : 0 : return 2; /* H atom */
4814 : : }
4815 : : else
4816 : : {
4817 : : /* djb-rwth: removing redundant code */
4818 [ # # # # ]: 0 : for (j = 0, bAccept = 1; j < at->valence && bAccept; j++)
4819 : : {
4820 : 0 : at2 = atom + (int)at->neighbor[j];
4821 [ # # # # ]: 0 : if ((at2->charge && at->charge) ||
4822 [ # # # # ]: 0 : (at2->radical && RADICAL_SINGLET != at2->radical)) /* djb-rwth: addressing LLVM warning */
4823 : : {
4824 : 0 : return 0; /* adjacent charged/radical atoms: do not neutralizate */
4825 : : }
4826 : : }
4827 : : }
4828 : :
4829 : 0 : return 1;
4830 : : }
4831 : :
4832 : : #endif
4833 : :
4834 : : /****************************************************************************/
4835 : 122 : int bNumHeterAtomHasIsotopicH(inp_ATOM *atom, int num_atoms)
4836 : : {
4837 : 122 : int i, j, val, is_H = 0, num_H, iat_numb, bAccept, num_iso_H, cur_num_iso_H, num_iso_atoms; /* djb-rwth: removing redundant variables */
4838 : : inp_ATOM *at, *at2;
4839 : :
4840 : 122 : num_iso_H = 0;
4841 : 122 : num_iso_atoms = 0;
4842 : :
4843 [ + + ]: 929 : for (i = 0, at = atom; i < num_atoms; i++, at++)
4844 : : {
4845 : :
4846 [ + - - + ]: 807 : num_iso_atoms += (at->iso_atw_diff != 0 || NUM_ISO_H(at, 0));
4847 : : /* isotopic atoms and implicit isotopic H */
4848 : :
4849 [ + + ]: 807 : if (0 > (iat_numb = get_iat_number(at->el_number)))
4850 : : {
4851 : 66 : continue;
4852 : : }
4853 : :
4854 [ + + - + : 741 : if (abs(at->charge) > 1 || (at->radical && RADICAL_SINGLET != at->radical)) /* djb-rwth: addressing LLVM warning */
- - ]
4855 : : {
4856 : 4 : continue;
4857 : : }
4858 : :
4859 : 737 : val = -1;
4860 [ + + + + : 737 : switch (iat_numb)
+ ]
4861 : : {
4862 : 19 : case IAT_N:
4863 : : case IAT_P:
4864 : : /* djb-rwth: removing redundant code */
4865 : 19 : val = 3 + at->charge;
4866 : 19 : break;
4867 : :
4868 : 124 : case IAT_O:
4869 : : case IAT_S:
4870 : : case IAT_Se:
4871 : : case IAT_Te:
4872 : : /* djb-rwth: removing redundant code */
4873 : 124 : val = 2 + at->charge;
4874 : 124 : break;
4875 : :
4876 : 120 : case IAT_F:
4877 : : case IAT_Cl:
4878 : : case IAT_Br:
4879 : : case IAT_I:
4880 [ + + ]: 120 : if (at->charge == 0)
4881 : : {
4882 : : /* djb-rwth: removing redundant code */
4883 : 117 : val = 1;
4884 : : }
4885 : 120 : break;
4886 : :
4887 : 3 : case IAT_H:
4888 [ - + ]: 3 : if (at->valence == 0 &&
4889 [ # # ]: 0 : at->charge == 1)
4890 : : {
4891 : 0 : is_H = 1; /* isolated proton */
4892 : 0 : val = 0;
4893 : : }
4894 : : }
4895 [ + + ]: 737 : if (val < 0)
4896 : : {
4897 : 477 : continue;
4898 : : }
4899 : :
4900 : 260 : num_H = NUMH(at, 0);
4901 [ + + ]: 260 : if (val != at->chem_bonds_valence + num_H)
4902 : : {
4903 : 4 : continue;
4904 : : }
4905 : :
4906 [ - + ]: 256 : if (is_H)
4907 : : {
4908 : 0 : bAccept = 1;
4909 : 0 : cur_num_iso_H = (at->iso_atw_diff != 0);
4910 : : }
4911 : : else
4912 : : {
4913 : 256 : cur_num_iso_H = 0;
4914 [ + + + - ]: 510 : for (j = 0, bAccept = 1; j < at->valence && bAccept; j++)
4915 : : {
4916 : 254 : at2 = atom + (int)at->neighbor[j];
4917 [ + + + - ]: 254 : if ((at2->charge && at->charge) ||
4918 [ - + - - ]: 254 : (at2->radical && RADICAL_SINGLET != at2->radical)) /* djb-rwth: addressing LLVM warning */
4919 : : {
4920 : 0 : bAccept = 0; /* adjacent charged/radical atoms: do not neutralizate */
4921 : 0 : break;
4922 : : }
4923 [ + + ]: 254 : else if (at2->el_number == EL_NUMBER_H &&
4924 [ + - - + ]: 2 : at2->valence == 1 && at2->iso_atw_diff)
4925 : : {
4926 : 0 : cur_num_iso_H++; /* isotopic explicit H */
4927 : : }
4928 : : }
4929 : :
4930 [ + - ]: 256 : if (bAccept)
4931 : : {
4932 : 256 : num_iso_atoms -= cur_num_iso_H; /* avoid counting explicit H as isotopic atom */
4933 : 256 : cur_num_iso_H += NUM_ISO_H(at, 0);
4934 : : }
4935 : : }
4936 : :
4937 [ + - - + ]: 256 : num_iso_H += (bAccept && cur_num_iso_H); /* number of acceptable heteroatoms that have isotopic H */
4938 : : }
4939 : :
4940 [ - + ]: 122 : return ((num_iso_H ? 1 : 0) | (num_iso_atoms ? 2 : 0));
4941 : : }
4942 : :
4943 : : /****************************************************/
4944 : : /* Mark and count disconnected structure components */
4945 : : /* by Depth-first searching each component */
4946 : : /****************************************************/
4947 : 44 : int cmp_components(const void *a1, const void *a2)
4948 : : {
4949 : : int ret;
4950 : : AT_NUMB n1;
4951 : : AT_NUMB n2;
4952 : :
4953 : 44 : n1 = ((const AT_NUMB *)a1)[0];
4954 : : /* number of atoms in the component -- descending order */
4955 : 44 : n2 = ((const AT_NUMB *)a2)[0];
4956 : :
4957 [ + + ]: 44 : if ((ret = (int)n2 - (int)n1)) /* djb-rwth: addressing LLVM warning */
4958 : : {
4959 : 17 : return ret;
4960 : : }
4961 : :
4962 : : /* stable sort */
4963 : 27 : n1 = ((const AT_NUMB *)a1)[1];
4964 : : /* component ordering number -- ascending order */
4965 : 27 : n2 = ((const AT_NUMB *)a2)[1];
4966 : :
4967 : 27 : ret = (int)n1 - (int)n2;
4968 : :
4969 : 27 : return ret;
4970 : : }
4971 : :
4972 : : /**
4973 : : * @brief Get the canonical atom number from original atom number
4974 : : *
4975 : : * @param aux Pointer to INChI auxiliary data
4976 : : * @param orig_atom_num Original atom number
4977 : : * @return Returns the canonical atom number, or -1 if not found
4978 : : */
4979 : 670 : int get_canonical_atom_number( const INChI_Aux *aux,
4980 : : int orig_atom_num)
4981 : : {
4982 [ - + ]: 670 : if (aux == NULL) {
4983 : 0 : return -1;
4984 : : }
4985 : :
4986 [ - + ]: 670 : if (aux->nOrigAtNosInCanonOrd == NULL) {
4987 : 0 : return -1;
4988 : : }
4989 : :
4990 [ + + ]: 7290 : for (int canon_num = 1; canon_num <= aux->nNumberOfAtoms; canon_num++) {
4991 [ + + ]: 6964 : if (aux->nOrigAtNosInCanonOrd[canon_num - 1] == orig_atom_num) {
4992 : 344 : return canon_num;
4993 : : }
4994 : : }
4995 : 326 : return -1;
4996 : : }
4997 : :
4998 : : /**
4999 : : * @brief Get the parity idx from canonical atom number object
5000 : : *
5001 : : * @param canon_atom_num Canonical atom number
5002 : : * @param nNumber Pointer to array of canonical atom numbers
5003 : : * @param nof_atoms Number of atoms
5004 : : * @return Returns the parity index, or -1 if not found
5005 : : */
5006 : 137 : int get_parity_idx_from_canonical_atom_number( int canon_atom_num,
5007 : : const AT_NUMB *nNumber,
5008 : : int nof_atoms)
5009 : : {
5010 [ - + ]: 137 : if (nNumber == NULL) {
5011 : 0 : return -1;
5012 : : }
5013 : :
5014 [ - + ]: 137 : if (nof_atoms <= 0) {
5015 : 0 : return -1;
5016 : : }
5017 : :
5018 [ + + ]: 425 : for (int i = 0; i < nof_atoms; i++) {
5019 [ + + ]: 418 : if (nNumber[i] == canon_atom_num) {
5020 : 130 : return i;
5021 : : }
5022 : : }
5023 : 7 : return -1;
5024 : : }
5025 : :
5026 : : /**
5027 : : * @brief Invert the parities for enhanced stereochemistry t- and m-layers
5028 : : *
5029 : : * @param inchi Pointer to INChI structure
5030 : : * @param aux Pointer to INChI auxiliary data
5031 : : * @param list_atoms Pointer to list of atom lists for abs, rel or rac information
5032 : : * @param nof_lists Number of lists
5033 : : * @param is_absolute Flag indicating if processing absolute stereochemistry
5034 : : * @return Returns 0 on success, 1 if list_atoms is NULL
5035 : : */
5036 : 153 : int invert_parities(const INChI *inchi,
5037 : : const INChI_Aux *aux,
5038 : : int **list_atoms,
5039 : : int nof_lists,
5040 : : int is_absolute)
5041 : : {
5042 : :
5043 : : // t - layer: parities
5044 : : // 2 = +
5045 : : // 1 = -
5046 : :
5047 : : // m - layer
5048 : : // -1 = m0
5049 : : // 1 = m1
5050 : :
5051 [ + + ]: 153 : if (list_atoms == NULL) {
5052 : 64 : return 1;
5053 : : }
5054 : :
5055 [ - + ]: 89 : if (nof_lists == 0)
5056 : : {
5057 : 0 : return 1;
5058 : : }
5059 : :
5060 : 89 : S_CHAR *t_parity = inchi->Stereo->t_parity;
5061 : :
5062 [ + + ]: 254 : for (int i = 0; i < nof_lists; i++) {
5063 : 165 : int nof_atoms = list_atoms[i][1];
5064 : :
5065 : 165 : AT_NUMB min_c_atom_num = (AT_NUMB)INT_MAX;
5066 [ + + ]: 478 : for (int j = 0; j < nof_atoms; j++) {
5067 : 313 : int orig_atom_num = list_atoms[i][2 + j];
5068 : 313 : AT_NUMB canon_atom_num = (AT_NUMB)get_canonical_atom_number(aux, orig_atom_num);
5069 [ + + ]: 313 : if (canon_atom_num < min_c_atom_num) {
5070 : 153 : min_c_atom_num = canon_atom_num;
5071 : : }
5072 : : }
5073 [ + + ]: 165 : if (min_c_atom_num == (AT_NUMB)INT_MAX) {
5074 : 53 : continue;
5075 : : }
5076 : 112 : int min_c_parity_idx = get_parity_idx_from_canonical_atom_number(min_c_atom_num,
5077 : 112 : inchi->Stereo->nNumber,
5078 : 112 : inchi->Stereo->nNumberOfStereoCenters);
5079 : :
5080 [ + + ]: 112 : if (min_c_parity_idx == -1) {
5081 : 3 : continue;
5082 : : }
5083 : :
5084 : 109 : int min_c_atom_parity = t_parity[min_c_parity_idx];
5085 [ + + ]: 109 : if (min_c_atom_parity == 2) {
5086 : :
5087 [ + + ]: 38 : for (int j = 0; j < nof_atoms; j++) {
5088 : 25 : int orig_atom_num = list_atoms[i][2 + j];
5089 : 25 : AT_NUMB canon_atom_num = (AT_NUMB)get_canonical_atom_number(aux, orig_atom_num);
5090 : 25 : int parity_idx = get_parity_idx_from_canonical_atom_number(canon_atom_num,
5091 : 25 : inchi->Stereo->nNumber,
5092 : 25 : inchi->Stereo->nNumberOfStereoCenters);
5093 : :
5094 [ + + ]: 25 : if (parity_idx == -1) {
5095 : 4 : continue;
5096 : : }
5097 : :
5098 [ + + ]: 21 : if (t_parity[parity_idx] == 2) {
5099 : 19 : t_parity[parity_idx] = 1;
5100 [ + - ]: 2 : } else if(t_parity[parity_idx] == 1) {
5101 : 2 : t_parity[parity_idx] = 2;
5102 : : }
5103 : : }
5104 : :
5105 [ + + ]: 13 : if (is_absolute) {
5106 : 2 : inchi->Stereo->nCompInv2Abs = -1; //m1
5107 : : }
5108 : : }
5109 : : }
5110 : 89 : return 0;
5111 : : }
5112 : :
5113 : : /**
5114 : : * @brief Set the enhanced stereochemistry information for t- and m-layers
5115 : : *
5116 : : * @param orig_inp_data Pointer to original input atom data
5117 : : * @param inchi Pointer to INChI structure
5118 : : * @param aux Pointer to INChI auxiliary data
5119 : : * @return Retruns 1 if not V3000, otherwise 0
5120 : : */
5121 : 57 : int set_EnhancedStereo_t_m_layers( const ORIG_ATOM_DATA *orig_inp_data,
5122 : : const INChI *inchi,
5123 : : const INChI_Aux *aux)
5124 : : {
5125 : 57 : int ret = 0;
5126 : :
5127 [ + + ]: 57 : if (!orig_inp_data->v3000)
5128 : : {
5129 : 1 : return 1;
5130 : : }
5131 : :
5132 [ + - - + ]: 56 : if (inchi == NULL || aux == NULL)
5133 : : {
5134 : 0 : return 1;
5135 : : }
5136 : :
5137 [ + - ]: 56 : if (inchi->Stereo == NULL ||
5138 [ + - ]: 56 : inchi->Stereo->t_parity == NULL ||
5139 [ + - ]: 56 : inchi->Stereo->nNumber == NULL ||
5140 [ + + ]: 56 : inchi->Stereo->nNumberOfStereoCenters <= 0) {
5141 : 5 : return 1;
5142 : : }
5143 : :
5144 [ + - ]: 51 : if (aux->nOrigAtNosInCanonOrd == NULL ||
5145 [ - + ]: 51 : aux->nNumberOfAtoms <= 0) {
5146 : 0 : return 1;
5147 : : }
5148 : :
5149 : 51 : int ret_abs = invert_parities(inchi, aux, orig_inp_data->v3000->lists_steabs, orig_inp_data->v3000->n_steabs, 1);
5150 : 51 : int ret_rac = invert_parities(inchi, aux, orig_inp_data->v3000->lists_sterac, orig_inp_data->v3000->n_sterac, 0);
5151 : 51 : int ret_rel = invert_parities(inchi, aux, orig_inp_data->v3000->lists_sterel, orig_inp_data->v3000->n_sterel, 0);
5152 : :
5153 [ + + ]: 51 : if ((orig_inp_data->v3000->n_steabs == 0) &&
5154 [ + + ]: 21 : (orig_inp_data->v3000->n_sterel > 0 ||
5155 [ + + ]: 17 : orig_inp_data->v3000->n_sterac)) {
5156 : 15 : inchi->Stereo->nCompInv2Abs = 1; //m0
5157 : : }
5158 : :
5159 : 51 : return ret;
5160 : : }
5161 : :
5162 : : /****************************************************************************
5163 : : Set the (disconnected) component numbers in ORIG_ATOM_DATA 'at[*].component'
5164 : : NB: components are (stable) sorted by number of heavy atoms
5165 : : ****************************************************************************/
5166 : 130 : int MarkDisconnectedComponents(ORIG_ATOM_DATA *orig_at_data,
5167 : : int bProcessOldCompNumbers)
5168 : : {
5169 : : typedef AT_NUMB AT_TRIPLE[3];
5170 : :
5171 : 130 : inp_ATOM *at = orig_at_data->at;
5172 : 130 : int num_at = orig_at_data->num_inp_atoms;
5173 : 130 : AT_NUMB *nCurAtLen = NULL;
5174 : :
5175 : 130 : AT_NUMB *nNewCompNumber = NULL;
5176 : 130 : AT_NUMB *nPrevAtom = NULL;
5177 : 130 : S_CHAR *iNeigh = NULL;
5178 : :
5179 : 130 : AT_NUMB *nOldCompNumber = NULL;
5180 : : int i, j, num_components, ret;
5181 : : int new_comp_no;
5182 : : AT_NUMB old_comp_no, another_comp_no, no_component;
5183 : :
5184 : : /* component_nbr[i][0] = number of atoms in the component i-1
5185 : : * component_nbr[i][1] = original component number (id-1) = i
5186 : : * after sorting:
5187 : : * component_nbr[j][2] = new number of component #(component_nbr[i][1]+1)
5188 : : */
5189 : 130 : AT_TRIPLE *component_nbr = NULL;
5190 : : int fst_at, nxt_at, cur_at, cur_neq_fst; /* moved from below 2024-09-01 DT */
5191 : :
5192 : : /* initialize */
5193 [ + + - + ]: 130 : if (bProcessOldCompNumbers && !orig_at_data->nOldCompNumber)
5194 : : {
5195 : 0 : bProcessOldCompNumbers = 0;
5196 : : }
5197 : 130 : num_components = 0;
5198 : :
5199 : : /*
5200 : : for ( j = 0; j < num_at; j ++ )
5201 : : {
5202 : : at[j].component = 0;
5203 : : }
5204 : : */
5205 : :
5206 : 130 : ret = -1;
5207 [ - + ]: 130 : if (!num_at)
5208 : : {
5209 : 0 : return 0;
5210 : : }
5211 : :
5212 : 130 : nNewCompNumber = (AT_NUMB *)inchi_calloc(num_at, sizeof(nNewCompNumber[0]));
5213 : 130 : nPrevAtom = (AT_NUMB *)inchi_calloc(num_at, sizeof(nPrevAtom[0]));
5214 : 130 : iNeigh = (S_CHAR *)inchi_calloc(num_at, sizeof(iNeigh[0]));
5215 : :
5216 [ + - + - : 130 : if (!nNewCompNumber || !nPrevAtom || !iNeigh) /* nNewCompNumber: for non-recursive DFS only: */
- + ]
5217 : : {
5218 : 0 : goto exit_function;
5219 : : }
5220 : :
5221 : : /*printf("\nnum_at = %d\n", num_at);*/
5222 : :
5223 : : /* Mark and count; avoid deep DFS recursion: it may make verifying software unhappy */
5224 : : /* nNewCompNumber[i] will contain new component number for atoms at[i], i=0..num_at-1 */
5225 : :
5226 [ + + ]: 984 : for (j = 0; j < num_at; j++)
5227 : : {
5228 [ + + ]: 854 : if (!nNewCompNumber[j])
5229 : : {
5230 : : /* mark starting with at[j] */
5231 : 169 : fst_at = 0;
5232 : 169 : nxt_at = 0;
5233 : 169 : cur_at = j;
5234 : 169 : cur_neq_fst = 1;
5235 : 169 : num_components++;
5236 : :
5237 : : /* first time at at[j] */
5238 : 169 : fst_at = cur_at;
5239 : 169 : nNewCompNumber[fst_at] = (AT_NUMB)num_components;
5240 : :
5241 : : /* find next neighbor */
5242 : : do
5243 : : {
5244 [ + + ]: 2316 : if (iNeigh[cur_at] < at[cur_at].valence)
5245 : : {
5246 : 1462 : int ineigh_incr = (int)iNeigh[cur_at];
5247 : 1462 : nxt_at = at[cur_at].neighbor[ineigh_incr];
5248 : 1462 : iNeigh[cur_at]++;
5249 : :
5250 [ + + ]: 1462 : if (!nNewCompNumber[nxt_at])
5251 : : {
5252 : : /* forward edge: found new atom */
5253 : 685 : nNewCompNumber[nxt_at] = (AT_NUMB)num_components;
5254 : 685 : nPrevAtom[nxt_at] = (AT_NUMB)cur_at;
5255 : 685 : cur_at = nxt_at;
5256 : : }
5257 : : }
5258 [ + + ]: 854 : else if (cur_at == fst_at)
5259 : : {
5260 : 169 : cur_neq_fst = 0;
5261 : : /* break; done */
5262 : : }
5263 : : else
5264 : : {
5265 : 685 : cur_at = nPrevAtom[cur_at]; /* retract */
5266 : : }
5267 [ + + ]: 2316 : } while (cur_neq_fst);
5268 : : }
5269 : : }
5270 : :
5271 [ + - ]: 130 : inchi_free(nPrevAtom);
5272 : 130 : nPrevAtom = NULL;
5273 [ + - ]: 130 : inchi_free(iNeigh);
5274 : 130 : iNeigh = NULL;
5275 : :
5276 : : /* Allocate more memory */
5277 : 130 : i = inchi_max(num_components, orig_at_data->num_components);
5278 : :
5279 : 130 : nCurAtLen = (AT_NUMB *)inchi_calloc((long long)num_components + 1, sizeof(nCurAtLen[0])); /* djb-rwth: cast operator added */
5280 : 130 : nOldCompNumber = (AT_NUMB *)inchi_calloc((long long)i + 1, sizeof(nOldCompNumber[0])); /* djb-rwth: cast operator added */
5281 : 130 : component_nbr = (AT_TRIPLE *)inchi_calloc((long long)num_components + 1, sizeof(component_nbr[0])); /* djb-rwth: cast operator added */
5282 : :
5283 [ + - + - : 130 : if (!nCurAtLen || !nOldCompNumber || !component_nbr)
- + ]
5284 : : {
5285 : 0 : goto exit_function;
5286 : : }
5287 : :
5288 : : /* Count atoms per component and renumber the components */
5289 [ + + ]: 299 : for (i = 0; i < num_components; i++)
5290 : : {
5291 : 169 : component_nbr[i][0] = 0; /* number of atoms in the component */
5292 : 169 : component_nbr[i][1] = i; /* component ordering number */
5293 : : }
5294 : :
5295 [ + + ]: 984 : for (j = 0; j < num_at; j++)
5296 : : {
5297 : 854 : component_nbr[(int)nNewCompNumber[j] - 1][0]++; /* count atoms in each component */
5298 : : }
5299 : :
5300 : : /* Sort settings
5301 : : key: number of atoms
5302 : : order: descending
5303 : : stable sort
5304 : : */
5305 : :
5306 : 130 : qsort( (void*) component_nbr[0], num_components, sizeof( component_nbr[0] ), cmp_components ); /* djb-rwth: fixed buffer overrun */
5307 : :
5308 : : /* Invert the transposition */
5309 [ + + ]: 299 : for (i = 0; i < num_components; i++)
5310 : : {
5311 : 169 : nCurAtLen[i] = component_nbr[i][0];
5312 : 169 : component_nbr[component_nbr[i][1]][2] = i + 1;
5313 : : }
5314 : :
5315 : : /* Renumber the components so that the component with the greatest number of atoms is the first */
5316 : 130 : no_component = num_at + 1;
5317 : :
5318 [ + + ]: 984 : for (j = 0; j < num_at; j++)
5319 : : {
5320 : : /* new component number for at[j] */
5321 : 854 : new_comp_no = component_nbr[(int)nNewCompNumber[j] - 1][2] - 1; /* starts from 0 */
5322 [ + + ]: 854 : if (bProcessOldCompNumbers)
5323 : : {
5324 : : /* old component number for at[j] */
5325 : 25 : old_comp_no = at[j].component;
5326 : : /* fill out nOldCompNumber[]; initially it contains zeroes */
5327 [ - + ]: 25 : if (!old_comp_no)
5328 : : {
5329 : 0 : nOldCompNumber[new_comp_no] = no_component; /* atom did not have component number */
5330 : : }
5331 [ + + ]: 25 : else if (nOldCompNumber[new_comp_no] != old_comp_no)
5332 : : {
5333 [ + - ]: 11 : if (!nOldCompNumber[new_comp_no])
5334 : : {
5335 : 11 : nOldCompNumber[new_comp_no] = old_comp_no;
5336 : : }
5337 : : else
5338 : : {
5339 : : /* at[j] moved from old comp #old_comp_no to old comp #nOldCompNumber[new_comp_no]
5340 : : Both components cannot be equal to any current component */
5341 : 0 : another_comp_no = nOldCompNumber[new_comp_no];
5342 [ # # ]: 0 : for (i = 0; i < num_components; i++)
5343 : : {
5344 [ # # ]: 0 : if (nOldCompNumber[i] == old_comp_no ||
5345 [ # # ]: 0 : nOldCompNumber[i] == another_comp_no)
5346 : : {
5347 : 0 : nOldCompNumber[i] = no_component;
5348 : : }
5349 : : }
5350 : : /* nOldCompNumber[new_comp_no] = num_at+1; */
5351 : : }
5352 : : }
5353 : : }
5354 : :
5355 : : /* orig_at_data->nOldCompNumber */
5356 : :
5357 : : /* Finally, set the new component number for atom j (NB: starts from 1 ) */
5358 : 854 : at[j].component = new_comp_no + 1;
5359 : : }
5360 : :
5361 [ + + ]: 130 : if (bProcessOldCompNumbers)
5362 : : {
5363 [ + + ]: 15 : for (j = 0; j < num_components; j++)
5364 : : {
5365 [ - + ]: 11 : if (nOldCompNumber[j] == no_component)
5366 : : {
5367 : : /* the component has atom from another component */
5368 : 0 : nOldCompNumber[j] = 0;
5369 : : }
5370 [ + - ]: 11 : else if (nOldCompNumber[j] &&
5371 [ + - ]: 11 : !orig_at_data->nOldCompNumber[nOldCompNumber[j] - 1])
5372 : : {
5373 : : /* the component has changed in the previous processing */
5374 : 11 : nOldCompNumber[j] = 0;
5375 : : }
5376 : : }
5377 : : }
5378 : : else
5379 : : {
5380 [ + + ]: 284 : for (j = 0; j < num_components; j++)
5381 : : {
5382 : 158 : nOldCompNumber[j] = j + 1;
5383 : : }
5384 : : }
5385 : :
5386 : 130 : ret = num_components;
5387 : :
5388 : 130 : exit_function:
5389 : :
5390 [ + - ]: 130 : if (nNewCompNumber)
5391 : : {
5392 [ + - ]: 130 : inchi_free(nNewCompNumber);
5393 : : }
5394 [ + - ]: 130 : if (component_nbr)
5395 : : {
5396 [ + - ]: 130 : inchi_free(component_nbr);
5397 : : }
5398 : :
5399 [ - + ]: 130 : if (ret < 0)
5400 : : {
5401 [ # # ]: 0 : if (nPrevAtom)
5402 : : {
5403 [ # # ]: 0 : inchi_free(nPrevAtom);
5404 : 0 : nPrevAtom = NULL;
5405 : : }
5406 [ # # ]: 0 : if (iNeigh)
5407 : : {
5408 [ # # ]: 0 : inchi_free(iNeigh);
5409 : 0 : iNeigh = NULL;
5410 : : }
5411 [ # # ]: 0 : if (nCurAtLen)
5412 : : {
5413 [ # # ]: 0 : inchi_free(nCurAtLen);
5414 : 0 : nCurAtLen = NULL;
5415 : : }
5416 [ # # ]: 0 : if (nOldCompNumber)
5417 : : {
5418 [ # # ]: 0 : inchi_free(nOldCompNumber);
5419 : 0 : nOldCompNumber = NULL;
5420 : : }
5421 : 0 : num_components = ret;
5422 : : }
5423 : :
5424 : : /* avoid memory leaks */
5425 [ + - ]: 130 : if (orig_at_data->nCurAtLen)
5426 : : {
5427 [ + - ]: 130 : inchi_free(orig_at_data->nCurAtLen);
5428 : : }
5429 [ + - ]: 130 : if (orig_at_data->nOldCompNumber)
5430 : : {
5431 [ + - ]: 130 : inchi_free(orig_at_data->nOldCompNumber);
5432 : : }
5433 : :
5434 : 130 : orig_at_data->nCurAtLen = nCurAtLen;
5435 : 130 : orig_at_data->nOldCompNumber = nOldCompNumber;
5436 : :
5437 : 130 : orig_at_data->num_components = num_components;
5438 : :
5439 : 130 : return ret; /* number of disconnected components;
5440 : : 1=>single connected structure */
5441 : : }
5442 : :
5443 : : /****************************************************************************
5444 : : Extract one (connected) component
5445 : : ****************************************************************************/
5446 : 161 : int ExtractConnectedComponent(inp_ATOM *at,
5447 : : int num_at,
5448 : : int component_number,
5449 : : inp_ATOM *component_at)
5450 : : {
5451 : : int i, j, num_component_at;
5452 : : AT_NUMB *number;
5453 : :
5454 [ - + ]: 161 : if (NULL == (number = (AT_NUMB *)inchi_calloc(num_at, sizeof(AT_NUMB))))
5455 : : {
5456 : 0 : return CT_OUT_OF_RAM; /* out of memory */ /* <BRKPT> */
5457 : : }
5458 : :
5459 : : /* copy atoms */
5460 [ + + ]: 1572 : for (i = 0, num_component_at = 0; i < num_at; i++)
5461 : : {
5462 [ + + ]: 1411 : if (at[i].component == component_number)
5463 : : {
5464 : 810 : number[i] = num_component_at;
5465 : 810 : component_at[num_component_at++] = at[i];
5466 : : }
5467 : : }
5468 : :
5469 : : /* renumber neighbors */
5470 [ + + ]: 971 : for (i = 0; i < num_component_at; i++)
5471 : : {
5472 : 810 : component_at[i].orig_compt_at_numb = (AT_NUMB)(i + 1);
5473 [ + + ]: 2160 : for (j = 0; j < component_at[i].valence; j++)
5474 : : {
5475 : 1350 : component_at[i].neighbor[j] = number[(int)component_at[i].neighbor[j]];
5476 : : }
5477 : : }
5478 : :
5479 [ + - ]: 161 : inchi_free(number);
5480 : :
5481 : 161 : return num_component_at;
5482 : : }
5483 : :
5484 : : /****************************************************************************/
5485 : 161 : int SetConnectedComponentNumber(inp_ATOM *at, int num_at, int component_number)
5486 : : {
5487 : : int i;
5488 [ + + ]: 971 : for (i = 0; i < num_at; i++)
5489 : : {
5490 : 810 : at[i].component = (AT_NUMB)component_number;
5491 : : }
5492 : :
5493 : 161 : return 0;
5494 : : }
5495 : :
5496 : : /****************************************************************************/
5497 : 326 : int Free_INChI_Stereo(INChI_Stereo *pINChI_Stereo)
5498 : : {
5499 [ + + ]: 326 : if (pINChI_Stereo)
5500 : : {
5501 [ + - + - ]: 161 : qzfree(pINChI_Stereo->nNumber);
5502 [ + - + - ]: 161 : qzfree(pINChI_Stereo->t_parity);
5503 [ + - + - ]: 161 : qzfree(pINChI_Stereo->nNumberInv);
5504 [ + - + - ]: 161 : qzfree(pINChI_Stereo->t_parityInv);
5505 [ + + + - ]: 161 : qzfree(pINChI_Stereo->nBondAtom1);
5506 [ + + + - ]: 161 : qzfree(pINChI_Stereo->nBondAtom2);
5507 [ + + + - ]: 161 : qzfree(pINChI_Stereo->b_parity);
5508 : : }
5509 : :
5510 : 326 : return 0;
5511 : : }
5512 : :
5513 : : /****************************************************************************/
5514 : 161 : INChI_Stereo *Alloc_INChI_Stereo(int num_at, int num_bonds)
5515 : : {
5516 : :
5517 : : INChI_Stereo *pINChI_Stereo = (INChI_Stereo *)
5518 : 161 : inchi_calloc(1, sizeof(INChI_Stereo));
5519 : :
5520 [ + - ]: 161 : if (pINChI_Stereo)
5521 : : {
5522 [ + - ]: 161 : if (num_at &&
5523 [ + - ]: 161 : (pINChI_Stereo->nNumber = (AT_NUMB *)inchi_calloc(num_at, sizeof(pINChI_Stereo->nNumber[0]))) &&
5524 [ + - ]: 161 : (pINChI_Stereo->t_parity = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI_Stereo->t_parity[0]))) &&
5525 [ + - ]: 161 : (pINChI_Stereo->nNumberInv = (AT_NUMB *)inchi_calloc(num_at, sizeof(pINChI_Stereo->nNumberInv[0]))) &&
5526 [ + - ]: 161 : (pINChI_Stereo->t_parityInv = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI_Stereo->t_parityInv[0]))))
5527 : : {
5528 : : ;
5529 : : }
5530 [ # # ]: 0 : else if (num_at)
5531 : : {
5532 : 0 : goto out_of_RAM;
5533 : : }
5534 : :
5535 [ + + ]: 161 : if (num_bonds &&
5536 [ + - ]: 77 : (pINChI_Stereo->nBondAtom1 = (AT_NUMB *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->nBondAtom1[0]))) &&
5537 [ + - ]: 77 : (pINChI_Stereo->nBondAtom2 = (AT_NUMB *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->nBondAtom2[0]))) &&
5538 [ + - ]: 77 : (pINChI_Stereo->b_parity = (S_CHAR *)inchi_calloc(num_bonds, sizeof(pINChI_Stereo->b_parity[0]))))
5539 : : {
5540 : : ;
5541 : : }
5542 [ - + ]: 84 : else if (num_bonds)
5543 : : {
5544 : 0 : goto out_of_RAM;
5545 : : }
5546 : :
5547 : 161 : return pINChI_Stereo;
5548 : :
5549 : 0 : out_of_RAM:
5550 : :
5551 : 0 : Free_INChI_Stereo(pINChI_Stereo);
5552 [ # # # # ]: 0 : qzfree(pINChI_Stereo);
5553 : : } /* if ( pINChI_Stereo ) */
5554 : :
5555 : 0 : return NULL;
5556 : : }
5557 : :
5558 : : /****************************************************************************/
5559 : 322 : int Free_INChI(INChI **ppINChI)
5560 : : {
5561 : :
5562 : : INChI *pINChI;
5563 : :
5564 [ + + ]: 322 : if ((pINChI = *ppINChI)) /* djb-rwth: addressing LLVM warning */
5565 : : {
5566 : :
5567 : : #if (bREUSE_INCHI == 1)
5568 [ - + ]: 161 : if (pINChI->nRefCount-- > 0)
5569 : 0 : return 1;
5570 : : #endif
5571 : :
5572 : 161 : Free_INChI_Members(pINChI);
5573 [ + - + - ]: 161 : qzfree(pINChI);
5574 : 161 : *ppINChI = NULL;
5575 : : }
5576 : :
5577 : 322 : return 0;
5578 : : }
5579 : :
5580 : : /****************************************************************************/
5581 : 163 : int Free_INChI_Members(INChI *pINChI)
5582 : : {
5583 [ + - ]: 163 : if (pINChI)
5584 : : {
5585 : 163 : Free_INChI_Stereo(pINChI->Stereo);
5586 : 163 : Free_INChI_Stereo(pINChI->StereoIsotopic);
5587 [ + - + - ]: 163 : qzfree(pINChI->nAtom);
5588 [ + - + - ]: 163 : qzfree(pINChI->nConnTable);
5589 [ + + + - ]: 163 : qzfree(pINChI->nTautomer);
5590 [ + - + - ]: 163 : qzfree(pINChI->nNum_H);
5591 [ + + + - ]: 163 : qzfree(pINChI->nNum_H_fixed);
5592 [ - + - - ]: 163 : qzfree(pINChI->IsotopicAtom);
5593 [ - + - - ]: 163 : qzfree(pINChI->IsotopicTGroup);
5594 [ - + - - ]: 163 : qzfree(pINChI->nPossibleLocationsOfIsotopicH);
5595 [ + + + - ]: 163 : qzfree(pINChI->Stereo);
5596 [ - + - - ]: 163 : qzfree(pINChI->StereoIsotopic);
5597 [ + - + - ]: 163 : qzfree(pINChI->szHillFormula);
5598 : : }
5599 : :
5600 : 163 : return 0;
5601 : : }
5602 : :
5603 : : /****************************************************************************/
5604 : 161 : INChI *Alloc_INChI(inp_ATOM *at,
5605 : : int num_at,
5606 : : int *found_num_bonds,
5607 : : int *found_num_isotopic,
5608 : : int nAllocMode)
5609 : : {
5610 : : int i, num_bonds, num_isotopic_atoms;
5611 : : INChI *pINChI;
5612 : 161 : int bIsotopic = (nAllocMode & REQ_MODE_ISO);
5613 : : /* int bTautomeric = (nAllocMode & REQ_MODE_TAUT); */
5614 : :
5615 [ + - ]: 161 : if (num_at <= 0 ||
5616 [ - + ]: 161 : NULL == (pINChI = (INChI *)inchi_calloc(1, sizeof(INChI))))
5617 : : {
5618 : 0 : return NULL;
5619 : : }
5620 : :
5621 [ + + ]: 971 : for (i = 0, num_bonds = 0, num_isotopic_atoms = 0; i < num_at; i++)
5622 : : {
5623 : 810 : num_bonds += at[i].valence;
5624 : : /* if ( bIsotopic ) { */
5625 : 810 : num_isotopic_atoms += (0 != at[i].iso_atw_diff ||
5626 [ + - ]: 810 : !strcmp(at[i].elname, "D") ||
5627 [ + - ]: 810 : !strcmp(at[i].elname, "T") ||
5628 [ + - ]: 810 : at[i].num_iso_H[0] ||
5629 [ + - + - ]: 2430 : at[i].num_iso_H[1] ||
5630 [ - + ]: 810 : at[i].num_iso_H[2]);
5631 : : /* } */
5632 : : }
5633 : 161 : num_bonds /= 2;
5634 : :
5635 : 161 : *found_num_bonds = num_bonds;
5636 : 161 : *found_num_isotopic = num_isotopic_atoms;
5637 : :
5638 [ + - ]: 161 : if ((pINChI->nAtom = (U_CHAR *)inchi_calloc(num_at, sizeof(pINChI->nAtom[0]))) &&
5639 [ + - ]: 161 : (pINChI->nConnTable = (AT_NUMB *)inchi_calloc((long long)num_at + (long long)num_bonds, sizeof(pINChI->nConnTable[0]))) && /* djb-rwth: cast operator added */
5640 [ + - ]: 161 : (pINChI->nTautomer = (AT_NUMB *)inchi_calloc(((3 + INCHI_T_NUM_MOVABLE) * (long long)num_at) / 2 + 1, sizeof(pINChI->nTautomer[0]))) && /* djb-rwth: cast operator added */
5641 [ + - ]: 161 : (pINChI->nNum_H = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI->nNum_H[0]))) &&
5642 [ + - ]: 161 : (pINChI->nNum_H_fixed = (S_CHAR *)inchi_calloc(num_at, sizeof(pINChI->nNum_H_fixed[0]))))
5643 : : {
5644 : : ;
5645 : : /* nTautomer length: max. number of tautomeric groups is num_at/2
5646 : :
5647 : : 1 word -> number of t-groups
5648 : :
5649 : : each group has:
5650 : :
5651 : : 1 word -> number of endpoints+INCHI_T_NUM_MOVABLE
5652 : : INCHI_T_NUM_MOVABLE words -> number(s) of moveable attachments
5653 : : numbers of endpoints words -> canon. numbers
5654 : :
5655 : : max. occurs if each t-group has 2 atoms (num_at/2 t-groups) and all atoms
5656 : : belong to t-groups (num_at endpoints)
5657 : :
5658 : : Total: 1 + (number of t-groups)*(1+INCHI_T_NUM_MOVABLE) + (number of endpoints) <=
5659 : : 1 + (num_at/2) * (1+INCHI_T_NUM_MOVABLE) + num_at <=
5660 : : 1 + (3+INCHI_T_NUM_MOVABLE)*num_at/2 words.
5661 : : */
5662 : : }
5663 : : else
5664 : : {
5665 : 0 : goto out_of_RAM;
5666 : : }
5667 : :
5668 : 161 : pINChI->szHillFormula = NULL; /* the length is unknown */
5669 : :
5670 [ - + ]: 161 : if (bIsotopic)
5671 : : {
5672 [ # # ]: 0 : if (num_isotopic_atoms &&
5673 [ # # ]: 0 : (pINChI->IsotopicAtom = (INChI_IsotopicAtom *)inchi_calloc(num_isotopic_atoms, sizeof(INChI_IsotopicAtom))) &&
5674 [ # # ]: 0 : (pINChI->IsotopicTGroup = (INChI_IsotopicTGroup *)inchi_calloc(num_isotopic_atoms, sizeof(INChI_IsotopicTGroup))))
5675 : : {
5676 : : ;
5677 : : }
5678 [ # # ]: 0 : else if (num_isotopic_atoms)
5679 : : {
5680 : 0 : goto out_of_RAM;
5681 : : }
5682 [ # # ]: 0 : if (!(pINChI->nPossibleLocationsOfIsotopicH = (AT_NUMB *)inchi_calloc((long long)num_at + 1, sizeof(pINChI->nPossibleLocationsOfIsotopicH[0])))) /* djb-rwth: cast operator added */
5683 : : {
5684 : 0 : goto out_of_RAM;
5685 : : }
5686 : : }
5687 : :
5688 [ - + ]: 161 : if ((pINChI->Stereo = Alloc_INChI_Stereo(num_at, num_bonds)))
5689 : : {
5690 : : ;
5691 : : }
5692 : : else
5693 : : {
5694 : 0 : goto out_of_RAM;
5695 : : }
5696 : :
5697 [ - + ]: 161 : if (bIsotopic)
5698 : : {
5699 [ # # ]: 0 : if ((pINChI->StereoIsotopic = Alloc_INChI_Stereo(num_at, num_bonds)))
5700 : : {
5701 : : ;
5702 : : }
5703 : : else
5704 : : {
5705 : 0 : goto out_of_RAM;
5706 : : }
5707 : : }
5708 : :
5709 : 161 : return pINChI;
5710 : :
5711 : 0 : out_of_RAM:
5712 [ # # ]: 0 : if (pINChI)
5713 : : {
5714 : 0 : Free_INChI(&pINChI);
5715 : : /*
5716 : : inchi_free(pINChI);
5717 : : */
5718 : : }
5719 : :
5720 : 0 : return NULL;
5721 : : }
5722 : :
5723 : : /****************************************************************************/
5724 : 322 : int Free_INChI_Aux(INChI_Aux **ppINChI_Aux)
5725 : : {
5726 : 322 : INChI_Aux *pINChI_Aux = *ppINChI_Aux;
5727 [ + + ]: 322 : if (pINChI_Aux)
5728 : : {
5729 : :
5730 : : #if (bREUSE_INCHI == 1)
5731 [ - + ]: 161 : if (pINChI_Aux->nRefCount-- > 0)
5732 : 0 : return 1;
5733 : : #endif
5734 : :
5735 [ + - + - ]: 161 : qzfree(pINChI_Aux->nOrigAtNosInCanonOrd);
5736 [ - + - - ]: 161 : qzfree(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd);
5737 [ + - + - ]: 161 : qzfree(pINChI_Aux->nOrigAtNosInCanonOrdInv);
5738 [ - + - - ]: 161 : qzfree(pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv);
5739 [ + - + - ]: 161 : qzfree(pINChI_Aux->szOrigCoord);
5740 [ + - + - ]: 161 : qzfree(pINChI_Aux->OrigInfo);
5741 : : /*
5742 : : qzfree( pINChI_Aux->nOriginalAtomNumber );
5743 : : qzfree( pINChI_Aux->nCanonicalTGroupNumbers );
5744 : : qzfree( pINChI_Aux->nIsotopicCanonicalTGroupNumbers);
5745 : : qzfree( pINChI_Aux->nTautomer );
5746 : : qzfree( pINChI_Aux->nNontautomericCanonicalNumbers );
5747 : : qzfree( pINChI_Aux->nIsotopicCanonicalNumbers );
5748 : : qzfree( pINChI_Aux->nNontautomericIsotopicCanonicalNumbers );
5749 : : qzfree( pINChI_Aux->nNontautomericEquNumbers );
5750 : : qzfree( pINChI_Aux->nNontautomericIsotopicEquNumbers );
5751 : : */
5752 [ + - + - ]: 161 : qzfree(pINChI_Aux->nConstitEquNumbers);
5753 [ + + + - ]: 161 : qzfree(pINChI_Aux->nConstitEquTGroupNumbers);
5754 [ - + - - ]: 161 : qzfree(pINChI_Aux->nConstitEquIsotopicNumbers);
5755 [ - + - - ]: 161 : qzfree(pINChI_Aux->nConstitEquIsotopicTGroupNumbers);
5756 [ + - + - ]: 161 : qzfree(pINChI_Aux);
5757 : 161 : *ppINChI_Aux = NULL;
5758 : : }
5759 : :
5760 : 322 : return 0;
5761 : : }
5762 : :
5763 : : /****************************************************************************/
5764 : 161 : INChI_Aux *Alloc_INChI_Aux(int num_at,
5765 : : int num_isotopic_atoms,
5766 : : int nAllocMode,
5767 : : int bOrigCoord)
5768 : : {
5769 : : INChI_Aux *pINChI_Aux;
5770 : 161 : int bIsotopic = (nAllocMode & REQ_MODE_ISO);
5771 : 161 : int num_at_tg = num_at + num_at / 2;
5772 : : /* int bTautomeric = (nAllocMode & REQ_MODE_TAUT); */
5773 : :
5774 [ + - ]: 161 : if (num_at <= 0 ||
5775 [ - + ]: 161 : NULL == (pINChI_Aux = (INChI_Aux *)inchi_calloc(1, sizeof(INChI_Aux))))
5776 : : {
5777 : 0 : return NULL;
5778 : : }
5779 : :
5780 : 161 : if ((pINChI_Aux->nOrigAtNosInCanonOrd = (AT_NUMB *)
5781 [ + - ]: 161 : inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0]))) &&
5782 : 161 : (pINChI_Aux->nOrigAtNosInCanonOrdInv = (AT_NUMB *)
5783 [ + - ]: 161 : inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nOrigAtNosInCanonOrd[0]))) &&
5784 : 161 : (pINChI_Aux->nConstitEquNumbers = (AT_NUMB *)
5785 [ + - ]: 161 : inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nConstitEquNumbers[0]))))
5786 : : {
5787 : : ;
5788 : : }
5789 : : else
5790 : : {
5791 : 0 : goto out_of_RAM;
5792 : : }
5793 : :
5794 [ + + ]: 238 : if (num_at > 1 &&
5795 [ + - ]: 77 : (pINChI_Aux->nConstitEquTGroupNumbers = (AT_NUMB *)inchi_calloc((long long)num_at / 2 + 1, sizeof(pINChI_Aux->nConstitEquTGroupNumbers[0])))) /* djb-rwth: cast operator added */
5796 : : {
5797 : : ;
5798 : : }
5799 : : else
5800 : : {
5801 [ - + ]: 84 : if (num_at > 1)
5802 : : {
5803 : 0 : goto out_of_RAM;
5804 : : }
5805 : : }
5806 : :
5807 [ + - ]: 161 : if (num_at > 0)
5808 : : {
5809 : 161 : pINChI_Aux->OrigInfo = (ORIG_INFO *)inchi_calloc(num_at, sizeof(pINChI_Aux->OrigInfo[0]));
5810 [ - + ]: 161 : if (!pINChI_Aux->OrigInfo)
5811 : 0 : goto out_of_RAM;
5812 : : }
5813 : :
5814 [ + - + - ]: 161 : if (bOrigCoord && num_at > 0)
5815 : : {
5816 : 161 : pINChI_Aux->szOrigCoord = (MOL_COORD *)inchi_calloc(num_at, sizeof(pINChI_Aux->szOrigCoord[0]));
5817 [ - + ]: 161 : if (!pINChI_Aux->szOrigCoord)
5818 : 0 : goto out_of_RAM;
5819 : : }
5820 : :
5821 [ - + ]: 161 : if (bIsotopic)
5822 : : {
5823 : 0 : if (/*num_isotopic_atoms &&*/
5824 [ # # ]: 0 : (pINChI_Aux->nIsotopicOrigAtNosInCanonOrd = (AT_NUMB *)inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0]))) &&
5825 [ # # ]: 0 : (pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv = (AT_NUMB *)inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[0]))) &&
5826 [ # # ]: 0 : (pINChI_Aux->nConstitEquIsotopicNumbers = (AT_NUMB *)inchi_calloc(num_at_tg, sizeof(pINChI_Aux->nConstitEquIsotopicNumbers[0]))))
5827 : : {
5828 : : ;
5829 : : }
5830 [ # # ]: 0 : else if (num_isotopic_atoms)
5831 : : {
5832 : 0 : goto out_of_RAM;
5833 : : }
5834 : :
5835 : 0 : if ( /*num_isotopic_atoms && num_at > 1 &&*/
5836 [ # # ]: 0 : (pINChI_Aux->nConstitEquIsotopicTGroupNumbers = (AT_NUMB *)inchi_calloc((long long)num_at / 2 + 1, sizeof(pINChI_Aux->nConstitEquIsotopicTGroupNumbers[0])))) /* djb-rwth: cast operator added */
5837 : : {
5838 : : ;
5839 : : }
5840 [ # # # # ]: 0 : else if (num_isotopic_atoms && num_at > 1)
5841 : : {
5842 : 0 : goto out_of_RAM;
5843 : : }
5844 : : }
5845 : :
5846 : 161 : return pINChI_Aux;
5847 : :
5848 : 0 : out_of_RAM:
5849 : :
5850 [ # # ]: 0 : if (pINChI_Aux)
5851 : : {
5852 : 0 : Free_INChI_Aux(&pINChI_Aux);
5853 : : /*
5854 : : inchi_free(pINChI_Aux);
5855 : : */
5856 : : }
5857 : :
5858 : 0 : return NULL;
5859 : : }
5860 : :
5861 : : /****************************************************************************
5862 : : Note that orig_num, curr_num are allocd by caller as (n+1)-long lists
5863 : : ****************************************************************************/
5864 : 0 : void CompAtomData_GetNumMapping(COMP_ATOM_DATA *adata, int *orig_num, int *curr_num)
5865 : : {
5866 : : int i;
5867 [ # # # # ]: 0 : if (!orig_num || !curr_num)
5868 : : {
5869 : 0 : return;
5870 : : }
5871 [ # # ]: 0 : for (i = 0; i < adata->num_at; i++)
5872 : : {
5873 : 0 : int orig = adata->at[i].orig_at_number;
5874 : 0 : orig_num[i] = orig; /* orig's are from 1 */
5875 : 0 : curr_num[orig] = i; /* curr's are from 0 */
5876 : : }
5877 : : }
5878 : :
5879 : : /****************************************************************************
5880 : : Allocate integer matrix [mxn]
5881 : : ****************************************************************************/
5882 : 7 : int imat_new(int m, int n, int ***a)
5883 : : {
5884 : : int i;
5885 [ + + - + ]: 7 : if (m == 0 || n == 0)
5886 : : {
5887 : 1 : return 0;
5888 : : }
5889 [ - + ]: 6 : if (*a)
5890 : : {
5891 : 0 : imat_free(m, *a);
5892 : 0 : *a = NULL;
5893 : : }
5894 : 6 : *a = (int **)inchi_calloc(m, sizeof(int *));
5895 [ - + ]: 6 : if (NULL == *a)
5896 : : {
5897 : 0 : return 1;
5898 : : }
5899 [ + + ]: 42 : for (i = 0; i < m; i++)
5900 : : {
5901 : 36 : (*a)[i] = (int *)inchi_calloc(n, sizeof(int));
5902 [ - + ]: 36 : if (NULL == (*a)[i])
5903 : : {
5904 : 0 : return 1;
5905 : : }
5906 : : }
5907 : 6 : return 0;
5908 : : }
5909 : :
5910 : : /****************************************************************************
5911 : : Free integer matrix [mxn]
5912 : : ****************************************************************************/
5913 : 6 : void imat_free(int m, int **a)
5914 : : {
5915 : : int i;
5916 [ + - ]: 6 : if (NULL != a)
5917 : : {
5918 [ + + ]: 42 : for (i = 0; i < m; i++)
5919 : : {
5920 [ + - ]: 36 : if (NULL != a[i]) /* djb-rwth: unresolved issue -- revision required? -- false positive as this function just does the clean-up job */
5921 : : {
5922 [ + - ]: 36 : inchi_free(a[i]);
5923 : : }
5924 : : }
5925 [ + - ]: 6 : inchi_free(a);
5926 : 6 : a = NULL;
5927 : : }
5928 : :
5929 : 6 : return;
5930 : : }
5931 : :
5932 : : /*
5933 : : Lt-wt subgraph
5934 : : */
5935 : :
5936 : : /****************************************************************************
5937 : : Establish light-weight subgraph representing (part of) orig_inp_data
5938 : : ****************************************************************************/
5939 : 0 : subgraf *subgraf_new(ORIG_ATOM_DATA *orig_inp_data,
5940 : : int nnodes,
5941 : : int *nodes)
5942 : : {
5943 : 0 : int i, j, iat, nbr, jat, nj, degree, nat, err = 0;
5944 : :
5945 : 0 : subgraf *sg = (subgraf *)inchi_calloc(1, sizeof(subgraf));
5946 [ # # ]: 0 : if (!sg)
5947 : : {
5948 : 0 : return NULL;
5949 : : }
5950 : :
5951 : 0 : nat = orig_inp_data->num_inp_atoms;
5952 : :
5953 : : /* orig2node is mapping of original at numbers --> subgraph node numbers */
5954 : 0 : err = 1;
5955 [ # # ]: 0 : if (!(sg->orig2node = (int *)inchi_calloc((long long)nat + 1, sizeof(int)))) /* djb-rwth: cast operator added */
5956 : : {
5957 : 0 : goto exit_function;
5958 : : }
5959 [ # # ]: 0 : if (!(sg->nodes = (int *)inchi_calloc(nnodes, sizeof(int))))
5960 : : {
5961 : 0 : goto exit_function;
5962 : : }
5963 [ # # ]: 0 : if (!(sg->degrees = (int *)inchi_calloc(nnodes, sizeof(int))))
5964 : : {
5965 : 0 : goto exit_function;
5966 : : }
5967 : : /* NB: input list of 'nodes' is assumed to be in 'original_atom_numbering domain' which starts from 1.
5968 : : Now it is mapped to current atom numbers which starts from 0/connections using at[j].orig_at_number */
5969 : 0 : sg->nnodes = 0;
5970 [ # # ]: 0 : for (i = 0; i < nnodes; i++)
5971 : : {
5972 : 0 : sg->nodes[sg->nnodes++] = nodes[i];
5973 : : }
5974 : :
5975 [ # # ]: 0 : for (i = 0; i <= nat; i++)
5976 : : {
5977 : 0 : sg->orig2node[i] = -1;
5978 : : }
5979 [ # # ]: 0 : for (i = 0; i < nnodes; i++)
5980 : : {
5981 : 0 : sg->orig2node[sg->nodes[i]] = i;
5982 : : }
5983 : :
5984 : : /* Create and fill subgraph adjacency matrix based on nodes/orig atom numbers
5985 : : and connections stored in orig_inp_data */
5986 : 0 : sg->adj = (subgraf_edge **)inchi_calloc(nnodes, sizeof(subgraf_edge *));
5987 [ # # ]: 0 : if (!sg->adj)
5988 : : {
5989 : 0 : goto exit_function;
5990 : : }
5991 : :
5992 [ # # ]: 0 : for (i = 0; i < sg->nnodes; i++)
5993 : : {
5994 : 0 : iat = nodes[i] - 1; /* current atom number for this node */
5995 : 0 : degree = orig_inp_data->at[iat].valence;
5996 : 0 : nj = -1;
5997 : 0 : sg->adj[i] = (subgraf_edge *)inchi_calloc(degree, sizeof(subgraf_edge));
5998 [ # # ]: 0 : if (!sg->adj[i])
5999 : : {
6000 : 0 : goto exit_function;
6001 : : }
6002 [ # # ]: 0 : for (j = 0; j < degree; j++)
6003 : : {
6004 : 0 : jat = orig_inp_data->at[iat].neighbor[j]; /* for curr num jat, a (jat+1) would be an orig num */
6005 : 0 : nbr = sg->orig2node[jat + 1];
6006 [ # # ]: 0 : if (nbr < 0)
6007 : 0 : continue;
6008 : 0 : nj++;
6009 : 0 : sg->adj[i][nj].nbr = nbr;
6010 : 0 : sg->adj[i][nj].etype = orig_inp_data->at[iat].bond_type[j];
6011 : : }
6012 : 0 : sg->degrees[i] = nj + 1;
6013 : : }
6014 : 0 : err = 0;
6015 : :
6016 : : /* subgraf_debug_trace( sg ); */
6017 : :
6018 : 0 : exit_function:
6019 [ # # ]: 0 : if (err)
6020 : : {
6021 : 0 : subgraf_free(sg);
6022 : 0 : return NULL; /* djb-rwth: avoiding reading from freed memory */
6023 : : }
6024 : :
6025 : 0 : return sg;
6026 : : }
6027 : :
6028 : : /****************************************************************************/
6029 : 0 : void subgraf_free(subgraf *sg)
6030 : : {
6031 : : int i;
6032 [ # # ]: 0 : if (!sg)
6033 : : {
6034 : 0 : return;
6035 : : }
6036 [ # # ]: 0 : if (sg->nodes)
6037 : : {
6038 [ # # ]: 0 : inchi_free(sg->nodes);
6039 : : }
6040 [ # # ]: 0 : if (sg->degrees)
6041 : : {
6042 [ # # ]: 0 : inchi_free(sg->degrees);
6043 : : }
6044 [ # # ]: 0 : if (sg->orig2node)
6045 : : {
6046 [ # # ]: 0 : inchi_free(sg->orig2node);
6047 : : }
6048 [ # # ]: 0 : if (sg->adj)
6049 : : {
6050 [ # # ]: 0 : for (i = 0; i < sg->nnodes; i++)
6051 : : {
6052 [ # # ]: 0 : if (sg->adj[i]) /* djb-rwth: unresolved issue -- revision required? -- false positive as this function just does the clean-up job */
6053 : : {
6054 [ # # ]: 0 : inchi_free(sg->adj[i]);
6055 : : }
6056 : : }
6057 [ # # ]: 0 : inchi_free(sg->adj);
6058 : : }
6059 [ # # ]: 0 : inchi_free(sg);
6060 : 0 : sg = NULL;
6061 : :
6062 : 0 : return;
6063 : : }
6064 : :
6065 : : /****************************************************************************/
6066 : 0 : void subgraf_debug_trace(subgraf *sg)
6067 : : {
6068 : : int p, q;
6069 : :
6070 : : ITRACE_("\n\n*********************************************************************\n* Subgraf:");
6071 : : ITRACE_("\n\tNodes: %-d ( ", sg->nnodes);
6072 [ # # ]: 0 : for (p = 0; p < sg->nnodes; p++)
6073 : : {
6074 : : ITRACE_("%-d ", sg->nodes[p]);
6075 : : }
6076 : : ITRACE_(")\n\tAdj lists:\n");
6077 [ # # ]: 0 : for (p = 0; p < sg->nnodes; p++)
6078 : : {
6079 : : ITRACE_("\tNode #%-d (orig# %-d) ::: Neighbors (node#, orig#) : ",
6080 : : p, sg->nodes[p]);
6081 [ # # ]: 0 : for (q = 0; q < sg->degrees[p]; q++)
6082 : : {
6083 : 0 : int nbr = sg->adj[p][q].nbr; /* djb-rwth: ignoring LLVM warning: variable used */
6084 : : ITRACE_("(%-d/%-d/%-d) ", nbr, sg->nodes[nbr]);
6085 : : }
6086 : : ITRACE_("\n");
6087 : : }
6088 : : ITRACE_("\n* End Subgraf\n*********************************************************************\n");
6089 : :
6090 : 0 : return;
6091 : : }
6092 : :
6093 : : /****************************************************************************/
6094 : 0 : subgraf_pathfinder *subgraf_pathfinder_new(subgraf *sg,
6095 : : ORIG_ATOM_DATA *orig_inp_data,
6096 : : int start,
6097 : : int end)
6098 : : {
6099 : 0 : subgraf_pathfinder *spf = NULL;
6100 : :
6101 : 0 : spf = (subgraf_pathfinder *)inchi_calloc(1, sizeof(subgraf_pathfinder));
6102 [ # # ]: 0 : if (!spf)
6103 : : {
6104 : 0 : goto exit_function;
6105 : : }
6106 : :
6107 : 0 : spf->sg = sg;
6108 : 0 : spf->start = start;
6109 : 0 : spf->end = end;
6110 : 0 : spf->nbonds = 0;
6111 : 0 : spf->nseen = 0;
6112 : :
6113 : 0 : spf->seen = (int *)inchi_calloc(spf->sg->nnodes, sizeof(int));
6114 [ # # ]: 0 : if (!spf->seen)
6115 : : {
6116 [ # # ]: 0 : inchi_free(spf);
6117 : 0 : spf = NULL;
6118 : : }
6119 : :
6120 : 0 : exit_function:
6121 : 0 : return spf;
6122 : : }
6123 : :
6124 : : /****************************************************************************/
6125 : 0 : void subgraf_pathfinder_free(subgraf_pathfinder *spf)
6126 : : {
6127 [ # # ]: 0 : if (!spf)
6128 : : {
6129 : 0 : return;
6130 : : }
6131 [ # # ]: 0 : if (spf->seen)
6132 : : {
6133 [ # # ]: 0 : inchi_free(spf->seen);
6134 : : }
6135 [ # # ]: 0 : inchi_free(spf);
6136 : 0 : spf = NULL;
6137 : 0 : return;
6138 : : }
6139 : :
6140 : : /****************************************************************************
6141 : : Find path(s) from subgraf node spf->start to spf->end
6142 : : and fill bonds[nbonds] and atoms[natoms]
6143 : : Do not traverse through supplied forbidden edges (if not zero/NULL)
6144 : : ****************************************************************************/
6145 : 0 : void subgraf_pathfinder_run(subgraf_pathfinder *spf,
6146 : : int nforbidden, /* number of edges forbidden for traversal */
6147 : : int *forbidden, /* nodes of forbidden edges: [edge1node1,edge1node2, edge2node1, edge2node2, ... ] */
6148 : : int *nbonds,
6149 : : int **bonds, /* collect subgraf bonds here */
6150 : : int *natoms,
6151 : : int *atoms /* if not NULL, collect subgraf atoms here */
6152 : : )
6153 : : {
6154 : : int j, k, node, node0;
6155 : : int f, skip;
6156 : :
6157 [ # # ]: 0 : if (spf->nseen < 1)
6158 : : {
6159 : : /* Even at very beginning, push start node to seen and set nseen = 1
6160 : : and put end node into subgraf_pathfinder's end */
6161 : 0 : return;
6162 : : }
6163 : :
6164 : 0 : node0 = spf->seen[spf->nseen - 1];
6165 [ # # ]: 0 : for (j = 0; j < spf->sg->degrees[node0]; j++)
6166 : : {
6167 : 0 : node = spf->sg->adj[node0][j].nbr;
6168 [ # # ]: 0 : if (is_in_the_ilist(spf->seen, node, spf->nseen))
6169 : : {
6170 : 0 : continue;
6171 : : }
6172 [ # # # # ]: 0 : if (nforbidden && forbidden)
6173 : : {
6174 : 0 : skip = 0;
6175 [ # # ]: 0 : for (f = 0; f < nforbidden; f++)
6176 : : {
6177 [ # # ]: 0 : if (bIsSameBond(node0, node, forbidden[2 * f], forbidden[2 * f + 1]))
6178 : : {
6179 : 0 : skip = 1;
6180 : 0 : break;
6181 : : }
6182 : : }
6183 [ # # ]: 0 : if (skip)
6184 : : {
6185 : 0 : continue;
6186 : : }
6187 : : }
6188 [ # # ]: 0 : if (node == spf->end)
6189 : : {
6190 : 0 : spf->seen[spf->nseen++] = node;
6191 : :
6192 : : ITRACE_("\n\tFound path (in orig atom numbers):\t");
6193 [ # # ]: 0 : for (k = 0; k < spf->nseen; k++)
6194 : : {
6195 : 0 : int orig_atnum = spf->sg->nodes[spf->seen[k]];
6196 : : ITRACE_("%-d ", orig_atnum);
6197 [ # # # # ]: 0 : if (atoms && !is_in_the_ilist(atoms, orig_atnum, *natoms))
6198 : : {
6199 : 0 : atoms[(*natoms)++] = orig_atnum;
6200 : : }
6201 : : }
6202 : : ITRACE_("\t( In node nums: ");
6203 [ # # ]: 0 : for (k = 1; k < spf->nseen; k++)
6204 : : {
6205 : 0 : int at1 = spf->seen[k - 1];
6206 : 0 : int at2 = spf->seen[k];
6207 : 0 : add_bond_if_unseen(spf, at1, at2, nbonds, bonds);
6208 : :
6209 : : ITRACE_("%-d ", spf->seen[k]);
6210 : : }
6211 : : ITRACE_(")");
6212 : :
6213 : 0 : spf->seen[spf->nseen - 1] = 0;
6214 : 0 : spf->nseen--; /* pop_back */
6215 : 0 : break;
6216 : : }
6217 : : }
6218 [ # # ]: 0 : for (j = 0; j < spf->sg->degrees[node0]; j++)
6219 : : {
6220 : 0 : node = spf->sg->adj[node0][j].nbr;
6221 [ # # # # ]: 0 : if (node == spf->end || is_in_the_ilist(spf->seen, node, spf->nseen))
6222 : : {
6223 : 0 : continue;
6224 : : }
6225 [ # # # # ]: 0 : if (nforbidden && forbidden)
6226 : : {
6227 : 0 : skip = 0;
6228 [ # # ]: 0 : for (f = 0; f < nforbidden; f++)
6229 : : {
6230 [ # # ]: 0 : if (bIsSameBond(node0, node, forbidden[2 * f], forbidden[2 * f + 1]))
6231 : : {
6232 : 0 : skip = 1;
6233 : 0 : break;
6234 : : }
6235 : : }
6236 [ # # ]: 0 : if (skip)
6237 : : {
6238 : 0 : continue;
6239 : : }
6240 : : }
6241 : 0 : spf->seen[spf->nseen++] = node;
6242 : 0 : subgraf_pathfinder_run(spf, 0, NULL, nbonds, bonds, natoms, atoms);
6243 : 0 : spf->seen[spf->nseen - 1] = 0;
6244 : 0 : spf->nseen--;
6245 : : }
6246 : :
6247 : 0 : return;
6248 : : }
6249 : :
6250 : : /****************************************************************************/
6251 : 0 : void add_bond_if_unseen(subgraf_pathfinder *spf,
6252 : : int node0,
6253 : : int node,
6254 : : int *nbonds,
6255 : : int **bonds)
6256 : : {
6257 : : int seen, p, at1, at2;
6258 : :
6259 : 0 : at1 = spf->sg->nodes[node0];
6260 : 0 : at2 = spf->sg->nodes[node];
6261 : : #if 0
6262 : : if ( at1 > at2 )
6263 : : {
6264 : : int tmp = at1;
6265 : : at1 = at2;
6266 : : at2 = tmp;
6267 : : }
6268 : : #endif
6269 : 0 : seen = 0;
6270 [ # # ]: 0 : for (p = 0; p < *nbonds; p++)
6271 : : {
6272 : : /*if (bonds[p][0] == at1 && bonds[p][1] == at2)*/
6273 [ # # ]: 0 : if (bIsSameBond(at1, at2, bonds[p][0], bonds[p][1]))
6274 : : {
6275 : 0 : seen = 1;
6276 : 0 : break;
6277 : : }
6278 : : }
6279 [ # # # # ]: 0 : if (!seen && bonds)
6280 : : {
6281 : 0 : bonds[*nbonds][0] = at1;
6282 : 0 : bonds[*nbonds][1] = at2;
6283 : 0 : (*nbonds)++;
6284 : : }
6285 : :
6286 : 0 : return;
6287 : : }
6288 : :
6289 : : /****************************************************************************
6290 : : At the first call, push start node to spf->start and set spf->nseen = 0
6291 : : ****************************************************************************/
6292 : 0 : int subgraf_pathfinder_collect_all(subgraf_pathfinder *spf,
6293 : : int nforbidden, /* number of edges forbidden for traversal */
6294 : : int *forbidden, /* nodes of forbidden edges: [edge1node1,edge1node2, edge2node1, edge2node2, ... ] */
6295 : : int *atnums /* 1-based origs# */
6296 : : )
6297 : : {
6298 : : int j, f, node, next_node, skip;
6299 : :
6300 : 0 : node = spf->start;
6301 : 0 : spf->seen[spf->nseen] = node;
6302 : 0 : atnums[spf->nseen] = spf->sg->nodes[node];
6303 : 0 : spf->nseen++;
6304 : :
6305 [ # # ]: 0 : for (j = 0; j < spf->sg->degrees[node]; j++)
6306 : : {
6307 : 0 : next_node = spf->sg->adj[node][j].nbr;
6308 [ # # ]: 0 : if (is_in_the_ilist(spf->seen, next_node, spf->nseen))
6309 : : {
6310 : 0 : continue;
6311 : : }
6312 [ # # # # ]: 0 : if (nforbidden && forbidden)
6313 : : {
6314 : 0 : skip = 0;
6315 [ # # ]: 0 : for (f = 0; f < nforbidden; f++)
6316 : : {
6317 [ # # ]: 0 : if (bIsSameBond(node, next_node, forbidden[2 * f], forbidden[2 * f + 1]))
6318 : : {
6319 : 0 : skip = 1;
6320 : 0 : break;
6321 : : }
6322 : : }
6323 [ # # ]: 0 : if (skip)
6324 : : {
6325 : 0 : continue;
6326 : : }
6327 : : }
6328 : 0 : spf->start = next_node;
6329 : 0 : subgraf_pathfinder_collect_all(spf, nforbidden, forbidden, atnums);
6330 : : }
6331 : :
6332 : 0 : return spf->nseen;
6333 : : }
6334 : :
6335 : : #if (FIX_ADJ_RAD == 1)
6336 : :
6337 : : /****************************************************************************/
6338 : : int FixNextRadicals(int cur_at, inp_ATOM *at);
6339 : : int FixNextRadicals(int cur_at, inp_ATOM *at)
6340 : : {
6341 : : int j, neigh, num_found = 0;
6342 : :
6343 : : for (j = 0; j < at[cur_at].valence; j++)
6344 : : {
6345 : : neigh = at[cur_at].neighbor[j];
6346 : : if (at[neigh].radical == RADICAL_DOUBLET)
6347 : : {
6348 : : at[neigh].radical = 0;
6349 : : num_found++;
6350 : : num_found += FixNextRadicals(neigh, at);
6351 : : }
6352 : : }
6353 : :
6354 : : return num_found;
6355 : : }
6356 : :
6357 : : /****************************************************************************/
6358 : : int FixAdjacentRadicals(int num_inp_atoms, inp_ATOM *at)
6359 : : {
6360 : : int i, j;
6361 : : char *bVisited = NULL;
6362 : : int nNumFound = 0, neigh, cur_found;
6363 : :
6364 : : for (i = 0; i < num_inp_atoms; i++)
6365 : : {
6366 : : if (at[i].radical == RADICAL_DOUBLET)
6367 : : {
6368 : : cur_found = 1;
6369 : : for (j = 0; j < at[i].valence; j++)
6370 : : {
6371 : : neigh = at[i].neighbor[j];
6372 : : if (at[neigh].radical == RADICAL_DOUBLET)
6373 : : {
6374 : : cur_found++;
6375 : : }
6376 : : }
6377 : : if (cur_found >= 3)
6378 : : {
6379 : : nNumFound++;
6380 : : at[i].radical = 0;
6381 : : nNumFound += FixNextRadicals(i, at);
6382 : : }
6383 : : }
6384 : : }
6385 : :
6386 : : return nNumFound;
6387 : : }
6388 : :
6389 : : #endif
6390 : :
6391 : : #ifdef COMPILE_ANSI_ONLY
6392 : :
6393 : : #ifndef TARGET_API_LIB
6394 : : /*
6395 : : #include <stdio.h>
6396 : : #include "inpdef.h"
6397 : : */
6398 : :
6399 : : /****************************************************************************/
6400 : : void PrintFileName(const char *fmt,
6401 : : FILE *out_file,
6402 : : /* INCHI_IOSTREAM *out_file, */
6403 : : const char *szFname)
6404 : : {
6405 : : inchi_print_nodisplay(out_file, fmt, szFname);
6406 : : }
6407 : : #endif
6408 : :
6409 : : #endif
|