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