Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : : #include <math.h>
7 : : #include <string.h>
8 : :
9 : : #include "mode.h"
10 : : #include "ichister.h"
11 : : #include "ichiring.h"
12 : : #include "ichi.h"
13 : : #include "ichitaut.h"
14 : : #include "ichicomp.h"
15 : : #include "ichicant.h"
16 : : #include "util.h"
17 : :
18 : : #include "bcf_s.h"
19 : :
20 : : #define ZTYPE_DOWN (-1) /* should be equal to -ZTYPE_UP */
21 : : #define ZTYPE_NONE 0
22 : : #define ZTYPE_UP 1 /* should be equal to -ZTYPE_DOWN */
23 : : #define ZTYPE_3D 3
24 : : #define ZTYPE_EITHER 9999
25 : :
26 : : #define ARR_DIM 3 /* djb-rwth: default dimension of arrays */
27 : :
28 : : /* criteria for ill-defined */
29 : : #define MIN_ANGLE 0.10 /* 5.73 degrees */ /* treshold for proximity to in-line angle of 180 deg */
30 : : #define MIN_SINE 0.03 /*min edge/plane angle in case the tetrahedra has significantly different edge length */
31 : : #define MIN_ANGLE_RELAXED 0.001
32 : : #define MIN_SINE_RELAXED 0.001
33 : : #define MIN_ANGLE_DBOND 0.087156 /* 5 degrees = max angle considered as too small for unambiguous double bond stereo */
34 : : #define MIN_SINE_OUTSIDE 0.06 /* min edge/plane angle to determine whether the central atom is outside of the tetrahedra */
35 : : #define MIN_SINE_SQUARE 0.125 /* min edge/plane angle in case the tetrahedra is somewhat close to a parallelogram */
36 : : #define MIN_SINE_EDGE 0.167 /* min sine/(min.edge) ratio to avoid undefined in case of long edges */
37 : : #define MIN_LEN_STRAIGHT 1.900 /* min length of two normalized to 1 bonds in a straight line */
38 : : #define MAX_SINE 0.70710678118654752440084436210485 /* 1/sqrt(2)=sin(pi/4) */
39 : : #define MIN_BOND_LEN 0.000001
40 : : #define ZERO_LENGTH MIN_BOND_LEN
41 : : #define ZERO_FLOAT 1.0e-12
42 : : #define BOND_PARITY_UNDEFINED 64
43 : : #if ( STEREO_CENTER_BONDS_NORM == 1 )
44 : : #define MPY_SINE 1.00 /* was 3.0 */
45 : : #define MAX_EDGE_RATIO 2.50 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
46 : : #else
47 : : #define MPY_SINE 3.00
48 : : #define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
49 : : #endif
50 : : /* local prototypes */
51 : : static int save_a_stereo_bond( int z_prod, int result_action,
52 : : int at1, int ord1, AT_NUMB *stereo_bond_neighbor1, S_CHAR *stereo_bond_ord1, S_CHAR *stereo_bond_z_prod1, S_CHAR *stereo_bond_parity1,
53 : : int at2, int ord2, AT_NUMB *stereo_bond_neighbor2, S_CHAR *stereo_bond_ord2, S_CHAR *stereo_bond_z_prod2, S_CHAR *stereo_bond_parity2 );
54 : : static double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType, int bPointedEdgeStereo );
55 : : static double len3( const double c[] );
56 : : static double len2( const double c[] );
57 : : static void* diff3( const double a[], const double b[], double result[] );
58 : : static void add3( const double a[], const double b[], double result[] );
59 : : static void mult3( const double a[], double b, double result[] );
60 : : /* static double* copy3(const double a[], double result[]); */
61 : : static void change_sign3( const double a[], double result[] );
62 : : double dot_prod3( const double a[], const double b[] );
63 : : static int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
64 : : static double triple_prod( double a[], double b[], double c[], double *sine_value );
65 : : static double triple_prod_and_min_abs_sine( double at_coord[][3], double *min_sine );
66 : : static int are_3_vect_in_one_plane( double at_coord[][3], double min_sine );
67 : : static int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
68 : : int at_2, int i_next_at_2, S_CHAR *z_dir2 );
69 : :
70 : : static int CompDble( const void *a1, const void *a2, void * );
71 : : static int Get2DTetrahedralAmbiguity( CANON_GLOBALS *pCG, double at_coord[][3], int bAddExplicitNeighbor, int bFix2DstereoBorderCase, double vMinAngle );
72 : : static double triple_prod_and_min_abs_sine2( double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor,
73 : : double *min_sine, int *bAmbiguous, double vMinSine );
74 : : static int are_4at_in_one_plane( double at_coord[][3], double min_sine );
75 : : static int bInpAtomHasRequirdNeigh( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds, int bStereoAtZz );
76 : : static int bIsSuitableHeteroInpAtom( inp_ATOM *at );
77 : : static int bIsOxide( inp_ATOM *at, int cur_at );
78 : : static int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir,
79 : : int bPointedEdgeStereo, int vABParityUnknown );
80 : : static int get_allowed_stereo_bond_type( int bond_type );
81 : : static int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode );
82 : : static int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic, int vABParityUnknown );
83 : : static int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
84 : : INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel,
85 : : S_CHAR *cSource, AT_RANK min_sb_ring_size,
86 : : int bPointedEdgeStereo, int vABParityUnknown );
87 : : static int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at, int bPointedEdgeStereo, int bStereoAtZz );
88 : : static int set_stereo_atom_parity( CANON_GLOBALS *pCG, sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H,
89 : : int bPointedEdgeStereo, int vABParityUnknown, int LooseTSACheck, int bStereoAtZz );
90 : : /*
91 : : int get_opposite_sb_atom( inp_ATOM *at, int cur_atom, int icur2nxt, int *pnxt_atom, int *pinxt2cur, int *pinxt_sb_parity_ord );
92 : : */
93 : : int ReconcileCmlIncidentBondParities( inp_ATOM *at, int cur_atom, int prev_atom, S_CHAR *visited, int bDisconnected );
94 : : int comp_AT_NUMB( const void* a1, const void* a2, void * );
95 : : int GetHalfStereobond0DParity( inp_ATOM *at, int cur_at, AT_NUMB nSbNeighOrigAtNumb[], int nNumExplictAttachments, int bond_parity, int nFlag );
96 : : int GetStereocenter0DParity( CANON_GLOBALS *pCG, inp_ATOM *at, int cur_at, int j1, AT_NUMB nSbNeighOrigAtNumb[], int nFlag );
97 : : int GetSbNeighOrigAtNumb( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, AT_NUMB nSbNeighOrigAtNumb[] );
98 : : int FixSb0DParities( inp_ATOM *at, /* inp_ATOM *at_removed_H, int num_removed_H,*/ int chain_length,
99 : : int at_1, int i_next_at_1, S_CHAR z_dir1[],
100 : : int at_2, int i_next_at_2, S_CHAR z_dir2[],
101 : : int *pparity1, int *pparity2 );
102 : :
103 : :
104 : : /****************************************************************************/
105 : 0 : int comp_AT_NUMB( const void* a1, const void* a2, void *p )
106 : : {
107 : 0 : return (int)(*(const AT_NUMB*)a1) - (int)(*(const AT_NUMB*)a2);
108 : : }
109 : :
110 : :
111 : : /****************************************************************************/
112 : 603 : double get_z_coord( inp_ATOM* at,
113 : : int cur_atom,
114 : : int neigh_no,
115 : : int *nType,
116 : : int bPointedEdgeStereo )
117 : : {
118 : 603 : int stereo_value = at[cur_atom].bond_stereo[neigh_no];
119 : 603 : int stereo_type = abs( stereo_value );
120 : 603 : int neigh = (int) at[cur_atom].neighbor[neigh_no];
121 : 603 : double z = at[neigh].z - at[cur_atom].z;
122 : : int bFlat;
123 : :
124 [ + - ]: 603 : if ((bFlat = ( fabs( z ) < ZERO_LENGTH ))) /* djb-rwth: addressing LLVM warning */
125 : : {
126 : : int i;
127 [ + + ]: 2412 : for (i = 0; i < at[cur_atom].valence; i++)
128 : : {
129 [ - + ]: 1809 : if (fabs( at[cur_atom].z - at[(int) at[cur_atom].neighbor[i]].z ) > ZERO_LENGTH)
130 : : {
131 : 0 : bFlat = 0;
132 : 0 : break;
133 : : }
134 : : }
135 : : }
136 : :
137 [ + - ]: 603 : if (bFlat)
138 : : {
139 [ + - + - ]: 603 : if (!bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0)
140 : : {
141 : : /* bPointedEdgeStereo > 0: define stereo from pointed end of the stereo bond only */
142 : : /* bPointedEdgeStereo < 0: define stereo from wide end of the stereo bond only (case of removed H) */
143 [ + + - + : 603 : switch (stereo_type)
- ]
144 : : {
145 : : /* 1=Up (solid triangle), 6=Down (Dashed triangle), 4=Either (zigzag triangle) */
146 : 426 : case 0: /* No stereo */
147 : 426 : *nType = ZTYPE_NONE;
148 : 426 : break;
149 : 146 : case STEREO_SNGL_UP: /* 1= Up */
150 : 146 : *nType = ZTYPE_UP;
151 : 146 : break;
152 : 0 : case STEREO_SNGL_EITHER: /* 4 = Either */
153 : 0 : *nType = ZTYPE_EITHER;
154 : 0 : break;
155 : 31 : case STEREO_SNGL_DOWN: /* 6 = Down */
156 : 31 : *nType = ZTYPE_DOWN;
157 : 31 : break;
158 : 0 : default:
159 : 0 : *nType = ZTYPE_NONE; /* ignore unexpected values */
160 : : }
161 [ - + - - : 603 : if (stereo_value < 0 && ( *nType == ZTYPE_DOWN || *nType == ZTYPE_UP ))
- - ]
162 : 0 : *nType = -*nType;
163 : : }
164 : : else
165 : : {
166 : 0 : *nType = ZTYPE_NONE; /* no stereo */
167 : : }
168 : : }
169 : : else
170 : : {
171 [ # # # # ]: 0 : if (stereo_type == STEREO_SNGL_EITHER &&
172 [ # # ]: 0 : ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ))
173 : : {
174 : 0 : *nType = ZTYPE_EITHER;
175 : : }
176 : : else
177 : : {
178 : 0 : *nType = ZTYPE_3D;
179 : : }
180 : : }
181 : :
182 : 603 : return z;
183 : : }
184 : :
185 : : /****************************************************************************/
186 : 3966 : double len3( const double c[] ) /* djb-rwth: avoiding uninitialised values */
187 : : {
188 : 3966 : double tmpar[ARR_DIM] = { 0.0 };
189 : : #if USE_BCF
190 : : memcpy_s(tmpar, ARR_DIM * sizeof(c[0]), c, ARR_DIM * sizeof(c[0]));
191 : : #else
192 : 3966 : memcpy(tmpar, c, ARR_DIM * sizeof(c[0]));
193 : : #endif
194 : 3966 : return sqrt(pow(tmpar[0],2.0) + pow(tmpar[1],2.0) + pow(tmpar[2],2.0) );
195 : : }
196 : :
197 : :
198 : : /****************************************************************************/
199 : 603 : double len2( const double c[] ) /* djb-rwth: avoiding uninitialised values */
200 : : {
201 : 603 : double tmpar[ARR_DIM - 1] = { 0,0 };
202 : : #if USE_BCF
203 : : memcpy_s(tmpar, (ARR_DIM - 1) * sizeof(c[0]), c, (ARR_DIM - 1) * sizeof(c[0]));
204 : : #else
205 : 603 : memcpy(tmpar, c, (ARR_DIM - 1) * sizeof(c[0]));
206 : : #endif
207 : 603 : return sqrt(pow(tmpar[0],2.0) + pow(tmpar[1],2.0));
208 : : }
209 : :
210 : :
211 : : /****************************************************************************/
212 : 1416 : void* diff3( const double a[], const double b[], double result[] ) /* djb-rwth: changed function type */
213 : : {
214 : :
215 : 1416 : result[0] = a[0] - b[0];
216 : 1416 : result[1] = a[1] - b[1];
217 : 1416 : result[2] = a[2] - b[2];
218 : :
219 : 1416 : return result;
220 : : }
221 : :
222 : :
223 : : /****************************************************************************/
224 : 603 : void add3( const double a[], const double b[], double result[] ) /* djb-rwth: changed function type */
225 : : {
226 : 603 : result[0] = a[0] + b[0];
227 : 603 : result[1] = a[1] + b[1];
228 : 603 : result[2] = a[2] + b[2];
229 : :
230 : : /* return result; */
231 : 603 : }
232 : :
233 : :
234 : : /****************************************************************************/
235 : 603 : void mult3( const double a[], double b, double result[] ) /* djb-rwth: changed function type */
236 : : {
237 : 603 : result[0] = a[0] * b;
238 : 603 : result[1] = a[1] * b;
239 : 603 : result[2] = a[2] * b;
240 : :
241 : : /* return result; */
242 : 603 : }
243 : :
244 : :
245 : : /****************************************************************************/
246 : : /* double* copy3(const double a[], double result[]) -- djb-rwth: removing the function completely
247 : : {
248 : : result[0] = a[0];
249 : : result[1] = a[1];
250 : : result[2] = a[2];
251 : :
252 : : return result;
253 : : } */
254 : :
255 : :
256 : : /****************************************************************************/
257 : 177 : void change_sign3( const double a[], double result[] ) /* djb-rwth: changed function type */
258 : : {
259 : 177 : result[0] = -a[0];
260 : 177 : result[1] = -a[1];
261 : 177 : result[2] = -a[2];
262 : :
263 : : /* return result; */
264 : 177 : }
265 : :
266 : :
267 : : /****************************************************************************/
268 : 1416 : double dot_prod3( const double a[], const double b[] )
269 : : {
270 : 1416 : return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
271 : : }
272 : :
273 : :
274 : : /****************************************************************************/
275 : 0 : int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] )
276 : : {
277 : 0 : int prod = ( (int)a[0]*(int)b[0] + (int)a[1]*(int)b[1] + (int)a[2]*(int)b[2] ) / 100;
278 [ # # ]: 0 : if (prod > 100)
279 : : {
280 : 0 : prod = 100;
281 : : }
282 : : else
283 : : {
284 [ # # ]: 0 : if (prod < -100)
285 : : {
286 : 0 : prod = -100;
287 : : }
288 : : }
289 : :
290 : 0 : return prod;
291 : : }
292 : :
293 : :
294 : : /****************************************************************************/
295 : 2124 : void* cross_prod3( const double a[], const double b[], double result[] ) /* djb-rwth: changed function type */
296 : : {
297 : : double tmp[3];
298 : :
299 : 2124 : tmp[0] = ( a[1] * b[2] - a[2] * b[1] );
300 : 2124 : tmp[1] = -( a[0] * b[2] - a[2] * b[0] );
301 : 2124 : tmp[2] = ( a[0] * b[1] - a[1] * b[0] );
302 : :
303 : 2124 : result[0] = tmp[0];
304 : 2124 : result[1] = tmp[1];
305 : 2124 : result[2] = tmp[2];
306 : :
307 : 2124 : return result;
308 : : }
309 : :
310 : :
311 : : /****************************************************************************/
312 : 1416 : double triple_prod( double a[], double b[], double c[], double *sine_value )
313 : : {
314 : : double ab[3], dot_prod_ab_c, abs_c, abs_ab;
315 : 1416 : cross_prod3( a, b, ab );
316 : : /* ab[0] = (a[1]*b[2]-a[2]*b[1]); */
317 : : /* ab[1] = -(a[0]*b[2]-a[2]*b[0]); */
318 : : /* ab[2] = (a[0]*b[1]-a[1]*b[0]); */
319 : 1416 : dot_prod_ab_c = dot_prod3( ab, c );
320 : : /* dot_prod_ab_c = ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2]; */
321 [ + + ]: 1416 : if (sine_value)
322 : : {
323 : 708 : abs_c = len3( c );
324 : : /* abs_c = sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ); */
325 : 708 : abs_ab = len3( ab );
326 : : /* abs_ab = sqrt( ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2] ); */
327 : :
328 [ + - + - ]: 708 : if (abs_c > 1.e-7 /* otherwise c has zero length */ && abs_ab > 1.e-7 /* otherwise a is parallel to b*/)
329 : : {
330 : 708 : *sine_value = MPY_SINE * dot_prod_ab_c / ( abs_c * abs_ab );
331 : : /* *sine_value = dot_prod_ab_c / ( abs_c * abs_ab); */
332 : : }
333 : : else
334 : : {
335 : 0 : *sine_value = 0.0;
336 : : }
337 : : }
338 : :
339 : 1416 : return dot_prod_ab_c;
340 : : }
341 : :
342 : :
343 : : /****************************************************************************/
344 : 471 : int CompDble( const void *a1, const void *a2, void *p )
345 : : {
346 : 471 : double *pDoubleForSort = (double *) p;
347 : 471 : double diff = pDoubleForSort[*(const int*) a1] - pDoubleForSort[*(const int*) a2];
348 [ + + ]: 471 : if (diff > 0.0)
349 : : {
350 : 305 : return 1;
351 : : }
352 [ + - ]: 166 : if (diff < 0.0)
353 : : {
354 : 166 : return -1;
355 : : }
356 : 0 : return 0;
357 : : }
358 : :
359 : :
360 : : /****************************************************************************/
361 : : #define T2D_OKAY 1
362 : : #define T2D_WARN 2
363 : : #define T2D_UNDF 4
364 : :
365 : :
366 : : /****************************************************************************/
367 : 177 : int Get2DTetrahedralAmbiguity( CANON_GLOBALS *pCG,
368 : : double at_coord[][3],
369 : : int bAddExplicitNeighbor,
370 : : int bFix2DstereoBorderCase,
371 : : double vMinAngle )
372 : : {
373 : : /* const double one_pi = 2.0*atan2(1.0 , 0.0 ); */
374 : 177 : const double one_pi = 3.14159265358979323846; /* M_PI */
375 : 177 : const double two_pi = 2.0*one_pi;
376 : 177 : const double dAngleAndPiMaxDiff = 2.0*atan2( 1.0, sqrt( 7.0 ) ); /* min sine between 2 InPlane bonds */
377 : : double *pDoubleForSort;
378 : : int nBondType[MAX_NUM_STEREO_ATOM_NEIGH], nBondOrder[MAX_NUM_STEREO_ATOM_NEIGH];
379 : : double dBondDirection[MAX_NUM_STEREO_ATOM_NEIGH];
380 : : volatile double dAngle, dAlpha, dLimit, dBisector;
381 : : /* 2010-02-10 added 'volatile': workaround ensuring proper behavior for gcc 32-bit */
382 : : /* cml-enabled compiles at >=O1 for SID484922 and alike (both lin&win had problems) */
383 [ + - ]: 177 : int nNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH - ( bAddExplicitNeighbor != 0 );
384 : 177 : int i, num_Up, num_Dn, bPrev_Up, cur_len_Up, cur_first_Up, len_Up, first_Up = 0; /* djb-rwth: initialisation required to avoid garbage values */
385 : 177 : int ret = 0;
386 : :
387 [ + + ]: 708 : for (i = 0, num_Up = num_Dn = 0; i < nNumNeigh; i++)
388 : : {
389 : 531 : dAngle = atan2( at_coord[i][1], at_coord[i][0] ); /* range from -pi to +pi */
390 [ + + ]: 531 : if (dAngle < 0.0)
391 : : {
392 : 261 : dAngle += two_pi;
393 : : }
394 : 531 : dBondDirection[i] = dAngle;
395 [ + + + + ]: 531 : nBondType[i] = ( at_coord[i][2] > 0.0 ) ? 1 : ( at_coord[i][2] < 0.0 ) ? -1 : 0; /* z-coord sign */
396 [ + + ]: 531 : if (nBondType[i] > 0)
397 : : {
398 : 146 : num_Up++;
399 : : }
400 : : else
401 : : {
402 [ + + ]: 385 : if (nBondType[i] < 0)
403 : : {
404 : 31 : num_Dn++;
405 : : }
406 : : }
407 : 531 : nBondOrder[i] = i;
408 : : }
409 [ + + ]: 177 : if (num_Up < num_Dn)
410 : : {
411 [ + + ]: 124 : for (i = 0; i < nNumNeigh; i++)
412 : : {
413 : 93 : nBondType[i] = -nBondType[i];
414 : : }
415 : 31 : inchi_swap( (char*) &num_Dn, (char*) &num_Up, sizeof( num_Dn ) );
416 : : }
417 [ - + ]: 177 : if (!num_Up)
418 : : {
419 : 0 : return T2D_UNDF;
420 : : }
421 : :
422 : : /* Sort according to the bond orientations */
423 : 177 : pDoubleForSort = dBondDirection;
424 : 177 : insertions_sort( pDoubleForSort, nBondOrder, nNumNeigh,
425 : : sizeof( nBondOrder[0] ), CompDble );
426 : :
427 : : /* Find the longest contiguous sequence of Up bonds */
428 [ - + ]: 177 : if (num_Up == nNumNeigh)
429 : : {
430 : : /* all bonds are Up */
431 : 0 : len_Up = cur_len_Up = nNumNeigh; /* added cur_len_Up initialization 1/8/2002 */
432 : 0 : first_Up = 0;
433 : : }
434 : : else
435 : : {
436 : : /* at least one bond is not Up */
437 : 177 : cur_len_Up = len_Up = bPrev_Up = 0;
438 : : /* prev. cycle header version ---
439 : : for ( i = 0; 1; i ++ )
440 : : {
441 : : if ( i >= nNumNeigh && !bPrev_Up )
442 : : {
443 : : break;
444 : : }
445 : : ----------
446 : : }
447 : : */
448 : :
449 : : /* look at all bonds and continue (circle therough the beginning) as long as the current bond is Up */
450 [ + + + + ]: 780 : for (i = 0; i < nNumNeigh || bPrev_Up; i++)
451 : : {
452 [ + + ]: 603 : if (nBondType[nBondOrder[i % nNumNeigh]] > 0)
453 : : {
454 [ - + ]: 177 : if (bPrev_Up)
455 : : {
456 : 0 : cur_len_Up++; /* uncrement number of Up bonds in current contiguous sequence of them */
457 : : }
458 : : else
459 : : {
460 : 177 : bPrev_Up = 1; /* start new contiguous sequence of Up bonds */
461 : 177 : cur_len_Up = 1;
462 : 177 : cur_first_Up = i % nNumNeigh;
463 : : }
464 : : }
465 : : else
466 : : {
467 [ + + ]: 426 : if (bPrev_Up)
468 : : { /* end of contiguous sequence of Up bonds */
469 [ + - ]: 177 : if (cur_len_Up > len_Up)
470 : : {
471 : 177 : first_Up = cur_first_Up; /* store the sequence because it is longer than the ptrvious one */
472 : 177 : len_Up = cur_len_Up;
473 : : }
474 : 177 : bPrev_Up = 0;
475 : : }
476 : : }
477 : : }
478 : : }
479 : : #if ( FIX_2D_STEREO_BORDER_CASE == 1 )
480 : : /* check if the bonds with ordering numbers first_Up+len_Up and first_Up+len_Up+1 */
481 : : /* have identical angles. In this case switch their order to enlarge the Up sequence */
482 : : #define ZERO_ANGLE 0.000001
483 : : if (nNumNeigh - len_Up >= 2)
484 : : {
485 : : int next1, next2;
486 : : for (i = 1; i < nNumNeigh - len_Up; i++)
487 : : {
488 : : next2 = ( first_Up + len_Up + i ) % nNumNeigh; /* the 2nd after Up sequence */
489 : : if (nBondType[nBondOrder[next2]] > 0)
490 : : {
491 : : next1 = ( first_Up + len_Up ) % nNumNeigh; /* the 1st after Up sequence */
492 : : dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
493 : : if (fabs( dAngle ) < ZERO_ANGLE)
494 : : {
495 : : inchi_swap( (char*) &nBondOrder[next1], (char*) &nBondOrder[next2], sizeof( nBondOrder[0] ) );
496 : : len_Up++;
497 : : break;
498 : : }
499 : : }
500 : : }
501 : : }
502 : : /* Check whether the not-Up bond (located before the found first-Up) has */
503 : : /* same angle as the Up bond that precedes this not-Up bond */
504 : : if (nNumNeigh - len_Up >= 2)
505 : : {
506 : : int next1, next2;
507 : : for (i = 1; i < nNumNeigh - len_Up; i++)
508 : : {
509 : : next2 = ( first_Up + nNumNeigh - i - 1 ) % nNumNeigh; /* the 2nd before Up sequence */
510 : : if (nBondType[nBondOrder[next2]] > 0)
511 : : {
512 : : next1 = ( first_Up + nNumNeigh - 1 ) % nNumNeigh; /* the 1st before Up sequence */
513 : : dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
514 : : if (fabs( dAngle ) < ZERO_ANGLE)
515 : : {
516 : : inchi_swap( (char*) &nBondOrder[next1], (char*) &nBondOrder[next2], sizeof( nBondOrder[0] ) );
517 : : first_Up = next1;
518 : : len_Up++;
519 : : break;
520 : : }
521 : : }
522 : : }
523 : : }
524 : : #else
525 [ + - ]: 177 : if (bFix2DstereoBorderCase)
526 : : {
527 : : /* Check if the bonds with ordering numbers first_Up+len_Up and first_Up+len_Up+1 */
528 : : /* have identical angles. In this case switch their order to enlarge the Up sequence */
529 : : #define ZERO_ANGLE 0.000001
530 [ + - ]: 177 : if (nNumNeigh - len_Up >= 2)
531 : : {
532 : : int next1, next2;
533 [ + + ]: 354 : for (i = 1; i < nNumNeigh - len_Up; i++)
534 : : {
535 : 177 : next2 = ( first_Up + len_Up + i ) % nNumNeigh; /* the 2nd after Up sequence */
536 [ - + ]: 177 : if (nBondType[nBondOrder[next2]] > 0)
537 : : {
538 : 0 : next1 = ( first_Up + len_Up ) % nNumNeigh; /* the 1st after Up sequence */
539 : 0 : dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
540 [ # # ]: 0 : if (fabs( dAngle ) < ZERO_ANGLE)
541 : : {
542 : 0 : inchi_swap( (char*) &nBondOrder[next1], (char*) &nBondOrder[next2], sizeof( nBondOrder[0] ) );
543 : 0 : len_Up++;
544 : 0 : break;
545 : : }
546 : : }
547 : : }
548 : : }
549 : :
550 : : /* Check whether the not-Up bond (located before the found first-Up) has */
551 : : /* same angle as the Up bond that precedes this not-Up bond */
552 [ + - ]: 177 : if (nNumNeigh - len_Up >= 2)
553 : : {
554 : : int next1, next2;
555 [ + + ]: 354 : for (i = 1; i < nNumNeigh - len_Up; i++)
556 : : {
557 : 177 : next2 = ( first_Up + nNumNeigh - i - 1 ) % nNumNeigh; /* the 2nd before Up sequence */
558 [ - + ]: 177 : if (nBondType[nBondOrder[next2]] > 0)
559 : : {
560 : 0 : next1 = ( first_Up + nNumNeigh - 1 ) % nNumNeigh; /* the 1st before Up sequence */
561 : 0 : dAngle = dBondDirection[nBondOrder[next1]] - dBondDirection[nBondOrder[next2]];
562 [ # # ]: 0 : if (fabs( dAngle ) < ZERO_ANGLE)
563 : : {
564 : 0 : inchi_swap( (char*) &nBondOrder[next1], (char*) &nBondOrder[next2], sizeof( nBondOrder[0] ) );
565 : 0 : first_Up = next1;
566 : 0 : len_Up++;
567 : 0 : break;
568 : : }
569 : : }
570 : : }
571 : : }
572 : : }
573 : : #endif
574 : : /* Turn all the bonds around the center so that */
575 : : /* the 1st Up bond has zero radian direction */
576 : 177 : dAlpha = dBondDirection[nBondOrder[first_Up]];
577 [ + + ]: 708 : for (i = 0; i < nNumNeigh; i++)
578 : : {
579 [ + + ]: 531 : if (i == nBondOrder[first_Up])
580 : : {
581 : 177 : dBondDirection[i] = 0.0;
582 : : }
583 : : else
584 : : {
585 : 354 : dAngle = dBondDirection[i] - dAlpha;
586 [ + + ]: 354 : if (dAngle < 0.0)
587 : : {
588 : 156 : dAngle += two_pi;
589 : : }
590 : 354 : dBondDirection[i] = dAngle;
591 : : }
592 : : }
593 : :
594 : : /********************************************************
595 : : * Process particular cases
596 : : ********************************************************/
597 : :
598 [ + - ]: 177 : if (nNumNeigh == 3)
599 : : {
600 : : /************************ 3 bonds ************************/
601 [ - + - - : 177 : switch (num_Up)
- ]
602 : : {
603 : :
604 : 0 : case 0: /* 0 Up */
605 : 0 : return T2D_UNDF;
606 : :
607 : 177 : case 1: /* 1 Up */
608 [ - + ]: 177 : if (num_Dn)
609 : : {
610 : : #ifdef _DEBUG
611 : : if (num_Dn != 1) /* debug only */
612 : : {
613 : : return -1;
614 : : }
615 : : #endif
616 : 0 : ret = ( T2D_UNDF | T2D_WARN );
617 : : }
618 : : else
619 : : {
620 : 177 : dAngle = dBondDirection[nBondOrder[( first_Up + 2 ) % nNumNeigh]] -
621 : 177 : dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
622 : :
623 [ - + ]: 177 : if (dAngle < 0.0)
624 : : {
625 : 0 : dAngle += two_pi;
626 : : }
627 [ - + - - ]: 177 : if (dAngle - one_pi < -vMinAngle || dAngle - one_pi > vMinAngle)
628 : : {
629 : 177 : ret = T2D_OKAY;
630 : : }
631 : : else
632 : : {
633 : 0 : ret = ( T2D_UNDF | T2D_WARN );
634 : : }
635 : : }
636 : 177 : break;
637 : :
638 : 0 : case 2: /* 2 Up */
639 [ # # ]: 0 : if (num_Dn)
640 : : {
641 : 0 : dAlpha = dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]] -
642 : 0 : dBondDirection[nBondOrder[( first_Up ) % nNumNeigh]];
643 : :
644 [ # # ]: 0 : if (dAlpha < 0.0)
645 : : {
646 : 0 : dAlpha += two_pi;
647 : : }
648 : :
649 [ # # ]: 0 : if (dAlpha > one_pi - vMinAngle)
650 : : {
651 : 0 : ret = T2D_OKAY;
652 : : }
653 [ # # ]: 0 : else if (dAlpha < two_pi / 3.0 - vMinAngle)
654 : : {
655 : 0 : ret = ( T2D_UNDF | T2D_WARN );
656 : : }
657 : : else
658 : : {
659 : : /* angle between 2 Up bonds is between 120 and 180 degrees */
660 : : /* direction of the (Alpha angle bisector) + 180 degrees */
661 : 0 : dBisector = dBondDirection[nBondOrder[( first_Up ) % nNumNeigh]];
662 : 0 : dBisector += dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
663 : 0 : dBisector /= 2.0;
664 : 0 : dBisector -= one_pi;
665 [ # # ]: 0 : if (dBisector < 0.0)
666 : : {
667 : 0 : dBisector += two_pi;
668 : : }
669 [ # # ]: 0 : if (dAlpha < two_pi / 3.0 + vMinAngle)
670 : : {
671 : : /* dAlpha is inside ( 2pi/3 - eps, 2pi/3 + eps ) interval */
672 : 0 : dLimit = vMinAngle * 3.0 / 2.0;
673 : : }
674 : : else
675 : : {
676 : 0 : dLimit = dAlpha * 3.0 / 2.0 - one_pi;
677 : : }
678 : :
679 : 0 : dAngle = dBondDirection[nBondOrder[( first_Up + 2 ) % nNumNeigh]];
680 : :
681 [ # # ]: 0 : if (dBisector - dAngle < -dLimit ||
682 [ # # ]: 0 : dBisector - dAngle > dLimit)
683 : : {
684 : 0 : ret = ( T2D_UNDF | T2D_WARN );
685 : : }
686 : : else
687 : : {
688 : 0 : ret = T2D_OKAY;
689 : : }
690 : : }
691 : : } /* if ( num_Dn ) */
692 : : else
693 : : {
694 : 0 : ret = T2D_OKAY;
695 : : }
696 : 0 : break;
697 : :
698 : 0 : case 3: /* 3 Up */
699 : 0 : ret = T2D_OKAY;
700 : 0 : break;
701 : :
702 : 0 : default:/* other Up */
703 : 0 : return -1;
704 : : } /* eof switch( num_Up ) at nNumNeigh == 3 */
705 : : }
706 : :
707 [ # # ]: 0 : else if (nNumNeigh == 4)
708 : : {
709 : : /******************************* 4 bonds ********************/
710 [ # # # # : 0 : switch (num_Up)
# # ]
711 : : {
712 : :
713 : 0 : case 0: /* 0 Up */
714 : 0 : return T2D_UNDF;
715 : :
716 : 0 : case 1: /* 1 Up */
717 [ # # ]: 0 : if (num_Dn)
718 : : {
719 [ # # ]: 0 : if (nBondType[nBondOrder[( first_Up + 2 ) % nNumNeigh]] < 0)
720 : : {
721 : : /*
722 : : * Up, In Plane, Dn, In Plane. Undefined if angle between
723 : : * two In Plane bonds is wuthin pi +/- 2*arcsine(1/sqrt(8)) interval
724 : : * That is, 138.5 to 221.4 degrees; for certainty the interval is
725 : : * increased by 5.7 degrees at each end to
726 : : * 134.8 to 227.1 degrees
727 : : */
728 : 0 : dAngle = dBondDirection[nBondOrder[( first_Up + 3 ) % nNumNeigh]] -
729 : 0 : dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
730 [ # # ]: 0 : if (dAngle < 0.0)
731 : : {
732 : 0 : dAngle += two_pi;
733 : : }
734 [ # # ]: 0 : if (fabs( dAngle - one_pi ) < dAngleAndPiMaxDiff + vMinAngle)
735 : : {
736 : 0 : ret = ( T2D_UNDF | T2D_WARN );
737 : : }
738 : : else
739 : : {
740 : 0 : ret = T2D_OKAY;
741 : : }
742 : : }
743 : : else
744 : : {
745 : 0 : ret = T2D_OKAY;
746 : : }
747 : : #ifdef _DEBUG
748 : : if (num_Dn != 1) /* debug only */
749 : : {
750 : : return -1;
751 : : }
752 : : #endif
753 : : }
754 : : else
755 : : {
756 : 0 : ret = T2D_OKAY;
757 : 0 : dAngle = dBondDirection[nBondOrder[( first_Up + 3 ) % nNumNeigh]] -
758 : 0 : dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
759 [ # # ]: 0 : if (dAngle < 0.0)
760 : : {
761 : 0 : dAngle += two_pi;
762 : : }
763 [ # # ]: 0 : if (dAngle < one_pi - vMinAngle)
764 : : {
765 : 0 : ret |= T2D_WARN;
766 : : }
767 : : }
768 : 0 : break;
769 : :
770 : 0 : case 2: /* 2 Up */
771 : : #if ( FIX_2D_STEREO_BORDER_CASE == 1 )
772 : : if (len_Up == 1)
773 : : {
774 : : ret = T2D_OKAY;
775 : : }
776 : : else
777 : : {
778 : : dAngle = dBondDirection[nBondOrder[( first_Up + 3 ) % nNumNeigh]] -
779 : : dBondDirection[nBondOrder[( first_Up + 0 ) % nNumNeigh]];
780 : : dAngle = fabs( two_pi - dAngle );
781 : : dAlpha = dBondDirection[nBondOrder[( first_Up + 2 ) % nNumNeigh]] -
782 : : dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
783 : : dAlpha = fabs( dAlpha );
784 : : if (dAngle < 2.0 * ZERO_ANGLE && dAlpha > vMinAngle ||
785 : : dAlpha < 2.0 * ZERO_ANGLE && dAngle > vMinAngle)
786 : : {
787 : : ret = ( T2D_OKAY | T2D_WARN );
788 : : }
789 : : else
790 : : {
791 : : ret = ( T2D_UNDF | T2D_WARN );
792 : : }
793 : : }
794 : : #else
795 [ # # ]: 0 : if (bFix2DstereoBorderCase)
796 : : {
797 : : /* bug fix */
798 [ # # ]: 0 : if (len_Up == 1)
799 : : {
800 : 0 : ret = T2D_OKAY;
801 : : }
802 : : else
803 : : {
804 : 0 : dAngle = dBondDirection[nBondOrder[( first_Up + 3 ) % nNumNeigh]] -
805 : 0 : dBondDirection[nBondOrder[( first_Up + 0 ) % nNumNeigh]];
806 : 0 : dAngle = fabs( two_pi - dAngle );
807 : 0 : dAlpha = dBondDirection[nBondOrder[( first_Up + 2 ) % nNumNeigh]] -
808 : 0 : dBondDirection[nBondOrder[( first_Up + 1 ) % nNumNeigh]];
809 : 0 : dAlpha = fabs( dAlpha );
810 [ # # # # ]: 0 : if ((dAngle < 2.0 * ZERO_ANGLE && dAlpha > vMinAngle) ||
811 [ # # # # ]: 0 : (dAlpha < 2.0 * ZERO_ANGLE && dAngle > vMinAngle)) /* djb-rwth: addressing LLVM warnings */
812 : : {
813 : 0 : ret = ( T2D_OKAY | T2D_WARN );
814 : : }
815 : : else
816 : : {
817 : 0 : ret = ( T2D_UNDF | T2D_WARN );
818 : : }
819 : : }
820 : : }
821 : : else
822 : : {
823 : : /* original InChI v. 1 bug */
824 [ # # ]: 0 : if (cur_len_Up == 1)
825 : : {
826 : 0 : ret = T2D_OKAY;
827 : : }
828 : : else
829 : : {
830 : 0 : ret = ( T2D_UNDF | T2D_WARN );
831 : : }
832 : : }
833 : : #endif
834 : 0 : break;
835 : :
836 : 0 : case 3: /* 3 Up */
837 : 0 : ret = T2D_OKAY;
838 : 0 : dAngle = dBondDirection[nBondOrder[( first_Up + 2 ) % nNumNeigh]] -
839 : 0 : dBondDirection[nBondOrder[( first_Up + 0 ) % nNumNeigh]];
840 [ # # ]: 0 : if (dAngle < 0.0)
841 : : {
842 : 0 : dAngle += two_pi;
843 : : }
844 [ # # ]: 0 : if (dAngle < one_pi - vMinAngle)
845 : : {
846 : 0 : ret |= T2D_WARN;
847 : : }
848 : 0 : break;
849 : :
850 : 0 : case 4: /* 4 Up */
851 : 0 : ret = ( T2D_UNDF | T2D_WARN );
852 : 0 : break;
853 : :
854 : 0 : default:/* other Up */
855 : 0 : return -1; /* program error */
856 : : } /* eof switch( num_Up ) at nNumNeigh == 4 */
857 : :
858 : :
859 [ # # ]: 0 : if (ret == T2D_OKAY)
860 : : {
861 : : /* Check whether all bonds are inside a less than 180 degrees sector */
862 [ # # ]: 0 : for (i = 0; i < nNumNeigh; i++)
863 : : {
864 : 0 : dAngle = dBondDirection[nBondOrder[( i + nNumNeigh - 1 ) % nNumNeigh]] -
865 : 0 : dBondDirection[nBondOrder[i % nNumNeigh]];
866 [ # # ]: 0 : if (dAngle < 0.0)
867 : : {
868 : 0 : dAngle += two_pi;
869 : : }
870 [ # # ]: 0 : if (dAngle < one_pi - vMinAngle)
871 : : {
872 : 0 : ret |= T2D_WARN;
873 : 0 : break;
874 : : }
875 : : }
876 : : }
877 : : } /* eof nNumNeigh == 4 */
878 : :
879 : : else
880 : : {
881 : : /*************************** number of bonds != 3 or 4 ******************/
882 : :
883 : 0 : return -1; /* error */
884 : : }
885 : :
886 : 177 : return ret;
887 : : }
888 : :
889 : :
890 : : /****************************************************************************/
891 : 177 : double triple_prod_and_min_abs_sine2( double at_coord[][3],
892 : : double central_at_coord[],
893 : : int bAddedExplicitNeighbor,
894 : : double *min_sine,
895 : : int *bAmbiguous,
896 : : double vMinSine )
897 : : {
898 : 177 : double min_sine_value = 9999.0, sine_value, min_edge_len, max_edge_len, min_edge_len_NoExplNeigh, max_edge_len_NoExplNeigh;
899 : : double s0, s1, s2, s3, e01, e02, e03, e12, e13, e23, tmp[3], e[3][3];
900 : : double prod, ret, central_prod[4];
901 : : int bLongEdges;
902 : :
903 [ - + ]: 177 : if (!min_sine)
904 : : {
905 : 0 : return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
906 : : }
907 : :
908 : 177 : ret = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
909 : 177 : sine_value = MPY_SINE * fabs( sine_value );
910 : :
911 : 177 : diff3( at_coord[1], at_coord[0], e[2] );
912 : 177 : diff3( at_coord[0], at_coord[2], e[1] );
913 : 177 : diff3( at_coord[2], at_coord[1], e[0] );
914 : :
915 : : /* lengths of the 6 edges of the tetrahedra */
916 : 177 : e03 = len3( at_coord[0] ); /* 1 */
917 : 177 : e13 = len3( at_coord[1] );
918 : 177 : e23 = len3( at_coord[2] ); /* includes added neighbor if bAddedExplicitNeighbor*/
919 : 177 : e02 = len3( e[1] ); /* includes added neighbor if bAddedExplicitNeighbor*/
920 : 177 : e12 = len3( e[0] ); /* includes added neighbor if bAddedExplicitNeighbor*/
921 : 177 : e01 = len3( e[2] );
922 : :
923 : : /* min & max edge length */
924 : 177 : max_edge_len =
925 : 177 : min_edge_len = e03;
926 : :
927 [ + + ]: 177 : if (min_edge_len > e13)
928 : : {
929 : 122 : min_edge_len = e13;
930 : : }
931 [ + + ]: 177 : if (min_edge_len > e01)
932 : : {
933 : 75 : min_edge_len = e01;
934 : : }
935 : 177 : min_edge_len_NoExplNeigh = min_edge_len;
936 : :
937 [ + - ]: 177 : if (min_edge_len > e23)
938 : : {
939 : 177 : min_edge_len = e23;
940 : : }
941 [ + + ]: 177 : if (min_edge_len > e02)
942 : : {
943 : 65 : min_edge_len = e02;
944 : : }
945 [ + + ]: 177 : if (min_edge_len > e12)
946 : : {
947 : 29 : min_edge_len = e12;
948 : : }
949 : :
950 [ + + ]: 177 : if (max_edge_len < e13)
951 : : {
952 : 55 : max_edge_len = e13;
953 : : }
954 [ + + ]: 177 : if (max_edge_len < e01)
955 : : {
956 : 9 : max_edge_len = e01;
957 : : }
958 : 177 : max_edge_len_NoExplNeigh = max_edge_len;
959 : :
960 [ - + ]: 177 : if (max_edge_len < e23)
961 : : {
962 : 0 : max_edge_len = e23;
963 : : }
964 [ - + ]: 177 : if (max_edge_len < e02)
965 : : {
966 : 0 : max_edge_len = e02;
967 : : }
968 [ - + ]: 177 : if (max_edge_len < e12)
969 : : {
970 : 0 : max_edge_len = e12;
971 : : }
972 : :
973 [ - + ]: 177 : if (!bAddedExplicitNeighbor)
974 : : {
975 : 0 : min_edge_len_NoExplNeigh = min_edge_len;
976 : 0 : max_edge_len_NoExplNeigh = max_edge_len;
977 : : }
978 : :
979 : 177 : bLongEdges = bAddedExplicitNeighbor
980 : 177 : ? ( max_edge_len_NoExplNeigh < MAX_EDGE_RATIO * min_edge_len_NoExplNeigh )
981 [ + - ]: 177 : : ( max_edge_len < MAX_EDGE_RATIO * min_edge_len );
982 : :
983 [ + - - + : 177 : if (sine_value > vMinSine && ( min_sine || bAmbiguous )) /* djb-rwth: fixing coverity ID #499548 -- unresolved issue -- revision required */
- - ]
984 : : {
985 [ + - ]: 177 : if (min_sine)
986 : : {
987 : 177 : prod = fabs( ret );
988 : : /* tetrahedra height = volume(prod) / area of a plane(cross_prod) */
989 : : /* (instead of a tetrahedra calculate parallelogram/parallelepiped area/volume) */
990 : :
991 : : /* 4 heights from each of the 4 vertices to the opposite plane */
992 : 177 : s0 = prod / len3((double *)cross_prod3( at_coord[1], at_coord[2], tmp ) ); /* djb-rwth: cast operator added for compatibility */
993 : 177 : s1 = prod / len3((double *)cross_prod3( at_coord[0], at_coord[2], tmp ) ); /* djb-rwth: cast operator added for compatibility */
994 : 177 : s2 = prod / len3((double *)cross_prod3( at_coord[0], at_coord[1], tmp ) ); /* djb-rwth: cast operator added for compatibility */
995 : 177 : s3 = prod / len3((double *)cross_prod3( e[0], e[1], tmp ) ); /* djb-rwth: cast operator added for compatibility */
996 : : /* abs. value of a sine of an angle between each tetrahedra edge and plane */
997 : : /* sine = height / edge length */
998 [ + - ]: 177 : if (( sine_value = s0 / e01 ) < min_sine_value)
999 : : {
1000 : 177 : min_sine_value = sine_value;
1001 : : }
1002 [ - + ]: 177 : if (( sine_value = s0 / e02 ) < min_sine_value)
1003 : : {
1004 : 0 : min_sine_value = sine_value;
1005 : : }
1006 [ + + ]: 177 : if (( sine_value = s0 / e03 ) < min_sine_value)
1007 : : {
1008 : 138 : min_sine_value = sine_value;
1009 : : }
1010 : :
1011 [ + + ]: 177 : if (( sine_value = s1 / e01 ) < min_sine_value)
1012 : : {
1013 : 55 : min_sine_value = sine_value;
1014 : : }
1015 [ - + ]: 177 : if (( sine_value = s1 / e12 ) < min_sine_value)
1016 : : {
1017 : 0 : min_sine_value = sine_value;
1018 : : }
1019 [ + + ]: 177 : if (( sine_value = s1 / e13 ) < min_sine_value)
1020 : : {
1021 : 53 : min_sine_value = sine_value;
1022 : : }
1023 : :
1024 [ + - ]: 177 : if (( sine_value = s2 / e02 ) < min_sine_value)
1025 : : {
1026 : 177 : min_sine_value = sine_value;
1027 : : }
1028 [ + + ]: 177 : if (( sine_value = s2 / e12 ) < min_sine_value)
1029 : : {
1030 : 122 : min_sine_value = sine_value;
1031 : : }
1032 [ + + ]: 177 : if (( sine_value = s2 / e23 ) < min_sine_value)
1033 : : {
1034 : 9 : min_sine_value = sine_value;
1035 : : }
1036 : :
1037 [ - + ]: 177 : if (( sine_value = s3 / e03 ) < min_sine_value)
1038 : : {
1039 : 0 : min_sine_value = sine_value;
1040 : : }
1041 [ - + ]: 177 : if (( sine_value = s3 / e13 ) < min_sine_value)
1042 : : {
1043 : 0 : min_sine_value = sine_value;
1044 : : }
1045 [ - + ]: 177 : if (( sine_value = s3 / e23 ) < min_sine_value)
1046 : : {
1047 : 0 : min_sine_value = sine_value;
1048 : : }
1049 : : /* actually use triple sine */
1050 : 177 : *min_sine = sine_value = MPY_SINE * min_sine_value;
1051 : : }
1052 : :
1053 [ + - + - ]: 177 : if (bAmbiguous && sine_value >= vMinSine)
1054 : : {
1055 : : /* Check whether the central atom is outside the tetrahedra (0,0,0), at_coord[0,1,2] */
1056 : : /* compare the tetrahedra volume and the volume of a tetrahedra having central_at_coord[] vertex */
1057 : : int i;
1058 : 177 : diff3( central_at_coord, at_coord[0], tmp );
1059 : 177 : central_prod[0] = triple_prod( at_coord[0], at_coord[1], central_at_coord, NULL );
1060 : 177 : central_prod[1] = triple_prod( at_coord[1], at_coord[2], central_at_coord, NULL );
1061 : 177 : central_prod[2] = triple_prod( at_coord[2], at_coord[0], central_at_coord, NULL );
1062 : 177 : central_prod[3] = triple_prod( e[2], e[1], tmp, NULL );
1063 [ + + ]: 885 : for (i = 0; i <= 3; i++)
1064 : : {
1065 [ - + ]: 708 : if (central_prod[i] / ret < -MIN_SINE_OUTSIDE)
1066 : : {
1067 : 0 : *bAmbiguous |= AMBIGUOUS_STEREO;
1068 : 0 : break;
1069 : : }
1070 : : }
1071 : : }
1072 : : #if ( STEREO_CENTER_BONDS_NORM == 1 )
1073 : :
1074 [ + - - + : 177 : if (bLongEdges && !bAddedExplicitNeighbor && max_edge_len >= MIN_LEN_STRAIGHT)
- - ]
1075 : : {
1076 : : /* possible planar tetragon */
1077 [ # # ]: 0 : if (sine_value < MIN_SINE_SQUARE)
1078 : : {
1079 : 0 : *min_sine = vMinSine / 2.0; /* force parity to be undefined */
1080 [ # # # # ]: 0 : if (bAmbiguous && !*bAmbiguous)
1081 : : {
1082 : 0 : *bAmbiguous |= AMBIGUOUS_STEREO;
1083 : : }
1084 : : }
1085 : : }
1086 : :
1087 [ + - - + : 177 : if (bLongEdges && sine_value < MIN_SINE_SQUARE && sine_value < MIN_SINE_EDGE * min_edge_len_NoExplNeigh)
- - ]
1088 : : {
1089 : 0 : *min_sine = vMinSine / 2.0; /* force parity to be undefined */
1090 [ # # # # ]: 0 : if (bAmbiguous && !*bAmbiguous)
1091 : : {
1092 : 0 : *bAmbiguous |= AMBIGUOUS_STEREO;
1093 : : }
1094 : : }
1095 : : #endif
1096 : : }
1097 : : else
1098 : : {
1099 [ # # ]: 0 : if (min_sine)
1100 : : {
1101 : 0 : *min_sine = sine_value;
1102 : : }
1103 : : }
1104 : :
1105 : 177 : return ret;
1106 : : }
1107 : :
1108 : :
1109 : : /****************************************************************************/
1110 : 177 : double triple_prod_and_min_abs_sine( double at_coord[][3], double *min_sine )
1111 : : {
1112 : 177 : double min_sine_value = 9999.0, sine_value;
1113 : 177 : double prod = 0.0;
1114 : :
1115 [ - + ]: 177 : if (!min_sine)
1116 : : {
1117 : 0 : return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
1118 : : }
1119 : :
1120 : 177 : prod = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1121 : 177 : sine_value = fabs( sine_value );
1122 [ - + ]: 177 : min_sine_value = inchi_min( min_sine_value, sine_value );
1123 : :
1124 : 177 : prod = triple_prod( at_coord[1], at_coord[2], at_coord[0], &sine_value ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1125 : 177 : sine_value = fabs( sine_value );
1126 [ + + ]: 177 : min_sine_value = inchi_min( min_sine_value, sine_value );
1127 : :
1128 : 177 : prod = triple_prod( at_coord[2], at_coord[0], at_coord[1], &sine_value ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1129 : 177 : sine_value = fabs( sine_value );
1130 [ + + ]: 177 : min_sine_value = inchi_min( min_sine_value, sine_value );
1131 : :
1132 : 177 : *min_sine = min_sine_value;
1133 : :
1134 : 177 : return prod;
1135 : : }
1136 : :
1137 : :
1138 : : /****************************************************************************
1139 : : Find if point (0,0,0)a and 3 atoms are in one plane
1140 : : ****************************************************************************/
1141 : 177 : int are_3_vect_in_one_plane( double at_coord[][3], double min_sine )
1142 : : {
1143 : : double actual_min_sine;
1144 : : double prod; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1145 : :
1146 : 177 : prod = triple_prod_and_min_abs_sine( at_coord, &actual_min_sine ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1147 : :
1148 : 177 : return actual_min_sine <= min_sine;
1149 : : }
1150 : :
1151 : :
1152 : : /****************************************************************************
1153 : : Find if 4 atoms are in one plane
1154 : : ****************************************************************************/
1155 : 0 : int are_4at_in_one_plane( double at_coord[][3], double min_sine )
1156 : : {
1157 : : double actual_min_sine, min_actual_min_sine;
1158 : : double coord[3][3], prod; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1159 : : int i, k, j;
1160 [ # # ]: 0 : for (k = 0; k < 4; k++)
1161 : : {
1162 [ # # ]: 0 : for (i = j = 0; i < 4; i++)
1163 : : {
1164 [ # # ]: 0 : if (i != k)
1165 : : {
1166 : 0 : diff3( at_coord[i], at_coord[k], coord[j] );
1167 : 0 : j++;
1168 : : }
1169 : : }
1170 : :
1171 : 0 : prod = triple_prod_and_min_abs_sine( coord, &actual_min_sine ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1172 [ # # # # ]: 0 : if (!k || actual_min_sine < min_actual_min_sine)
1173 : : {
1174 : 0 : min_actual_min_sine = actual_min_sine;
1175 : : }
1176 : : }
1177 : :
1178 : 0 : return min_actual_min_sine <= min_sine;
1179 : : }
1180 : :
1181 : :
1182 : : /****************************************************************************/
1183 : 0 : int triple_prod_char( inp_ATOM *at,
1184 : : int at_1,
1185 : : int i_next_at_1,
1186 : : S_CHAR *z_dir1,
1187 : : int at_2,
1188 : : int i_next_at_2,
1189 : : S_CHAR *z_dir2 )
1190 : : {
1191 : : inp_ATOM *at1, *at2;
1192 : : double pnt[3][3], len;
1193 : : int i;
1194 : 0 : int ret = 0;
1195 : :
1196 : 0 : at1 = at + at_1;
1197 : 0 : at2 = at + at[at_1].neighbor[i_next_at_1];
1198 : :
1199 : 0 : pnt[0][0] = at2->x - at1->x;
1200 : 0 : pnt[0][1] = at2->y - at1->y;
1201 : 0 : pnt[0][2] = at2->z - at1->z;
1202 : :
1203 : 0 : at2 = at + at_2;
1204 : 0 : at1 = at + at[at_2].neighbor[i_next_at_2];
1205 : :
1206 : 0 : pnt[1][0] = at2->x - at1->x;
1207 : 0 : pnt[1][1] = at2->y - at1->y;
1208 : 0 : pnt[1][2] = at2->z - at1->z;
1209 : : /*
1210 : : * resultant pnt vector directions:
1211 : : *
1212 : : * pnt[0] pnt[1]
1213 : : *
1214 : : * [at_1]---->[...] [...]---->[at_2]
1215 : : *
1216 : : *
1217 : : * add3 below: (pnt[0] + pnt[1]) -> pnt[1]
1218 : : */
1219 : 0 : add3( pnt[0], pnt[1], pnt[1] );
1220 : :
1221 [ # # ]: 0 : for (i = 0; i < 3; i++)
1222 : : {
1223 : 0 : pnt[0][i] = (double) z_dir1[i];
1224 : 0 : pnt[2][i] = (double) z_dir2[i];
1225 : : }
1226 [ # # ]: 0 : for (i = 0; i < 3; i++)
1227 : : {
1228 : 0 : len = len3( pnt[i] );
1229 [ # # ]: 0 : if (len < MIN_BOND_LEN)
1230 : : {
1231 [ # # # # : 0 : if (i == 1 && ( at[at_1].bUsed0DParity || at[at_2].bUsed0DParity ))
# # ]
1232 : : {
1233 : 0 : pnt[i][0] = 0.0;
1234 : 0 : pnt[i][1] = 1.0;
1235 : 0 : pnt[i][2] = 0.0;
1236 : 0 : len = 1.0; /* standard at_1-->at_2 vector coordinates in case of 0D allene */
1237 : : }
1238 : : else
1239 : : {
1240 : 0 : goto exit_function; /* too short bond */
1241 : : }
1242 : : }
1243 : 0 : mult3( pnt[i], 1.0 / len, pnt[i] );
1244 : : }
1245 : :
1246 : 0 : len = 100.0*triple_prod( pnt[0], pnt[1], pnt[2], NULL );
1247 : :
1248 : : /*
1249 : : * ^ pnt[0]
1250 : : * | The orientation on this diagram
1251 : : * | produces len = -100
1252 : : * [at_1]------>[at_2]
1253 : : * pnt[1] /
1254 : : * /
1255 : : * / pnt[2] (up from the plane)
1256 : : * v
1257 : : *
1258 : : * Note: len is invariant upon at_1 <--> at_2 transposition because
1259 : : * triple product changes sign upon pnt[0]<-->pnt[2] transposition and
1260 : : * triple product changes sign upon pnt[1]--> -pnt[1] change of direction:
1261 : : *
1262 : : * triple_prod(pnt[0], pnt[1], pnt[2], NULL ) =
1263 : : * triple_prod(pnt[2], -pnt[1], pnt[0], NULL )
1264 : : *
1265 : : */
1266 : :
1267 [ # # ]: 0 : ret = len >= 0.0 ? (int) ( floor( len + 0.5 ) ) : -(int) ( floor( 0.5 - len ) );
1268 : :
1269 : 0 : exit_function:
1270 : :
1271 : 0 : return ret;
1272 : : }
1273 : :
1274 : :
1275 : : /****************************************************************************/
1276 : :
1277 : :
1278 : : #if ( NEW_STEREOCENTER_CHECK == 1 ) /* { */
1279 : :
1280 : :
1281 : : /****************************************************************************/
1282 : 822 : int bInpAtomHasRequirdNeigh( inp_ATOM *at,
1283 : : int cur_at,
1284 : : int RequirdNeighType,
1285 : : int NumDbleBonds,
1286 : : int bStereoAtZz )
1287 : : {
1288 : : /* RequirdNeighType:
1289 : : reqired neighbor types (bitmap):
1290 : : 0 => any neighbors
1291 : : 1 => no terminal hydrogen atom neighbors
1292 : : 2 => no terminal -X and -XH together (don't care about -X, -XH bond type, charge, radical)
1293 : : (X = tautomeric endpoint atom)
1294 : : NumDbleBonds:
1295 : : if non-zero then allow double, alternating and tautomeric bonds
1296 : : */
1297 : : int i, j, ni, nj, bond_type, num_1s, num_mult, num_other;
1298 : :
1299 [ - + ]: 822 : if (at[cur_at].endpoint)
1300 : : {
1301 : : /* tautomeric endpoint cannot be a stereo center */
1302 : 0 : return 0;
1303 : : }
1304 : :
1305 [ + + - + ]: 822 : if (( 1 & RequirdNeighType ) && at[cur_at].num_H)
1306 : : {
1307 : 0 : return 0;
1308 : : }
1309 : :
1310 [ + + ]: 822 : if (2 & RequirdNeighType)
1311 : : {
1312 [ + + ]: 8 : for (i = 0; i < at[cur_at].valence; i++)
1313 : : {
1314 : 4 : ni = (int) at[cur_at].neighbor[i];
1315 [ + - - + ]: 8 : if (at[ni].valence != 1 ||
1316 : 4 : !get_endpoint_valence( at[ni].el_number ))
1317 : : {
1318 : 0 : continue;
1319 : : }
1320 [ + - ]: 6 : for (j = i + 1; j < at[cur_at].valence; j++)
1321 : : {
1322 : 6 : nj = (int) at[cur_at].neighbor[j];
1323 [ + - ]: 6 : if (at[nj].valence != 1 ||
1324 [ + - - + ]: 12 : at[ni].el_number != at[nj].el_number ||
1325 : 6 : !get_endpoint_valence( at[nj].el_number ))
1326 : : {
1327 : 0 : continue;
1328 : : }
1329 : : /*
1330 : : * if (at[ni].num_H != at[nj].num_H) then the atoms (neighbors of at[cur_at]
1331 : : * are tautomeric endpoints and are indistinguishable => cur_at is not stereogenic
1332 : : * if (at[ni].num_H == at[nj].num_H) then the neighbors are indistinguishable
1333 : : * and cur_at will be found non-sterogenic later
1334 : : * get_endpoint_valence() check will not allow the neighbors to be carbons
1335 : : * Therefore the following "if" is not needed; we may just return 0.
1336 : : */
1337 [ + + + - ]: 6 : if (at[ni].num_H != at[nj].num_H && strcmp( at[ni].elname, "C" ))
1338 : : {
1339 : 4 : return 0; /* found -X and -XH neighbors */
1340 : : }
1341 : : }
1342 : : }
1343 : : }
1344 : :
1345 [ + - ]: 818 : if (0==bStereoAtZz)
1346 : : {
1347 : : /* No stereo allowed at centers connected to pseudoelement atoms "Zz","Zy" */
1348 : : int nbr, inbr;
1349 [ + + ]: 2598 : for (inbr = 0; inbr < at[cur_at].valence; inbr++)
1350 : : {
1351 : 1780 : nbr = (int) at[cur_at].neighbor[inbr];
1352 [ + - - + ]: 1780 : if (!strcmp( at[nbr].elname, "Zz" ) || !strcmp( at[nbr].elname, "Zy" ))
1353 : : {
1354 : 0 : return 0;
1355 : : }
1356 : : }
1357 : : }
1358 : :
1359 : 818 : num_1s = num_mult = num_other = 0;
1360 : :
1361 [ + + ]: 2598 : for (i = 0; i < at[cur_at].valence; i++)
1362 : : {
1363 : 1780 : bond_type = ( at[cur_at].bond_type[i] & ~BOND_MARK_ALL );
1364 [ + - - ]: 1780 : switch (bond_type)
1365 : : {
1366 : 1780 : case BOND_SINGLE:
1367 : 1780 : num_1s++;
1368 : 1780 : break;
1369 : 0 : case BOND_DOUBLE:
1370 : : case BOND_ALTERN:
1371 : : case BOND_TAUTOM:
1372 : : case BOND_ALT12NS:
1373 : 0 : num_mult++;
1374 : 0 : break;
1375 : 0 : default:
1376 : 0 : num_other++;
1377 : 0 : break;
1378 : : }
1379 : : }
1380 : :
1381 [ - + ]: 818 : if (num_other)
1382 : : {
1383 : 0 : return 0;
1384 : : }
1385 : :
1386 [ - + - - : 818 : if ((NumDbleBonds && NumDbleBonds > num_mult) ||
+ - ]
1387 [ - + ]: 818 : (!NumDbleBonds && at[cur_at].valence != num_1s)) /* djb-rwth: addressing LLVM warning */
1388 : : {
1389 : 0 : return 0;
1390 : : }
1391 : :
1392 : 818 : return 1;
1393 : : }
1394 : :
1395 : :
1396 : : /****************************************************************************/
1397 : 1620 : int bCanInpAtomBeAStereoCenter( inp_ATOM *at,
1398 : : int cur_at,
1399 : : int bPointedEdgeStereo,
1400 : : int bStereoAtZz )
1401 : : {
1402 : : /*************************************************************************************
1403 : : * current version
1404 : : *************************************************************************************
1405 : : * Use #define to split the stereocenter description table into parts
1406 : : * to make it easier to read
1407 : : *
1408 : : * --------- 4 single bonds stereocenters -------
1409 : : * 0 1 2 3 4 5
1410 : : *
1411 : : * | | | | | |
1412 : : * -C- -Si- -Ge- -Sn- >As[+] >B[-]
1413 : : * | | | | | |
1414 : : */
1415 : : #define SZELEM1 "C\000","Si", "Ge", "Sn", "As", "B\000",
1416 : : #define CCHARGE1 0, 0, 0, 0, 1, -1,
1417 : : #define CNUMBONDSANDH1 4, 4, 4, 4, 4, 4,
1418 : : #define CCHEMVALENCEH1 4, 4, 4, 4, 4, 4,
1419 : : #define CHAS3MEMBRING1 0, 0, 0, 0, 0, 0,
1420 : : #define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
1421 : : /*
1422 : : * --------------- S, Se stereocenters ----------
1423 : : * 6 7 8 9 10 11 12 13
1424 : : *
1425 : : * | | || | | ||
1426 : : * -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
1427 : : * | | | | | | | |
1428 : : */
1429 : : #define SZELEM2 "S\000","S\000","S\000","S\000","Se", "Se", "Se", "Se",
1430 : : #define CCHARGE2 0, 0, 1, 1, 0, 0, 1, 1,
1431 : : #define CNUMBONDSANDH2 3, 4, 3, 4, 3, 4, 3, 4,
1432 : : #define CCHEMVALENCEH2 4, 6, 3, 5, 4, 6, 3, 5,
1433 : : #define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
1434 : : #define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
1435 : : /*
1436 : : * ------------------ N, P stereocenters -----------------
1437 : : * 14 15 16 17 18 19 20
1438 : : *
1439 : : * Phosphine Arsine
1440 : : * X---Y
1441 : : * | | \ / | | \ / \ /
1442 : : * =N- >N[+] N >P[+] =P- P As
1443 : : * | | | | | | |
1444 : : */
1445 : : #define SZELEM3 "N\000","N\000","N\000","P\000","P\000","P\000", "As",
1446 : : #define CCHARGE3 0, 1, 0, 1, 0, 0, 0,
1447 : : #define CNUMBONDSANDH3 4, 4, 3, 4, 4, 3, 3,
1448 : : #define CCHEMVALENCEH3 5, 4, 3, 4, 5, 3, 3,
1449 : : #define CHAS3MEMBRING3 0, 0, 1, 0, 0, 0, 0,
1450 : : #define CREQUIRDNEIGH3 3, 3, 1, 3, 3, 2, 2,
1451 : :
1452 : : #define PHOSPHINE_STEREO 19 /* the number must match Phosphine number in the comments, see above */
1453 : : #define ARSINE_STEREO 20 /* the number must match Arsine number in the comments, see above */
1454 : :
1455 : : static const char szElem[][3] = { SZELEM1 SZELEM2 SZELEM3 };
1456 : : static const S_CHAR cCharge[] = { CCHARGE1 CCHARGE2 CCHARGE3 };
1457 : : static const S_CHAR cNumBondsAndH[] = { CNUMBONDSANDH1 CNUMBONDSANDH2 CNUMBONDSANDH3 };
1458 : : static const S_CHAR cChemValenceH[] = { CCHEMVALENCEH1 CCHEMVALENCEH2 CCHEMVALENCEH3 };
1459 : : static const S_CHAR cHas3MembRing[] = { CHAS3MEMBRING1 CHAS3MEMBRING2 CHAS3MEMBRING3 };
1460 : : static const S_CHAR cRequirdNeigh[] = { CREQUIRDNEIGH1 CREQUIRDNEIGH2 CREQUIRDNEIGH3 };
1461 : :
1462 : : static const int n = sizeof( szElem ) / sizeof( szElem[0] );
1463 : : /* reqired neighbor types (bitmap):
1464 : : 0 => check bonds only
1465 : : 1 => no terminal hydrogen atom neighbors
1466 : : 2 => no terminal -X and -XH together (don't care the bond type, charge, radical)
1467 : : (X = tautomeric endpoint atom)
1468 : : Note: whenever cChemValenceH[] > cNumBondsAndH[]
1469 : : the tautomeric and/or alternating bonds
1470 : : are permitted
1471 : :
1472 : : */
1473 : 1620 : int i, ret = 0;
1474 [ + + ]: 18546 : for (i = 0; i < n; i++)
1475 : : {
1476 [ + + ]: 17744 : if (!strcmp( at[cur_at].elname, szElem[i] ) &&
1477 [ + + ]: 1100 : ( at[cur_at].charge == cCharge[i]
1478 : : #ifdef ALLOW_NO_CHARGE_ON_STEREO_CENTERS
1479 : : || at[cur_at].charge == 0
1480 : : #endif
1481 : 1038 : ) &&
1482 [ - + - - ]: 1038 : ( !at[cur_at].radical || at[cur_at].radical == 1 ) &&
1483 [ + + ]: 1038 : at[cur_at].valence + at[cur_at].num_H == cNumBondsAndH[i] &&
1484 [ + + - + ]: 898 : at[cur_at].chem_bonds_valence + at[cur_at].num_H == cChemValenceH[i] &&
1485 [ + + + + ]: 1680 : ( cHas3MembRing[i] ? is_atom_in_3memb_ring( at, cur_at ) : 1 ) &&
1486 : 822 : bInpAtomHasRequirdNeigh( at, cur_at, cRequirdNeigh[i], cChemValenceH[i] - cNumBondsAndH[i], bStereoAtZz ))
1487 : : /*
1488 : : if (!strcmp( at[cur_at].elname, szElem[i] ) &&
1489 : : at[cur_at].charge == cCharge[i] &&
1490 : : ( !at[cur_at].radical || at[cur_at].radical == 1 ) &&
1491 : : at[cur_at].valence + at[cur_at].num_H == cNumBondsAndH[i] &&
1492 : : at[cur_at].chem_bonds_valence + at[cur_at].num_H == cChemValenceH[i] &&
1493 : : ( cHas3MembRing[i] ? is_atom_in_3memb_ring( at, cur_at ) : 1 ) &&
1494 : : bInpAtomHasRequirdNeigh( at, cur_at, cRequirdNeigh[i], cChemValenceH[i] - cNumBondsAndH[i], bStereoAtZz ))*/
1495 : : {
1496 : 818 : ret = cNumBondsAndH[i];
1497 : 818 : break;
1498 : : }
1499 : : }
1500 : :
1501 [ + + - + ]: 1620 : if (i == PHOSPHINE_STEREO && !( bPointedEdgeStereo & PES_BIT_PHOSPHINE_STEREO ))
1502 : : {
1503 : 0 : ret = 0;
1504 : : }
1505 [ + + - + ]: 1620 : if (i == ARSINE_STEREO && !( bPointedEdgeStereo & PES_BIT_ARSINE_STEREO ))
1506 : : {
1507 : 0 : ret = 0;
1508 : : }
1509 : :
1510 : 1620 : return ret;
1511 : : }
1512 : :
1513 : :
1514 : : #else /* } NEW_STEREOCENTER_CHECK { */
1515 : :
1516 : :
1517 : : /****************************************************************************/
1518 : : int bCanAtomBeAStereoCenter( char *elname, S_CHAR charge, S_CHAR radical )
1519 : : {
1520 : : static const char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "P\000", "As", "B\000" };
1521 : : static const S_CHAR cCharge[] = { 0, 0, 0, 1, 1, 1, -1 };
1522 : : int i, ret = 0;
1523 : : for (i = 0; i < sizeof( szElem ) / sizeof( szElem[0] ); i++)
1524 : : {
1525 : : if (!strcmp( elname, szElem[i] ) && ( charge == cCharge[i] ))
1526 : : {
1527 : : ret = ( !radical || radical == RADICAL_SINGLET );
1528 : : break;
1529 : : }
1530 : : }
1531 : : return ret;
1532 : : }
1533 : : #endif /* } NEW_STEREOCENTER_CHECK */
1534 : :
1535 : :
1536 : : /****************************************************************************
1537 : : used for atoms adjacent to stereogenic bonds only
1538 : : ****************************************************************************/
1539 : 0 : int bAtomHasValence3( char *elname, S_CHAR charge, S_CHAR radical )
1540 : : {
1541 : : static const char szElem[][3] = { "N\000" };
1542 : : static const S_CHAR cCharge[] = { 0, };
1543 : 0 : int i, ret = 0;
1544 [ # # ]: 0 : for (i = 0; i < (int) ( sizeof( szElem ) / sizeof( szElem[0] ) ); i++)
1545 : : {
1546 [ # # # # ]: 0 : if (!strcmp( elname, szElem[i] ) && ( charge == cCharge[i] ))
1547 : : {
1548 [ # # # # ]: 0 : ret = ( !radical || radical == RADICAL_SINGLET );
1549 : 0 : break;
1550 : : }
1551 : : }
1552 : 0 : return ret;
1553 : : }
1554 : :
1555 : :
1556 : : /****************************************************************************
1557 : : used for atoms adjacent to stereogenic bonds only
1558 : : ****************************************************************************/
1559 : 510 : int bCanAtomHaveAStereoBond( char *elname, S_CHAR charge, S_CHAR radical )
1560 : : {
1561 : : static const char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "N\000" };
1562 : : static const S_CHAR cCharge[] = { 0, 0, 0, 0, 1, };
1563 : : static const int n = sizeof( szElem ) / sizeof( szElem[0] );
1564 : 510 : int i, ret = 0;
1565 [ + + ]: 1758 : for (i = 0; i < n; i++)
1566 : : {
1567 [ + + + + ]: 1530 : if (!strcmp( elname, szElem[i] ) && ( charge == cCharge[i] ))
1568 : : {
1569 [ - + - - ]: 282 : ret = ( !radical || radical == RADICAL_SINGLET );
1570 : 282 : break;
1571 : : }
1572 : : }
1573 : 510 : return ret;
1574 : : }
1575 : :
1576 : :
1577 : : /****************************************************************************
1578 : : used for atoms adjacent to stereogenic bonds only
1579 : : ****************************************************************************/
1580 : 0 : int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical )
1581 : : {
1582 : : static const char szElem[][3] = { "C\000", "Si", "Ge", };
1583 : : static const S_CHAR cCharge[] = { 0, 0, 0, };
1584 : : static const int n = sizeof( szElem ) / sizeof( szElem[0] );
1585 : 0 : int i, ret = 0;
1586 [ # # ]: 0 : for (i = 0; i < n; i++)
1587 : : {
1588 [ # # # # ]: 0 : if (!strcmp( elname, szElem[i] ) && ( charge == cCharge[i] ))
1589 : : {
1590 [ # # # # ]: 0 : ret = ( !radical || radical == RADICAL_SINGLET );
1591 : 0 : break;
1592 : : }
1593 : : }
1594 : 0 : return ret;
1595 : : }
1596 : :
1597 : :
1598 : : /****************************************************************************/
1599 : 40 : int bIsSuitableHeteroInpAtom( inp_ATOM *at )
1600 : : {
1601 : : int val, num_H;
1602 [ + - ]: 40 : if (0 == at->charge &&
1603 [ - + - - : 80 : ( !at->radical || RADICAL_SINGLET == at->radical ) &&
+ + ]
1604 : 40 : 0 < ( val = get_endpoint_valence( at->el_number ) ))
1605 : : {
1606 : 4 : num_H = at->num_H;
1607 [ - + ]: 4 : if (val == at->chem_bonds_valence + num_H)
1608 : : {
1609 [ # # # ]: 0 : switch (val)
1610 : : {
1611 : 0 : case 2: /* O */
1612 [ # # # # ]: 0 : if (!num_H && 1 == at->valence)
1613 : : {
1614 : 0 : return 0; /* =O */
1615 : : }
1616 : 0 : break; /* not found */
1617 : 0 : case 3: /* N */
1618 [ # # # # ]: 0 : if ((1 == at->valence && 1 == num_H) ||
1619 [ # # # # ]: 0 : (2 == at->valence && 0 == num_H)) /* djb-rwth: addressing LLVM warnings */
1620 : : {
1621 : 0 : return 1; /* =N- or =NH */
1622 : : }
1623 : 0 : break; /* not found */
1624 : : }
1625 : : }
1626 : : }
1627 : 40 : return -1;
1628 : : }
1629 : :
1630 : :
1631 : : /****************************************************************************/
1632 : 0 : int bIsOxide( inp_ATOM *at, int cur_at )
1633 : : {
1634 : : int i, bond_type;
1635 : 0 : inp_ATOM *a = at + cur_at, *an;
1636 [ # # ]: 0 : for (i = 0; i < a->valence; i++)
1637 : : {
1638 : 0 : bond_type = ( a->bond_type[i] &= ~BOND_MARK_ALL );
1639 [ # # ]: 0 : if (bond_type == BOND_DOUBLE)
1640 : : {
1641 : 0 : an = at + (int) a->neighbor[i];
1642 [ # # ]: 0 : if (1 == an->valence &&
1643 [ # # # # : 0 : !an->charge && !an->num_H && !an->radical &&
# # # # ]
1644 : 0 : 2 == get_endpoint_valence( an->el_number ))
1645 : : {
1646 : 0 : return 1;
1647 : : }
1648 : : }
1649 : : else
1650 : : {
1651 [ # # # # ]: 0 : if (bond_type == BOND_TAUTOM || bond_type == BOND_ALT12NS)
1652 : : {
1653 : 0 : an = at + (int) a->neighbor[i];
1654 [ # # # # ]: 0 : if (1 == an->valence &&
1655 : 0 : 2 == get_endpoint_valence( an->el_number ))
1656 : : {
1657 : 0 : return 1;
1658 : : }
1659 : : }
1660 : : }
1661 : : }
1662 : :
1663 : 0 : return 0;
1664 : : }
1665 : :
1666 : :
1667 : : /****************************************************************************
1668 : : used for atoms adjacent to stereogenic bonds only
1669 : : ****************************************************************************/
1670 : 14 : int bCanAtomBeTerminalAllene( char *elname, S_CHAR charge, S_CHAR radical )
1671 : : {
1672 : : static const char szElem[][3] = { "C\000", "Si", "Ge", };
1673 : : static const S_CHAR cCharge[] = { 0, 0, 0, };
1674 : : static const int n = sizeof( szElem ) / sizeof( szElem[0] );
1675 : 14 : int i, ret = 0;
1676 [ + - ]: 14 : for (i = 0; i < n; i++)
1677 : : {
1678 [ + - + - ]: 14 : if (!strcmp( elname, szElem[i] ) && ( charge == cCharge[i] ))
1679 : : {
1680 [ - + - - ]: 14 : ret = ( !radical || radical == RADICAL_SINGLET );
1681 : 14 : break;
1682 : : }
1683 : : }
1684 : :
1685 : 14 : return ret;
1686 : : }
1687 : :
1688 : :
1689 : : /****************************************************************************/
1690 : 0 : int GetHalfStereobond0DParity( inp_ATOM *at,
1691 : : int cur_at,
1692 : : AT_NUMB nSbNeighOrigAtNumb[],
1693 : : int nNumExplictAttachments,
1694 : : int bond_parity,
1695 : : int nFlag )
1696 : : {
1697 : : int m, last_parity, cur_parity;
1698 : : int i, icur2nxt, icur2neigh, cur_order_parity, nxt_at;
1699 : : AT_NUMB nNextSbAtOrigNumb;
1700 : : /* find atom parities for all valid streobonds incident to at[cur_at] */
1701 [ # # # # ]: 0 : for (m = 0, last_parity = 0; m < MAX_NUM_STEREO_BONDS && at[cur_at].sb_parity[m]; m++)
1702 : : {
1703 : 0 : icur2nxt = icur2neigh = -1; /* ordering number of neighbors in nSbNeighOrigAtNumb[] */
1704 : 0 : cur_parity = 0; /* parity for mth stereobond incident to the cur_at */
1705 : 0 : nxt_at = at[cur_at].neighbor[(int)at[cur_at].sb_ord[m]]; /* djb-rwth: fixing coverity ID #499549 */
1706 [ # # # # ]: 0 : if (0 <= at[cur_at].sb_ord[m] && at[cur_at].sb_ord[m] < at[cur_at].valence &&
1707 [ # # ]: 0 : at[nxt_at].valence <= MAX_NUM_STEREO_BONDS && /* make sure it is a valid stereobond */
1708 [ # # ]: 0 : ( nNextSbAtOrigNumb = at[nxt_at].orig_at_number ))
1709 : : {
1710 : : /* since at[cur_at].sn_ord[m] = -1 for explicit H use at[cur_at].sn_orig_at_num[m] */
1711 [ # # ]: 0 : for (i = 0; i < nNumExplictAttachments; i++)
1712 : : {
1713 [ # # ]: 0 : if (at[cur_at].sn_orig_at_num[m] == nSbNeighOrigAtNumb[i])
1714 : : {
1715 : 0 : icur2neigh = i; /* neighbor */
1716 : : }
1717 : : else
1718 : : {
1719 [ # # ]: 0 : if (nNextSbAtOrigNumb == nSbNeighOrigAtNumb[i])
1720 : : {
1721 : 0 : icur2nxt = i; /* atom connected by a stereobond */
1722 : : }
1723 : : }
1724 : : }
1725 [ # # # # ]: 0 : if (icur2neigh >= 0 && icur2nxt >= 0)
1726 : : {
1727 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[cur_at].sb_parity[m] ))
1728 : : {
1729 : : /* parity of at[cur_atom] neighbor permutation to reach this order: { next_atom, neigh_atom, ...} */
1730 : 0 : cur_order_parity = ( icur2nxt + icur2neigh + ( icur2nxt > icur2neigh ) - 1 ) % 2;
1731 : 0 : cur_parity = 2 - ( cur_order_parity + at[cur_at].sb_parity[m] ) % 2;
1732 : : }
1733 : : else
1734 : : {
1735 : : /* unknowm/undef parities do not depend on the neighbor order */
1736 : 0 : cur_parity = at[cur_at].sb_parity[m];
1737 : : }
1738 : : }
1739 : : }
1740 : : else
1741 : : {
1742 : 0 : continue;
1743 : : }
1744 : : /* use a well-known parity if available; if not then use preferably the unknown */
1745 [ # # ]: 0 : if (!last_parity)
1746 : : {
1747 : 0 : last_parity = cur_parity;
1748 : : }
1749 : : else
1750 : : {
1751 [ # # # # ]: 0 : if (last_parity != cur_parity && cur_parity)
1752 : : {
1753 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( last_parity ))
1754 : : {
1755 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( cur_parity ))
1756 : : {
1757 : 0 : last_parity = 0; /* error: all well-defined parities should be same */
1758 : 0 : break;
1759 : : }
1760 : : }
1761 : : else
1762 : : {
1763 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( cur_parity ))
1764 : : {
1765 : : /* replace unknown/undefined parity with well-known */
1766 : 0 : last_parity = cur_parity;
1767 : : }
1768 : : else
1769 : : {
1770 : : /* select min unknown/undefined parity (out of AB_PARITY_UNKN and AB_PARITY_UNDF) */
1771 : 0 : last_parity = inchi_min( cur_parity, last_parity );
1772 : : }
1773 : : }
1774 : : }
1775 : : }
1776 : : }
1777 : :
1778 [ # # ]: 0 : if (last_parity)
1779 : : {
1780 : 0 : bond_parity = last_parity;
1781 : 0 : at[cur_at].bUsed0DParity |= nFlag; /* set flag: used stereobond 0D parity */
1782 : : }
1783 : :
1784 : 0 : return bond_parity;
1785 : : }
1786 : :
1787 : :
1788 : : /****************************************************************************/
1789 : 0 : int FixSb0DParities( inp_ATOM *at,
1790 : : /* inp_ATOM *at_removed_H,
1791 : : int num_removed_H,*/
1792 : : int chain_length,
1793 : : int at_1,
1794 : : int i_next_at_1,
1795 : : S_CHAR z_dir1[],
1796 : : int at_2,
1797 : : int i_next_at_2,
1798 : : S_CHAR z_dir2[],
1799 : : int *pparity1,
1800 : : int *pparity2 )
1801 : : {
1802 : : int k, parity1, parity2, abs_parity1, abs_parity2;
1803 : : int j1, j2, parity_sign;
1804 : : /*
1805 : : AT_NUMB nSbNeighOrigAtNumb1[MAX_NUM_STEREO_BOND_NEIGH], nSbNeighOrigAtNumb2[MAX_NUM_STEREO_BOND_NEIGH];
1806 : : int nNumExplictAttachments1, nNumExplictAttachments2;
1807 : : */
1808 : 0 : parity1 = parity2 = AB_PARITY_NONE;
1809 : 0 : j1 = j2 = -1;
1810 [ # # # # ]: 0 : parity_sign = ( *pparity1 < 0 || *pparity2 < 0 ) ? -1 : 1;
1811 : :
1812 : 0 : abs_parity1 = abs( *pparity1 );
1813 : 0 : abs_parity2 = abs( *pparity2 );
1814 : :
1815 [ # # # # ]: 0 : for (k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k++)
1816 : : {
1817 [ # # ]: 0 : if (at[at_1].sb_ord[k] == i_next_at_1)
1818 : : {
1819 : 0 : parity1 = at[at_1].sb_parity[k];
1820 : 0 : j1 = k;
1821 : : }
1822 : : }
1823 [ # # # # ]: 0 : for (k = 0; k < MAX_NUM_STEREO_BONDS && at[at_2].sb_parity[k]; k++)
1824 : : {
1825 [ # # ]: 0 : if (at[at_2].sb_ord[k] == i_next_at_2)
1826 : : {
1827 : 0 : parity2 = at[at_2].sb_parity[k];
1828 : 0 : j2 = k;
1829 : : }
1830 : : }
1831 [ # # # # : 0 : switch (( j1 >= 0 ) + 2 * ( j2 >= 0 ))
# # ]
1832 : : {
1833 : 0 : case 0:
1834 : : /* the bond has no 0D parity */
1835 : 0 : *pparity1 = *pparity2 = parity_sign * AB_PARITY_UNDF;
1836 : 0 : return 0;
1837 : 0 : case 1:
1838 : : case 2:
1839 : : /* 0D parity data error */
1840 : 0 : *pparity1 = *pparity2 = AB_PARITY_NONE;
1841 : 0 : return -1;
1842 : 0 : case 3:
1843 : : /* the bond has 0D parity */
1844 [ # # # # : 0 : switch (!( ATOM_PARITY_WELL_DEF( abs_parity1 ) && ATOM_PARITY_WELL_DEF( parity1 ) ) +
# # # # ]
1845 [ # # # # : 0 : 2 * !( ATOM_PARITY_WELL_DEF( abs_parity2 ) && ATOM_PARITY_WELL_DEF( parity2 ) ))
# # # # #
# # # # ]
1846 : : {
1847 : 0 : case 0:
1848 : : /* both parities are well-defined; continue */
1849 : 0 : break;
1850 : 0 : case 1:
1851 : : /* 0D parity not well-defined for at_1 */
1852 [ # # # # ]: 0 : *pparity1 = parity_sign * ( ATOM_PARITY_WELL_DEF( parity1 ) ? abs_parity1 :
1853 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( abs_parity1 ) ? parity1 :
1854 : : inchi_min( abs_parity1, parity1 ) );
1855 : 0 : *pparity2 = parity_sign * abs_parity2;
1856 : 0 : return -1;
1857 : 0 : case 2:
1858 : : /* 0D parity not well-defined for at_2 */
1859 : 0 : *pparity1 = parity_sign * abs_parity1;
1860 [ # # # # ]: 0 : *pparity2 = parity_sign * ( ATOM_PARITY_WELL_DEF( parity2 ) ? abs_parity2 :
1861 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( abs_parity2 ) ? parity2 :
1862 : : inchi_min( abs_parity2, parity2 ) );
1863 : 0 : return -1;
1864 : 0 : case 3:
1865 [ # # # # ]: 0 : abs_parity1 = ( ATOM_PARITY_WELL_DEF( parity1 ) ? abs_parity1 :
1866 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( abs_parity1 ) ? parity1 :
1867 : : inchi_min( abs_parity1, parity1 ) );
1868 [ # # # # ]: 0 : abs_parity2 = ( ATOM_PARITY_WELL_DEF( parity2 ) ? abs_parity2 :
1869 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( abs_parity2 ) ? parity2 :
1870 : : inchi_min( abs_parity2, parity2 ) );
1871 : 0 : *pparity1 = *pparity2 = parity_sign * inchi_min( abs_parity1, abs_parity2 );
1872 : : /*return (parity1 == parity2)? 0 : -1;*/
1873 : 0 : return -1;
1874 : : }
1875 : 0 : break;
1876 : : }
1877 : : /* we are here if both end-atoms of the bond have well-defined 0D parities */
1878 : : /*
1879 : : nNumExplictAttachments1 = GetSbNeighOrigAtNumb( at, at_1, at_removed_H, num_removed_H, nSbNeighOrigAtNumb1 );
1880 : : nNumExplictAttachments2 = GetSbNeighOrigAtNumb( at, at_2, at_removed_H, num_removed_H, nSbNeighOrigAtNumb2 );
1881 : : parity1 = GetHalfStereobond0DParity( at, at_1, nSbNeighOrigAtNumb1, nNumExplictAttachments1, *pparity1, 0 );
1882 : : parity2 = GetHalfStereobond0DParity( at, at_2, nSbNeighOrigAtNumb2, nNumExplictAttachments2, *pparity2, 0 );
1883 : : */
1884 : 0 : *pparity1 = parity_sign * abs_parity1;
1885 : 0 : *pparity2 = parity_sign * abs_parity2;
1886 : :
1887 [ # # ]: 0 : if (chain_length % 2)
1888 : : {
1889 : : /* allene; chain_length = (number of double bonds) - 1 */
1890 : : /*
1891 : : int zer1 = ( !z_dir1[0] && !z_dir1[1] && !z_dir1[2] );
1892 : : int zer2 = ( !z_dir2[0] && !z_dir2[1] && !z_dir2[2] );
1893 : : */
1894 : 0 : int bWrong_z_dir1 = ( 0 != ( at[at_1].bUsed0DParity & FlagSB_0D ) );
1895 : 0 : int bWrong_z_dir2 = ( 0 != ( at[at_2].bUsed0DParity & FlagSB_0D ) );
1896 : :
1897 [ # # # # ]: 0 : if (bWrong_z_dir1 && bWrong_z_dir2)
1898 : : {
1899 : 0 : goto set_default;
1900 : : }
1901 : : else
1902 : : {
1903 [ # # # # ]: 0 : if (bWrong_z_dir1 || bWrong_z_dir2)
1904 : : {
1905 : : double r12[3], zi1[3], zi2[3], abs_r12, abs_zi2;
1906 : : int at_i1, at_i2, j; /* djb-rwth: ignoring LLVM warning: variables used */
1907 : : S_CHAR z_dir[3];
1908 : 0 : r12[0] = at[at_2].x - at[at_1].x;
1909 : 0 : r12[1] = at[at_2].y - at[at_1].y;
1910 : 0 : r12[2] = at[at_2].z - at[at_1].z;
1911 : 0 : abs_r12 = len3( r12 );
1912 [ # # ]: 0 : if (abs_r12 < MIN_BOND_LEN)
1913 : : {
1914 : 0 : goto set_default;
1915 : : }
1916 : : /* make r12[] point to the atom with 'good' z_dir[] */
1917 [ # # ]: 0 : if (bWrong_z_dir1)
1918 : : {
1919 : 0 : at_i1 = at_2; /* has good z_dir2[] */ /* djb-rwth: ignoring LLVM warning: variable used */
1920 : 0 : at_i2 = at_1; /* has bad z_dir1[] */ /* djb-rwth: ignoring LLVM warning: variable used */
1921 : 0 : zi1[0] = z_dir2[0];
1922 : 0 : zi1[1] = z_dir2[1];
1923 : 0 : zi1[2] = z_dir2[2];
1924 : 0 : mult3( r12, 1.0 / abs_r12, r12 ); /* make length = 1 */
1925 : : }
1926 : : else
1927 : : {
1928 : 0 : at_i1 = at_1; /* has good z_dir1[] */ /* djb-rwth: ignoring LLVM warning: variable used */
1929 : 0 : at_i2 = at_2; /* has bad z_dir2[] */ /* djb-rwth: ignoring LLVM warning: variable used */
1930 : 0 : zi1[0] = z_dir1[0];
1931 : 0 : zi1[1] = z_dir1[1];
1932 : 0 : zi1[2] = z_dir1[2];
1933 : 0 : mult3( r12, -1.0 / abs_r12, r12 ); /* make length = 1 */
1934 : : }
1935 : 0 : cross_prod3( r12, zi1, zi2 );
1936 : 0 : abs_zi2 = len3( zi2 );
1937 : 0 : mult3( zi2, 100.0 / abs_zi2, zi2 ); /* make length = 100 */
1938 [ # # ]: 0 : for (j = 0; j < 3; j++)
1939 : : {
1940 [ # # ]: 0 : z_dir[j] = (S_CHAR) ( zi2[j] >= 0.0 ? floor( 0.5 + zi2[j] ) :
1941 : 0 : -floor( 0.5 - zi2[j] ) ); /* abs(z_dir) = 100 */
1942 : : }
1943 [ # # ]: 0 : if (bWrong_z_dir1)
1944 : : {
1945 : 0 : memcpy(z_dir1, z_dir, sizeof(z_dir));
1946 : : }
1947 : : else
1948 : : {
1949 : 0 : memcpy(z_dir2, z_dir, sizeof(z_dir));
1950 : : }
1951 : : }
1952 : : }
1953 : 0 : return 0;
1954 : :
1955 : 0 : set_default:
1956 : : /* z_dir1[] = x-direction; z_dir2[] = z-direction; r12[] = y-direction */
1957 : 0 : z_dir1[0] = 100;
1958 : 0 : z_dir1[1] = z_dir1[2] = 0;
1959 : 0 : z_dir2[0] = z_dir2[1] = 0;
1960 : 0 : z_dir2[2] = 100;
1961 : : }
1962 : :
1963 : 0 : return 0;
1964 : : }
1965 : :
1966 : :
1967 : : /****************************************************************************
1968 : : without this InChI fails on reconstructed CID=450438
1969 : : (isotopic, Unknown SB adjacent to SB with known parity)
1970 : : ****************************************************************************/
1971 : 0 : int FixUnkn0DStereoBonds( inp_ATOM *at, int num_at )
1972 : : {
1973 : 0 : int i, m, num = 0;
1974 : :
1975 : : /* Add usual Unknown stereobond descriptors to each Unknown bond */
1976 [ # # ]: 0 : for (i = 0; i < num_at; i++)
1977 : : {
1978 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[i].sb_parity[m]; m++)
1979 : : {
1980 [ # # ]: 0 : if (AB_PARITY_UNKN == at[i].sb_parity[m])
1981 : : {
1982 : 0 : at[i].bond_stereo[(int) at[i].sb_ord[m]] = STEREO_DBLE_EITHER;
1983 : 0 : num++;
1984 : : }
1985 : : }
1986 : : }
1987 : : #ifdef NEVER
1988 : : if (num)
1989 : : {
1990 : : int j;
1991 : : /* how to remove Unknown stereo bond parities */
1992 : : for (i = 0; i < num_at; i++)
1993 : : {
1994 : : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[i].sb_parity[m]; m++)
1995 : : {
1996 : : if (AB_PARITY_UNKN == at[i].sb_parity[m])
1997 : : {
1998 : : for (j = m + 1; j < MAX_NUM_STEREO_BONDS; j++)
1999 : : {
2000 : : at[i].sb_parity[j - 1] = at[i].sb_parity[j];
2001 : : at[i].sb_ord[j - 1] = at[i].sb_ord[j];
2002 : : at[i].sn_ord[j - 1] = at[i].sn_ord[j];
2003 : : at[i].sn_orig_at_num[j - 1] = at[i].sn_orig_at_num[j];
2004 : : }
2005 : : at[i].sb_parity[j - 1] = 0;
2006 : : at[i].sb_ord[j - 1] = 0;
2007 : : at[i].sn_ord[j - 1] = 0;
2008 : : at[i].sn_orig_at_num[j - 1] = 0;
2009 : : }
2010 : : }
2011 : : }
2012 : : }
2013 : : #endif
2014 : :
2015 : 0 : return num;
2016 : : }
2017 : :
2018 : :
2019 : : /*======================================================================================================
2020 : :
2021 : : half_stereo_bond_parity() General Description:
2022 : :
2023 : : A) find projections of 3 bonds on a reasonable plane defined
2024 : : by a vector z_dir perpendicular to the plane
2025 : : B) calculate parity
2026 : :
2027 : : half_stereo_bond_parity() Detailed Description:
2028 : :
2029 : : 1) Find at_coord[] = vectors from the central atoms to its neighbors
2030 : : 2) If only 2 neighbors are present, then create a reasonable 3rd neighbor
2031 : : (an implicit H or a fictitious atom in case of =NX) coordinates
2032 : : 3) Normalize at_coord[] to unit length
2033 : : 4) Find unit vector pnt[2] perpendicular to the plane containing
2034 : : at_coord[] arrow ends.
2035 : : Even though it is not necessary, make z-coordinate of pnt[2] positive.
2036 : : ** pnt[2] has the new z-axis direction **
2037 : : 5) Let pnt[0] = perpendicular to pnt[2] component of at_coord[0];
2038 : : Normalize pnt[0] to unit length.
2039 : : ** pnt[0] has the new x-axis direction **
2040 : : 6) Let pnt[1] = pnt[2] x pnt[0] (cross-product);
2041 : : ** pnt[1] has the new y-axis direction **
2042 : : 7) Find at_coord[] in the new xyz-basis and normalize their xy-projections
2043 : : to a unit length
2044 : : 8) In the new xy-plane find (counterclockwise) angles:
2045 : : tmp1 = (from at_coord[0] to at_coord[1])
2046 : : tmp2 = (from at_coord[0] to at_coord[2])
2047 : : 9) Calculate the parity: if tmp1 < tmp2 then 1 (odd) else 2 (even)
2048 : : (even: looking from the arrow end of the new z-axis, 0, 1, and 2 neighbors
2049 : : are in clockwise order)
2050 : : 10) Calculate z_dir = 100*pnt[2].
2051 : :
2052 : : Note1. If z_dir vectors of atoms located at the opposite ends of a double bond have approximately
2053 : : opposite directions (that is, their dot-product is negative) then the parity of the
2054 : : stereogenic bond calculated from half-bond-parities should be inverted
2055 : :
2056 : : Note2. In case of a tetrahedral cumulene a triple product (z_dir1, (1->2), z_dir2) is used instead
2057 : : of the dot-product. (1->2) is a vector from the atom#1 to the atom #2. This triple product
2058 : : is invariant with respect to the atom numbering because it does not change upon (1,2)
2059 : : permutation.
2060 : :
2061 : : Stereo ambiguity in case of 2 neighbors:
2062 : : ----------------------------------------
2063 : : Undefined: single-double bond angle > pi - arcsin(0.03) = 178.28164199834454285275613218975 degrees
2064 : : Ambiguous: single-double bond angle > 175 degrees = pi - 0.087156 Rad
2065 : :
2066 : : Return values
2067 : : (cases: I=only in case of isotopic H atoms the neighbors are different,
2068 : : N=in case of non-isotopic H atoms the neighbors are different)
2069 : :
2070 : : -4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, I
2071 : : -3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, I
2072 : : -2 =-AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, I
2073 : : -1 =-AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, I
2074 : : 0 = AB_PARITY_NONE => the atom is not adjacent to a stereogenic bond
2075 : : 1 = AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, N&I
2076 : : 2 = AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, N&I
2077 : : 3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, N&I
2078 : : 4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, N&I
2079 : : 5 = AB_PARITY_IISO => atom constitutionally equivalent to this atom may be adjacent to a stereogenic bond, I
2080 : :
2081 : :
2082 : : =====================================================================================================*/
2083 : :
2084 : :
2085 : : /****************************************************************************/
2086 : 0 : int half_stereo_bond_parity( inp_ATOM *at,
2087 : : int cur_at,
2088 : : inp_ATOM *at_removed_H,
2089 : : int num_removed_H,
2090 : : S_CHAR *z_dir,
2091 : : int bPointedEdgeStereo,
2092 : : int vABParityUnknown )
2093 : : {
2094 : : double at_coord[MAX_NUM_STEREO_BOND_NEIGH][3], c, s, tmp[3], tmp1, tmp2, min_tmp, max_tmp, z;
2095 : : double temp[3], pnt[3][3];
2096 : 0 : int j, k, p0, p1, p2, next, bValence3 = 0, num_z, nType, num_either_single; /* djb-rwth: ignoring LLVM warning: variable used in switch statement; removing redundant variables */
2097 : : int nNumExplictAttachments;
2098 : 0 : int bond_parity = AB_PARITY_UNDF;
2099 : 0 : int num_H = 0, num_iH, num_eH = 0, num_nH = 0 /* = num_iso_H[0] */;
2100 : : int num_iso_H[NUM_H_ISOTOPES + 1];
2101 : : int index_H[5]; /* cannot have more than 4 elements: 1 H, 1 1H, 1 D, 1 T atom(s) */
2102 : : /* const double one_pi = 2.0*atan2(1.0 , 0.0 ); */
2103 : 0 : const double one_pi = 3.14159265358979323846; /* M_PI */
2104 : 0 : const double two_pi = 2.0*one_pi;
2105 : 0 : int bIgnoreIsotopicH = ( 0 != ( at[cur_at].cFlags & AT_FLAG_ISO_H_POINT ) );
2106 : : AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_BOND_NEIGH];
2107 : :
2108 : :
2109 [ # # # # : 0 : if (z_dir && !z_dir[0] && !z_dir[1] && !z_dir[2])
# # # # ]
2110 : : {
2111 : 0 : z_dir[2] = 100;
2112 : : }
2113 : :
2114 : 0 : num_H = at[cur_at].num_H;
2115 [ # # ]: 0 : if (num_H > NUM_H_ISOTOPES)
2116 : : {
2117 : 0 : return 0; /* at least 2 H atoms are isotopically identical */
2118 : : }
2119 : :
2120 [ # # ]: 0 : if (MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence + num_H ||
2121 [ # # ]: 0 : MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence + num_H)
2122 : : {
2123 : 0 : return 0;
2124 : : }
2125 : :
2126 [ # # ]: 0 : if (!bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ))
2127 : : {
2128 : 0 : return 0;
2129 : : }
2130 : :
2131 [ # # ]: 0 : if (!bIgnoreIsotopicH)
2132 : : {
2133 [ # # ]: 0 : for (j = 0, num_nH = num_H; j < NUM_H_ISOTOPES; j++)
2134 : : {
2135 [ # # ]: 0 : if (( k = (int) at[cur_at].num_iso_H[j] ) > 1)
2136 : : {
2137 : 0 : return AB_PARITY_IISO; /* two or more identical isotopic H atoms */
2138 : : }
2139 : 0 : num_nH -= k;
2140 : : }
2141 : : }
2142 : :
2143 : : /* at this point num_nH = number of non-isotopic H atoms */
2144 [ # # ]: 0 : if (num_nH > 1)
2145 : : {
2146 : 0 : return AB_PARITY_IISO; /* two or more identical non-isotopic H atoms */
2147 : : }
2148 : :
2149 [ # # ]: 0 : if (num_nH < 0)
2150 : : {
2151 : 0 : return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
2152 : : }
2153 : :
2154 [ # # ]: 0 : for (j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j++) /* djb-rwth: avoiding garbage values with proper initialisation */
2155 : : {
2156 [ # # ]: 0 : for (k = 0; k < 3; k++)
2157 : : {
2158 : 0 : at_coord[j][k] = 0;
2159 : : }
2160 : : }
2161 : :
2162 : : /********************************************************************
2163 : : * Note. At this point all (implicit and explicit) isotopic
2164 : : * terminal H neighbors are either different or not present.
2165 : : ********************************************************************/
2166 : :
2167 : : /* locate explicit hydrogen atoms */
2168 : : /* (at_removed_H are sorted in ascending isotopic H mass order, non-isotopic first) */
2169 : 0 : memset( num_iso_H, 0, sizeof( num_iso_H ) ); /* djb-rwth: memset_s C11/Annex K variant? */
2170 [ # # # # ]: 0 : if (at_removed_H && num_removed_H > 0)
2171 : : {
2172 [ # # ]: 0 : for (j = 0; j < num_removed_H; j++)
2173 : : {
2174 [ # # ]: 0 : if (at_removed_H[j].neighbor[0] == cur_at)
2175 : : {
2176 [ # # ]: 0 : k = bIgnoreIsotopicH ? 0 : at_removed_H[j].iso_atw_diff;
2177 [ # # # # ]: 0 : if (0 <= k && k <= NUM_H_ISOTOPES)
2178 : : {
2179 [ # # ]: 0 : if (++num_iso_H[k] > 1) /* num_iso_H[0] = number of non-isotopic H atoms */
2180 : 0 : return CT_ISO_H_ERR; /* program error in counting hydrogens */ /* <BRKPT> */
2181 : 0 : index_H[num_eH++] = j;
2182 : : }
2183 : : else
2184 : : {
2185 : 0 : return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
2186 : : }
2187 : : }
2188 : : }
2189 : 0 : num_iH = num_H - num_eH; /* number of implicit non-isotopic and isotopic H atoms */
2190 [ # # ]: 0 : if (num_iH > 1)
2191 : : {
2192 : : /* more than one implicit H: cannot reconstruct the geometry */
2193 : 0 : bond_parity = -AB_PARITY_UNDF;
2194 : 0 : goto exit_function;
2195 : : }
2196 : : }
2197 : : /* djb-rwth: removing redundant code */
2198 : : /* at this point num_iH = number of implicit non-isotopic and isotopic H atoms */
2199 [ # # ]: 0 : if (at[cur_at].valence + num_eH < MIN_NUM_STEREO_BOND_NEIGH)
2200 : : {
2201 : : /* =NH or =CHD when no explicit H is present */
2202 [ # # ]: 0 : return num_H == 1 ? AB_PARITY_UNDF : -AB_PARITY_UNDF;
2203 : : }
2204 : :
2205 : 0 : bValence3 = bAtomHasValence3( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical );
2206 : : /*
2207 : : * Can one explicit hydrogen be added to make asymmetric configuration?
2208 : : * For now we can add 1 H atom in case of an appropriate geometry if:
2209 : : * (a) one non-isotopic H (even if explicit isotopic H atoms are present), or
2210 : : * (b) one isotopic or non-isotopic H if NO explicit isotopic or non-isotopic H atom is present
2211 : : * This makes sense only in case chem. valence = 4. In case of chem. valence = 3, do not check.
2212 : : */
2213 [ # # # # : 0 : if (at[cur_at].valence + num_eH == MIN_NUM_STEREO_BOND_NEIGH && !bValence3 &&
# # ]
2214 [ # # # # ]: 0 : !(/*(a)*/ (1 == num_nH && !num_iso_H[0]) ||
2215 [ # # ]: 0 : /*(b)*/ (1 == num_H && !num_eH )) /* djb-rwth: addressing LLVM warnings */
2216 : : )
2217 : : {
2218 : 0 : goto exit_function;
2219 : : /* return num_H == 1? AB_PARITY_UNDF : -AB_PARITY_UNDF; */
2220 : : }
2221 : :
2222 : : /* store neighbors coordinates */
2223 : 0 : num_z = num_either_single = 0; /* djb-rwth: ignoring LLVM warning: variable used for switch statement; removing redundant code */
2224 [ # # ]: 0 : for (k = nNumExplictAttachments = 0; k < 2; k++)
2225 : : {
2226 [ # # # ]: 0 : switch (k)
2227 : : {
2228 : 0 : case 0:
2229 [ # # ]: 0 : for (j = 0; j < num_eH; j++, nNumExplictAttachments++)
2230 : : {
2231 : 0 : next = index_H[j];
2232 : 0 : at_coord[nNumExplictAttachments][0] = at_removed_H[next].x - at[cur_at].x;
2233 : 0 : at_coord[nNumExplictAttachments][1] = at_removed_H[next].y - at[cur_at].y;
2234 : 0 : nSbNeighOrigAtNumb[nNumExplictAttachments] = at_removed_H[next].orig_at_number;
2235 : : /* use the fact that (at_removed_H - at) = (number of atoms except removed explicit H) */
2236 : 0 : z = -get_z_coord( at, (int) ( at_removed_H - at ) + next,
2237 : : 0 /*neighbor #*/,
2238 : : &nType,
2239 : 0 : -( bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO ) );
2240 [ # # # # ]: 0 : switch (nType)
2241 : : {
2242 : 0 : case ZTYPE_EITHER:
2243 : 0 : num_either_single++; /* bond in "Either" direction. */
2244 : 0 : break;
2245 : 0 : case ZTYPE_UP:
2246 : : case ZTYPE_DOWN:
2247 : 0 : nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
2248 : 0 : z = len2( at_coord[nNumExplictAttachments] );
2249 : : /*
2250 : : z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
2251 : : + at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
2252 : : */
2253 [ # # ]: 0 : if (nType == ZTYPE_DOWN)
2254 : : {
2255 : 0 : z = -z;
2256 : : }
2257 : : /* no break; here */
2258 : : case ZTYPE_3D:
2259 : 0 : num_z++;
2260 : : }
2261 : 0 : at_coord[nNumExplictAttachments][2] = z;
2262 : : }
2263 : 0 : break;
2264 : 0 : case 1:
2265 [ # # ]: 0 : for (j = 0; j < at[cur_at].valence; j++, nNumExplictAttachments++)
2266 : : {
2267 : 0 : next = at[cur_at].neighbor[j];
2268 : 0 : at_coord[nNumExplictAttachments][0] = at[next].x - at[cur_at].x;
2269 : 0 : at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
2270 : 0 : nSbNeighOrigAtNumb[nNumExplictAttachments] = at[next].orig_at_number;
2271 : :
2272 : 0 : z = get_z_coord( at, cur_at, j /*neighbor #*/, &nType, ( bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO ) );
2273 [ # # # # ]: 0 : switch (nType)
2274 : : {
2275 : 0 : case ZTYPE_EITHER:
2276 : 0 : num_either_single++; /* bond in "Either" direction. */
2277 : 0 : break;
2278 : 0 : case ZTYPE_UP:
2279 : : case ZTYPE_DOWN:
2280 : 0 : z = len2( at_coord[nNumExplictAttachments] );
2281 : : /*
2282 : : z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
2283 : : + at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
2284 : : */
2285 [ # # ]: 0 : if (nType == ZTYPE_DOWN)
2286 : : {
2287 : 0 : z = -z;
2288 : : }
2289 : : /* no break; here */
2290 : : case ZTYPE_3D:
2291 : 0 : num_z++;
2292 : : }
2293 : 0 : at_coord[nNumExplictAttachments][2] = z;
2294 : : }
2295 : 0 : break;
2296 : : }
2297 : : }
2298 : :
2299 [ # # ]: 0 : if (num_either_single)
2300 : : {
2301 : 0 : bond_parity = vABParityUnknown /*AB_PARITY_UNKN*/; /* single bond is 'unknown' */
2302 : 0 : goto exit_function;
2303 : : }
2304 : :
2305 : : /* nNumExplictAttachments is a total number of attachments, including removed explicit terminal hydrogens */
2306 [ # # ]: 0 : if (nNumExplictAttachments == 2)
2307 : : {
2308 : : /* create coordinates of the implicit hydrogen (or a fictitious atom in case of ==N-X ), */
2309 : : /* coord[2][], attached to the cur_at. */
2310 [ # # ]: 0 : for (j = 0; j < 3; j++)
2311 : : {
2312 : 0 : at_coord[2][j] = -( at_coord[0][j] + at_coord[1][j] );
2313 : : }
2314 : 0 : nSbNeighOrigAtNumb[nNumExplictAttachments] = 0; /* implicit H or lone pair */
2315 : : }
2316 [ # # ]: 0 : for (j = 0; j < 3; j++)
2317 : : {
2318 : 0 : tmp[j] = len3( at_coord[j] );
2319 : : }
2320 [ # # # # : 0 : min_tmp = inchi_min( tmp[0], inchi_min( tmp[1], tmp[2] ) );
# # ]
2321 [ # # # # : 0 : max_tmp = inchi_max( tmp[0], inchi_max( tmp[1], tmp[2] ) );
# # ]
2322 [ # # # # ]: 0 : if (min_tmp < MIN_BOND_LEN || min_tmp < MIN_SINE*max_tmp)
2323 : : {
2324 : : /* all bonds or some of bonds are too short */
2325 [ # # ]: 0 : if (at[cur_at].sb_parity[0])
2326 : : {
2327 : : /* use bond psrity; the reconciliation in ReconcileAllCmlBondParities()
2328 : : * has made all ways to calculate parity produce same result
2329 : : */
2330 : 0 : bond_parity = GetHalfStereobond0DParity( at, cur_at, nSbNeighOrigAtNumb,
2331 : : nNumExplictAttachments, bond_parity, FlagSB_0D );
2332 : : }
2333 : :
2334 : 0 : goto exit_function;
2335 : : }
2336 : : /* normalize lengths to 1 */
2337 [ # # ]: 0 : for (j = 0; j < 3; j++)
2338 : : {
2339 : 0 : mult3( at_coord[j], 1.0 / tmp[j], at_coord[j] );
2340 : : }
2341 : :
2342 : : /* find projections of at_coord vector differences on the plane containing their arrowhead ends */
2343 [ # # ]: 0 : for (j = 0; j < 3; j++)
2344 : : {
2345 : : /* pnt[0..2] = {0-1, 1-2, 2-0} */
2346 : 0 : tmp[j] = len3((double *)diff3( at_coord[j], at_coord[( j + 1 ) % 3], pnt[j] ) ); /* djb-rwth: cast operator added for compatibility */
2347 [ # # ]: 0 : if (tmp[j] < MIN_SINE)
2348 : : {
2349 : 0 : goto exit_function; /* angle #i-cur_at-#j is too small */
2350 : : }
2351 : 0 : mult3( pnt[j], 1.0 / tmp[j], pnt[j] ); /* 2003-10-06 */
2352 : : }
2353 : : /* find pnt[p2], a vector perpendicular to the plane, and its length tmp[p2] */
2354 : : /* replace previous pnt[p2], tmp[p2] with new values; the old values do not have any additional */
2355 : : /* information because pnt[p0]+pnt[p1]+pnt[p2]=0 */
2356 : : /* 10-6-2003: a cross-product of one pair pnt[j], pnt[(j+1)%3] can be very small. Find the larges one */
2357 : 0 : tmp1 = len3((double *)cross_prod3( pnt[0], pnt[1], temp ) ); /* djb-rwth: cast operator added for compatibility */
2358 [ # # ]: 0 : for (j = 1, k = 0; j < 3; j++)
2359 : : {
2360 : 0 : tmp2 = len3((double *)cross_prod3( pnt[j], pnt[( j + 1 ) % 3], temp ) ); /* djb-rwth: cast operator added for compatibility */
2361 [ # # ]: 0 : if (tmp2 > tmp1)
2362 : : {
2363 : 0 : tmp1 = tmp2;
2364 : 0 : k = j;
2365 : : }
2366 : : }
2367 : : /* previously p0=0, p1=1, p2=2 */
2368 : 0 : p0 = k;
2369 : 0 : p1 = ( k + 1 ) % 3;
2370 : 0 : p2 = ( k + 2 ) % 3;
2371 : 0 : tmp[p2] = len3((double *)cross_prod3( pnt[p0], pnt[p1], pnt[p2] ) ); /* djb-rwth: cast operator added for compatibility */
2372 [ # # ]: 0 : if (tmp[p2] < MIN_SINE*tmp[p0] * tmp[p1])
2373 : : {
2374 : 0 : goto exit_function; /* pnt[p0] is almost colinear to pnt[p1] */
2375 : : }
2376 : : /* new basis: pnt[p0], pnt[p1], pnt[p2]; set z-coord sign and make abs(pnt[p2]) = 1 */
2377 [ # # ]: 0 : mult3( pnt[p2], ( pnt[p2][2] > 0.0 ? 1.0 : -1.0 ) / tmp[p2], pnt[p2] ); /* unit vector in the new z-axis direction */
2378 : :
2379 : 0 : min_tmp = dot_prod3( at_coord[0], pnt[p2] ); /* non-planarity measure (sine): hight of at_coord[] pyramid */
2380 : 0 : mult3( pnt[p2], min_tmp, pnt[p0] ); /* vector height of the pyramid, ideally 0 */
2381 : : /* find new pnt[p0] = projection of at_coord[p0] on plane orthogonal to pnt[p2] */
2382 : 0 : tmp[p0] = len3((double *)diff3( at_coord[0], pnt[p0], pnt[p0] ) ); /* djb-rwth: cast operator added for compatibility */
2383 : 0 : mult3( pnt[p0], 1.0 / tmp[p0], pnt[p0] ); /* new x axis basis vector */
2384 : 0 : cross_prod3( pnt[p2], pnt[p0], pnt[p1] ); /* new y axis basis vector */
2385 : : /* find at_coord in the new basis of {pnt[p0], pnt[p1], pnt[p2]} */
2386 [ # # ]: 0 : for (j = 0; j < 3; j++)
2387 : : {
2388 : : /* copy3(at_coord[j], temp);-- djb-rwth: removing copy3 function */
2389 : 0 : memcpy(temp, at_coord[j], sizeof(at_coord[j]));
2390 [ # # ]: 0 : for (k = 0; k < 3; k++)
2391 : : {
2392 : 0 : at_coord[j][k] = dot_prod3( temp, pnt[( k + p0 ) % 3] );
2393 : : }
2394 : : /* new xy plane projection length */
2395 : 0 : tmp[j] = sqrt( at_coord[j][0] * at_coord[j][0] + at_coord[j][1] * at_coord[j][1] );
2396 : : /* make new xy plane projection length = 1 */
2397 : 0 : mult3( at_coord[j], 1.0 / tmp[j], at_coord[j] );
2398 : : }
2399 : :
2400 : 0 : s = fabs( at_coord[1][0] * at_coord[2][1] - at_coord[1][1] * at_coord[2][0] ); /* 1-2 sine */
2401 : 0 : c = at_coord[1][0] * at_coord[2][0] + at_coord[1][1] * at_coord[2][1]; /* 1-2 cosine */
2402 [ # # # # ]: 0 : if (s < MIN_SINE && c > 0.5)
2403 : : {
2404 : 0 : goto exit_function; /* bonds to neigh. 1 and 2 have almost same direction; relative angles are undefined */
2405 : : }
2406 : 0 : c = at_coord[0][0]; /* cosine of the angle between new Ox axis and a bond to the neighbor 0. Should be 1 */
2407 : 0 : s = at_coord[0][1]; /* sine. Should be 0 */
2408 : : /* turn vectors so that vector #1 (at_coord[0]) becomes {1, 0} */
2409 [ # # ]: 0 : for (j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j++)
2410 : : {
2411 : 0 : tmp1 = c*at_coord[j][0] + s*at_coord[j][1];
2412 : 0 : tmp2 = -s*at_coord[j][0] + c*at_coord[j][1];
2413 : 0 : at_coord[j][0] = tmp1;
2414 : 0 : at_coord[j][1] = tmp2;
2415 : : }
2416 : : /* counterclockwise angles from the direction to neigh 0 to to directions to neighbors 1 and 2: */
2417 : 0 : tmp1 = atan2( at_coord[1][1], at_coord[1][0] ); /* range -pi and +pi */
2418 : 0 : tmp2 = atan2( at_coord[2][1], at_coord[2][0] );
2419 [ # # ]: 0 : if (tmp1 < 0.0)
2420 : : {
2421 : 0 : tmp1 += two_pi; /* range 0 to 2*pi */
2422 : : }
2423 [ # # ]: 0 : if (tmp2 < 0.0)
2424 : : {
2425 : 0 : tmp2 += two_pi;
2426 : : }
2427 : : /*-----------------------------------
2428 : : Example
2429 : : 1 \ case tmp1 < tmp2
2430 : : \ parity is odd
2431 : : \ (counterclockwise)
2432 : : A------- 0
2433 : : /
2434 : : /
2435 : : 2 /
2436 : :
2437 : : ------------------------------------*/
2438 [ # # ]: 0 : bond_parity = 2 - ( tmp1 < tmp2 );
2439 [ # # ]: 0 : for (j = 0; j < 3; j++)
2440 : : {
2441 [ # # ]: 0 : if (z_dir)
2442 [ # # ]: 0 : z_dir[j] = (S_CHAR) ( pnt[p2][j] >= 0.0 ? floor( 0.5 + 100.0 * pnt[p2][j] ) :
2443 : 0 : -floor( 0.5 - 100.0 * pnt[p2][j] ) ); /* abs(z_dir) = 100 */
2444 : : }
2445 : : /* check for ambiguity */
2446 [ # # ]: 0 : if (nNumExplictAttachments > 2)
2447 : : {
2448 [ # # ]: 0 : min_tmp = inchi_min( tmp1, tmp2 );
2449 [ # # ]: 0 : max_tmp = inchi_max( tmp1, tmp2 );
2450 [ # # # # : 0 : if (min_tmp > one_pi - MIN_SINE || max_tmp < one_pi + MIN_SINE || max_tmp - min_tmp > one_pi - MIN_SINE)
# # ]
2451 : : {
2452 : 0 : at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
2453 : : }
2454 : : else /* 3D ambiguity 8-28-2002 */
2455 : : {
2456 [ # # ]: 0 : if (fabs( at_coord[0][2] ) > MAX_SINE)
2457 : : { /* all fabs(at_coord[j][2] (j=0..2) must be equal */
2458 : 0 : at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
2459 : : }
2460 : : }
2461 : : }
2462 : : else
2463 : : {
2464 [ # # ]: 0 : if (nNumExplictAttachments == 2)
2465 : : { /* 10-6-2003: added */
2466 : 0 : min_tmp = fabs( tmp1 - one_pi );
2467 [ # # ]: 0 : if (min_tmp < MIN_SINE)
2468 : : {
2469 : 0 : bond_parity = AB_PARITY_UNDF; /* consider as undefined 10-6-2003 */
2470 : : }
2471 : : else
2472 : : {
2473 [ # # ]: 0 : if (min_tmp < MIN_ANGLE_DBOND)
2474 : : {
2475 : 0 : at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
2476 : : }
2477 : : }
2478 : : }
2479 : : }
2480 : :
2481 : : /* for 3 neighbors moving implicit H to the index=0 from index=2 position */
2482 : : /* can be done in 2 transpositions and does not change atom's parity */
2483 : :
2484 : 0 : exit_function:
2485 : :
2486 [ # # # # : 0 : if (num_H > 1 && bond_parity > 0 && !( bond_parity & AB_PARITY_0D ) /*&& PARITY_WELL_DEF(bond_parity)*/)
# # ]
2487 : : {
2488 : : /*
2489 : : * stereo only if isotopes are counted. Do not inverse
2490 : : * Examples: sign for this:
2491 : : * H D
2492 : : * / / H
2493 : : * ==C or ==CH /
2494 : : * \ ==N (bValence3=1)
2495 : : * D
2496 : : * two explicit one explicit H isotope (D),
2497 : : * isotopic H atoms one implicit H
2498 : : */
2499 : 0 : bond_parity = -bond_parity; /* refers to isotopically substituted structure only */
2500 : : }
2501 : :
2502 : 0 : return bond_parity;
2503 : : }
2504 : :
2505 : :
2506 : : /****************************************************************************/
2507 : 0 : int save_a_stereo_bond( int z_prod,
2508 : : int result_action,
2509 : : int at1,
2510 : : int ord1,
2511 : : AT_NUMB *stereo_bond_neighbor1,
2512 : : S_CHAR *stereo_bond_ord1,
2513 : : S_CHAR *stereo_bond_z_prod1,
2514 : : S_CHAR *stereo_bond_parity1,
2515 : : int at2,
2516 : : int ord2,
2517 : : AT_NUMB *stereo_bond_neighbor2,
2518 : : S_CHAR *stereo_bond_ord2,
2519 : : S_CHAR *stereo_bond_z_prod2,
2520 : : S_CHAR *stereo_bond_parity2 )
2521 : : {
2522 : : int i1, i2;
2523 : :
2524 [ # # # # ]: 0 : for (i1 = 0; i1 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor1[i1]; i1++)
2525 : : {
2526 : : ;
2527 : : }
2528 [ # # # # ]: 0 : for (i2 = 0; i2 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor2[i2]; i2++)
2529 : : {
2530 : : ;
2531 : : }
2532 : :
2533 [ # # # # ]: 0 : if (i1 == MAX_NUM_STEREO_BONDS || i2 == MAX_NUM_STEREO_BONDS)
2534 : : {
2535 : 0 : return 0;
2536 : : }
2537 : :
2538 : 0 : stereo_bond_parity1[i1] =
2539 : 0 : stereo_bond_parity2[i2] = result_action;
2540 : :
2541 : 0 : stereo_bond_neighbor1[i1] = (AT_NUMB) ( at2 + 1 );
2542 : 0 : stereo_bond_ord1[i1] = (S_CHAR) ord1;
2543 : 0 : stereo_bond_neighbor2[i2] = (AT_NUMB) ( at1 + 1 );
2544 : 0 : stereo_bond_ord2[i2] = (S_CHAR) ord2;
2545 : 0 : stereo_bond_z_prod1[i1] =
2546 : 0 : stereo_bond_z_prod2[i2] = (S_CHAR) z_prod;
2547 : :
2548 : 0 : return 1;
2549 : : }
2550 : :
2551 : :
2552 : : /****************************************************************************/
2553 : 566 : int get_allowed_stereo_bond_type( int bond_type )
2554 : : {
2555 : : #if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 0 )
2556 : : if (( bond_type & ~BOND_MARK_ALL ) == BOND_TAUTOM)
2557 : : {
2558 : : return 0; /* no tautomer bonds allowed */
2559 : : }
2560 : : else
2561 : : #endif
2562 : : #if ( EXCL_ALL_AROM_BOND_PARITY == 1 ) /* { */
2563 : : /* a stereo bond cannot belong to an aromatic atom */
2564 : : if (( bond_type &= ~BOND_MARK_ALL ) == BOND_ALTERN)
2565 : : {
2566 : : return 0;
2567 : : }
2568 : : #else /* } { */
2569 : : #if ( ADD_6MEMB_AROM_BOND_PARITY == 1 )
2570 : : /* accept any aromatic bond as a stereo bond */
2571 [ + + ]: 566 : if (( bond_type &= ~BOND_MARK_ALL ) == BOND_ALTERN)
2572 : : #else
2573 : : /* accept only aromatic bonds in non-6-member rings */
2574 : : if (( bond_type &= ~BOND_MARK_ALL ) == BOND_ALTERN) )
2575 : : #endif
2576 : : {
2577 : 288 : return BOND_ALTERN;
2578 : : }
2579 : : #endif /* } */
2580 : : else
2581 : : {
2582 : : /* at this point BOND_MARK_ALL bits have been removed from bond_type */
2583 [ + + + + ]: 278 : if (bond_type == BOND_DOUBLE || bond_type == BOND_SINGLE)
2584 : : {
2585 : 238 : return bond_type;
2586 : : }
2587 : : #if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 1 )
2588 : : else
2589 : : {
2590 [ + - ]: 40 : if (bond_type == BOND_TAUTOM)
2591 : : {
2592 : 40 : return BOND_TAUTOM;
2593 : : }
2594 : : }
2595 : : #endif
2596 : : }
2597 : :
2598 : 0 : return 0; /* wrong bond type */
2599 : : }
2600 : :
2601 : :
2602 : : /****************************************************************************/
2603 : 404 : int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at,
2604 : : int cur_at,
2605 : : INCHI_MODE nMode )
2606 : : {
2607 : : int i, j, next_at, num_stereo_bonds, bFound;
2608 : : int bond_type, num_2s, num_alt;
2609 : : int num_2s_next, num_alt_next, num_wrong_bonds_1, num_wrong_bonds_2;
2610 : : #if ( N_V_STEREOBONDS == 1 )
2611 : : int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
2612 : : #endif
2613 : :
2614 [ + + ]: 404 : if (MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence + at[cur_at].num_H ||
2615 [ + + ]: 392 : MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence + at[cur_at].num_H)
2616 : : {
2617 : 215 : return 0;
2618 : : }
2619 [ + + ]: 189 : if (!bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ))
2620 : : {
2621 : 111 : return 0;
2622 : : }
2623 : :
2624 : : /* Count bonds and find the second atom on the stereo bond */
2625 : 78 : num_2s = num_alt = num_wrong_bonds_1 = 0;
2626 : : #if ( N_V_STEREOBONDS == 1 )
2627 : 78 : num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
2628 [ + + + - : 114 : if (0 == at[cur_at].num_H && 0 == at[cur_at].charge && 0 == at[cur_at].radical &&
+ - - + ]
2629 : 36 : 3 == get_endpoint_valence( at[cur_at].el_number ))
2630 : : {
2631 [ # # # # ]: 0 : if (2 == at[cur_at].valence && 3 == at[cur_at].chem_bonds_valence)
2632 : : {
2633 : 0 : type_N = 1;
2634 : : }
2635 : : else
2636 : : {
2637 [ # # # # ]: 0 : if (3 == at[cur_at].valence && 5 == at[cur_at].chem_bonds_valence)
2638 : : {
2639 : 0 : type_N = 2; /* unfortunately includes >N# */
2640 : : }
2641 : : }
2642 : : }
2643 : : #endif
2644 [ + + ]: 251 : for (i = 0, num_stereo_bonds = 0; i < at[cur_at].valence; i++)
2645 : : {
2646 : 173 : bFound = 0;
2647 : 173 : next_at = at[cur_at].neighbor[i];
2648 : 173 : bond_type = get_allowed_stereo_bond_type( (int) at[cur_at].bond_type[i] );
2649 [ + + ]: 173 : if (bond_type == BOND_ALTERN)
2650 : : {
2651 : 72 : num_alt++;
2652 [ + + + - ]: 72 : if (cur_at > next_at && !( nMode & CMODE_NO_ALT_SBONDS ))
2653 : : {
2654 : 36 : bFound = 1;
2655 : : }
2656 : : }
2657 : : else
2658 : : {
2659 [ + + ]: 101 : if (bond_type == BOND_DOUBLE)
2660 : : {
2661 : 14 : num_2s++;
2662 : : #if ( N_V_STEREOBONDS == 1 )
2663 [ - + ]: 14 : if (0 <= ( n2sh = bIsSuitableHeteroInpAtom( at + next_at ) ))
2664 : : {
2665 : 0 : num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
2666 : : }
2667 : : #endif
2668 [ + + ]: 14 : if (cur_at > next_at)
2669 : 8 : bFound = 1;
2670 : : }
2671 : : else
2672 : : {
2673 [ + + - + ]: 87 : if (bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM)
2674 : : {
2675 : 0 : num_wrong_bonds_1++;
2676 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
2677 [ # # # # : 0 : if (num_wrong_bonds_1 > 1 || (num_wrong_bonds_1 && 2 >= at[cur_at].valence)) /* djb-rwth: addressing LLVM warning */
# # ]
2678 : : {
2679 : 0 : return 0; /* wrong bond type */
2680 : : }
2681 : : else
2682 : : {
2683 : 0 : continue;
2684 : : }
2685 : : #else
2686 : : return 0; /* wrong bond type */
2687 : : #endif
2688 : : }
2689 : : }
2690 : : }
2691 : :
2692 [ + + ]: 173 : if (bFound)
2693 : : {
2694 : : /* check "next_at" atom on the opposite side of the bond */
2695 [ + - ]: 44 : if (MAX_NUM_STEREO_BOND_NEIGH < at[next_at].valence + at[next_at].num_H ||
2696 [ - + ]: 44 : MIN_NUM_STEREO_BOND_NEIGH > at[next_at].valence + at[next_at].num_H)
2697 : : {
2698 : 0 : continue;
2699 : : }
2700 [ + + ]: 44 : if (!bCanAtomHaveAStereoBond( at[next_at].elname, at[next_at].charge, at[next_at].radical ))
2701 : : {
2702 : 2 : continue;
2703 : : }
2704 : : /* next atom neighbors */
2705 : 42 : num_2s_next = num_alt_next = num_wrong_bonds_2 = 0;
2706 : : #if ( N_V_STEREOBONDS == 1 )
2707 : 42 : num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
2708 [ + + + - : 66 : if (0 == at[next_at].num_H && 0 == at[next_at].charge && 0 == at[next_at].radical &&
+ - - + ]
2709 : 24 : 3 == get_endpoint_valence( at[next_at].el_number ))
2710 : : {
2711 [ # # # # ]: 0 : if (2 == at[next_at].valence && 3 == at[next_at].chem_bonds_valence)
2712 : : {
2713 : 0 : type_N_next = 1; /* -N= */
2714 : : }
2715 : : else
2716 : : {
2717 [ # # # # ]: 0 : if (3 == at[next_at].valence && 5 == at[next_at].chem_bonds_valence)
2718 : : {
2719 : 0 : type_N_next = 2; /* unfortunately includes >N# */
2720 : : }
2721 : : }
2722 : : }
2723 : : #endif
2724 [ + + ]: 150 : for (j = 0; j < at[next_at].valence; j++)
2725 : : {
2726 : 108 : bond_type = get_allowed_stereo_bond_type( (int) at[next_at].bond_type[j] );
2727 [ + + ]: 108 : if (bond_type == BOND_ALTERN)
2728 : : {
2729 : 72 : num_alt_next++;
2730 : : }
2731 : : else
2732 : : {
2733 [ + + ]: 36 : if (bond_type == BOND_DOUBLE)
2734 : : {
2735 : 6 : num_2s_next++;
2736 : : #if ( N_V_STEREOBONDS == 1 )
2737 : 6 : next_next_at = at[next_at].neighbor[j];
2738 [ - + ]: 6 : if (0 <= ( n2sh = bIsSuitableHeteroInpAtom( at + next_next_at ) ))
2739 : : {
2740 : 0 : num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
2741 : : }
2742 : : #endif
2743 : : }
2744 : : else
2745 : : {
2746 [ - + - - ]: 30 : if (bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM)
2747 : : {
2748 : 0 : num_wrong_bonds_2++;
2749 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
2750 [ # # # # : 0 : if (num_wrong_bonds_1 > 1 || (num_wrong_bonds_1 && 2 >= at[cur_at].valence)) /* djb-rwth: addressing LLVM warning */
# # ]
2751 : : {
2752 : : break; /* wrong bond type */
2753 : : }
2754 : : else
2755 : : {
2756 : 0 : continue;
2757 : : }
2758 : : #else
2759 : : break; /* wrong bond type */
2760 : : #endif
2761 : : }
2762 : : }
2763 : : }
2764 : : }
2765 : : /* figure out whether the at[cur_at]--at[next_at] bond may not be stereogenic */
2766 : :
2767 : : #if ( N_V_STEREOBONDS == 1 )
2768 [ - + - - ]: 42 : if (3 == ( type_N | type_N_next ) &&
2769 [ # # # # ]: 0 : ( (2 == type_N && !bIsOxide( at, cur_at )) ||
2770 [ # # ]: 0 : (2 == type_N_next && !bIsOxide( at, next_at )) )) /* djb-rwth: addressing LLVM warnings */
2771 : : {
2772 : 0 : bFound = 0;
2773 : : }
2774 : : else
2775 : : #endif
2776 : : {
2777 [ + - ]: 42 : if (j < at[next_at].valence || /* at[next_at] has a wrong bond type*/
2778 [ - + ]: 42 : ( num_alt_next > 0 ) + ( num_2s_next > 0 ) != 1 /* only one type of stereogenic bond permitted */
2779 : : )
2780 : : {
2781 : 0 : bFound = 0;
2782 : : }
2783 : : else
2784 : : {
2785 [ - + ]: 42 : if (2 < num_2s_next)
2786 : : {
2787 : 0 : bFound = 0;
2788 : : }
2789 : : else
2790 : : {
2791 [ - + ]: 42 : if (2 == num_2s_next)
2792 : : {
2793 [ # # ]: 0 : if (2 == at[next_at].valence)
2794 : : {
2795 : : ; /* only one double bond permitted except cumulenes */
2796 : : #if ( N_V_STEREOBONDS == 1 )
2797 : : }
2798 : : else
2799 : : {
2800 [ # # ]: 0 : if (1 == ( num_2s_hetero_next[0] | num_2s_hetero_next[1] ) &&
2801 [ # # ]: 0 : 3 == at[next_at].valence + at[next_at].num_H &&
2802 [ # # # # ]: 0 : 5 == at[next_at].chem_bonds_valence + at[next_at].num_H &&
2803 [ # # ]: 0 : 3 == get_endpoint_valence( at[next_at].el_number ) &&
2804 [ # # ]: 0 : ( !type_N || bIsOxide( at, next_at ) ))
2805 : : {
2806 : : ; /*
2807 : : * found:
2808 : : *
2809 : : * \ / \ / \ /
2810 : : * \ / \ / \ /
2811 : : * N==C or N==C or N==N
2812 : : * // \ // \ // \
2813 : : * O ^ \ N ^ \ O ^ \
2814 : : * | | |
2815 : : * | | |
2816 : : * at[next_at] at[next_at] at[next_at]
2817 : : */
2818 : : #endif
2819 : : }
2820 : : else
2821 : : {
2822 : 0 : bFound = 0;
2823 : : }
2824 : : }
2825 : : }
2826 : : }
2827 : : }
2828 : : }
2829 : : }
2830 [ + + ]: 171 : if (bFound)
2831 : : {
2832 : 42 : num_stereo_bonds++;
2833 : : }
2834 : : }
2835 : :
2836 [ + + + + ]: 78 : if (( num_alt > 0 ) + ( num_2s > 0 ) != 1 || !num_stereo_bonds)
2837 : : {
2838 : 42 : return 0;
2839 : : }
2840 : :
2841 [ - + ]: 36 : if (num_2s > 1)
2842 : : {
2843 : : #if ( N_V_STEREOBONDS == 1 )
2844 [ # # ]: 0 : if (2 == num_2s &&
2845 [ # # ]: 0 : 1 == ( num_2s_hetero[0] | num_2s_hetero[1] ) &&
2846 [ # # ]: 0 : 3 == at[cur_at].valence + at[cur_at].num_H &&
2847 [ # # # # ]: 0 : 5 == at[cur_at].chem_bonds_valence + at[cur_at].num_H &&
2848 : 0 : 3 == get_endpoint_valence( at[cur_at].el_number ))
2849 : : {
2850 : : ;
2851 : : }
2852 : : else
2853 : : {
2854 : 0 : return 0;
2855 : : }
2856 : : #else
2857 : : return 0;
2858 : : #endif
2859 : : }
2860 : :
2861 : 36 : return num_stereo_bonds;
2862 : : }
2863 : :
2864 : :
2865 : : /****************************************************************************/
2866 : 0 : int half_stereo_bond_action( int nParity,
2867 : : int bUnknown,
2868 : : int bIsotopic,
2869 : : int vABParityUnknown )
2870 : : {
2871 : : #define AB_NEGATIVE 0x10
2872 : : #define AB_UNKNOWN 0x20
2873 : : int nAction;
2874 : :
2875 [ # # ]: 0 : if (nParity == AB_PARITY_NONE)
2876 : : {
2877 : 0 : return AB_PARITY_NONE;
2878 : : }
2879 : :
2880 : : /* Unknown (type 1) in the parity value may come from the 'Either' single bond only */
2881 : : /* Treat it as a known single bond geometry and unknown (Either) double bond */
2882 [ # # ]: 0 : if (nParity == vABParityUnknown /*AB_PARITY_UNKN*/)
2883 : : {
2884 : 0 : nParity = AB_PARITY_ODD | AB_UNKNOWN;
2885 : : }
2886 [ # # ]: 0 : if (nParity == -vABParityUnknown /*AB_PARITY_UNKN*/)
2887 : : {
2888 : 0 : nParity = AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE;
2889 : : }
2890 : :
2891 : : /* make positive, replace AB_PARITY_EVEN with AB_PARITY_ODD */
2892 [ # # ]: 0 : if (nParity < 0)
2893 : : {
2894 [ # # ]: 0 : nParity = ( ( nParity == -AB_PARITY_EVEN ) ? AB_PARITY_ODD : ( -nParity ) ) | AB_NEGATIVE;
2895 : : }
2896 : : else
2897 : : {
2898 [ # # ]: 0 : if (nParity == AB_PARITY_EVEN)
2899 : : {
2900 : 0 : nParity = AB_PARITY_ODD;
2901 : : }
2902 : : }
2903 : :
2904 : : /* Unknown (type 2): was detected in the double bond attribute */
2905 : : /* (this 'unknown' came from 'Either' double bond) */
2906 : : /* Treat both unknowns in the same way */
2907 [ # # ]: 0 : if (bUnknown)
2908 : : {
2909 : 0 : nParity |= AB_UNKNOWN;
2910 : : }
2911 : :
2912 [ # # ]: 0 : if (bIsotopic)
2913 : : {
2914 [ # # # # : 0 : switch (nParity)
# ]
2915 : : {
2916 : 0 : case AB_PARITY_ODD:
2917 : : case AB_PARITY_ODD | AB_NEGATIVE:
2918 : 0 : nAction = AB_PARITY_CALC;
2919 : 0 : break;
2920 : 0 : case AB_PARITY_ODD | AB_UNKNOWN:
2921 : : case AB_PARITY_UNDF | AB_UNKNOWN:
2922 : : case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
2923 : : case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
2924 : 0 : nAction = vABParityUnknown /*AB_PARITY_UNKN*/;
2925 : 0 : break;
2926 : 0 : case AB_PARITY_IISO:
2927 : : case AB_PARITY_IISO | AB_UNKNOWN:
2928 : 0 : nAction = AB_PARITY_NONE;
2929 : 0 : break;
2930 : 0 : case AB_PARITY_UNDF:
2931 : : case AB_PARITY_UNDF | AB_NEGATIVE:
2932 : 0 : nAction = AB_PARITY_UNDF;
2933 : 0 : break;
2934 : 0 : default:
2935 : 0 : nAction = -1; /* program error */
2936 : : }
2937 : : }
2938 : : else
2939 : : {
2940 : : /* Non-isotopic */
2941 [ # # # # : 0 : switch (nParity)
# ]
2942 : : {
2943 : 0 : case AB_PARITY_ODD:
2944 : 0 : nAction = AB_PARITY_CALC;
2945 : 0 : break;
2946 : 0 : case AB_PARITY_ODD | AB_UNKNOWN:
2947 : : case AB_PARITY_UNDF | AB_UNKNOWN:
2948 : 0 : nAction = vABParityUnknown /*AB_PARITY_UNKN*/;
2949 : 0 : break;
2950 : : /* case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE: */
2951 : 0 : case AB_PARITY_UNDF:
2952 : 0 : nAction = AB_PARITY_UNDF;
2953 : 0 : break;
2954 : 0 : case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
2955 : : case AB_PARITY_ODD | AB_NEGATIVE:
2956 : : case AB_PARITY_IISO:
2957 : : case AB_PARITY_IISO | AB_UNKNOWN:
2958 : : case AB_PARITY_UNDF | AB_NEGATIVE:
2959 : : case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
2960 : 0 : nAction = AB_PARITY_NONE;
2961 : 0 : break;
2962 : 0 : default:
2963 : 0 : nAction = -1; /* program error */
2964 : : }
2965 : : }
2966 : :
2967 : 0 : return nAction;
2968 : : #undef AB_NEGATIVE
2969 : : #undef AB_UNKNOWN
2970 : : }
2971 : :
2972 : :
2973 : : /****************************************************************************/
2974 : 609 : int set_stereo_bonds_parity( sp_ATOM *out_at,
2975 : : inp_ATOM *at,
2976 : : int at_1,
2977 : : inp_ATOM *at_removed_H,
2978 : : int num_removed_H,
2979 : : INCHI_MODE nMode, QUEUE *q,
2980 : : AT_RANK *nAtomLevel,
2981 : : S_CHAR *cSource,
2982 : : AT_RANK min_sb_ring_size,
2983 : : int bPointedEdgeStereo,
2984 : : int vABParityUnknown )
2985 : : {
2986 : : int j, k, i_next_at_1, i_next_at_2, at_2, next_at_2, num_stereo_bonds, bFound, bAllene; /* djb-rwth: removing redundant variables */
2987 : : int bond_type, num_2s_1, num_alt_1;
2988 : : int num_2s_2, num_alt_2;
2989 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
2990 : : int num_wrong_bonds_1, num_wrong_bonds_2;
2991 : : #endif
2992 : : #if ( N_V_STEREOBONDS == 1 )
2993 : : int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
2994 : : #endif
2995 : : int num_stored_isotopic_stereo_bonds; /* djb-rwth: removing redundant variables/code */
2996 : : int chain_length, num_chains, cur_chain_length;
2997 : : int all_at_2[MAX_NUM_STEREO_BONDS];
2998 : : int all_pos_1[MAX_NUM_STEREO_BONDS], all_pos_2[MAX_NUM_STEREO_BONDS];
2999 : : S_CHAR all_unkn[MAX_NUM_STEREO_BONDS];
3000 : 609 : int /*at_1_parity, at_2_parity,*/ nUnknown, stop = 0;
3001 : :
3002 : : /* at_1_parity = AB_PARITY_NONE; */ /* do not know */
3003 : :
3004 : : /* Check valence */
3005 [ + + ]: 609 : if (MAX_NUM_STEREO_BOND_NEIGH < at[at_1].valence + at[at_1].num_H ||
3006 [ + + ]: 394 : MIN_NUM_STEREO_BOND_NEIGH > at[at_1].valence + at[at_1].num_H)
3007 : : {
3008 : 418 : return 0;
3009 : : }
3010 [ + + ]: 191 : if (!bCanAtomHaveAStereoBond( at[at_1].elname, at[at_1].charge, at[at_1].radical ))
3011 : : {
3012 : 113 : return 0;
3013 : : }
3014 [ - + ]: 78 : if (at[at_1].c_point)
3015 : : {
3016 : 0 : return 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
3017 : : }
3018 : :
3019 : : /* middle cumulene atoms, for example, =C=, should be ignored here */
3020 : : /* only atoms at the ends of cumulene chains are considered. */
3021 [ + + - + : 78 : if (!at[at_1].num_H && 2 == at[at_1].valence &&
- - ]
3022 [ # # ]: 0 : BOND_DOUBLE == get_allowed_stereo_bond_type( (int) at[at_1].bond_type[0] ) &&
3023 : 0 : BOND_DOUBLE == get_allowed_stereo_bond_type( (int) at[at_1].bond_type[1] ))
3024 : : {
3025 : 0 : return 0;
3026 : : }
3027 : :
3028 : : /* count bonds and find the second atom on the stereo bond */
3029 : 78 : num_2s_1 = num_alt_1 = 0;
3030 : 78 : chain_length = 0;
3031 : 78 : num_chains = 0;
3032 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3033 : 78 : num_wrong_bonds_1 = 0;
3034 : : #endif
3035 : : #if ( N_V_STEREOBONDS == 1 )
3036 : 78 : num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
3037 [ + + + - : 114 : if (0 == at[at_1].num_H && 0 == at[at_1].charge && 0 == at[at_1].radical &&
+ - - + ]
3038 : 36 : 3 == get_endpoint_valence( at[at_1].el_number ))
3039 : : {
3040 [ # # # # ]: 0 : if (2 == at[at_1].valence && 3 == at[at_1].chem_bonds_valence)
3041 : : {
3042 : 0 : type_N = 1;
3043 : : }
3044 : : else
3045 : : {
3046 [ # # # # ]: 0 : if (3 == at[at_1].valence && 5 == at[at_1].chem_bonds_valence)
3047 : : {
3048 : 0 : type_N = 2; /* unfortunately includes >N# */
3049 : : }
3050 : : }
3051 : : }
3052 : : #endif
3053 [ + + ]: 251 : for (i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].valence; i_next_at_1++)
3054 : : {
3055 : 173 : nUnknown = ( at[at_1].bond_stereo[i_next_at_1] == STEREO_DBLE_EITHER );
3056 : 173 : bond_type = get_allowed_stereo_bond_type( (int) at[at_1].bond_type[i_next_at_1] );
3057 : 173 : at_2 = -1; /* not found */
3058 [ + + + + ]: 173 : if (bond_type == BOND_ALTERN ||
3059 : : bond_type == BOND_DOUBLE)
3060 : : {
3061 : 86 : at_2 = at[at_1].neighbor[i_next_at_1]; /* djb-rwth: removing redundant code */
3062 : 86 : next_at_2 = at_1;
3063 : : }
3064 [ + + + - ]: 173 : switch (bond_type)
3065 : : {
3066 : 72 : case BOND_ALTERN:
3067 : 72 : num_alt_1++;
3068 : : #if ( FIND_RING_SYSTEMS == 1 )
3069 [ - + ]: 72 : if (at[at_1].nRingSystem != at[at_2].nRingSystem)
3070 : : {
3071 : 0 : continue; /* reject alt. bond connecting different ring systems */
3072 : : }
3073 : : #endif
3074 [ + - - + ]: 144 : if (( nMode & CMODE_NO_ALT_SBONDS ) ||
3075 : 72 : !bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ))
3076 : : {
3077 : 0 : continue; /* reject non-stereogenic bond to neighbor ord. #i_next_at_1 */
3078 : : }
3079 : 72 : break;
3080 : 14 : case BOND_DOUBLE:
3081 : : /* check for cumulene/allene */
3082 : 14 : num_2s_1++;
3083 : 14 : cur_chain_length = 0;
3084 [ + - ]: 14 : if (bCanAtomBeTerminalAllene( at[at_1].elname, at[at_1].charge, at[at_1].radical ))
3085 : : {
3086 : : /*
3087 : : * Example of cumulene
3088 : : * chain length = 2: >X=C=C=Y<
3089 : : * | | | |
3090 : : * 1st cumulene atom= at_1 | | at_2 =last cumlene chain atom
3091 : : * next to at_1= next_at_1 next_at_2 =previous to at_2
3092 : : *
3093 : : * chain length odd: stereocenter on the middle atom ( 1=> allene )
3094 : : * chain length even: "long stereogenic bond"
3095 : : */
3096 : 14 : while (( bAllene =
3097 [ + + + - ]: 8 : !at[at_2].num_H && at[at_2].valence == 2 &&
3098 [ + + - + ]: 22 : BOND_DOUBLE == get_allowed_stereo_bond_type( (int) at[at_2].bond_type[0] ) &&
3099 [ - + - - ]: 16 : BOND_DOUBLE == get_allowed_stereo_bond_type( (int) at[at_2].bond_type[1] ) ) &&
3100 : 0 : bCanAtomBeMiddleAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ))
3101 : : {
3102 : 0 : k = ( (int) at[at_2].neighbor[0] == next_at_2 ); /* opposite neighbor position */
3103 : 0 : next_at_2 = at_2;
3104 : 0 : nUnknown += ( at[at_2].bond_stereo[k] == STEREO_DBLE_EITHER );
3105 : 0 : at_2 = (int) at[at_2].neighbor[k];
3106 : 0 : cur_chain_length++; /* count =C= atoms */
3107 : : }
3108 [ - + ]: 14 : if (cur_chain_length)
3109 : : {
3110 : 0 : num_chains++;
3111 [ # # # # ]: 0 : if (bAllene /* at the end of the chain atom Y is =Y=, not =Y< or =Y- */ ||
3112 : 0 : !bCanAtomBeTerminalAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ))
3113 : : {
3114 : 0 : cur_chain_length = 0; /* djb-rwth: ignoring LLVM warning: value used */
3115 : 0 : continue; /* ignore: does not fit cumulene description; go to check next at_1 neighbor */
3116 : : }
3117 : 0 : chain_length = cur_chain_length; /* accept a stereogenic cumulele */
3118 : : }
3119 : : }
3120 : : #if ( N_V_STEREOBONDS == 1 )
3121 [ + - - + ]: 28 : if (!cur_chain_length &&
3122 : 14 : 0 <= ( n2sh = bIsSuitableHeteroInpAtom( at + at_2 ) ))
3123 : : {
3124 : 0 : num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
3125 : : }
3126 : : #endif
3127 [ + - + + ]: 28 : if (!cur_chain_length &&
3128 : 14 : !bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ))
3129 : : {
3130 : 2 : continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
3131 : : }
3132 : :
3133 : 12 : break;
3134 : :
3135 : 87 : case BOND_SINGLE:
3136 : : case BOND_TAUTOM:
3137 : 87 : continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
3138 : 0 : default:
3139 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3140 : 0 : num_wrong_bonds_1++;
3141 : 0 : continue;
3142 : : #else
3143 : : return 0; /* wrong bond type; */
3144 : : #endif
3145 : : }
3146 : :
3147 : : /* Check atom at the opposite end of possibly stereogenic bond */
3148 : :
3149 [ + - + + ]: 84 : bFound = ( at_2 >= 0 && at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
3150 : :
3151 [ + + ]: 84 : if (bFound)
3152 : : {
3153 : : /* Check "at_2" atom on the opposite side of the bond or cumulene chain */
3154 [ + - ]: 42 : if (MAX_NUM_STEREO_BOND_NEIGH < at[at_2].valence + at[at_2].num_H ||
3155 [ - + ]: 42 : MIN_NUM_STEREO_BOND_NEIGH > at[at_2].valence + at[at_2].num_H)
3156 : 0 : continue;
3157 : :
3158 : : /* Check at_2 neighbors and bonds */
3159 : 42 : num_2s_2 = num_alt_2 = 0;
3160 : : #if ( N_V_STEREOBONDS == 1 )
3161 : 42 : num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
3162 [ + + + - : 66 : if (0 == at[at_2].num_H && 0 == at[at_2].charge && 0 == at[at_2].radical &&
+ - - + ]
3163 : 24 : 3 == get_endpoint_valence( at[at_2].el_number ))
3164 : : {
3165 [ # # # # ]: 0 : if (2 == at[at_2].valence && 3 == at[at_2].chem_bonds_valence)
3166 : : {
3167 : 0 : type_N_next = 1; /* -N= */
3168 : : }
3169 : : else
3170 : : {
3171 [ # # # # ]: 0 : if (3 == at[at_2].valence && 5 == at[at_2].chem_bonds_valence)
3172 : : {
3173 : 0 : type_N_next = 2; /* unfortunately includes >N# */
3174 : : }
3175 : : }
3176 : : }
3177 : : #endif
3178 : 42 : i_next_at_2 = -1; /* unassigned mark */
3179 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3180 : 42 : num_wrong_bonds_2 = 0;
3181 : : #endif
3182 [ + + ]: 150 : for (j = 0; j < at[at_2].valence; j++)
3183 : : {
3184 : 108 : bond_type = get_allowed_stereo_bond_type( (int) at[at_2].bond_type[j] );
3185 [ - + ]: 108 : if (!bond_type)
3186 : : {
3187 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3188 : 0 : num_wrong_bonds_2++;
3189 : 0 : continue; /* this bond type is not allowed to be adjacent to a stereo bond */
3190 : : #else
3191 : : break;
3192 : : #endif
3193 : : }
3194 [ + + ]: 108 : if (bond_type == BOND_DOUBLE)
3195 : : {
3196 : 6 : num_2s_2++;
3197 : : #if ( N_V_STEREOBONDS == 1 )
3198 : 6 : next_next_at = at[at_2].neighbor[j];
3199 [ - + ]: 6 : if (0 <= ( n2sh = bIsSuitableHeteroInpAtom( at + next_next_at ) ))
3200 : : {
3201 : 0 : num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
3202 : : }
3203 : : #endif
3204 : : }
3205 : : else
3206 : : {
3207 : 102 : num_alt_2 += ( bond_type == BOND_ALTERN );
3208 : : }
3209 [ + + ]: 108 : if ((int) at[at_2].neighbor[j] == next_at_2)
3210 : : {
3211 : 42 : i_next_at_2 = j; /* assigned */
3212 : : }
3213 : : }
3214 [ + - ]: 42 : if (
3215 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3216 [ - + - - ]: 42 : num_wrong_bonds_2 > 1 || (num_wrong_bonds_2 && 2 >= at[at_2].valence) || /* djb-rwth: addressing LLVM warning */
3217 : : #else
3218 : : j < at[at_2].valence /* "next" has a wrong bond type*/ ||
3219 : : #endif
3220 [ + - - + ]: 42 : ( num_alt_2 > 0 ) + ( num_2s_2 > 0 ) != 1 || /* all double XOR all alt bonds only */
3221 : : /* num_2s_2 > 1 ||*/ /* only one double bond permitted */
3222 : : i_next_at_2 < 0 /* atom next to the opposite atom not found */)
3223 : : {
3224 : 0 : bFound = 0;
3225 : : }
3226 : : else
3227 [ - + ]: 42 : if (at[at_2].c_point)
3228 : : {
3229 : 0 : bFound = 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
3230 : : }
3231 : : else
3232 [ - + ]: 42 : if (num_2s_2 > 2)
3233 : : {
3234 : 0 : bFound = 0;
3235 : : }
3236 : : else
3237 : : #if ( N_V_STEREOBONDS == 1 )
3238 [ - + - - : 42 : if ( 3==( type_N | type_N_next ) && ( (2==type_N && !bIsOxide( at, at_1 )) ||
- - - - ]
3239 [ # # ]: 0 : (2==type_N_next && !bIsOxide( at, at_2 )) )) /* djb-rwth: addressing LLVM warnings */
3240 : : {
3241 : 0 : bFound = 0;
3242 : : }
3243 : : else
3244 : : #endif
3245 : : {
3246 [ - + ]: 42 : if (2 == num_2s_2)
3247 : : {
3248 : : #if ( N_V_STEREOBONDS == 1 )
3249 [ # # ]: 0 : if (!chain_length &&
3250 [ # # ]: 0 : 1 == ( num_2s_hetero_next[0] | num_2s_hetero_next[1] ) &&
3251 [ # # ]: 0 : 3 == at[at_2].valence + at[at_2].num_H &&
3252 [ # # # # ]: 0 : 5 == at[at_2].chem_bonds_valence + at[at_2].num_H &&
3253 [ # # ]: 0 : 3 == get_endpoint_valence( at[at_2].el_number ) &&
3254 [ # # ]: 0 : ( !type_N || bIsOxide( at, at_2 ) ))
3255 : : {
3256 : : /*
3257 : : * found:
3258 : : *
3259 : : * \ / \ / \ /
3260 : : * \ / \ / \ /
3261 : : * N==C or N==C or N==N
3262 : : * // \ // \ // \
3263 : : * O ^ \ N ^ \ O ^ \
3264 : : * | | |
3265 : : * | | |
3266 : : * at[at_2] at[at_2] at[at_2]
3267 : : */
3268 : : ;
3269 : : }
3270 : : else
3271 : : {
3272 : 0 : bFound = 0;
3273 : : }
3274 : : #else
3275 : : bFound = 0;
3276 : : #endif
3277 : : }
3278 : : }
3279 : :
3280 [ - + - - ]: 42 : if (chain_length && num_alt_2)
3281 : : {
3282 : 0 : return 0; /* allow no alt bonds in cumulenes */
3283 : : }
3284 : : }
3285 : :
3286 [ + + ]: 84 : if (bFound)
3287 : : {
3288 : 42 : all_pos_1[num_stereo_bonds] = i_next_at_1; /* neighbor to at_1 position */
3289 : 42 : all_pos_2[num_stereo_bonds] = i_next_at_2; /* neighbor to at_2 position */
3290 : 42 : all_at_2[num_stereo_bonds] = at_2; /* at_2 */
3291 : 42 : all_unkn[num_stereo_bonds] = nUnknown; /* stereogenic bond has Unknown configuration */
3292 : : /*
3293 : : if ( (at[at_1].bUsed0DParity & 2) || (at[at_2].bUsed0DParity & 2) ) {
3294 : : for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k ++ ) {
3295 : : if ( at[at_1].sb_neigh[k] == i_next_at_1 ) {
3296 : : if ( at[at_1].sb_parity[k] == AB_PARITY_UNKN && !nUnknown ) {
3297 : : all_unkn[num_stereo_bonds] = 1;
3298 : : }
3299 : : break;
3300 : : }
3301 : : }
3302 : : }
3303 : : */
3304 : 42 : num_stereo_bonds++;
3305 : : }
3306 : : }
3307 [ - + ]: 78 : if (num_chains > 1)
3308 : : {
3309 : 0 : return 0; /* cannot be more than 1 cumulene chain. */
3310 : : }
3311 : : #if ( ONE_BAD_SB_NEIGHBOR == 1 )
3312 [ + - - + : 78 : if (num_wrong_bonds_1 > 1 || (num_wrong_bonds_1 && 2 >= at[at_1].valence)) /* djb-rwth: addressing LLVM warning */
- - ]
3313 : : {
3314 : 0 : return 0; /* wrong bond type */
3315 : : }
3316 : : #endif
3317 : : /* Accept only short chains for now */
3318 : : /* chain_length=1: >C=C=C< tetrahedral center, allene */
3319 : : /* chain_length=2: >C=C=C=C< stereogenic bond, cumulene */
3320 [ - + - - : 78 : if (chain_length && ( num_stereo_bonds != 1 || num_alt_1 || chain_length > MAX_CUMULENE_LEN ))
- - - - ]
3321 : : {
3322 : 0 : return 0;
3323 : : }
3324 : :
3325 : : /* We need 1 double bond/chain XOR up to 3 arom. bonds */
3326 : : /* to have a stereogenic bond */
3327 [ + + + + ]: 78 : if (( num_alt_1 > 0 ) + ( num_2s_1 > 0 ) != 1 || !num_stereo_bonds /*|| num_2s_1 > 1*/)
3328 : 42 : return 0;
3329 : :
3330 [ - + ]: 36 : if (num_2s_1 > 1)
3331 : : {
3332 : : #if ( N_V_STEREOBONDS == 1 )
3333 [ # # # # ]: 0 : if (2 == num_2s_1 &&
3334 : 0 : 2 == type_N &&
3335 [ # # ]: 0 : 1 == ( num_2s_hetero[0] | num_2s_hetero[1] ) &&
3336 [ # # ]: 0 : 3 == at[at_1].valence + at[at_1].num_H &&
3337 [ # # # # ]: 0 : 5 == at[at_1].chem_bonds_valence + at[at_1].num_H &&
3338 : 0 : 3 == get_endpoint_valence( at[at_1].el_number ))
3339 : : {
3340 : : ;
3341 : : }
3342 : : else
3343 : : {
3344 : 0 : return 0;
3345 : : }
3346 : : #else
3347 : : return 0;
3348 : : #endif
3349 : : }
3350 : :
3351 : : /* ================== Calculate parities ====================== */
3352 : :
3353 : :
3354 : : /* Find possibly stereo bonds and save them */
3355 : 36 : num_stored_isotopic_stereo_bonds = 0;
3356 : : /* djb-rwth: removing redundant code */
3357 [ + + ]: 78 : for (k = 0; k < num_stereo_bonds; k++)
3358 : : {
3359 : :
3360 : : int cur_parity, next_parity, abs_cur_parity, abs_next_parity, dot_prod_z;
3361 : : S_CHAR z_dir1[3], z_dir2[3]; /* 3D vectors for half stereo bond parity direction */
3362 : 42 : int chain_len_bits = MAKE_BITS_CUMULENE_LEN( chain_length );
3363 : : int cur_parity_defined, next_parity_defined;
3364 : : int cur_action, next_action, result_action;
3365 : :
3366 : 42 : at_2 = all_at_2[k];
3367 : 42 : i_next_at_1 = all_pos_1[k];
3368 : :
3369 : : #if ( MIN_SB_RING_SIZE > 0 )
3370 [ + - ]: 42 : if (at[at_1].nRingSystem == at[at_2].nRingSystem)
3371 : : {
3372 : : /* check min. ring size only if both double bond/cumulene */
3373 : : /* ending atoms belong to the same ring system */
3374 : 42 : j = is_bond_in_Nmax_memb_ring( at, at_1, i_next_at_1, q, nAtomLevel, cSource, min_sb_ring_size );
3375 [ + - ]: 42 : if (j > 0)
3376 : : {
3377 : 42 : continue;
3378 : : }
3379 : : else
3380 : : {
3381 [ # # ]: 0 : if (j < 0)
3382 : : {
3383 : 0 : return CT_STEREOBOND_ERROR;
3384 : : }
3385 : : }
3386 : : }
3387 : : #endif
3388 : :
3389 : 0 : i_next_at_2 = all_pos_2[k];
3390 : 0 : nUnknown = all_unkn[k];
3391 : 0 : memset( z_dir1, 0, sizeof( z_dir1 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3392 : 0 : memset( z_dir2, 0, sizeof( z_dir2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3393 : :
3394 : : /********************************************************************************
3395 : : * Find atom parities (negative means parity due to H-isotopes only)
3396 : : * and half stereo bond parity directions z_dir1, z_dir2.
3397 : : *
3398 : : * Bond can have unknown or undefined parity or no parity because of:
3399 : : * 1. Geometry (poorly defined, cannot calculate, for example linear =C-F
3400 : : * or =CHD with no geometry) -- Undefined parity
3401 : : * H
3402 : : * 2. Identical H atoms (no parity in principle, for example =C< )
3403 : : * -- No parity H
3404 : : *
3405 : : * 3. The user said double bond stereo is unknown
3406 : : * or at least one of single bonds is in unknown direction
3407 : : * -- Unknown parity
3408 : : *
3409 : : * These 3 cases (see above) are referred below as 1, 2, 3.
3410 : : * Each of the cases may be present or not (2 possibilities)
3411 : : * Total number of combination is 2*2*2=8
3412 : : *
3413 : : * Since a case when all 3 are not present is a well-defined parity,
3414 : : * we do not consider this case here. Then 2*2*2-1=7 cases are left.
3415 : : *
3416 : : * If several cases are present, list them below separated by "+".
3417 : : * For example, 1+2 means (1) undefined geometry and (2) no parity
3418 : : * is possible because of identical H atoms.
3419 : : *
3420 : : * N) Decision table, Non-isotopic, 2*2*2-1=7 cases:
3421 : : * =================================================
3422 : : * none : 2+any: 1+2(e.g.=CH2); 1+2+3; 2; 2+3 AB_PARITY_NONE=0
3423 : : * undefined: 1 AB_PARITY_UNDF
3424 : : * unknown : 1+3; 3 AB_PARITY_UNKN
3425 : : *
3426 : : * I) Decision table, Isotopic, 2*2*2-1=7 cases:
3427 : : * =============================================
3428 : : * none : none
3429 : : * undefined: 1; 1+2; 1+2+3; 2; 2+3
3430 : : * unknown : 1+3; 3
3431 : : *
3432 : : * Note: When defining identical atoms H atoms in case 2,
3433 : : * Isotopic and Non-isotopic cases are different:
3434 : : * N: do NOT take into account the isotopic composition of H atoms
3435 : : * I: DO take into account the isotopic composition of H atoms
3436 : : * (it is assumed that H isotopes are always different)
3437 : : *
3438 : : * half_stereo_bond_parity() returns:
3439 : : * ==================================
3440 : : * Note: half_stereo_bond_parity() is unaware of case 3.
3441 : : *
3442 : : * can't be a half of a stereo bond AB_PARITY_NONE
3443 : : * 1, isotopic & non-isotopic: AB_PARITY_UNDF
3444 : : * 1, isotopic only -AB_PARITY_UNDF
3445 : : * 2, no parity: identical H isotopes AB_PARITY_IISO
3446 : : * 3, 'Either' single bond(s) AB_PARITY_UNKN ???
3447 : : * 3, 'Either' single bond(s), iso H -AB_PARITY_UNKN ???
3448 : : * defined parity AB_PARITY_ODD, AB_PARITY_EVEN
3449 : : * defined parity for isotopic only: -AB_PARITY_ODD, -AB_PARITY_EVEN
3450 : : *
3451 : : * Resultant value for the stereo bond parity
3452 : : * ---+-------------------+-------+--------+----------------+
3453 : : * 3? | half_stereo_bond_ | N or I| case 1,| bond parity |
3454 : : * | parity()= | | 2 or 3 | |
3455 : : * ---+-------------------+-------+--------+----------------+
3456 : : * ( AB_PARITY_ODD/EVEN) => N&I: - => AB_PARITY_CALC (=6, calc.later)
3457 : : * 3+( AB_PARITY_ODD/EVEN) => N&I: 3 => AB_PARITY_UNKN (=3)
3458 : : * (-AB_PARITY_ODD/EVEN) => N: 2 => AB_PARITY_NONE (=0)
3459 : : * (-AB_PARITY_ODD/EVEN) => I: - => AB_PARITY_CALC
3460 : : * 3+(-AB_PARITY_ODD/EVEN) => N: 2+3 => AB_PARITY_UNDF (=4)
3461 : : * 3+(-AB_PARITY_ODD/EVEN) => I: 3 => AB_PARITY_UNKN
3462 : : * ( AB_PARITY_IISO ) => N: 1+2, 2 => AB_PARITY_NONE (=0)
3463 : : * ( AB_PARITY_IISO ) => I: 1+2, 2 => AB_PARITY_UNDF
3464 : : * 3+( AB_PARITY_IISO ) => N: 1+2+3,2+3=> AB_PARITY_NONE
3465 : : * 3+( AB_PARITY_IISO ) => I: 1+2+3,2+3=> AB_PARITY_UNDF
3466 : : * ( AB_PARITY_UNDF ) => N&I: 1 => AB_PARITY_UNDF
3467 : : * 3+( AB_PARITY_UNDF ) => N&I: 1+3 => AB_PARITY_UNKN
3468 : : * (-AB_PARITY_UNDF ) => N: 1+2 => AB_PARITY_NONE
3469 : : * (-AB_PARITY_UNDF ) => I: 1 => AB_PARITY_UNDF
3470 : : * 3+(-AB_PARITY_UNDF ) => N: 1+2+3 => AB_PARITY_NONE
3471 : : * 3+(-AB_PARITY_UNDF ) => I: 1+3 => AB_PARITY_UNKN
3472 : : * ---+-------------------+-------+--------+----------------+
3473 : :
3474 : : * If bond parity is undefined because abs(dot_prod_z) < MIN_DOT_PROD
3475 : : * then replace: AB_PARITY_CALC
3476 : : * with: AB_PARITY_UNDF
3477 : : * Joining two half_bond_parity() results:
3478 : : *
3479 : : *
3480 : : * atom1 \ atom2 | AB_PARITY_NONE AB_PARITY_UNKN AB_PARITY_UNDF AB_PARITY_CALC
3481 : : * ----------------+---------------------------------------------------------------
3482 : : *0=AB_PARITY_NONE | AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE
3483 : : *3=AB_PARITY_UNKN | AB_PARITY_UNKN AB_PARITY_UNKN AB_PARITY_UNKN
3484 : : *4=AB_PARITY_UNDF | AB_PARITY_UNDF AB_PARITY_UNDF
3485 : : *6=AB_PARITY_CALC | AB_PARITY_CALC
3486 : : *
3487 : : * that is, take min out of the two
3488 : : *********************************************************************************/
3489 : :
3490 : 0 : cur_parity = half_stereo_bond_parity( at, at_1, at_removed_H, num_removed_H,
3491 : : z_dir1, bPointedEdgeStereo, vABParityUnknown );
3492 : 0 : next_parity = half_stereo_bond_parity( at, at_2, at_removed_H, num_removed_H,
3493 : : z_dir2, bPointedEdgeStereo, vABParityUnknown );
3494 : :
3495 [ # # # # : 0 : if (RETURNED_ERROR( cur_parity ) || RETURNED_ERROR( next_parity ))
# # # # ]
3496 : : {
3497 : 0 : return CT_CALC_STEREO_ERR;
3498 : : }
3499 [ # # # # ]: 0 : if (( at[at_1].bUsed0DParity & FlagSB_0D ) || ( at[at_2].bUsed0DParity & FlagSB_0D )) /* djb-rwth: condition corrected */
3500 : : {
3501 : 0 : FixSb0DParities( at, /* at_removed_H, num_removed_H,*/ chain_length,
3502 : : at_1, i_next_at_1, z_dir1,
3503 : : at_2, i_next_at_2, z_dir2, &cur_parity, &next_parity );
3504 : : }
3505 : :
3506 [ # # # # ]: 0 : if (cur_parity == AB_PARITY_NONE || abs( cur_parity ) == AB_PARITY_IISO)
3507 : : {
3508 : 0 : continue;
3509 : : }
3510 [ # # # # ]: 0 : if (next_parity == AB_PARITY_NONE || abs( next_parity ) == AB_PARITY_IISO)
3511 : : {
3512 : 0 : continue;
3513 : : }
3514 : :
3515 : 0 : cur_action = half_stereo_bond_action( cur_parity, nUnknown, 0, vABParityUnknown ); /* -1 => program error */
3516 : 0 : next_action = half_stereo_bond_action( next_parity, nUnknown, 0, vABParityUnknown );
3517 : 0 : result_action = inchi_min( cur_action, next_action );
3518 : :
3519 [ # # ]: 0 : if (result_action == -1)
3520 : : {
3521 : 0 : stop = 1; /* program error <BRKPT> */
3522 : : }
3523 : :
3524 : 0 : abs_cur_parity = abs( cur_parity );
3525 : 0 : abs_next_parity = abs( next_parity );
3526 [ # # # # ]: 0 : cur_parity_defined = ATOM_PARITY_WELL_DEF( abs_cur_parity );
3527 [ # # # # ]: 0 : next_parity_defined = ATOM_PARITY_WELL_DEF( abs_next_parity );
3528 : :
3529 [ # # # # ]: 0 : if (cur_parity_defined && next_parity_defined)
3530 : : {
3531 : : /* find how the whole bond parity depend on geometry */
3532 : : /* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
3533 : : /* can be done only for a well-defined geometry */
3534 : : /*
3535 : : dot_prod_z = (chain_len_bits & BIT_CUMULENE_CHI)?
3536 : : triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
3537 : : dot_prodchar3(z_dir1, z_dir2);
3538 : : */
3539 : :
3540 [ # # ]: 0 : dot_prod_z = ( chain_len_bits && BOND_CHAIN_LEN( chain_len_bits ) % 2 )
3541 : 0 : ? triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 )
3542 [ # # ]: 0 : : dot_prodchar3( z_dir1, z_dir2 );
3543 : :
3544 [ # # # # ]: 0 : if (abs( dot_prod_z ) < MIN_DOT_PROD)
3545 : : {
3546 : : /* The geometry is not well-defined. Eliminate AB_PARITY_CALC */
3547 : 0 : result_action = inchi_min( result_action, AB_PARITY_UNDF );
3548 : : }
3549 : : }
3550 : : else
3551 : : {
3552 : 0 : dot_prod_z = 0;
3553 : : }
3554 : :
3555 [ # # # # ]: 0 : if (result_action != AB_PARITY_NONE && result_action != -1)
3556 : : {
3557 : : /* Stereo, no isotopes (only positive) */
3558 [ # # # # ]: 0 : if (cur_parity > 0 && next_parity > 0)
3559 : : {
3560 [ # # ]: 0 : if (save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
3561 : 0 : at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor,
3562 : 0 : out_at[at_1].stereo_bond_ord, out_at[at_1].stereo_bond_z_prod,
3563 : 0 : out_at[at_1].stereo_bond_parity,
3564 : 0 : at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor,
3565 : 0 : out_at[at_2].stereo_bond_ord, out_at[at_2].stereo_bond_z_prod,
3566 : 0 : out_at[at_2].stereo_bond_parity ))
3567 : : {
3568 [ # # # # ]: 0 : if (!out_at[at_1].parity ||
3569 [ # # # # ]: 0 : (cur_parity_defined && !ATOM_PARITY_WELL_DEF( abs( out_at[at_1].parity )) )) /* djb-rwth: addressing LLVM warning */
3570 : : {
3571 : 0 : out_at[at_1].parity = cur_parity;
3572 : 0 : memcpy(out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir));
3573 : : }
3574 [ # # # # ]: 0 : if (!out_at[at_2].parity ||
3575 [ # # # # ]: 0 : (next_parity_defined && !ATOM_PARITY_WELL_DEF( abs( out_at[at_2].parity )) )) /* djb-rwth: addressing LLVM warning */
3576 : : {
3577 : 0 : out_at[at_2].parity = next_parity;
3578 : 0 : memcpy(out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir));
3579 : : }
3580 : 0 : out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
3581 : 0 : out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
3582 : : /* djb-rwth: removing redundant code */
3583 : : }
3584 : : }
3585 : : }
3586 : :
3587 : : /* Stereo + isotopic (all non-zero) */
3588 : 0 : cur_action = half_stereo_bond_action( cur_parity, nUnknown, 1, vABParityUnknown ); /* -1 => program error */
3589 : 0 : next_action = half_stereo_bond_action( next_parity, nUnknown, 1, vABParityUnknown );
3590 : 0 : result_action = inchi_min( cur_action, next_action );
3591 : 0 : cur_parity = abs_cur_parity;
3592 : 0 : next_parity = abs_next_parity;
3593 [ # # # # ]: 0 : if (result_action != AB_PARITY_NONE && result_action != -1)
3594 : : {
3595 : : /* Stereo, isotopic */
3596 [ # # # # ]: 0 : if (cur_parity > 0 && next_parity > 0)
3597 : : {
3598 [ # # ]: 0 : if (save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
3599 : 0 : at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor2,
3600 : 0 : out_at[at_1].stereo_bond_ord2, out_at[at_1].stereo_bond_z_prod2,
3601 : 0 : out_at[at_1].stereo_bond_parity2,
3602 : 0 : at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor2,
3603 : 0 : out_at[at_2].stereo_bond_ord2, out_at[at_2].stereo_bond_z_prod2,
3604 : 0 : out_at[at_2].stereo_bond_parity2 ))
3605 : : {
3606 [ # # # # ]: 0 : if (!out_at[at_1].parity2 ||
3607 [ # # # # ]: 0 : (cur_parity_defined && !ATOM_PARITY_WELL_DEF( abs( out_at[at_1].parity2 )) )) /* djb-rwth: addressing LLVM warning */
3608 : : {
3609 : 0 : out_at[at_1].parity2 = cur_parity /*| chain_len_bits*/;
3610 [ # # ]: 0 : if (!out_at[at_1].parity)
3611 : : {
3612 : 0 : memcpy(out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir));
3613 : : }
3614 : : }
3615 [ # # # # ]: 0 : if (!out_at[at_2].parity2 || /* next line changed from abs(out_at[at_2].parity) 2006-03-05 */
3616 [ # # # # ]: 0 : (next_parity_defined && !ATOM_PARITY_WELL_DEF( abs( out_at[at_2].parity2 )) )) /* djb-rwth: addressing LLVM warning */
3617 : : {
3618 : 0 : out_at[at_2].parity2 = next_parity /*| chain_len_bits*/;
3619 [ # # ]: 0 : if (!out_at[at_2].parity)
3620 : : {
3621 : 0 : memcpy(out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir));
3622 : : }
3623 : : }
3624 : 0 : out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
3625 : 0 : out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
3626 : 0 : num_stored_isotopic_stereo_bonds++;
3627 : : }
3628 : : }
3629 : : }
3630 : : else
3631 : : {
3632 [ # # ]: 0 : if (result_action == -1)
3633 : : {
3634 : 0 : stop = 1; /* program error? <BRKPT> */
3635 : : }
3636 : : }
3637 : : }
3638 : :
3639 [ - + ]: 36 : if (stop)
3640 : : {
3641 : 0 : return CT_CALC_STEREO_ERR;
3642 : : }
3643 : :
3644 : 36 : return /*num_stored_stereo_bonds+*/ num_stored_isotopic_stereo_bonds;
3645 : : }
3646 : :
3647 : :
3648 : : #if ( NEW_STEREOCENTER_CHECK == 1 )
3649 : :
3650 : : /* int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at, int bStereoAtZz ) */
3651 : :
3652 : : /****************************************************************************
3653 : : If isotopic H, D, T added, can the atom be a stereo center?
3654 : : ****************************************************************************/
3655 : 810 : int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at,
3656 : : int cur_at,
3657 : : int bPointedEdgeStereo,
3658 : : int bStereoAtZz )
3659 : : {
3660 : : int nNumNeigh;
3661 [ + + ]: 810 : if (( nNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at, bPointedEdgeStereo, bStereoAtZz ) ) &&
3662 [ + - ]: 409 : at[cur_at].valence + at[cur_at].num_H == nNumNeigh &&
3663 [ + + ]: 409 : at[cur_at].num_H <= NUM_H_ISOTOPES
3664 : : )
3665 : : {
3666 : 406 : return 1;
3667 : : }
3668 : :
3669 : 404 : return 0;
3670 : : }
3671 : :
3672 : :
3673 : : #else
3674 : :
3675 : : /****************************************************************************/
3676 : : int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
3677 : : {
3678 : : int j, ret = 0;
3679 : : if (bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) &&
3680 : : at[cur_at].valence + at[cur_at].num_H == MAX_NUM_STEREO_ATOM_NEIGH &&
3681 : : at[cur_at].num_H < MAX_NUM_STEREO_ATOM_NEIGH
3682 : : )
3683 : : {
3684 : : for (j = 0, ret = 1; ret && j < at[cur_at].valence; j++)
3685 : : {
3686 : : if (( at[cur_at].bond_type[j] & ~BOND_MARK_ALL ) != BOND_SINGLE)
3687 : : {
3688 : : ret = 0;
3689 : : }
3690 : : }
3691 : : }
3692 : :
3693 : : return ret;
3694 : : }
3695 : : #endif
3696 : :
3697 : :
3698 : : /****************************************************************************/
3699 : 24 : int GetStereocenter0DParity( CANON_GLOBALS *pCG,
3700 : : inp_ATOM *at,
3701 : : int cur_at,
3702 : : int j1,
3703 : : AT_NUMB nSbNeighOrigAtNumb[],
3704 : : int nFlag )
3705 : : {
3706 : 24 : int parity = AB_PARITY_NONE;
3707 [ - + - - : 24 : if (at[cur_at].p_parity && ( j1 == MAX_NUM_STEREO_ATOM_NEIGH - 1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH ))
- - ]
3708 : : {
3709 : : int i, num_trans_inp, num_trans_neigh;
3710 : : AT_NUMB nInpNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
3711 [ # # ]: 0 : for (i = 0; i < MAX_NUM_STEREO_ATOM_NEIGH; i++)
3712 : : {
3713 : 0 : nInpNeighOrigAtNumb[i] = at[cur_at].p_orig_at_num[i];
3714 [ # # ]: 0 : if (nInpNeighOrigAtNumb[i] == at[cur_at].orig_at_number)
3715 : : {
3716 : 0 : nInpNeighOrigAtNumb[i] = 0; /* lone pair or explicit H */
3717 : : }
3718 : : }
3719 : :
3720 : 0 : num_trans_inp = insertions_sort( pCG, nInpNeighOrigAtNumb, MAX_NUM_STEREO_ATOM_NEIGH, sizeof( nInpNeighOrigAtNumb[0] ), comp_AT_NUMB );
3721 : 0 : num_trans_neigh = insertions_sort( pCG, nSbNeighOrigAtNumb, j1, sizeof( nSbNeighOrigAtNumb[0] ), comp_AT_NUMB );
3722 : :
3723 : : if (j1 == MAX_NUM_STEREO_ATOM_NEIGH - 1)
3724 : : {
3725 : : ;
3726 : : /*num_trans_neigh += j1;*/
3727 : : /* the lone pair or implicit H is implicitly at the top of the list */
3728 : : }
3729 [ # # ]: 0 : if (!memcmp( nInpNeighOrigAtNumb + MAX_NUM_STEREO_ATOM_NEIGH - j1, nSbNeighOrigAtNumb, j1 * sizeof( AT_NUMB ) ))
3730 : : {
3731 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[cur_at].p_parity ))
3732 : : {
3733 : 0 : parity = 2 - ( num_trans_inp + num_trans_neigh + at[cur_at].p_parity ) % 2;
3734 : : }
3735 : : else
3736 : : {
3737 : 0 : parity = at[cur_at].p_parity;
3738 : : }
3739 : 0 : at[cur_at].bUsed0DParity |= nFlag; /* 0D parity used for streocenter parity */
3740 : : }
3741 : : }
3742 : :
3743 : 24 : return parity;
3744 : : }
3745 : :
3746 : :
3747 : : /****************************************************************************
3748 : : Get stereo atom parity for the current order of attachments
3749 : : The result in at[cur_at].parity is valid for previously removed
3750 : : explicit hydrogen atoms, including isotopic ones, that are located in at_removed_H[]
3751 : : The return value is a calculated parity.
3752 : : ****************************************************************************/
3753 : : #define ADD_EXPLICIT_HYDROGEN_NEIGH 1
3754 : : #define ADD_EXPLICIT_LONE_PAIR_NEIGH 2
3755 : 810 : int set_stereo_atom_parity( CANON_GLOBALS *pCG,
3756 : : sp_ATOM *out_at,
3757 : : inp_ATOM *at,
3758 : : int cur_at,
3759 : : inp_ATOM *at_removed_H,
3760 : : int num_removed_H,
3761 : : int bPointedEdgeStereo,
3762 : : int vABParityUnknown,
3763 : : int LooseTSACheck,
3764 : : int bStereoAtZz )
3765 : : {
3766 : : int j, k, next_at, num_z, j1, nType, num_explicit_H, tot_num_iso_H, nMustHaveNumNeigh;
3767 : : int num_explicit_iso_H[NUM_H_ISOTOPES + 1];
3768 : : /* numbers of removed hydrogen atoms */
3769 : : int index_H[MAX_NUM_STEREO_ATOM_NEIGH];
3770 : : /* cannot have more than 4 elements: 1 H, 1 D, 1 T atom(s) */
3771 : : double z, sum_xyz[3], min_sine, triple_product;
3772 : : double at_coord[MAX_NUM_STEREO_ATOM_NEIGH][3];
3773 : 810 : double bond_len_xy[4], rmax = 0.0, rmin = 0.0;
3774 : : double at_coord_center[3];
3775 : 810 : int parity, bAmbiguous = 0, bAddExplicitNeighbor = 0, b2D = 0, n2DTetrahedralAmbiguity = 0;
3776 : 810 : int bIgnoreIsotopicH = ( 0 != ( at[cur_at].cFlags & AT_FLAG_ISO_H_POINT ) );
3777 : : AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
3778 : :
3779 : 810 : double vMinAngle = MIN_ANGLE;
3780 : 810 : double vMinSine = MIN_SINE;
3781 [ - + ]: 810 : if (LooseTSACheck)
3782 : : {
3783 : : /* Relax check for principal 3-atomic angles close to 180 deg, for 2D tetrahedron, to account for */
3784 : : /* large cycles drawn as appear after applying some structure 'cleaning' algorithms/softwares */
3785 : :
3786 [ # # ]: 0 : if (at[cur_at].nNumAtInRingSystem >= 3) /* Ensure that central atom is in ring (ideally, one should check */
3787 : : /* also that neighbors are in-ring, and for large enough ring) */
3788 : : {
3789 : 0 : vMinAngle = MIN_ANGLE_RELAXED;
3790 : 0 : vMinSine = MIN_SINE_RELAXED;
3791 : : }
3792 : : }
3793 : :
3794 : 810 : out_at[cur_at].parity =
3795 : 810 : out_at[cur_at].parity2 =
3796 : 810 : out_at[cur_at].stereo_atom_parity =
3797 : 810 : out_at[cur_at].stereo_atom_parity2 =
3798 : : AB_PARITY_NONE;
3799 : 810 : parity = AB_PARITY_NONE;
3800 : :
3801 : 810 : memset( num_explicit_iso_H, 0, sizeof( num_explicit_iso_H ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3802 : 810 : num_explicit_H = 0;
3803 : :
3804 : : #if ( NEW_STEREOCENTER_CHECK == 1 )
3805 [ + + ]: 810 : if (!( nMustHaveNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at, bPointedEdgeStereo, bStereoAtZz ) ) ||
3806 [ + + ]: 409 : at[cur_at].num_H > NUM_H_ISOTOPES)
3807 : : {
3808 : 404 : goto exit_function;
3809 : : }
3810 : : #else
3811 : : nMustHaveNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH;
3812 : : if (!bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) ||
3813 : : at[cur_at].valence + at[cur_at].num_H != nMustHaveNumNeigh ||
3814 : : at[cur_at].num_H > NUM_H_ISOTOPES
3815 : : )
3816 : : {
3817 : : goto exit_function;
3818 : : }
3819 : : for (j = 0; j < at[cur_at].valence; j++)
3820 : : {
3821 : : if (( at[cur_at].bond_type[j] & ~BOND_MARK_ALL ) != BOND_SINGLE)
3822 : : {
3823 : : goto exit_function;
3824 : : }
3825 : : }
3826 : : #endif
3827 : :
3828 : : /* numbers of isotopic H atoms */
3829 [ + + ]: 1624 : for (j = 0, tot_num_iso_H = 0; j < NUM_H_ISOTOPES; j++)
3830 : : {
3831 [ - + ]: 1218 : if (at[cur_at].num_iso_H[j] > 1)
3832 : : {
3833 : 0 : goto exit_function; /* two or more identical hydrogen isotopic neighbors */
3834 : : }
3835 : 1218 : tot_num_iso_H += at[cur_at].num_iso_H[j];
3836 : : }
3837 [ - + ]: 406 : if (bIgnoreIsotopicH)
3838 : : {
3839 : 0 : tot_num_iso_H = 0; /* isotopic H considered subject to exchange => ignore isotopic */
3840 : : }
3841 : : /* number of non-isotopic H atoms */
3842 [ + + ]: 406 : if (at[cur_at].num_H - tot_num_iso_H > 1)
3843 : : {
3844 : 205 : goto exit_function; /* two or more identical hydrogen non-isotopic neighbors */
3845 : : }
3846 : :
3847 : : /* count removed explicit terminal hydrogens attached to at[cur_at]. */
3848 : : /* the result is num_explicit_H. */
3849 : : /* Removed hydrogens are sorted in increasing isotopic shift order */
3850 [ + - - + ]: 201 : if (at_removed_H && num_removed_H > 0)
3851 : : {
3852 [ # # ]: 0 : for (j = 0; j < num_removed_H; j++)
3853 : : {
3854 [ # # ]: 0 : if (at_removed_H[j].neighbor[0] == cur_at)
3855 : : {
3856 : 0 : k = at_removed_H[j].iso_atw_diff;
3857 : : /* iso_atw_diff values: H=>0, 1H=>1, D=2H=>2, T=3H=>3 */
3858 [ # # # # : 0 : if (k < 0 || k > NUM_H_ISOTOPES || bIgnoreIsotopicH)
# # ]
3859 : : {
3860 : 0 : k = 0; /* treat wrong H isotopes as non-isotopic H */
3861 : : }
3862 : 0 : num_explicit_iso_H[k] ++;
3863 : 0 : index_H[num_explicit_H++] = j;
3864 : : }
3865 : : }
3866 : : }
3867 : :
3868 : : /* coordinates initialization */
3869 : 201 : num_z = 0;
3870 : 201 : sum_xyz[0] = sum_xyz[1] = sum_xyz[2] = 0.0;
3871 : :
3872 : 201 : at_coord_center[0] =
3873 : 201 : at_coord_center[1] =
3874 : 201 : at_coord_center[2] =
3875 : : 0.0;
3876 : :
3877 : : /* fill out stereo center neighbors coordinates */
3878 : : /* and obtain the parity from the geometry */
3879 : :
3880 [ + + ]: 603 : for (k = 0, j1 = 0; k < 2; k++)
3881 : : {
3882 [ + + - ]: 402 : switch (k)
3883 : : {
3884 : :
3885 : 201 : case 0:
3886 : : /* add coordinates of removed hydrogens */
3887 [ - + ]: 201 : for (j = 0; j < num_explicit_H; j++, j1++)
3888 : : {
3889 : 0 : next_at = index_H[j];
3890 : : /* Use bond description located at removed_H atom */
3891 : : /* minus sign at get_z_coord: at_removed_H[] contains bonds TO at[cur_at], not FROM it. */
3892 : : /* Note: &at[(at_removed_H-at)+ next_at] == &at_removed_H[next_at] */
3893 : 0 : z = -get_z_coord( at,
3894 : 0 : (int) ( at_removed_H - at ) + next_at,
3895 : : 0 /*neighbor #*/,
3896 : : &nType,
3897 : 0 : -( bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO ) );
3898 [ # # # # ]: 0 : switch (nType)
3899 : : {
3900 : 0 : case ZTYPE_EITHER:
3901 : 0 : parity = vABParityUnknown /*AB_PARITY_UNKN*/; /* no parity: bond in "Either" direction. */
3902 : 0 : goto exit_function;
3903 : 0 : case ZTYPE_UP:
3904 : : case ZTYPE_DOWN:
3905 : 0 : nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
3906 : 0 : b2D++;
3907 : : /* no break; here */
3908 : 0 : case ZTYPE_3D:
3909 : 0 : num_z++;
3910 : : }
3911 : :
3912 [ # # ]: 0 : if (j1 < MAX_NUM_STEREO_ATOM_NEIGH) /* djb-rwth: fixing oss-fuzz issue #71142 */
3913 : : {
3914 : 0 : nSbNeighOrigAtNumb[j1] = at_removed_H[next_at].orig_at_number;
3915 : 0 : at_coord[j1][0] = at_removed_H[next_at].x - at[cur_at].x;
3916 : 0 : at_coord[j1][1] = at_removed_H[next_at].y - at[cur_at].y;
3917 : 0 : bond_len_xy[j1] = len2(at_coord[j1]);
3918 : : /* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
3919 [ # # ]: 0 : at_coord[j1][2] = (nType == ZTYPE_3D ? z : nType == ZTYPE_UP
3920 [ # # ]: 0 : ? bond_len_xy[j1] : nType == ZTYPE_DOWN
3921 [ # # ]: 0 : ? -bond_len_xy[j1] : 0.0);
3922 : : }
3923 : : else
3924 : : {
3925 : 0 : break;
3926 : : }
3927 : : }
3928 : 201 : break;
3929 : 201 : case 1:
3930 : : /* add all coordinates of other neighboring atoms */
3931 [ + + ]: 804 : for (j = 0; j < at[cur_at].valence; j++, j1++)
3932 : : {
3933 : 603 : next_at = at[cur_at].neighbor[j];
3934 : 603 : z = get_z_coord( at, cur_at, j, &nType, ( bPointedEdgeStereo & PES_BIT_POINT_EDGE_STEREO ) );
3935 [ - + - + ]: 603 : switch (nType)
3936 : : {
3937 : 0 : case ZTYPE_EITHER:
3938 : 0 : parity = vABParityUnknown /*AB_PARITY_UNKN*/; /* unknown parity: bond in "Either" direction. */
3939 : 0 : goto exit_function;
3940 : 177 : case ZTYPE_UP:
3941 : : case ZTYPE_DOWN:
3942 : 177 : b2D++;
3943 : 177 : case ZTYPE_3D:
3944 : 177 : num_z++;
3945 : : }
3946 : :
3947 [ + - ]: 603 : if (j1 < MAX_NUM_STEREO_ATOM_NEIGH) /* djb-rwth: fixing oss-fuzz issue #71142 */
3948 : : {
3949 : 603 : nSbNeighOrigAtNumb[j1] = at[next_at].orig_at_number;
3950 : 603 : at_coord[j1][0] = at[next_at].x - at[cur_at].x;
3951 : 603 : at_coord[j1][1] = at[next_at].y - at[cur_at].y;
3952 : 603 : bond_len_xy[j1] = len2(at_coord[j1]);
3953 : : /* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
3954 [ + - ]: 1206 : at_coord[j1][2] = (nType == ZTYPE_3D ? z :
3955 [ + + ]: 1060 : nType == ZTYPE_UP ? bond_len_xy[j1] :
3956 [ + + ]: 457 : nType == ZTYPE_DOWN ? -bond_len_xy[j1] : 0.0);
3957 : : }
3958 : : else
3959 : : {
3960 : 0 : break;
3961 : : }
3962 : : }
3963 : 201 : break;
3964 : : }
3965 : : }
3966 : : /* j1 is the number of explicit neighbors (that is, all neighbors except implicit H) */
3967 [ + - + + ]: 201 : b2D = ( b2D == num_z && num_z ); /* 1 => two-dimensional */
3968 : :
3969 [ + - ]: 201 : if (MAX_NUM_STEREO_ATOM_NEIGH != at[cur_at].valence + num_explicit_H &&
3970 [ - + ]: 201 : MAX_NUM_STEREO_ATOM_NEIGH - 1 != at[cur_at].valence + num_explicit_H)
3971 : : {
3972 : : /* not enough geometry data to find the central atom parity */
3973 [ # # ]: 0 : if (nMustHaveNumNeigh == at[cur_at].valence + at[cur_at].num_H &&
3974 [ # # ]: 0 : at[cur_at].num_H > 1)
3975 : : {
3976 : : /* only isotopic parity is possible; no non-isotopic parity */
3977 [ # # ]: 0 : if (parity == vABParityUnknown /*AB_PARITY_UNKN*/)
3978 : : {
3979 : 0 : parity = -vABParityUnknown /*AB_PARITY_UNKN*/; /* the user marked the center as "unknown" */
3980 : : }
3981 : : else
3982 : : {
3983 : 0 : parity = -AB_PARITY_UNDF; /* not enough geometry; only isotopic parity is possible */
3984 : : }
3985 : : }
3986 : : else
3987 : : {
3988 : 0 : parity = AB_PARITY_NONE; /* not a stereocenter at all */
3989 : : }
3990 : 0 : goto exit_function;
3991 : : }
3992 : : /* make all vector lengths equal to 1; exit if too short. 9-10-2002 */
3993 [ + + ]: 804 : for (j = 0; j < j1; j++)
3994 : : {
3995 : 603 : z = len3( at_coord[j] );
3996 [ - + ]: 603 : if (z < MIN_BOND_LEN)
3997 : : {
3998 : : /* bond length is too small: use 0D parities */
3999 [ # # ]: 0 : if (AB_PARITY_NONE == ( parity = GetStereocenter0DParity( pCG, at, cur_at,
4000 : : j1,nSbNeighOrigAtNumb,
4001 : : FlagSC_0D ) ))
4002 : : {
4003 : 0 : parity = AB_PARITY_UNDF;
4004 : : }
4005 : 0 : goto exit_function;
4006 : : }
4007 : : #if ( STEREO_CENTER_BONDS_NORM == 1 )
4008 : : else
4009 : : {
4010 : 603 : mult3( at_coord[j], 1.0 / z, at_coord[j] );
4011 : : }
4012 : : #endif
4013 [ + + + + ]: 603 : rmax = j ? inchi_max( rmax, z ) : z;
4014 [ + + + + ]: 603 : rmin = j ? inchi_min( rmin, z ) : z;
4015 : : }
4016 [ - + ]: 201 : if (rmin / rmax < MIN_SINE)
4017 : : {
4018 : : /* bond ratio is too small: use 0D parities */
4019 [ # # ]: 0 : if (AB_PARITY_NONE == ( parity = GetStereocenter0DParity( pCG, at, cur_at, j1,
4020 : : nSbNeighOrigAtNumb,
4021 : : FlagSC_0D ) ))
4022 : : {
4023 : 0 : parity = AB_PARITY_UNDF;
4024 : : }
4025 : 0 : goto exit_function;
4026 : : }
4027 [ + + ]: 804 : for (j = 0; j < j1; j++)
4028 : : {
4029 : 603 : add3( sum_xyz, at_coord[j], sum_xyz );
4030 : : }
4031 : :
4032 : : /* Here j1 is a number of neighbors including explicit terminal isotopic H */
4033 : : /* num_explicit_iso_H[0] = number of explicit non-isotopic hydrogen atom neighbors */
4034 : 201 : j = j1;
4035 : : /* Add Explicit Neighbor */
4036 [ + - ]: 201 : if (j1 == MAX_NUM_STEREO_ATOM_NEIGH - 1)
4037 : : {
4038 : : /* Add an explicit neighbor if possible */
4039 [ - + ]: 201 : if (nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH - 1)
4040 : : {
4041 : 0 : bAddExplicitNeighbor = ADD_EXPLICIT_LONE_PAIR_NEIGH;
4042 : : }
4043 : : else
4044 : : {
4045 [ + - ]: 201 : if (nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH)
4046 : : {
4047 : : /* Check whether an explicit non-isotopic hydrogen can be added */
4048 : : /* to an atom that is a stereogenic atom */
4049 [ + - ]: 201 : if (1 == at[cur_at].num_H - num_explicit_H && /* the atom has only one one implicit hydrogen */
4050 [ + - ]: 201 : 1 == at[cur_at].num_H - tot_num_iso_H)
4051 : : {
4052 : : /* this hydrogen is non-isotopic */
4053 : 201 : bAddExplicitNeighbor = ADD_EXPLICIT_HYDROGEN_NEIGH;
4054 : : }
4055 : : }
4056 : : }
4057 : : }
4058 : :
4059 [ + - ]: 201 : if (bAddExplicitNeighbor)
4060 : : {
4061 : : /***********************************************************
4062 : : * May happen only if (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1)
4063 : : * 3 neighbors only, no H-neighbors. Create and add coordinates of an implicit H
4064 : : * or a fake 4th neighbor, that is, a lone pair
4065 : : */
4066 [ - + ]: 201 : if (parity == vABParityUnknown /*AB_PARITY_UNKN*/)
4067 : : {
4068 : 0 : goto exit_function; /* the user insists the parity is unknown and the isotopic */
4069 : : /* composition of the neighbors does not contradict */
4070 : : }
4071 : : else
4072 : : {
4073 [ + + - + ]: 201 : if (num_z == 0 || are_3_vect_in_one_plane( at_coord, vMinSine ))
4074 : : {
4075 : : /* "hydrogen down" rule is needed to resolve an ambiguity */
4076 [ - + ]: 24 : if (num_z > 0)
4077 : : {
4078 : 0 : bAmbiguous |= AMBIGUOUS_STEREO;
4079 : : }
4080 : : #if ( APPLY_IMPLICIT_H_DOWN_RULE == 1 ) /* { */
4081 : : /* Although H should be at the top of the list, add it to the bottom. */
4082 : : /* This will be taken care of later by inverting parity 1<->2 */
4083 : : at_coord[j][0] = 0.0;
4084 : : at_coord[j][1] = 0.0;
4085 : : #if ( STEREO_CENTER_BONDS_NORM == 1 )
4086 : : at_coord[j][2] = -1.0;
4087 : : #else
4088 : : at_coord[j][2] = -( bond_len_xy[0] + bond_len_xy[1] + bond_len_xy[2] ) / 3.0;
4089 : : #endif
4090 : : #else /* } APPLY_IMPLICIT_H_DOWN_RULE { */
4091 : : #if (ALWAYS_SET_STEREO_PARITY == 1)
4092 : : parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
4093 : : #else
4094 : : /* All 3 bonds are in one plane: try to get 0D parities */
4095 [ + - ]: 24 : if (AB_PARITY_NONE == ( parity = GetStereocenter0DParity( pCG, at, cur_at,
4096 : : j1,
4097 : : nSbNeighOrigAtNumb,
4098 : : FlagSC_0D ) ))
4099 : : {
4100 : 24 : parity = AB_PARITY_UNDF;
4101 : : }
4102 : : /*parity = AB_PARITY_UNDF;*/ /* no parity can be calculated found */
4103 : : #endif
4104 : 24 : goto exit_function;
4105 : : #endif /* } APPLY_IMPLICIT_H_DOWN_RULE */
4106 : : }
4107 : : else
4108 : : {
4109 : : /* we have enough information to find implicit hydrogen coordinates */
4110 : : /*
4111 : : at_coord[j][0] = -sum_x;
4112 : : at_coord[j][1] = -sum_y;
4113 : : at_coord[j][2] = -sum_z;
4114 : : */
4115 : : /* copy3(sum_xyz, at_coord[j]); -- djb-rwth: removing copy3 function */
4116 : 177 : memcpy(at_coord[j], sum_xyz, sizeof(sum_xyz));
4117 : 177 : change_sign3( at_coord[j], at_coord[j] );
4118 : 177 : z = len3( at_coord[j] );
4119 : : #if ( FIX_STEREO_SCALING_BUG == 1 )
4120 : : if (z > 1.0)
4121 : : {
4122 : : rmax *= z;
4123 : : }
4124 : : else
4125 : : {
4126 : : rmin *= z;
4127 : : }
4128 : : #else
4129 : : /* Comparing the original bond lengths to lenghts derived from normalized to 1 */
4130 : : /* This bug leads to pronouncing legitimate stereogenic atoms */
4131 : : /* connected by 3 bonds "undefined" if in a nicely drawn 2D structure */
4132 : : /* bond lengths are about 20 or greater. Reported by Reinhard Dunkel 2005-08-05 */
4133 [ + - ]: 177 : if (bPointedEdgeStereo & PES_BIT_FIX_SP3_BUG)
4134 : : {
4135 : : /* coordinate scaling bug fixed here */
4136 [ - + ]: 177 : if (z > 1.0)
4137 : : {
4138 : 0 : rmax *= z;
4139 : : }
4140 : : else
4141 : : {
4142 : 177 : rmin *= z;
4143 : : }
4144 : : }
4145 : : else
4146 : : {
4147 : : /* original InChI v.1 bug */
4148 [ # # ]: 0 : rmax = inchi_max( rmax, z );
4149 [ # # ]: 0 : rmin = inchi_min( rmin, z );
4150 : : }
4151 : : #endif
4152 [ + - - + ]: 177 : if (z < MIN_BOND_LEN || rmin / rmax < MIN_SINE)
4153 : : {
4154 : : /* the new 4th bond is too short: try to get 0D parities */
4155 [ # # ]: 0 : if (AB_PARITY_NONE == ( parity = GetStereocenter0DParity( pCG, at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D ) ))
4156 : : {
4157 : 0 : parity = AB_PARITY_UNDF;
4158 : : }
4159 : 0 : goto exit_function;
4160 : : }
4161 : : #if ( STEREO_CENTER_BOND4_NORM == 1 )
4162 : : else
4163 : : {
4164 : : mult3( at_coord[j], 1.0 / z, at_coord[j] );
4165 : : }
4166 : : #endif
4167 : : }
4168 : : }
4169 : : }
4170 : :
4171 [ # # ]: 0 : else if (j1 != MAX_NUM_STEREO_ATOM_NEIGH)
4172 : : {
4173 [ # # ]: 0 : if (parity == vABParityUnknown /*AB_PARITY_UNKN*/)
4174 : : {
4175 : 0 : parity = -AB_PARITY_UNDF; /* isotopic composition of H-neighbors contradicts 'unknown' */
4176 : : }
4177 : 0 : goto exit_function;
4178 : : }
4179 : :
4180 : : else /* j1 == MAX_NUM_STEREO_ATOM_NEIGH */
4181 : : {
4182 [ # # # # ]: 0 : if (num_z == 0 || are_4at_in_one_plane( at_coord, vMinSine ))
4183 : : {
4184 : : /* all four neighours in xy plane: undefined geometry. */
4185 [ # # ]: 0 : if (num_z > 0)
4186 : : {
4187 : 0 : bAmbiguous |= AMBIGUOUS_STEREO;
4188 : : }
4189 [ # # ]: 0 : if (parity != vABParityUnknown /*AB_PARITY_UNKN*/)
4190 : : {
4191 : : #if (ALWAYS_SET_STEREO_PARITY == 1)
4192 : : parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
4193 : : #else
4194 : : /* All 4 bonds are in one plane: try to get 0D parities */
4195 [ # # ]: 0 : if (AB_PARITY_NONE == ( parity = GetStereocenter0DParity( pCG, at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D ) ))
4196 : : {
4197 : 0 : parity = AB_PARITY_UNDF;
4198 : : }
4199 [ # # # # ]: 0 : else if (ATOM_PARITY_WELL_DEF( parity ))
4200 : : {
4201 : 0 : bAmbiguous &= ~AMBIGUOUS_STEREO; /* 0D parity has resolved the ambiguity */
4202 : : }
4203 : : #endif
4204 : : }
4205 : 0 : goto exit_function;
4206 : : }
4207 : : }
4208 : :
4209 : : /***********************************************************
4210 : : * At this point we have 4 neighboring atoms.
4211 : : * check for tetrahedral ambiguity in 2D case
4212 : : */
4213 [ + - ]: 177 : if (b2D)
4214 : : {
4215 : :
4216 : 177 : n2DTetrahedralAmbiguity = Get2DTetrahedralAmbiguity( pCG,at_coord,
4217 : : bAddExplicitNeighbor,
4218 : : ( bPointedEdgeStereo & PES_BIT_FIX_SP3_BUG ),
4219 : : vMinAngle );
4220 : :
4221 [ + - ]: 177 : if (0 < n2DTetrahedralAmbiguity)
4222 : : {
4223 [ - + ]: 177 : if (T2D_WARN & n2DTetrahedralAmbiguity)
4224 : : {
4225 : 0 : bAmbiguous |= AMBIGUOUS_STEREO;
4226 : : }
4227 [ - + ]: 177 : if (T2D_UNDF & n2DTetrahedralAmbiguity)
4228 : : {
4229 [ # # ]: 0 : if (parity != vABParityUnknown /*AB_PARITY_UNKN*/)
4230 : : {
4231 : : #if (ALWAYS_SET_STEREO_PARITY == 1)
4232 : : parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
4233 : : #else
4234 : 0 : parity = AB_PARITY_UNDF; /* no parity */
4235 : : #endif
4236 : : }
4237 : 0 : goto exit_function;
4238 : : }
4239 : : }
4240 [ # # ]: 0 : else if (n2DTetrahedralAmbiguity < 0)
4241 : : {
4242 : 0 : bAmbiguous |= AMBIGUOUS_STEREO_ERROR; /* error */
4243 : 0 : parity = AB_PARITY_UNDF;
4244 : 0 : goto exit_function;
4245 : : }
4246 : : }
4247 : :
4248 : : /************************************************************/
4249 : : /* Move coordinates origin to the neighbor #0 */
4250 [ + + ]: 708 : for (j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j++)
4251 : : {
4252 : 531 : diff3( at_coord[j], at_coord[0], at_coord[j] );
4253 : : }
4254 : 177 : diff3( at_coord_center, at_coord[0], at_coord_center );
4255 : :
4256 : : /*
4257 : : for ( k = 0; k < 3; k++ )
4258 : : {
4259 : : for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ )
4260 : : {
4261 : : at_coord[j][k] -= at_coord[0][k];
4262 : : }
4263 : : at_coord_center[k] -= at_coord[0][k];
4264 : : }
4265 : : */
4266 : :
4267 : :
4268 : : /********************************************************
4269 : : * Find the central (cur_at) atom's parity
4270 : : * (orientation of atoms #1-3 when looking from #0)
4271 : : ********************************************************/
4272 : 177 : triple_product = triple_prod_and_min_abs_sine2( &at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous, vMinSine );
4273 : :
4274 : : /*
4275 : : * Check for tetrahedral ambiguity -- leave it out for now
4276 : : */
4277 [ + - - + : 177 : if (fabs( triple_product ) > ZERO_FLOAT && ( min_sine > vMinSine || (fabs( min_sine ) > ZERO_FLOAT && ( n2DTetrahedralAmbiguity & T2D_OKAY )) )) /* djb-rwth: addressing LLVM warning */
- - - - ]
4278 : : {
4279 : : /* Even => sorted in correct order, Odd=>transposed */
4280 [ + + ]: 177 : parity = triple_product > 0.0 ? AB_PARITY_EVEN : AB_PARITY_ODD;
4281 : : /* if ( num_explicit_H && at[cur_at].removed_H_parity % 2 ) */
4282 : : /* odd transposition of the removed implicit H */
4283 : : /* out_at[cur_at].parity = 3 - out_at[cur_at].parity; */
4284 : :
4285 : : /* moved; see below */
4286 : : /* out_at[cur_at].bAmbiguousStereo |= bAmbiguous; */
4287 : : /* at[cur_at].bAmbiguousStereo |= bAmbiguous; */
4288 : :
4289 : : /* for 4 attached atoms, moving the implicit H from index=3 to index=0 */
4290 : : /* can be done in odd number (3) transpositions: (23)(12)(01), which inverts the parity */
4291 [ + - ]: 177 : if (j1 == MAX_NUM_STEREO_ATOM_NEIGH - 1)
4292 : : {
4293 : 177 : parity = 3 - parity;
4294 : : }
4295 : : }
4296 : : else
4297 : : {
4298 : : #if (ALWAYS_SET_STEREO_PARITY == 1)
4299 : : parity = AT_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
4300 : : #else
4301 [ # # ]: 0 : if (num_z > 0)
4302 : : {
4303 : 0 : bAmbiguous |= AMBIGUOUS_STEREO;
4304 : : }
4305 : 0 : parity = AB_PARITY_UNDF; /* no parity: 4 bonds are in one plane. */
4306 : : #endif
4307 : : }
4308 : :
4309 : 810 : exit_function:
4310 : :
4311 [ + + ]: 810 : if (parity)
4312 : : {
4313 : 201 : out_at[cur_at].bAmbiguousStereo |= bAmbiguous;
4314 : 201 : at[cur_at].bAmbiguousStereo |= bAmbiguous;
4315 : : }
4316 : :
4317 : : /* Non-isotopic parity */
4318 [ + + + + ]: 810 : if (at[cur_at].num_H > 1 || parity <= 0)
4319 : : {
4320 : : ; /* no non-isotopic parity */
4321 : : }
4322 : : else
4323 : : {
4324 : 201 : out_at[cur_at].parity = parity;
4325 : : }
4326 : :
4327 : : /* isotopic parity */
4328 [ + - - + ]: 810 : if (parity == -AB_PARITY_UNDF || parity == -vABParityUnknown /*AB_PARITY_UNKN*/)
4329 : : {
4330 : 0 : parity = -parity;
4331 : : }
4332 [ - + ]: 810 : if (parity < 0)
4333 : : {
4334 : 0 : parity = AB_PARITY_NONE;
4335 : : }
4336 : 810 : out_at[cur_at].parity2 = parity;
4337 : :
4338 : 810 : parity = PARITY_VAL( out_at[cur_at].parity );
4339 [ + + + + ]: 810 : out_at[cur_at].stereo_atom_parity = ATOM_PARITY_WELL_DEF( parity ) ? AB_PARITY_CALC : parity;
4340 : 810 : parity = PARITY_VAL( out_at[cur_at].parity2 );
4341 [ + + + + ]: 810 : out_at[cur_at].stereo_atom_parity2 = ATOM_PARITY_WELL_DEF( parity ) ? AB_PARITY_CALC : parity;
4342 : : /*
4343 : : out_at[cur_at].parity2 = out_at[cur_at].parity; // save for stereo + isotopic canon.
4344 : : if ( out_at[cur_at].parity ) {
4345 : : if ( num_explicit_H > 1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 && num_explicit_H ) {
4346 : : // X H X
4347 : : // for example, >C< or >C-D
4348 : : // Y D Y
4349 : : // parity exists for stereo + isotopic atoms canonicalization only
4350 : : out_at[cur_at].parity = 0;
4351 : : }
4352 : : }
4353 : : returning 0 means this can be an adjacent to a stereogenic bond atom
4354 : : */
4355 : :
4356 : 810 : return (int) out_at[cur_at].parity2;
4357 : : }
4358 : : #undef ADD_EXPLICIT_HYDROGEN_NEIGH
4359 : : #undef ADD_EXPLICIT_LONE_PAIR_NEIGH
4360 : :
4361 : :
4362 : : /****************************************************************************/
4363 : 161 : int set_stereo_parity( CANON_GLOBALS *pCG,
4364 : : inp_ATOM* at,
4365 : : sp_ATOM* at_output,
4366 : : int num_at,
4367 : : int num_removed_H,
4368 : : int *nMaxNumStereoAtoms,
4369 : : int *nMaxNumStereoBonds,
4370 : : INCHI_MODE nMode,
4371 : : int bPointedEdgeStereo,
4372 : : int vABParityUnknown,
4373 : : int bLooseTSACheck,
4374 : : int bStereoAtZz )
4375 : : {
4376 : 161 : int num_3D_stereo_atoms = 0;
4377 : 161 : int num_stereo_bonds = 0; /* added to fix allene stereo bug reported for FClC=C=CFCl by Burt Leland - 2009-02-05 DT */
4378 : :
4379 : 161 : int i, is_stereo, num_stereo, max_stereo_atoms = 0, max_stereo_bonds = 0;
4380 : 161 : QUEUE *q = NULL;
4381 : 161 : AT_RANK *nAtomLevel = NULL;
4382 : 161 : S_CHAR *cSource = NULL;
4383 : 161 : AT_RANK min_sb_ring_size = 0;
4384 : :
4385 : : /**********************************************************
4386 : : *
4387 : : * Note: this parity reflects only relative positions of
4388 : : * the atoms-neighbors and their ordering in the
4389 : : * lists of neighbors.
4390 : : *
4391 : : * To obtain the actual parity, the parity of a number
4392 : : * of neighbors transpositions (to obtain a sorted
4393 : : * list of numbers assigned to the atoms) should be
4394 : : * added.
4395 : : *
4396 : : **********************************************************/
4397 : :
4398 : : /*********************************************************************************
4399 : :
4400 : : An example of parity=1 for stereogenic center, tetrahedral asymmetric atom
4401 : :
4402 : :
4403 : :
4404 : : (1)
4405 : : |
4406 : : |
4407 : : [C] |
4408 : : |
4409 : : (2)------(0)
4410 : : /
4411 : : /
4412 : : /
4413 : : /
4414 : : (3)
4415 : :
4416 : :
4417 : : Notation: (n) is a tetrahedral atom neighbor; n is an index of a neighbor in
4418 : : the central_at->neighbor[] array : neighbor atom number is central_at->neighbor[n].
4419 : :
4420 : : (0)-(1), (0)-(2), (0)-(3) are lines connecting atom [C] neighbors to neighbor (0)
4421 : : (0), (1) and (2) are in the plane
4422 : : (0)-(3) is directed from the plain to the viewer
4423 : : [C] is somewhere between (0), (1), (2), (3)
4424 : : Since (1)-(2)-(3) are in a clockwise order when looking from (0), parity is 2, or even;
4425 : : otherwise parity would be 1, or odd.
4426 : :
4427 : : **********************************************************************************
4428 : :
4429 : : Examples of a stereogenic bond.
4430 : :
4431 : : Notation: [atom number], (index of a neighbor):
4432 : : [1] and [2] are atoms connected by the stereogenic bond
4433 : : numbers in () are indexes of neighbors of [1] or [2].
4434 : : (12 x 16)z = z-component of [1]-[2] and [1]-[6] cross-product
4435 : :
4436 : : atom [1] atom [2]
4437 : : [8] [4] prod01 = (12 x 16)z < 0 prod01 = (21 x 24)z < 0
4438 : : \ / prod02 = (12 x 18)z > 0 prod02 = (21 x 25)z > 0
4439 : : (2) (1) 0 transpositions because 0 transpositions because
4440 : : \ / double bond is in 0 posit. double bond is in 0 position
4441 : : [1]==(0)(0)==[2] 0 = (prod01 > prod02) 0 = (prod01 > prod02)
4442 : : / \
4443 : : (1) (2) result: parity = 2, even result: parity=2, even
4444 : : / \
4445 : : [6] [5]
4446 : :
4447 : :
4448 : :
4449 : : atom [1] atom [2]
4450 : : [8] [5] prod01 = (12 x 18)z > 0 prod01 = (21 x 24)z > 0
4451 : : \ / prod02 = (12 x 16)z < 0 prod02 = (21 x 25)z < 0
4452 : : (0) (2) 2 transpositions to move 1 transposition to move
4453 : : \ / at [2] from 2 to 0 pos. at [1] from 1 to 0 position
4454 : : [1]==(2)(1)==[2] 1 = (prod01 > prod02) 1 = (prod01 > prod02)
4455 : : / \
4456 : : (1) (0) result: parity = (1+2) result: parity=(1+1)
4457 : : / \ 2-(1+2)%2 = 1, odd 2-(1+1)%2 = 2, even
4458 : : [6] [4]
4459 : :
4460 : :
4461 : : ***********************************************************************************
4462 : : Note: atoms' numbers [1], [2], [4],... are not used to calculate parity at this
4463 : : point. They will be used for each numbering in the canonicalization.
4464 : : Note: parity=3 for a stereo atom means entered undefined bond direction
4465 : : parity=4 for an atom means parity cannot be determined from the given geometry
4466 : : ***********************************************************************************/
4467 : :
4468 [ + - - + ]: 161 : if (!at_output || !at)
4469 : : {
4470 : 0 : return -1;
4471 : : }
4472 : :
4473 : : /* Clear stereo descriptors */
4474 [ + + ]: 971 : for (i = 0; i < num_at; i++)
4475 : : {
4476 : 810 : at_output[i].parity = 0;
4477 : 810 : at_output[i].parity2 = 0;
4478 : 810 : memset( &at_output[i].stereo_bond_neighbor[0], 0, sizeof( at_output[0].stereo_bond_neighbor ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4479 : 810 : memset( &at_output[i].stereo_bond_neighbor2[0], 0, sizeof( at_output[0].stereo_bond_neighbor2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4480 : 810 : memset( &at_output[i].stereo_bond_ord[0], 0, sizeof( at_output[0].stereo_bond_ord ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4481 : 810 : memset( &at_output[i].stereo_bond_ord2[0], 0, sizeof( at_output[0].stereo_bond_ord2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4482 : 810 : memset( &at_output[i].stereo_bond_z_prod[0], 0, sizeof( at_output[0].stereo_bond_z_prod ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4483 : 810 : memset( &at_output[i].stereo_bond_z_prod2[0], 0, sizeof( at_output[0].stereo_bond_z_prod2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4484 : 810 : memset( &at_output[i].stereo_bond_parity[0], 0, sizeof( at_output[0].stereo_bond_parity ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4485 : 810 : memset( &at_output[i].stereo_bond_parity2[0], 0, sizeof( at_output[0].stereo_bond_parity2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4486 : : }
4487 : :
4488 : : /* Estimate max numbers of stereo atoms and bonds if isotopic H are added */
4489 [ - + - - ]: 161 : if (nMaxNumStereoAtoms || nMaxNumStereoBonds)
4490 : : {
4491 [ + + ]: 971 : for (i = 0; i < num_at; i++) /* djb-rwth: removing redundant code */
4492 : : {
4493 : : int num;
4494 : 810 : num = can_be_a_stereo_atom_with_isotopic_H( at, i, bPointedEdgeStereo, bStereoAtZz );
4495 [ + + ]: 810 : if (num)
4496 : : {
4497 : 406 : max_stereo_atoms += num;
4498 : : }
4499 : : else
4500 : : {
4501 [ + + ]: 404 : if (( num = can_be_a_stereo_bond_with_isotopic_H( at, i, nMode ) ))
4502 : : {
4503 : : /* accept cumulenes */
4504 : 36 : max_stereo_bonds += num;
4505 : : }
4506 : : }
4507 : : }
4508 [ + - ]: 161 : if (nMaxNumStereoAtoms)
4509 : : {
4510 : 161 : *nMaxNumStereoAtoms = max_stereo_atoms;
4511 : : }
4512 [ + - ]: 161 : if (nMaxNumStereoBonds)
4513 : : {
4514 : 161 : *nMaxNumStereoBonds = max_stereo_bonds;
4515 : : }
4516 : : }
4517 : :
4518 : : /* Calculate stereo descriptors */
4519 : : #if ( MIN_SB_RING_SIZE > 0 )
4520 : 161 : min_sb_ring_size = (AT_RANK) ( ( ( nMode & REQ_MODE_MIN_SB_RING_MASK ) >> REQ_MODE_MIN_SB_RING_SHFT ) & AT_RANK_MASK );
4521 [ + - ]: 161 : if (min_sb_ring_size >= 3)
4522 : : {
4523 : : /* Create BFS data structure for finding for each stereo bond its min. ring sizes */
4524 : 161 : q = QueueCreate( num_at + 1, sizeof( qInt ) );
4525 : 161 : nAtomLevel = (AT_RANK*) inchi_calloc( num_at, sizeof( nAtomLevel[0] ) );
4526 : 161 : cSource = (S_CHAR *) inchi_calloc( num_at, sizeof( cSource[0] ) );
4527 [ + - + - : 161 : if (!q || !cSource || !nAtomLevel)
- + ]
4528 : : {
4529 : 0 : q = QueueDelete(q); /* djb-rwth: fixing coverity ID #499562 */
4530 [ # # ]: 0 : inchi_free(nAtomLevel); /* djb-rwth: avoiding memory leak */
4531 [ # # ]: 0 : inchi_free(cSource); /* djb-rwth: avoiding memory leak */
4532 : 0 : num_3D_stereo_atoms = CT_OUT_OF_RAM;
4533 : 0 : goto exit_function;
4534 : : }
4535 : : }
4536 : : else
4537 : : {
4538 : 0 : min_sb_ring_size = 2;
4539 : : }
4540 : : #endif
4541 : :
4542 : : /* Main cycle: set stereo parities */
4543 [ + + ]: 971 : for (i = 0, num_stereo = 0; i < num_at; i++)
4544 : : {
4545 : 810 : is_stereo = set_stereo_atom_parity( pCG, at_output, at, i, at + num_at, num_removed_H,
4546 : : bPointedEdgeStereo, vABParityUnknown, bLooseTSACheck, bStereoAtZz );
4547 [ + + ]: 810 : if (is_stereo)
4548 : : {
4549 [ + - + + ]: 201 : num_3D_stereo_atoms += ATOM_PARITY_WELL_DEF( is_stereo );
4550 : : }
4551 : : else
4552 : : {
4553 : 609 : is_stereo = set_stereo_bonds_parity( at_output, at, i, at + num_at,
4554 : : num_removed_H, nMode,q,
4555 : : nAtomLevel, cSource,
4556 : : min_sb_ring_size,
4557 : : bPointedEdgeStereo,
4558 : : vABParityUnknown );
4559 [ + - - + ]: 609 : if (RETURNED_ERROR( is_stereo ))
4560 : : {
4561 : 0 : num_3D_stereo_atoms = is_stereo;
4562 : 0 : break;
4563 : : }
4564 : 609 : num_stereo_bonds += ( is_stereo != 0 ); /* added to fix bug reported by Burt Leland - 2009-02-05 DT */
4565 : : }
4566 : 810 : num_stereo += ( is_stereo != 0 );
4567 : : /* djb-rwth: removing redundant code */
4568 : : }
4569 : :
4570 : : /* Added to fix bug reported by Burt Leland - 2009-02-05 DT */
4571 [ - + - - ]: 161 : if (max_stereo_atoms < num_3D_stereo_atoms && nMaxNumStereoAtoms)
4572 : : {
4573 : 0 : *nMaxNumStereoAtoms = num_3D_stereo_atoms;
4574 : : }
4575 [ - + - - ]: 161 : if (max_stereo_bonds < num_stereo_bonds && nMaxNumStereoBonds)
4576 : : {
4577 : 0 : *nMaxNumStereoBonds = num_stereo_bonds;
4578 : : }
4579 : :
4580 : : /*
4581 : : if ( (nMode & REQ_MODE_SC_IGN_ALL_UU )
4582 : : REQ_MODE_SC_IGN_ALL_UU
4583 : : REQ_MODE_SB_IGN_ALL_UU
4584 : : */
4585 : :
4586 : : #if ( MIN_SB_RING_SIZE > 0 )
4587 [ + - ]: 161 : if (q)
4588 : : {
4589 : 161 : q = QueueDelete( q ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4590 : : }
4591 [ + - ]: 161 : if (nAtomLevel)
4592 : : {
4593 [ + - ]: 161 : inchi_free( nAtomLevel );
4594 : : }
4595 [ - + ]: 161 : if (cSource)
4596 : : {
4597 [ - + ]: 161 : inchi_free( cSource );
4598 : : }
4599 : :
4600 : 0 : exit_function:
4601 : : #endif
4602 : :
4603 : 161 : return num_3D_stereo_atoms;
4604 : : }
4605 : :
4606 : :
4607 : : /*****************************************************************
4608 : : * Functions that disconnect bonds
4609 : : *
4610 : : *=== During Preprocessing ===
4611 : : *
4612 : : * RemoveInpAtBond
4613 : : * DisconnectMetalSalt (is not aware of bond parities)
4614 : : * DisconnectAmmoniumSalt
4615 : : *
4616 : : *=== Before Normalization ===
4617 : : *
4618 : : * remove_terminal_HDT
4619 : : *
4620 : : *=== During the Normalization ===
4621 : : *
4622 : : * AddOrRemoveExplOrImplH
4623 : : *
4624 : : *****************************************************************/
4625 : :
4626 : :
4627 : : /****************************************************************************/
4628 : 4 : int ReconcileAllCmlBondParities( inp_ATOM *at,
4629 : : int num_atoms,
4630 : : int bDisconnected )
4631 : : {
4632 : 4 : int i, ret = 0;
4633 : 4 : S_CHAR *visited = (S_CHAR*) inchi_calloc( num_atoms, sizeof( *visited ) );
4634 [ - + ]: 4 : if (!visited)
4635 : : {
4636 : 0 : return -1; /* out of RAM */
4637 : : }
4638 [ + + ]: 29 : for (i = 0; i < num_atoms; i++)
4639 : : {
4640 [ - + - - : 25 : if (at[i].sb_parity[0] && !visited[i] && !( bDisconnected && is_el_a_metal( at[i].el_number ) ))
- - - - ]
4641 : : {
4642 [ # # ]: 0 : if ((ret = ReconcileCmlIncidentBondParities( at, i, -1, visited, bDisconnected ))) /* djb-rwth: addressing LLVM warning */
4643 : : {
4644 : 0 : break; /* error */
4645 : : }
4646 : : }
4647 : : }
4648 [ + - ]: 4 : inchi_free( visited );
4649 : :
4650 : 4 : return ret;
4651 : : }
4652 : :
4653 : :
4654 : : /****************************************************************************/
4655 : 0 : int ReconcileCmlIncidentBondParities( inp_ATOM *at,
4656 : : int cur_atom,
4657 : : int prev_atom,
4658 : : S_CHAR *visited,
4659 : : int bDisconnected )
4660 : : {
4661 : : /* visited = 0 or parity => atom has not been visited
4662 : : 10 + parity => currently is on the stack + its final parity
4663 : : 20 + parity => has been visited; is not on the stack anymore + its final parity */
4664 : 0 : int i, j, nxt_atom, ret = 0, len;
4665 : : int icur2nxt, icur2neigh; /* cur atom neighbors */
4666 : : int inxt2cur, inxt2neigh; /* next atom neighbors */
4667 : : int cur_parity, nxt_parity;
4668 : : int cur_order_parity, nxt_order_parity, cur_sb_parity, nxt_sb_parity, bCurMask, bNxtMask;
4669 : : /* !(bDisconnected && is_el_a_metal(at[i].el_number) */
4670 : :
4671 [ # # ]: 0 : if (at[cur_atom].valence > MAX_NUM_STEREO_BONDS)
4672 : : {
4673 : 0 : return 0; /* ignore */
4674 : : }
4675 : :
4676 [ # # ]: 0 : if (!at[cur_atom].sb_parity[0])
4677 : : {
4678 : 0 : return 1; /* wrong call */
4679 : : }
4680 : :
4681 [ # # ]: 0 : if (visited[cur_atom] >= 10)
4682 : : {
4683 : 0 : return 2; /* program error */
4684 : : }
4685 : :
4686 : 0 : cur_parity = visited[cur_atom] % 10;
4687 : :
4688 : 0 : visited[cur_atom] += 10;
4689 : :
4690 [ # # # # ]: 0 : for (i = 0; i < MAX_NUM_STEREO_BONDS && at[cur_atom].sb_parity[i]; i++)
4691 : : {
4692 : 0 : icur2nxt = (int) at[cur_atom].sb_ord[i];
4693 : 0 : len = get_opposite_sb_atom( at, cur_atom, icur2nxt, &nxt_atom, &inxt2cur, &j );
4694 [ # # ]: 0 : if (!len)
4695 : : {
4696 : 0 : return 4; /* could not find the opposite atom: bond parity data error */
4697 : : }
4698 [ # # ]: 0 : if (nxt_atom == prev_atom)
4699 : : {
4700 : 0 : continue;
4701 : : }
4702 [ # # ]: 0 : if (visited[nxt_atom] >= 20)
4703 : : {
4704 : 0 : continue; /* back edge, second visit: ignore */
4705 : : }
4706 [ # # ]: 0 : if (at[nxt_atom].valence > MAX_NUM_STEREO_BONDS)
4707 : : {
4708 : 0 : continue; /* may be treated only after metal disconnection */
4709 : : }
4710 : :
4711 [ # # # # ]: 0 : if (bDisconnected && ( at[cur_atom].sb_parity[i] & SB_PARITY_FLAG ))
4712 : : {
4713 : 0 : cur_sb_parity = ( at[cur_atom].sb_parity[i] >> SB_PARITY_SHFT );
4714 : 0 : bCurMask = 3 << SB_PARITY_SHFT;
4715 : : }
4716 : : else
4717 : : {
4718 : 0 : cur_sb_parity = ( at[cur_atom].sb_parity[i] & SB_PARITY_MASK );
4719 : 0 : bCurMask = 3;
4720 : : }
4721 [ # # # # ]: 0 : if (bDisconnected && ( at[nxt_atom].sb_parity[j] & SB_PARITY_FLAG ))
4722 : : {
4723 : 0 : nxt_sb_parity = ( at[nxt_atom].sb_parity[j] >> SB_PARITY_SHFT );
4724 : 0 : bNxtMask = 3 << SB_PARITY_SHFT;
4725 : : }
4726 : : else
4727 : : {
4728 : 0 : nxt_sb_parity = ( at[nxt_atom].sb_parity[j] & SB_PARITY_MASK );
4729 : 0 : bNxtMask = 3;
4730 : : }
4731 : :
4732 [ # # # # : 0 : if (!ATOM_PARITY_WELL_DEF( cur_sb_parity ) ||
# # ]
4733 [ # # ]: 0 : !ATOM_PARITY_WELL_DEF( nxt_sb_parity ))
4734 : : {
4735 [ # # ]: 0 : if (cur_sb_parity == nxt_sb_parity)
4736 : : {
4737 : 0 : continue;
4738 : : /* goto move_forward; */
4739 : : /* bypass unknown/undefined */
4740 : : }
4741 : 0 : return 3; /* sb parities do not match: bond parity data error */
4742 : : }
4743 : :
4744 : 0 : icur2neigh = (int) at[cur_atom].sn_ord[i];
4745 : 0 : inxt2neigh = (int) at[nxt_atom].sn_ord[j];
4746 : : /* Parity of at[cur_atom].neighbor[] premutation to reach this order: { next_atom, neigh_atom, ...} */
4747 : :
4748 : : /* 1. move next_atom from position=icur2nxt to position=0 =>
4749 : : * icur2nxt permutations
4750 : : * 2. move neigh_atom from position=inxt2neigh+(inxt2cur > inxt2neigh) to position=1 =>
4751 : : * inxt2neigh+(inxt2cur > inxt2neigh)-1 permutations.
4752 : : * Note if (inxt2cur > inxt2neigh) then move #1 increments neigh_atom position
4753 : : * Note add 4 because icur2neigh may be negative due to isotopic H removal
4754 : : */
4755 : 0 : cur_order_parity = ( 4 + icur2nxt + icur2neigh + ( icur2neigh > icur2nxt ) ) % 2;
4756 : :
4757 : : /* Same for next atom: */
4758 : : /* parity of at[nxt_atom].neighbor[] premutation to reach this order: { cur_atom, neigh_atom, ...} */
4759 : 0 : nxt_order_parity = ( 4 + inxt2cur + inxt2neigh + ( inxt2neigh > inxt2cur ) ) % 2;
4760 : 0 : nxt_parity = visited[nxt_atom] % 10;
4761 : :
4762 [ # # ]: 0 : if (!cur_parity)
4763 : : {
4764 : 0 : cur_parity = 2 - ( cur_order_parity + cur_sb_parity ) % 2;
4765 : 0 : visited[cur_atom] += cur_parity;
4766 : : }
4767 : : else
4768 : : {
4769 [ # # ]: 0 : if (cur_parity != 2 - ( cur_order_parity + cur_sb_parity ) % 2)
4770 : : {
4771 : : /***** Reconcile bond parities *****/
4772 : :
4773 : : /* Each bond parity is split into two values located at the end atoms.
4774 : : For T (trans) the values are (1,1) or (2,2)
4775 : : For C (cis) the values are (1,2) or (2,1)
4776 : : The fact that one pair = another with inverted parities, namely
4777 : : Inv(1,1) = (2,2) and Inv(1,2) = (2,1), allows to
4778 : : simultaneouly invert parities of the current bond end atoms
4779 : : (at[cur_atom].sb_parity[i], at[nxt_atom].sb_parity[j])
4780 : : so that the final current atom parity cur_parity
4781 : : calculated later in stereochemical canonicalization for
4782 : : each stereobond incident with the current atomis same.
4783 : : Achieving this is called here RECONCILIATION.
4784 : : If at the closure of an aromatic circuit the parities of
4785 : : next atom cannot be reconciled with already calculated then
4786 : : this function returns 5 (error).
4787 : : */
4788 : 0 : at[cur_atom].sb_parity[i] ^= bCurMask;
4789 : 0 : at[nxt_atom].sb_parity[j] ^= bNxtMask;
4790 : : /* djb-rwth: removing redundant code */
4791 : 0 : nxt_sb_parity ^= 3;
4792 : : }
4793 : : }
4794 : :
4795 [ # # ]: 0 : if (!nxt_parity)
4796 : : {
4797 : 0 : nxt_parity = 2 - ( nxt_order_parity + nxt_sb_parity ) % 2;
4798 : 0 : visited[nxt_atom] += nxt_parity;
4799 : : }
4800 : : else
4801 : : {
4802 [ # # ]: 0 : if (nxt_parity != 2 - ( nxt_order_parity + nxt_sb_parity ) % 2)
4803 : : {
4804 : 0 : return 5; /* algorithm does not work for Mebius-like structures */
4805 : : }
4806 : : }
4807 : :
4808 : : /* Move_forward: */
4809 [ # # ]: 0 : if (visited[nxt_atom] < 10)
4810 : : {
4811 : 0 : ret = ReconcileCmlIncidentBondParities( at, nxt_atom, cur_atom, visited, bDisconnected );
4812 [ # # ]: 0 : if (ret)
4813 : : {
4814 : 0 : break;
4815 : : }
4816 : : }
4817 : : }
4818 : 0 : visited[cur_atom] += 10; /* all bonds incident to the current atom have
4819 : : been processed or an error occurred. */
4820 : :
4821 : 0 : return ret;
4822 : : }
4823 : :
4824 : :
4825 : : /****************************************************************************/
4826 : 0 : int get_opposite_sb_atom( inp_ATOM *at,
4827 : : int cur_atom,
4828 : : int icur2nxt,
4829 : : int *pnxt_atom,
4830 : : int *pinxt2cur,
4831 : : int *pinxt_sb_parity_ord )
4832 : : {
4833 : : AT_NUMB nxt_atom;
4834 : : int j, len;
4835 : :
4836 : 0 : len = 0;
4837 [ # # ]: 0 : while (len++ < 20)
4838 : : {
4839 : : /* Arbitrarily set cumulene length limit to avoid infinite loop */
4840 : 0 : nxt_atom = at[cur_atom].neighbor[icur2nxt];
4841 [ # # # # ]: 0 : for (j = 0; j < MAX_NUM_STEREO_BONDS && at[nxt_atom].sb_parity[j]; j++)
4842 : : {
4843 [ # # ]: 0 : if (cur_atom == at[nxt_atom].neighbor[(int) at[nxt_atom].sb_ord[j]])
4844 : : {
4845 : : /* Found the opposite atom */
4846 : 0 : *pnxt_atom = nxt_atom;
4847 : 0 : *pinxt2cur = at[nxt_atom].sb_ord[j];
4848 : 0 : *pinxt_sb_parity_ord = j;
4849 : 0 : return len;
4850 : : }
4851 : : }
4852 [ # # ]: 0 : if (j)
4853 : : {
4854 : 0 : return 0; /* reached atom(s) with stereobond (sb) parity, the opposite atom has not been found */
4855 : : }
4856 [ # # # # ]: 0 : if (at[nxt_atom].valence == 2 && 2 * BOND_TYPE_DOUBLE == at[nxt_atom].chem_bonds_valence)
4857 : : {
4858 : : /* Follow cumulene =X= path */
4859 : 0 : icur2nxt = ( at[nxt_atom].neighbor[0] == cur_atom );
4860 : 0 : cur_atom = nxt_atom;
4861 : : }
4862 : : else
4863 : : {
4864 : 0 : return 0; /* neither atom with a sb parity not middle cumulene could be reached */
4865 : : }
4866 : : }
4867 : :
4868 : 0 : return 0; /* too long chain of cumulene was found */
4869 : : }
|