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