rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,3538 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <math.h>
13
+ #include <string.h>
14
+
15
+ #include "mode.h"
16
+
17
+ #include "ichierr.h"
18
+ #include "inpdef.h"
19
+ #include "extr_ct.h"
20
+ #include "ichister.h"
21
+ #include "ichiring.h"
22
+ #include "ichi.h"
23
+
24
+ #include "ichicomp.h"
25
+ #include "util.h"
26
+
27
+ #define ZTYPE_DOWN (-1) /* should be equal to -ZTYPE_UP */
28
+ #define ZTYPE_NONE 0
29
+ #define ZTYPE_UP 1 /* should be equal to -ZTYPE_DOWN */
30
+ #define ZTYPE_3D 3
31
+ #define ZTYPE_EITHER 9999
32
+
33
+ /* criteria for ill-defined */
34
+ #define MIN_ANGLE 0.10 /* 5.73 degrees */
35
+ #define MIN_SINE 0.03 /* min edge/plane angle in case the tetrahedra has significantly different edge length */
36
+ #define MIN_ANGLE_DBOND 0.087156 /* 5 degrees = max angle considered as too small for unambiguous double bond stereo */
37
+ #define MIN_SINE_OUTSIDE 0.06 /* min edge/plane angle to determine whether the central atom is outside of the tetrahedra */
38
+ #define MIN_SINE_SQUARE 0.125 /* min edge/plane angle in case the tetrahedra is somewhat close to a parallelogram */
39
+ #define MIN_SINE_EDGE 0.167 /* min sine/(min.edge) ratio to avoid undefined in case of long edges */
40
+ #define MIN_LEN_STRAIGHT 1.900 /* min length of two normalized to 1 bonds in a straight line */
41
+ #define MAX_SINE 0.70710678118654752440084436210485 /* 1/sqrt(2)=sin(pi/4) */
42
+ #define MIN_BOND_LEN 0.000001
43
+ #define ZERO_LENGTH MIN_BOND_LEN
44
+ #define ZERO_FLOAT 1.0e-12
45
+ #define BOND_PARITY_UNDEFINED 64
46
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
47
+ #define MPY_SINE 1.00 /* was 3.0 */
48
+ #define MAX_EDGE_RATIO 2.50 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
49
+ #else
50
+ #define MPY_SINE 3.00
51
+ #define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
52
+ #endif
53
+ /* local prototypes */
54
+ int save_a_stereo_bond( int z_prod, int result_action,
55
+ 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,
56
+ 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 );
57
+ double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
58
+ double len3( const double c[] );
59
+ double len2( const double c[] );
60
+ double* diff3( const double a[], const double b[], double result[] );
61
+ double* add3( const double a[], const double b[], double result[] );
62
+ double* mult3( const double a[], double b, double result[] );
63
+ double* copy3( const double a[], double result[] );
64
+ double* change_sign3( const double a[], double result[] );
65
+ double dot_prod3( const double a[], const double b[] );
66
+ int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
67
+ double* cross_prod3( const double a[], const double b[], double result[] );
68
+ double triple_prod( double a[], double b[], double c[], double *sine_value );
69
+ double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
70
+ double sp3_triple_prod_and_min_abs_sine(double at_coord[][3], double central_at_coord[], double *min_sine, int *bAmbiguous);
71
+ int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
72
+ int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
73
+ int at_2, int i_next_at_2, S_CHAR *z_dir2 );
74
+
75
+ int CompDble( const void *a1, const void *a2 );
76
+ int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor );
77
+ double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
78
+ int are_4at_in_one_plane( double at_coord[][3], double min_sine);
79
+ int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds );
80
+ int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical );
81
+ int bIsSuitableHeteroInpAtom( inp_ATOM *at );
82
+ int bIsOxide( inp_ATOM *at, int cur_at );
83
+ int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo );
84
+ int get_allowed_stereo_bond_type( int bond_type );
85
+ int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode );
86
+ int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic );
87
+ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
88
+ INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo );
89
+ int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at );
90
+ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, int bPointedEdgeStereo );
91
+ /*
92
+ int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_removed_H,
93
+ int *nMaxNumStereoAtoms, int *nMaxNumStereoBonds, INCHI_MODE nMode, int bPointedEdgeStereo );
94
+ int get_opposite_sb_atom( inp_ATOM *at, int cur_atom, int icur2nxt, int *pnxt_atom, int *pinxt2cur, int *pinxt_sb_parity_ord );
95
+ */
96
+ int ReconcileCmlIncidentBondParities( inp_ATOM *at, int cur_atom, int prev_atom, S_CHAR *visited, int bDisconnected );
97
+ int comp_AT_NUMB( const void* a1, const void* a2);
98
+ int GetHalfStereobond0DParity( inp_ATOM *at, int cur_at, AT_NUMB nSbNeighOrigAtNumb[], int nNumExplictAttachments, int bond_parity, int nFlag );
99
+ int GetStereocenter0DParity( inp_ATOM *at, int cur_at, int j1, AT_NUMB nSbNeighOrigAtNumb[], int nFlag );
100
+ int GetSbNeighOrigAtNumb( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, AT_NUMB nSbNeighOrigAtNumb[]);
101
+ int FixSb0DParities( inp_ATOM *at, /* inp_ATOM *at_removed_H, int num_removed_H,*/ int chain_length,
102
+ 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
+ int *pparity1, int *pparity2 );
105
+
106
+ /******************************************************************/
107
+
108
+
109
+ static double *pDoubleForSort;
110
+
111
+ /**********************************************************************************/
112
+ int comp_AT_NUMB( const void* a1, const void* a2)
113
+ {
114
+ return (int)*(const AT_NUMB*)a1 - (int)*(const AT_NUMB*)a2;
115
+ }
116
+ /******************************************************************/
117
+ double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType, int bPointedEdgeStereo )
118
+ {
119
+ int stereo_value = at[cur_atom].bond_stereo[neigh_no];
120
+ int stereo_type = abs( stereo_value );
121
+ int neigh = (int)at[cur_atom].neighbor[neigh_no];
122
+ double z = at[neigh].z - at[cur_atom].z;
123
+ int bFlat;
124
+
125
+ if ( bFlat = (fabs(z) < ZERO_LENGTH) ) {
126
+ int i;
127
+ for ( i = 0; i < at[cur_atom].valence; i ++ ) {
128
+ if ( fabs(at[cur_atom].z - at[(int)at[cur_atom].neighbor[i]].z) > ZERO_LENGTH ) {
129
+ bFlat = 0;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+
135
+ if ( bFlat ) {
136
+ if ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) {
137
+ /* bPointedEdgeStereo > 0: define stereo from pointed end of the stereo bond only */
138
+ /* bPointedEdgeStereo < 0: define stereo from wide end of the stereo bond only (case of removed H) */
139
+ switch( stereo_type ) {
140
+ /* 1=Up (solid triangle), 6=Down (Dashed triangle), 4=Either (zigzag triangle) */
141
+ case 0: /* No stereo */
142
+ *nType = ZTYPE_NONE;
143
+ break;
144
+ case STEREO_SNGL_UP: /* 1= Up */
145
+ *nType = ZTYPE_UP;
146
+ break;
147
+ case STEREO_SNGL_EITHER: /* 4 = Either */
148
+ *nType = ZTYPE_EITHER;
149
+ break;
150
+ case STEREO_SNGL_DOWN: /* 6 = Down */
151
+ *nType = ZTYPE_DOWN;
152
+ break;
153
+ default:
154
+ *nType = ZTYPE_NONE; /* ignore unexpected values */
155
+ }
156
+ if ( stereo_value < 0 && (*nType == ZTYPE_DOWN || *nType == ZTYPE_UP) )
157
+ *nType = -*nType;
158
+ } else {
159
+ *nType = ZTYPE_NONE; /* no stereo */
160
+ }
161
+ } else
162
+ if ( stereo_type == STEREO_SNGL_EITHER &&
163
+ ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) ) {
164
+ *nType = ZTYPE_EITHER;
165
+ } else {
166
+ *nType = ZTYPE_3D;
167
+ }
168
+ return z;
169
+ }
170
+ /******************************************************************/
171
+ double len3( const double c[] )
172
+ {
173
+ return sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] );
174
+ }
175
+ /******************************************************************/
176
+ double len2( const double c[] )
177
+ {
178
+ return sqrt( c[0]*c[0] + c[1]*c[1] );
179
+ }
180
+ /******************************************************************/
181
+ double* diff3( const double a[], const double b[], double result[] )
182
+ {
183
+
184
+ result[0] = a[0] - b[0];
185
+ result[1] = a[1] - b[1];
186
+ result[2] = a[2] - b[2];
187
+
188
+ return result;
189
+ }
190
+ /******************************************************************/
191
+ double* add3( const double a[], const double b[], double result[] )
192
+ {
193
+ result[0] = a[0] + b[0];
194
+ result[1] = a[1] + b[1];
195
+ result[2] = a[2] + b[2];
196
+
197
+ return result;
198
+ }
199
+ /******************************************************************/
200
+ double* mult3( const double a[], double b, double result[] )
201
+ {
202
+ result[0] = a[0] * b;
203
+ result[1] = a[1] * b;
204
+ result[2] = a[2] * b;
205
+
206
+ return result;
207
+ }
208
+ /*************************************************************/
209
+ double* copy3( const double a[], double result[] )
210
+ {
211
+ result[0] = a[0];
212
+ result[1] = a[1];
213
+ result[2] = a[2];
214
+
215
+ return result;
216
+ }
217
+ /*************************************************************/
218
+ double* change_sign3( const double a[], double result[] )
219
+ {
220
+ result[0] = -a[0];
221
+ result[1] = -a[1];
222
+ result[2] = -a[2];
223
+
224
+ return result;
225
+ }
226
+ /*************************************************************/
227
+ double dot_prod3( const double a[], const double b[] )
228
+ {
229
+ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
230
+ }
231
+ /*************************************************************/
232
+ int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] )
233
+ {
234
+ int prod = ((int)a[0]*(int)b[0] + (int)a[1]*(int)b[1] + (int)a[2]*(int)b[2])/100;
235
+ if ( prod > 100 )
236
+ prod = 100;
237
+ else
238
+ if ( prod < -100 )
239
+ prod = -100;
240
+ return prod;
241
+ }
242
+ /*************************************************************/
243
+ double* cross_prod3( const double a[], const double b[], double result[] )
244
+ {
245
+ double tmp[3];
246
+
247
+ tmp[0] = (a[1]*b[2]-a[2]*b[1]);
248
+ tmp[1] = -(a[0]*b[2]-a[2]*b[0]);
249
+ tmp[2] = (a[0]*b[1]-a[1]*b[0]);
250
+
251
+ result[0] = tmp[0];
252
+ result[1] = tmp[1];
253
+ result[2] = tmp[2];
254
+
255
+ return result;
256
+ }
257
+ /*************************************************************/
258
+ double triple_prod( double a[], double b[], double c[], double *sine_value )
259
+ {
260
+ double ab[3], dot_prod_ab_c, abs_c, abs_ab;
261
+ cross_prod3( a, b, ab );
262
+ /* ab[0] = (a[1]*b[2]-a[2]*b[1]); */
263
+ /* ab[1] = -(a[0]*b[2]-a[2]*b[0]); */
264
+ /* ab[2] = (a[0]*b[1]-a[1]*b[0]); */
265
+ dot_prod_ab_c = dot_prod3( ab, c );
266
+ /* dot_prod_ab_c = ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2]; */
267
+ if ( sine_value ) {
268
+ abs_c = len3( c );
269
+ /* abs_c = sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ); */
270
+ abs_ab = len3( ab );
271
+ /* abs_ab = sqrt( ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2] ); */
272
+
273
+ if ( abs_c > 1.e-7 /* otherwise c has zero length */ && abs_ab > 1.e-7 /* otherwise a is parallel to b*/ ) {
274
+ *sine_value = MPY_SINE * dot_prod_ab_c / ( abs_c * abs_ab);
275
+ /* *sine_value = dot_prod_ab_c / ( abs_c * abs_ab); */
276
+ } else {
277
+ *sine_value = 0.0;
278
+ }
279
+ }
280
+ return dot_prod_ab_c;
281
+ }
282
+ /*************************************************************/
283
+ int CompDble( const void *a1, const void *a2 )
284
+ {
285
+ double diff = pDoubleForSort[*(const int*)a1] - pDoubleForSort[*(const int*)a2];
286
+ if ( diff > 0.0 )
287
+ return 1;
288
+ if ( diff < 0.0 )
289
+ return -1;
290
+ return 0;
291
+ }
292
+ /*************************************************************/
293
+ #define T2D_OKAY 1
294
+ #define T2D_WARN 2
295
+ #define T2D_UNDF 4
296
+ int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
297
+ {
298
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
299
+ const double two_pi = 2.0*one_pi;
300
+ const double dAngleAndPiMaxDiff = 2.0*atan2(1.0, sqrt(7.0)); /* min sine between 2 InPlane bonds */
301
+ int nBondType[MAX_NUM_STEREO_ATOM_NEIGH], nBondOrder[MAX_NUM_STEREO_ATOM_NEIGH];
302
+ double dBondDirection[MAX_NUM_STEREO_ATOM_NEIGH], dAngle, dAlpha, dLimit, dBisector;
303
+ int nNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH - (bAddExplicitNeighbor != 0);
304
+ int i, num_Up, num_Dn, bPrev_Up, cur_len_Up, cur_first_Up, len_Up, first_Up;
305
+ int ret;
306
+
307
+ ret = 0;
308
+ for ( i = 0, num_Up = num_Dn = 0; i < nNumNeigh; i ++ ) {
309
+ dAngle = atan2( at_coord[i][1], at_coord[i][0] ); /* range from -pi to +pi */
310
+ if ( dAngle < 0.0 ) {
311
+ dAngle += two_pi;
312
+ }
313
+ dBondDirection[i] = dAngle;
314
+ nBondType[i] = (at_coord[i][2] > 0.0)? 1 : (at_coord[i][2] < 0.0)? -1 : 0; /* z-coord sign */
315
+ if ( nBondType[i] > 0 ) {
316
+ num_Up ++;
317
+ } else
318
+ if ( nBondType[i] < 0 ) {
319
+ num_Dn ++;
320
+ }
321
+ nBondOrder[i] = i;
322
+ }
323
+ if ( num_Up < num_Dn ) {
324
+ for ( i = 0; i < nNumNeigh; i ++ ) {
325
+ nBondType[i] = -nBondType[i];
326
+ }
327
+ swap( (char*)&num_Dn, (char*)&num_Up, sizeof(num_Dn) );
328
+ }
329
+ if ( !num_Up ) {
330
+ return T2D_UNDF;
331
+ }
332
+ /* sort according to the bond orientations */
333
+ pDoubleForSort = dBondDirection;
334
+ insertions_sort( nBondOrder, nNumNeigh, sizeof(nBondOrder[0]), CompDble );
335
+
336
+ /* find the longest contiguous sequence of Up bonds */
337
+ if ( num_Up == nNumNeigh ) {
338
+ /* all bonds are Up */
339
+ len_Up = cur_len_Up = nNumNeigh; /* added cur_len_Up initialization 1/8/2002 */
340
+ first_Up = 0;
341
+ } else {
342
+ /* at least one bond is not Up */
343
+ cur_len_Up = len_Up = bPrev_Up = 0;
344
+ /* prev. cycle header version ---
345
+ for ( i = 0; 1; i ++ ) {
346
+ if ( i >= nNumNeigh && !bPrev_Up ) {
347
+ break;
348
+ }
349
+ ----------} */
350
+ /* look at all bonds and continue (circle therough the beginning) as long as the current bond is Up */
351
+ for ( i = 0; i < nNumNeigh || bPrev_Up; i ++ ) {
352
+ if ( nBondType[nBondOrder[i % nNumNeigh]] > 0 ) {
353
+ if ( bPrev_Up ) {
354
+ cur_len_Up ++; /* uncrement number of Up bonds in current contiguous sequence of them */
355
+ } else {
356
+ bPrev_Up = 1; /* start new contiguous sequence of Up bonds */
357
+ cur_len_Up = 1;
358
+ cur_first_Up = i % nNumNeigh;
359
+ }
360
+ } else
361
+ if ( bPrev_Up ) { /* end of contiguous sequence of Up bonds */
362
+ if ( cur_len_Up > len_Up ) {
363
+ first_Up = cur_first_Up; /* store the sequence because it is longer than the ptrvious one */
364
+ len_Up = cur_len_Up;
365
+ }
366
+ bPrev_Up = 0;
367
+ }
368
+ }
369
+ }
370
+ /* Turn all the bonds around the center so that */
371
+ /* the 1st Up bond has zero radian direction */
372
+ dAlpha = dBondDirection[nBondOrder[first_Up]];
373
+ for ( i = 0; i < nNumNeigh; i ++ ) {
374
+ if ( i == nBondOrder[first_Up] ) {
375
+ dBondDirection[i] = 0.0;
376
+ } else {
377
+ dAngle = dBondDirection[i] - dAlpha;
378
+ if ( dAngle < 0.0 ) {
379
+ dAngle += two_pi;
380
+ }
381
+ dBondDirection[i] = dAngle;
382
+ }
383
+ }
384
+
385
+ /********************************************************
386
+ * Process particular cases
387
+ ********************************************************/
388
+
389
+ switch( nNumNeigh ) {
390
+
391
+ /************************ 3 bonds ***********************
392
+ */
393
+ case 3:
394
+ switch( num_Up ) {
395
+ /* -------------------------- 0 Up ------------ */
396
+ case 0:
397
+ return T2D_UNDF;
398
+ /* -------------------------- 1 Up ------------ */
399
+ case 1:
400
+ if ( num_Dn ) {
401
+ #ifdef _DEBUG
402
+ if ( num_Dn != 1 ) /* debug only */
403
+ return -1;
404
+ #endif
405
+ ret = (T2D_UNDF | T2D_WARN);
406
+ } else {
407
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
408
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
409
+ if ( dAngle < 0.0 ) {
410
+ dAngle += two_pi;
411
+ }
412
+ if ( dAngle - one_pi < -MIN_ANGLE || dAngle - one_pi > MIN_ANGLE ) {
413
+ ret = T2D_OKAY;
414
+ } else {
415
+ ret = (T2D_UNDF | T2D_WARN);
416
+ }
417
+ }
418
+ break;
419
+ /* -------------------------- 2 Up ------------ */
420
+ case 2:
421
+ if ( num_Dn ) {
422
+ dAlpha = dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]] -
423
+ dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]];
424
+ if ( dAlpha < 0.0 ) {
425
+ dAlpha += two_pi;
426
+ }
427
+ if ( dAlpha > one_pi - MIN_ANGLE ) {
428
+ ret = T2D_OKAY;
429
+ } else
430
+ if ( dAlpha < two_pi / 3.0 - MIN_ANGLE ) {
431
+ ret = (T2D_UNDF | T2D_WARN);
432
+ } else {
433
+ /* angle between 2 Up bonds is between 120 and 180 degrees */
434
+ /* direction of the (Alpha angle bisector) + 180 degrees */
435
+ dBisector = (dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]] +
436
+ dBondDirection[nBondOrder[(first_Up + 1 ) % nNumNeigh]] ) / 2.0 - one_pi;
437
+ if ( dBisector < 0.0 ) {
438
+ dBisector += two_pi;
439
+ }
440
+ if ( dAlpha < two_pi / 3.0 + MIN_ANGLE ) {
441
+ /* dAlpha is inside ( 2pi/3 - eps, 2pi/3 + eps ) interval */
442
+ dLimit = MIN_ANGLE * 3.0 / 2.0;
443
+ } else {
444
+ dLimit = dAlpha * 3.0 / 2.0 - one_pi;
445
+ }
446
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2 ) % nNumNeigh]];
447
+ if ( dBisector - dAngle < -dLimit ||
448
+ dBisector - dAngle > dLimit ) {
449
+ ret = (T2D_UNDF | T2D_WARN);
450
+ } else {
451
+ ret = T2D_OKAY;
452
+ }
453
+ }
454
+ } else {
455
+ ret = T2D_OKAY;
456
+ }
457
+
458
+ break;
459
+ /* -------------------------- 3 Up ------------ */
460
+ case 3:
461
+ ret = T2D_OKAY;
462
+ break;
463
+ /* -------------------------- other Up -------- */
464
+ default:
465
+ return -1;
466
+
467
+ }
468
+
469
+ break;
470
+
471
+ /************************************** 4 bonds **************************
472
+ */
473
+ case 4:
474
+ switch( num_Up ) {
475
+ /* -------------------------- 0 Up ------------ */
476
+ case 0:
477
+ return T2D_UNDF;
478
+ /* -------------------------- 1 Up ------------ */
479
+ case 1:
480
+ if ( num_Dn ) {
481
+ if ( nBondType[nBondOrder[(first_Up + 2) % nNumNeigh]] < 0 ) {
482
+ /*
483
+ * Up, In Plane, Dn, In Plane. Undefined if angle between
484
+ * two In Plane bonds is wuthin pi +/- 2*arcsine(1/sqrt(8)) interval
485
+ * That is, 138.5 to 221.4 degrees; for certainty the interval is
486
+ * increased by 5.7 degrees at each end to
487
+ * 134.8 to 227.1 degrees
488
+ */
489
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
490
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
491
+ if ( dAngle < 0.0 ) {
492
+ dAngle += two_pi;
493
+ }
494
+ if ( fabs( dAngle - one_pi ) < dAngleAndPiMaxDiff + MIN_ANGLE ) {
495
+ ret = (T2D_UNDF | T2D_WARN);
496
+ } else {
497
+ ret = T2D_OKAY;
498
+ }
499
+ } else {
500
+ ret = T2D_OKAY;
501
+ }
502
+ #ifdef _DEBUG
503
+ if ( num_Dn != 1 ) /* debug only */
504
+ return -1;
505
+ #endif
506
+ } else {
507
+ ret = T2D_OKAY;
508
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
509
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
510
+ if ( dAngle < 0.0 ) {
511
+ dAngle += two_pi;
512
+ }
513
+ if ( dAngle < one_pi - MIN_ANGLE ) {
514
+ ret |= T2D_WARN;
515
+ }
516
+ }
517
+ break;
518
+ /* -------------------------- 2 Up ------------ */
519
+ case 2:
520
+ if ( cur_len_Up == 1 ) {
521
+ ret = T2D_OKAY;
522
+ } else {
523
+ ret = (T2D_UNDF | T2D_WARN);
524
+ }
525
+ break;
526
+ /* -------------------------- 3 Up ------------ */
527
+ case 3:
528
+ ret = T2D_OKAY;
529
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
530
+ dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
531
+ if ( dAngle < 0.0 ) {
532
+ dAngle += two_pi;
533
+ }
534
+ if ( dAngle < one_pi - MIN_ANGLE ) {
535
+ ret |= T2D_WARN;
536
+ }
537
+ break;
538
+ /* -------------------------- 4 Up ------------ */
539
+ case 4:
540
+ ret = (T2D_UNDF | T2D_WARN);
541
+ break;
542
+ /* -------------------------- other Up -------- */
543
+ default:
544
+ return -1; /* program error */
545
+ }
546
+
547
+ if ( ret == T2D_OKAY ) {
548
+ /* check whether all bonds are inside a less than 180 degrees sector */
549
+ for ( i = 0; i < nNumNeigh; i ++ ) {
550
+ dAngle = dBondDirection[nBondOrder[(i + nNumNeigh - 1) % nNumNeigh]] -
551
+ dBondDirection[nBondOrder[ i % nNumNeigh]];
552
+ if ( dAngle < 0.0 ) {
553
+ dAngle += two_pi;
554
+ }
555
+ if ( dAngle < one_pi - MIN_ANGLE ) {
556
+ ret |= T2D_WARN;
557
+ break;
558
+ }
559
+ }
560
+ }
561
+
562
+ break;
563
+ /*************************** other nuber of bonds ******************/
564
+ default:
565
+ return -1; /* error */
566
+ }
567
+
568
+ return ret;
569
+
570
+ }
571
+ /*************************************************************/
572
+ double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous)
573
+ {
574
+ double min_sine_value=9999.0, sine_value, min_edge_len, max_edge_len, min_edge_len_NoExplNeigh, max_edge_len_NoExplNeigh;
575
+ double s0, s1, s2, s3, e01, e02, e03, e12, e13, e23, tmp[3], e[3][3];
576
+ double prod, ret, central_prod[4];
577
+ int bLongEdges;
578
+
579
+ if ( !min_sine ) {
580
+ return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
581
+ }
582
+
583
+ ret = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
584
+ sine_value = MPY_SINE * fabs( sine_value );
585
+
586
+ diff3( at_coord[1], at_coord[0], e[2] );
587
+ diff3( at_coord[0], at_coord[2], e[1] );
588
+ diff3( at_coord[2], at_coord[1], e[0] );
589
+
590
+ /* lengths of the 6 edges of the tetrahedra */
591
+ e03 = len3( at_coord[0] ); /* 1 */
592
+ e13 = len3( at_coord[1] );
593
+ e23 = len3( at_coord[2] ); /* includes added neighbor if bAddedExplicitNeighbor*/
594
+ e02 = len3( e[1] ); /* includes added neighbor if bAddedExplicitNeighbor*/
595
+ e12 = len3( e[0] ); /* includes added neighbor if bAddedExplicitNeighbor*/
596
+ e01 = len3( e[2] );
597
+
598
+ /* min & max edge length */
599
+ max_edge_len =
600
+ min_edge_len = e03;
601
+
602
+ if ( min_edge_len > e13 )
603
+ min_edge_len = e13;
604
+ if ( min_edge_len > e01 )
605
+ min_edge_len = e01;
606
+ min_edge_len_NoExplNeigh = min_edge_len;
607
+
608
+ if ( min_edge_len > e23 )
609
+ min_edge_len = e23;
610
+ if ( min_edge_len > e02 )
611
+ min_edge_len = e02;
612
+ if ( min_edge_len > e12 )
613
+ min_edge_len = e12;
614
+
615
+ if ( max_edge_len < e13 )
616
+ max_edge_len = e13;
617
+ if ( max_edge_len < e01 )
618
+ max_edge_len = e01;
619
+ max_edge_len_NoExplNeigh = max_edge_len;
620
+
621
+ if ( max_edge_len < e23 )
622
+ max_edge_len = e23;
623
+ if ( max_edge_len < e02 )
624
+ max_edge_len = e02;
625
+ if ( max_edge_len < e12 )
626
+ max_edge_len = e12;
627
+
628
+ if ( !bAddedExplicitNeighbor ) {
629
+ min_edge_len_NoExplNeigh = min_edge_len;
630
+ max_edge_len_NoExplNeigh = max_edge_len;
631
+ }
632
+
633
+ bLongEdges = bAddedExplicitNeighbor?
634
+ ( max_edge_len_NoExplNeigh < MAX_EDGE_RATIO * min_edge_len_NoExplNeigh ) :
635
+ ( max_edge_len < MAX_EDGE_RATIO * min_edge_len );
636
+
637
+ if ( sine_value > MIN_SINE && ( min_sine || bAmbiguous ) ) {
638
+ if ( min_sine ) {
639
+ prod = fabs( ret );
640
+ /* tetrahedra height = volume(prod) / area of a plane(cross_prod) */
641
+ /* (instead of a tetrahedra calculate parallelogram/parallelepiped area/volume) */
642
+
643
+ /* 4 heights from each of the 4 vertices to the opposite plane */
644
+ s0 = prod / len3( cross_prod3( at_coord[1], at_coord[2], tmp ) );
645
+ s1 = prod / len3( cross_prod3( at_coord[0], at_coord[2], tmp ) );
646
+ s2 = prod / len3( cross_prod3( at_coord[0], at_coord[1], tmp ) );
647
+ s3 = prod / len3( cross_prod3( e[0], e[1], tmp ) );
648
+ /* abs. value of a sine of an angle between each tetrahedra edge and plane */
649
+ /* sine = height / edge length */
650
+ if ( (sine_value = s0/e01) < min_sine_value )
651
+ min_sine_value = sine_value;
652
+ if ( (sine_value = s0/e02) < min_sine_value )
653
+ min_sine_value = sine_value;
654
+ if ( (sine_value = s0/e03) < min_sine_value )
655
+ min_sine_value = sine_value;
656
+
657
+ if ( (sine_value = s1/e01) < min_sine_value )
658
+ min_sine_value = sine_value;
659
+ if ( (sine_value = s1/e12) < min_sine_value )
660
+ min_sine_value = sine_value;
661
+ if ( (sine_value = s1/e13) < min_sine_value )
662
+ min_sine_value = sine_value;
663
+
664
+ if ( (sine_value = s2/e02) < min_sine_value )
665
+ min_sine_value = sine_value;
666
+ if ( (sine_value = s2/e12) < min_sine_value )
667
+ min_sine_value = sine_value;
668
+ if ( (sine_value = s2/e23) < min_sine_value )
669
+ min_sine_value = sine_value;
670
+
671
+ if ( (sine_value = s3/e03) < min_sine_value )
672
+ min_sine_value = sine_value;
673
+ if ( (sine_value = s3/e13) < min_sine_value )
674
+ min_sine_value = sine_value;
675
+ if ( (sine_value = s3/e23) < min_sine_value )
676
+ min_sine_value = sine_value;
677
+ /* actually use triple sine */
678
+ *min_sine = sine_value = MPY_SINE * min_sine_value;
679
+ }
680
+
681
+ if ( bAmbiguous && sine_value >= MIN_SINE ) {
682
+ /* check whether the central atom is outside the tetrahedra (0,0,0), at_coord[0,1,2] */
683
+ /* compare the tetrahedra volume and the volume of a tetrahedra having central_at_coord[] vertex */
684
+ int i;
685
+ diff3( central_at_coord, at_coord[0], tmp );
686
+ central_prod[0] = triple_prod( at_coord[0], at_coord[1], central_at_coord, NULL );
687
+ central_prod[1] = triple_prod( at_coord[1], at_coord[2], central_at_coord, NULL );
688
+ central_prod[2] = triple_prod( at_coord[2], at_coord[0], central_at_coord, NULL );
689
+ central_prod[3] = triple_prod( e[2], e[1], tmp, NULL );
690
+ for ( i = 0; i <= 3; i ++ ) {
691
+ if ( central_prod[i] / ret < -MIN_SINE_OUTSIDE ) {
692
+ *bAmbiguous |= AMBIGUOUS_STEREO;
693
+ break;
694
+ }
695
+ }
696
+ }
697
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
698
+
699
+ if ( bLongEdges && !bAddedExplicitNeighbor && max_edge_len >= MIN_LEN_STRAIGHT ) {
700
+ /* possible planar tetragon */
701
+ if ( sine_value < MIN_SINE_SQUARE ) {
702
+ *min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
703
+ if ( bAmbiguous && !*bAmbiguous ) {
704
+ *bAmbiguous |= AMBIGUOUS_STEREO;
705
+ }
706
+ }
707
+ }
708
+
709
+ if ( bLongEdges && sine_value < MIN_SINE_SQUARE && sine_value < MIN_SINE_EDGE * min_edge_len_NoExplNeigh ) {
710
+ *min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
711
+ if ( bAmbiguous && !*bAmbiguous ) {
712
+ *bAmbiguous |= AMBIGUOUS_STEREO;
713
+ }
714
+ }
715
+ #endif
716
+
717
+ } else
718
+ if ( min_sine ) {
719
+ *min_sine = sine_value;
720
+ }
721
+
722
+ return ret;
723
+ }
724
+ /*************************************************************/
725
+ double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine)
726
+ {
727
+ double min_sine_value=9999.0, sine_value;
728
+ double prod=0.0;
729
+
730
+ if ( !min_sine ) {
731
+ return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
732
+ }
733
+
734
+ prod = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
735
+ sine_value = fabs( sine_value );
736
+ min_sine_value = inchi_min( min_sine_value, sine_value );
737
+
738
+ prod = triple_prod( at_coord[1], at_coord[2], at_coord[0], &sine_value );
739
+ sine_value = fabs( sine_value );
740
+ min_sine_value = inchi_min( min_sine_value, sine_value );
741
+
742
+ prod = triple_prod( at_coord[2], at_coord[0], at_coord[1], &sine_value );
743
+ sine_value = fabs( sine_value );
744
+ min_sine_value = inchi_min( min_sine_value, sine_value );
745
+
746
+ *min_sine = min_sine_value;
747
+
748
+ return prod;
749
+ }
750
+ /*************************************************************/
751
+ /* Find if point (0,0,0)a and 3 atoms are in one plane */
752
+ int are_3_vect_in_one_plane( double at_coord[][3], double min_sine)
753
+ {
754
+ double actual_min_sine;
755
+ double prod;
756
+ prod = triple_prod_and_min_abs_sine( at_coord, &actual_min_sine);
757
+ return actual_min_sine <= min_sine;
758
+ }
759
+ /*************************************************************/
760
+ /* Find if 4 atoms are in one plane */
761
+ int are_4at_in_one_plane( double at_coord[][3], double min_sine)
762
+ {
763
+ double actual_min_sine, min_actual_min_sine;
764
+ double coord[3][3], prod;
765
+ int i, k, j;
766
+ for ( k = 0; k < 4; k ++ ) { /* cycle added 4004-08-15 */
767
+ for ( i = j = 0; i < 4; i ++ ) {
768
+ if ( i != k ) {
769
+ diff3( at_coord[i], at_coord[k], coord[j] );
770
+ j ++;
771
+ }
772
+ }
773
+ prod = triple_prod_and_min_abs_sine( coord, &actual_min_sine);
774
+ if ( !k || actual_min_sine < min_actual_min_sine ) {
775
+ min_actual_min_sine = actual_min_sine;
776
+ }
777
+ }
778
+ return min_actual_min_sine <= min_sine;
779
+ }
780
+ /*************************************************************/
781
+ int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
782
+ int at_2, int i_next_at_2, S_CHAR *z_dir2 )
783
+ {
784
+ inp_ATOM *at1, *at2;
785
+ double pnt[3][3], len;
786
+ int i;
787
+ int ret = 0;
788
+
789
+ at1 = at + at_1;
790
+ at2 = at + at[at_1].neighbor[i_next_at_1];
791
+
792
+ pnt[0][0] = at2->x - at1->x;
793
+ pnt[0][1] = at2->y - at1->y;
794
+ pnt[0][2] = at2->z - at1->z;
795
+
796
+ at2 = at + at_2;
797
+ at1 = at + at[at_2].neighbor[i_next_at_2];
798
+
799
+ pnt[1][0] = at2->x - at1->x;
800
+ pnt[1][1] = at2->y - at1->y;
801
+ pnt[1][2] = at2->z - at1->z;
802
+ /*
803
+ * resultant pnt vector directions:
804
+ *
805
+ * pnt[0] pnt[1]
806
+ *
807
+ * [at_1]---->[...] [...]---->[at_2]
808
+ *
809
+ *
810
+ * add3 below: (pnt[0] + pnt[1]) -> pnt[1]
811
+ */
812
+ add3( pnt[0], pnt[1], pnt[1] );
813
+
814
+
815
+
816
+ for ( i = 0; i < 3; i ++ ) {
817
+ pnt[0][i] = (double)z_dir1[i];
818
+ pnt[2][i] = (double)z_dir2[i];
819
+ }
820
+ for ( i = 0; i < 3; i ++ ) {
821
+ len = len3( pnt[i] );
822
+ if ( len < MIN_BOND_LEN ) {
823
+ if ( i == 1 && (at[at_1].bUsed0DParity || at[at_2].bUsed0DParity) ) {
824
+ pnt[i][0] = 0.0;
825
+ pnt[i][1] = 1.0;
826
+ pnt[i][2] = 0.0;
827
+ len = 1.0; /* standard at_1-->at_2 vector coordinates in case of 0D allene */
828
+ } else {
829
+ goto exit_function; /* too short bond */
830
+ }
831
+ }
832
+ mult3( pnt[i], 1.0/len, pnt[i] );
833
+ }
834
+ len = 100.0*triple_prod(pnt[0], pnt[1], pnt[2], NULL );
835
+ /*
836
+ * ^ pnt[0]
837
+ * | The orientation on this diagram
838
+ * | produces len = -100
839
+ * [at_1]------>[at_2]
840
+ * pnt[1] /
841
+ * /
842
+ * / pnt[2] (up from the plane)
843
+ * v
844
+ *
845
+ * Note: len is invariant upon at_1 <--> at_2 transposition because
846
+ * triple product changes sign upon pnt[0]<-->pnt[2] transposition and
847
+ * triple product changes sign upon pnt[1]--> -pnt[1] change of direction:
848
+ *
849
+ * triple_prod(pnt[0], pnt[1], pnt[2], NULL ) =
850
+ * triple_prod(pnt[2], -pnt[1], pnt[0], NULL )
851
+ *
852
+ */
853
+
854
+ ret = len >= 0.0? (int)floor(len+0.5) : -(int)floor(0.5-len);
855
+
856
+ exit_function:
857
+
858
+ return ret;
859
+ }
860
+
861
+
862
+ /****************************************************************/
863
+
864
+ #if( NEW_STEREOCENTER_CHECK == 1 ) /* { */
865
+
866
+ /********************************************************************************************/
867
+ int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds )
868
+ {
869
+ /* RequirdNeighType:
870
+ reqired neighbor types (bitmap):
871
+ 0 => any neighbors
872
+ 1 => no terminal hydrogen atom neighbors
873
+ 2 => no terminal -X and -XH together (don't care about -X, -XH bond type, charge, radical)
874
+ (X = tautomeric endpoint atom)
875
+ NumDbleBonds:
876
+ if non-zero then allow double, alternating and tautomeric bonds
877
+ */
878
+ int i, j, ni, nj, bond_type, num_1s, num_mult, num_other;
879
+
880
+ if ( at[cur_at].endpoint ) { /* tautomeric endpoint cannot be a stereo center */
881
+ return 0;
882
+ }
883
+
884
+ if ( (1 & RequirdNeighType) && at[cur_at].num_H ) {
885
+ return 0;
886
+ }
887
+
888
+ if ( 2 & RequirdNeighType ) {
889
+ for ( i = 0; i < at[cur_at].valence; i ++ ) {
890
+ ni = (int)at[cur_at].neighbor[i];
891
+ if ( at[ni].valence != 1 ||
892
+ !get_endpoint_valence( at[ni].el_number ) ) {
893
+ continue;
894
+ }
895
+ for ( j = i+1; j < at[cur_at].valence; j ++ ) {
896
+ nj = (int)at[cur_at].neighbor[j];
897
+ if ( at[nj].valence != 1 ||
898
+ at[ni].el_number != at[nj].el_number ||
899
+ !get_endpoint_valence( at[nj].el_number ) ) {
900
+ continue;
901
+ }
902
+ /*
903
+ * if (at[ni].num_H != at[nj].num_H) then the atoms (neighbors of at[cur_at]
904
+ * are tautomeric endpoints and are indistinguishable => cur_at is not stereogenic
905
+ * if (at[ni].num_H == at[nj].num_H) then the neighbors are indistinguishable
906
+ * and cur_at will be found non-sterogenic later
907
+ * get_endpoint_valence() check will not allow the neighbors to be carbons
908
+ * Therefore the following "if" is not needed; we may just return 0.
909
+ */
910
+ if ( at[ni].num_H != at[nj].num_H && strcmp(at[ni].elname, "C" ) ) {
911
+ return 0; /* found -X and -XH neighbors */
912
+ }
913
+ }
914
+ }
915
+ }
916
+
917
+ num_1s = num_mult = num_other = 0;
918
+
919
+ for ( i = 0; i < at[cur_at].valence; i ++ ) {
920
+ bond_type = (at[cur_at].bond_type[i] & ~BOND_MARK_ALL);
921
+ switch( bond_type ) {
922
+ case BOND_SINGLE:
923
+ num_1s ++;
924
+ break;
925
+ case BOND_DOUBLE:
926
+ case BOND_ALTERN:
927
+ case BOND_TAUTOM:
928
+ case BOND_ALT12NS:
929
+ num_mult ++;
930
+ break;
931
+ default:
932
+ num_other ++;
933
+ break;
934
+ }
935
+ }
936
+
937
+ if ( num_other ) {
938
+ return 0;
939
+ }
940
+
941
+ if ( NumDbleBonds && NumDbleBonds > num_mult ||
942
+ !NumDbleBonds && at[cur_at].valence != num_1s ) {
943
+ return 0;
944
+ }
945
+ return 1;
946
+ }
947
+ /********************************************************************************************/
948
+ int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
949
+ {
950
+
951
+ /*************************************************************************************
952
+ * current version
953
+ *************************************************************************************
954
+ * Use #define to split the stereocenter description table into parts
955
+ * to make it easier to read
956
+ *
957
+ * --------- 4 single bonds stereocenters -------
958
+ *
959
+ * | | | | | |
960
+ * -C- -Si- -Ge- -Sn- >As[+] >B[-]
961
+ * | | | | | |
962
+ */
963
+ #define SZELEM1 "C\000","Si", "Ge", "Sn", "As", "B\000",
964
+ #define CCHARGE1 0, 0, 0, 0, 1, -1,
965
+ #define CNUMBONDSANDH1 4, 4, 4, 4, 4, 4,
966
+ #define CCHEMVALENCEH1 4, 4, 4, 4, 4, 4,
967
+ #define CHAS3MEMBRING1 0, 0, 0, 0, 0, 0,
968
+ #define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
969
+ /*
970
+ * --------------- S, Se stereocenters ----------
971
+ *
972
+ * | | || | | ||
973
+ * -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
974
+ * | | | | | | | |
975
+ */
976
+ #define SZELEM2 "S\000","S\000","S\000","S\000","Se", "Se", "Se", "Se",
977
+ #define CCHARGE2 0, 0, 1, 1, 0, 0, 1, 1,
978
+ #define CNUMBONDSANDH2 3, 4, 3, 4, 3, 4, 3, 4,
979
+ #define CCHEMVALENCEH2 4, 6, 3, 5, 4, 6, 3, 5,
980
+ #define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
981
+ #define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
982
+ /*
983
+ * ------------------ N, P stereocenters --------
984
+ *
985
+ * X---Y
986
+ * | | \ / | |
987
+ * =N- >N[+] N >P[+] =P-
988
+ * | | | | |
989
+ */
990
+ #define SZELEM3 "N\000","N\000","N\000","P\000","P\000",
991
+ #define CCHARGE3 0, 1, 0, 1, 0,
992
+ #define CNUMBONDSANDH3 4, 4, 3, 4, 4,
993
+ #define CCHEMVALENCEH3 5, 4, 3, 4, 5,
994
+ #define CHAS3MEMBRING3 0, 0, 1, 0, 0,
995
+ #define CREQUIRDNEIGH3 3, 3, 1, 3, 3,
996
+
997
+
998
+
999
+ static char szElem[][3]={ SZELEM1 SZELEM2 SZELEM3 };
1000
+ static S_CHAR cCharge[]={ CCHARGE1 CCHARGE2 CCHARGE3 };
1001
+ static S_CHAR cNumBondsAndH[]={ CNUMBONDSANDH1 CNUMBONDSANDH2 CNUMBONDSANDH3 };
1002
+ static S_CHAR cChemValenceH[]={ CCHEMVALENCEH1 CCHEMVALENCEH2 CCHEMVALENCEH3 };
1003
+ static S_CHAR cHas3MembRing[]={ CHAS3MEMBRING1 CHAS3MEMBRING2 CHAS3MEMBRING3 };
1004
+ static S_CHAR cRequirdNeigh[]={ CREQUIRDNEIGH1 CREQUIRDNEIGH2 CREQUIRDNEIGH3 };
1005
+
1006
+ static int n = sizeof(szElem)/sizeof(szElem[0]);
1007
+ /* reqired neighbor types (bitmap):
1008
+ 0 => check bonds only
1009
+ 1 => no terminal hydrogen atom neighbors
1010
+ 2 => no terminal -X and -XH together (don't care the bond type, charge, radical)
1011
+ (X = tautomeric endpoint atom)
1012
+ Note: whenever cChemValenceH[] > cNumBondsAndH[]
1013
+ the tautomeric and/or alternating bonds
1014
+ are permitted
1015
+
1016
+ */
1017
+ int i, ret = 0;
1018
+ for ( i = 0; i < n; i++ ) {
1019
+ if ( !strcmp( at[cur_at].elname, szElem[i]) &&
1020
+ at[cur_at].charge == cCharge[i] &&
1021
+ (!at[cur_at].radical || at[cur_at].radical == 1) &&
1022
+ at[cur_at].valence +at[cur_at].num_H == cNumBondsAndH[i] &&
1023
+ at[cur_at].chem_bonds_valence+at[cur_at].num_H == cChemValenceH[i] &&
1024
+ (cHas3MembRing[i]? is_atom_in_3memb_ring( at, cur_at ) : 1) &&
1025
+ bInpAtomHasRequirdNeigh ( at, cur_at, cRequirdNeigh[i], cChemValenceH[i]-cNumBondsAndH[i]) ) {
1026
+ ret = cNumBondsAndH[i];
1027
+ break;
1028
+ }
1029
+ }
1030
+ return ret;
1031
+ }
1032
+
1033
+ #else /* } NEW_STEREOCENTER_CHECK { */
1034
+
1035
+ /********************************************************************************************/
1036
+ int bCanAtomBeAStereoCenter( char *elname, S_CHAR charge, S_CHAR radical )
1037
+ {
1038
+ static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "P\000", "As", "B\000" };
1039
+ static S_CHAR cCharge[] = { 0, 0, 0, 1, 1, 1, -1 };
1040
+ int i, ret = 0;
1041
+ for ( i = 0; i < sizeof(szElem)/sizeof(szElem[0]); i++ ) {
1042
+ if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
1043
+ ret = (!radical || radical == RADICAL_SINGLET);
1044
+ break;
1045
+ }
1046
+ }
1047
+ return ret;
1048
+ }
1049
+ #endif /* } NEW_STEREOCENTER_CHECK */
1050
+
1051
+ /****************************************************************/
1052
+ /* used for atoms adjacent to stereogenic bonds only */
1053
+ int bAtomHasValence3( char *elname, S_CHAR charge, S_CHAR radical )
1054
+ {
1055
+ static char szElem[][3] = { "N\000" };
1056
+ static S_CHAR cCharge[] = { 0, };
1057
+ int i, ret = 0;
1058
+ for ( i = 0; i < (int)(sizeof(szElem)/sizeof(szElem[0])); i++ ) {
1059
+ if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
1060
+ ret = ( !radical || radical == RADICAL_SINGLET );
1061
+ break;
1062
+ }
1063
+ }
1064
+ return ret;
1065
+ }
1066
+
1067
+ /****************************************************************/
1068
+ /* used for atoms adjacent to stereogenic bonds only */
1069
+ int bCanAtomHaveAStereoBond( char *elname, S_CHAR charge, S_CHAR radical )
1070
+ {
1071
+ static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "N\000" };
1072
+ static S_CHAR cCharge[] = { 0, 0, 0, 0, 1, };
1073
+ static int n = sizeof(szElem)/sizeof(szElem[0]);
1074
+ int i, ret = 0;
1075
+ for ( i = 0; i < n; i++ ) {
1076
+ if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
1077
+ ret = (!radical || radical == RADICAL_SINGLET);
1078
+ break;
1079
+ }
1080
+ }
1081
+ return ret;
1082
+ }
1083
+ /****************************************************************/
1084
+ /* used for atoms adjacent to stereogenic bonds only */
1085
+ int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical )
1086
+ {
1087
+ static char szElem[][3] = { "C\000", "Si", "Ge", };
1088
+ static S_CHAR cCharge[] = { 0, 0, 0, };
1089
+ static int n = sizeof(szElem)/sizeof(szElem[0]);
1090
+ int i, ret = 0;
1091
+ for ( i = 0; i < n; i++ ) {
1092
+ if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
1093
+ ret = (!radical || radical == RADICAL_SINGLET);
1094
+ break;
1095
+ }
1096
+ }
1097
+ return ret;
1098
+ }
1099
+ /*****************************************************************/
1100
+ int bIsSuitableHeteroInpAtom( inp_ATOM *at )
1101
+ {
1102
+ int val, num_H;
1103
+ if ( 0 == at->charge &&
1104
+ (!at->radical || RADICAL_SINGLET == at->radical) &&
1105
+ 0 < (val=get_endpoint_valence( at->el_number ) )) {
1106
+ num_H = at->num_H;
1107
+ if ( val == at->chem_bonds_valence + num_H ) {
1108
+ switch( val ) {
1109
+ case 2: /* O */
1110
+ if ( !num_H && 1 == at->valence )
1111
+ return 0; /* =O */
1112
+ break; /* not found */
1113
+ case 3: /* N */
1114
+ if ( 1 == at->valence && 1 == num_H ||
1115
+ 2 == at->valence && 0 == num_H )
1116
+ return 1; /* =N- or =NH */
1117
+ break; /* not found */
1118
+ }
1119
+ }
1120
+ }
1121
+ return -1;
1122
+ }
1123
+ /****************************************************************/
1124
+ int bIsOxide( inp_ATOM *at, int cur_at )
1125
+ {
1126
+ int i, bond_type;
1127
+ inp_ATOM *a = at + cur_at, *an;
1128
+ for ( i = 0; i < a->valence; i ++ ) {
1129
+ bond_type = (a->bond_type[i] &= ~BOND_MARK_ALL);
1130
+ if ( bond_type == BOND_DOUBLE ) {
1131
+ an = at + (int)a->neighbor[i];
1132
+ if ( 1 == an->valence &&
1133
+ !an->charge && !an->num_H && !an->radical &&
1134
+ 2 == get_endpoint_valence( an->el_number ) ) {
1135
+ return 1;
1136
+ }
1137
+ } else
1138
+ if ( bond_type == BOND_TAUTOM || bond_type == BOND_ALT12NS ) {
1139
+ an = at + (int)a->neighbor[i];
1140
+ if ( 1 == an->valence &&
1141
+ 2 == get_endpoint_valence( an->el_number ) ) {
1142
+ return 1;
1143
+ }
1144
+ }
1145
+ }
1146
+ return 0;
1147
+ }
1148
+ /****************************************************************/
1149
+ /* used for atoms adjacent to stereogenic bonds only */
1150
+ int bCanAtomBeTerminalAllene( char *elname, S_CHAR charge, S_CHAR radical )
1151
+ {
1152
+ static char szElem[][3] = { "C\000", "Si", "Ge", };
1153
+ static S_CHAR cCharge[] = { 0, 0, 0, };
1154
+ static int n = sizeof(szElem)/sizeof(szElem[0]);
1155
+ int i, ret = 0;
1156
+ for ( i = 0; i < n; i++ ) {
1157
+ if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
1158
+ ret = (!radical || radical == RADICAL_SINGLET);
1159
+ break;
1160
+ }
1161
+ }
1162
+ return ret;
1163
+ }
1164
+ /************************************************************************/
1165
+ int GetHalfStereobond0DParity( inp_ATOM *at, int cur_at, AT_NUMB nSbNeighOrigAtNumb[],
1166
+ int nNumExplictAttachments, int bond_parity, int nFlag )
1167
+ {
1168
+ int m, last_parity, cur_parity;
1169
+ int i, icur2nxt, icur2neigh, cur_order_parity, nxt_at;
1170
+ AT_NUMB nNextSbAtOrigNumb;
1171
+ /* find atom parities for all valid streobonds incident to at[cur_at] */
1172
+ for ( m = 0, last_parity = 0; m < MAX_NUM_STEREO_BONDS && at[cur_at].sb_parity[m]; m ++ ) {
1173
+ icur2nxt = icur2neigh = -1; /* ordering number of neighbors in nSbNeighOrigAtNumb[] */
1174
+ cur_parity = 0; /* parity for mth stereobond incident to the cur_at */
1175
+ if ( 0 <= at[cur_at].sb_ord[m] && at[cur_at].sb_ord[m] < at[cur_at].valence &&
1176
+ 0 <= (nxt_at = at[cur_at].neighbor[(int)at[cur_at].sb_ord[m]]) &&
1177
+ at[nxt_at].valence <= MAX_NUM_STEREO_BONDS && /* make sure it is a valid stereobond */
1178
+ (nNextSbAtOrigNumb = at[nxt_at].orig_at_number) ) {
1179
+ /* since at[cur_at].sn_ord[m] = -1 for explicit H use at[cur_at].sn_orig_at_num[m] */
1180
+ for ( i = 0; i < nNumExplictAttachments; i ++ ) {
1181
+ if ( at[cur_at].sn_orig_at_num[m] == nSbNeighOrigAtNumb[i] ) {
1182
+ icur2neigh = i; /* neighbor */
1183
+ } else
1184
+ if ( nNextSbAtOrigNumb == nSbNeighOrigAtNumb[i] ) {
1185
+ icur2nxt = i; /* atom connected by a stereobond */
1186
+ }
1187
+ }
1188
+ if ( icur2neigh >= 0 && icur2nxt >= 0 ) {
1189
+ if ( ATOM_PARITY_WELL_DEF(at[cur_at].sb_parity[m]) ) {
1190
+ /* parity of at[cur_atom] neighbor permutation to reach this order: { next_atom, neigh_atom, ...} */
1191
+ cur_order_parity = (icur2nxt + icur2neigh + (icur2nxt > icur2neigh) - 1) % 2;
1192
+ cur_parity = 2 - (cur_order_parity + at[cur_at].sb_parity[m]) % 2;
1193
+ } else {
1194
+ /* unknowm/undef parities do not depend on the neighbor order */
1195
+ cur_parity = at[cur_at].sb_parity[m];
1196
+ }
1197
+ }
1198
+ } else {
1199
+ continue;
1200
+ }
1201
+ /* use a well-known parity if available; if not then use preferably the unknown */
1202
+ if ( !last_parity ) {
1203
+ last_parity = cur_parity;
1204
+ } else
1205
+ if ( last_parity != cur_parity && cur_parity ) {
1206
+ if ( ATOM_PARITY_WELL_DEF(last_parity) ) {
1207
+ if ( ATOM_PARITY_WELL_DEF(cur_parity) ) {
1208
+ last_parity = 0; /* error: all well-defined parities should be same */
1209
+ break;
1210
+ }
1211
+ } else
1212
+ if ( ATOM_PARITY_WELL_DEF(cur_parity) ) {
1213
+ /* replace unknown/undefined parity with well-known */
1214
+ last_parity = cur_parity;
1215
+ } else {
1216
+ /* select min unknown/undefined parity (out of AB_PARITY_UNKN and AB_PARITY_UNDF) */
1217
+ last_parity = inchi_min(cur_parity, last_parity);
1218
+ }
1219
+ }
1220
+ }
1221
+ if ( last_parity ) {
1222
+ bond_parity = last_parity;
1223
+ at[cur_at].bUsed0DParity |= nFlag; /* set flag: used stereobond 0D parity */
1224
+ }
1225
+ return bond_parity;
1226
+ }
1227
+ /*******************************************************************************************/
1228
+ int FixSb0DParities( inp_ATOM *at, /* inp_ATOM *at_removed_H, int num_removed_H,*/ int chain_length,
1229
+ int at_1, int i_next_at_1, S_CHAR z_dir1[],
1230
+ int at_2, int i_next_at_2, S_CHAR z_dir2[],
1231
+ int *pparity1, int *pparity2 )
1232
+ {
1233
+ int k, parity1, parity2, abs_parity1, abs_parity2;
1234
+ int j1, j2, parity_sign;
1235
+ /*
1236
+ AT_NUMB nSbNeighOrigAtNumb1[MAX_NUM_STEREO_BOND_NEIGH], nSbNeighOrigAtNumb2[MAX_NUM_STEREO_BOND_NEIGH];
1237
+ int nNumExplictAttachments1, nNumExplictAttachments2;
1238
+ */
1239
+ parity1 = parity2 = AB_PARITY_NONE;
1240
+ j1 = j2 = -1;
1241
+ parity_sign = ( *pparity1 < 0 || *pparity2 < 0 )? -1 : 1;
1242
+
1243
+ abs_parity1 = abs(*pparity1);
1244
+ abs_parity2 = abs(*pparity2);
1245
+
1246
+ for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k ++ ) {
1247
+ if ( at[at_1].sb_ord[k] == i_next_at_1 ) {
1248
+ parity1 = at[at_1].sb_parity[k];
1249
+ j1 = k;
1250
+ }
1251
+ }
1252
+ for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_2].sb_parity[k]; k ++ ) {
1253
+ if ( at[at_2].sb_ord[k] == i_next_at_2 ) {
1254
+ parity2 = at[at_2].sb_parity[k];
1255
+ j2 = k;
1256
+ }
1257
+ }
1258
+ switch( (j1 >= 0) + 2*(j2 >= 0) ) {
1259
+ case 0:
1260
+ /* the bond has no 0D parity */
1261
+ *pparity1 = *pparity2 = parity_sign * AB_PARITY_UNDF;
1262
+ return 0;
1263
+ case 1:
1264
+ case 2:
1265
+ /* 0D parity data error */
1266
+ *pparity1 = *pparity2 = AB_PARITY_NONE;
1267
+ return -1;
1268
+ case 3:
1269
+ /* the bond has 0D parity */
1270
+ switch ( !(ATOM_PARITY_WELL_DEF( abs_parity1 ) && ATOM_PARITY_WELL_DEF( parity1 )) +
1271
+ 2 * !(ATOM_PARITY_WELL_DEF( abs_parity2 ) && ATOM_PARITY_WELL_DEF( parity2 )) ) {
1272
+ case 0:
1273
+ /* both parities are well-defined; continue */
1274
+ break;
1275
+ case 1:
1276
+ /* 0D parity not well-defined for at_1 */
1277
+ *pparity1 = parity_sign * (ATOM_PARITY_WELL_DEF( parity1 )? abs_parity1 :
1278
+ ATOM_PARITY_WELL_DEF( abs_parity1 )? parity1 :
1279
+ inchi_min(abs_parity1, parity1));
1280
+ *pparity2 = parity_sign * abs_parity2;
1281
+ return -1;
1282
+ case 2:
1283
+ /* 0D parity not well-defined for at_2 */
1284
+ *pparity1 = parity_sign * abs_parity1;
1285
+ *pparity2 = parity_sign * (ATOM_PARITY_WELL_DEF( parity2 )? abs_parity2 :
1286
+ ATOM_PARITY_WELL_DEF( abs_parity2 )? parity2 :
1287
+ inchi_min(abs_parity2, parity2));
1288
+ return -1;
1289
+ case 3:
1290
+ abs_parity1 = (ATOM_PARITY_WELL_DEF( parity1 )? abs_parity1 :
1291
+ ATOM_PARITY_WELL_DEF( abs_parity1 )? parity1 :
1292
+ inchi_min(abs_parity1, parity1));
1293
+ abs_parity2 = (ATOM_PARITY_WELL_DEF( parity2 )? abs_parity2 :
1294
+ ATOM_PARITY_WELL_DEF( abs_parity2 )? parity2 :
1295
+ inchi_min(abs_parity2, parity2));
1296
+ *pparity1 = *pparity2 = parity_sign * inchi_min(abs_parity1, abs_parity2);
1297
+ /*return (parity1 == parity2)? 0 : -1;*/
1298
+ return -1;
1299
+ }
1300
+ break;
1301
+ }
1302
+ /* we are here if both end-atoms of the bond have well-defined 0D parities */
1303
+ /*
1304
+ nNumExplictAttachments1 = GetSbNeighOrigAtNumb( at, at_1, at_removed_H, num_removed_H, nSbNeighOrigAtNumb1 );
1305
+ nNumExplictAttachments2 = GetSbNeighOrigAtNumb( at, at_2, at_removed_H, num_removed_H, nSbNeighOrigAtNumb2 );
1306
+ parity1 = GetHalfStereobond0DParity( at, at_1, nSbNeighOrigAtNumb1, nNumExplictAttachments1, *pparity1, 0 );
1307
+ parity2 = GetHalfStereobond0DParity( at, at_2, nSbNeighOrigAtNumb2, nNumExplictAttachments2, *pparity2, 0 );
1308
+ */
1309
+ *pparity1 = parity_sign * abs_parity1;
1310
+ *pparity2 = parity_sign * abs_parity2;
1311
+
1312
+ if ( chain_length % 2 ) {
1313
+ /* allene; chain_length = (number of double bonds) - 1 */
1314
+ /*
1315
+ int zer1 = ( !z_dir1[0] && !z_dir1[1] && !z_dir1[2] );
1316
+ int zer2 = ( !z_dir2[0] && !z_dir2[1] && !z_dir2[2] );
1317
+ */
1318
+ int bWrong_z_dir1 = (0 != (at[at_1].bUsed0DParity & FlagSB_0D));
1319
+ int bWrong_z_dir2 = (0 != (at[at_2].bUsed0DParity & FlagSB_0D));
1320
+
1321
+ if ( bWrong_z_dir1 && bWrong_z_dir2 ) {
1322
+ goto set_default;
1323
+ } else
1324
+ if ( bWrong_z_dir1 || bWrong_z_dir2 ) {
1325
+ double r12[3], zi1[3], zi2[3], abs_r12, abs_zi2;
1326
+ int at_i1, at_i2, j;
1327
+ S_CHAR z_dir[3];
1328
+ r12[0] = at[at_2].x - at[at_1].x;
1329
+ r12[1] = at[at_2].y - at[at_1].y;
1330
+ r12[2] = at[at_2].z - at[at_1].z;
1331
+ abs_r12 = len3( r12 );
1332
+ if ( abs_r12 < MIN_BOND_LEN ) {
1333
+ goto set_default;
1334
+ }
1335
+ /* make r12[] point to the atom with 'good' z_dir[] */
1336
+ if ( bWrong_z_dir1 ) {
1337
+ at_i1 = at_2; /* has good z_dir2[] */
1338
+ at_i2 = at_1; /* has bad z_dir1[] */
1339
+ zi1[0] = z_dir2[0];
1340
+ zi1[1] = z_dir2[1];
1341
+ zi1[2] = z_dir2[2];
1342
+ mult3( r12, 1.0/abs_r12, r12 ); /* make length = 1 */
1343
+ } else {
1344
+ at_i1 = at_1; /* has good z_dir1[] */
1345
+ at_i2 = at_2; /* has bad z_dir2[] */
1346
+ zi1[0] = z_dir1[0];
1347
+ zi1[1] = z_dir1[1];
1348
+ zi1[2] = z_dir1[2];
1349
+ mult3( r12, -1.0/abs_r12, r12 ); /* make length = 1 */
1350
+ }
1351
+ cross_prod3( r12, zi1, zi2 );
1352
+ abs_zi2 = len3( zi2 );
1353
+ mult3( zi2, 100.0/abs_zi2, zi2 ); /* make length = 100 */
1354
+ for ( j = 0; j < 3; j ++ ) {
1355
+ z_dir[j] = (S_CHAR) (zi2[j]>= 0.0? floor(0.5 + zi2[j]) :
1356
+ -floor(0.5 - zi2[j])); /* abs(z_dir) = 100 */
1357
+ }
1358
+ if ( bWrong_z_dir1 ) {
1359
+ memcpy( z_dir1, z_dir, sizeof(z_dir) );
1360
+ } else {
1361
+ memcpy( z_dir2, z_dir, sizeof(z_dir) );
1362
+ }
1363
+ }
1364
+ return 0;
1365
+
1366
+ set_default:
1367
+ /* z_dir1[] = x-direction; z_dir2[] = z-direction; r12[] = y-direction */
1368
+ z_dir1[0] = 100;
1369
+ z_dir1[1] = z_dir1[2] = 0;
1370
+ z_dir2[0] = z_dir2[1] = 0;
1371
+ z_dir2[2] = 100;
1372
+ }
1373
+ return 0;
1374
+ }
1375
+
1376
+ /*======================================================================================================
1377
+
1378
+ half_stereo_bond_parity() General Description:
1379
+
1380
+ A) find projections of 3 bonds on a reasonable plane defined
1381
+ by a vector z_dir perpendicular to the plane
1382
+ B) calculate parity
1383
+
1384
+ half_stereo_bond_parity() Detailed Description:
1385
+
1386
+ 1) Find at_coord[] = vectors from the central atoms to its neighbors
1387
+ 2) If only 2 neighbors are present, then create a reasonable 3rd neighbor
1388
+ (an implicit H or a fictitious atom in case of =NX) coordinates
1389
+ 3) Normalize at_coord[] to unit length
1390
+ 4) Find unit vector pnt[2] perpendicular to the plane containing
1391
+ at_coord[] arrow ends.
1392
+ Even though it is not necessary, make z-coordinate of pnt[2] positive.
1393
+ ** pnt[2] has the new z-axis direction **
1394
+ 5) Let pnt[0] = perpendicular to pnt[2] component of at_coord[0];
1395
+ Normalize pnt[0] to unit length.
1396
+ ** pnt[0] has the new x-axis direction **
1397
+ 6) Let pnt[1] = pnt[2] x pnt[0] (cross-product);
1398
+ ** pnt[1] has the new y-axis direction **
1399
+ 7) Find at_coord[] in the new xyz-basis and normalize their xy-projections
1400
+ to a unit length
1401
+ 8) In the new xy-plane find (counterclockwise) angles:
1402
+ tmp1 = (from at_coord[0] to at_coord[1])
1403
+ tmp2 = (from at_coord[0] to at_coord[2])
1404
+ 9) Calculate the parity: if tmp1 < tmp2 then 1 (odd) else 2 (even)
1405
+ (even: looking from the arrow end of the new z-axis, 0, 1, and 2 neighbors
1406
+ are in clockwise order)
1407
+ 10) Calculate z_dir = 100*pnt[2].
1408
+
1409
+ Note1. If z_dir vectors of atoms located at the opposite ends of a double bond have approximately
1410
+ opposite directions (that is, their dot-product is negative) then the parity of the
1411
+ stereogenic bond calculated from half-bond-parities should be inverted
1412
+
1413
+ Note2. In case of a tetrahedral cumulene a triple product (z_dir1, (1->2), z_dir2) is used instead
1414
+ of the dot-product. (1->2) is a vector from the atom#1 to the atom #2. This triple product
1415
+ is invariant with respect to the atom numbering because it does not change upon (1,2)
1416
+ permutation.
1417
+
1418
+ Stereo ambiguity in case of 2 neighbors:
1419
+ ----------------------------------------
1420
+ Undefined: single-double bond angle > pi - arcsin(0.03) = 178.28164199834454285275613218975 degrees
1421
+ Ambiguous: single-double bond angle > 175 degrees = pi - 0.087156 Rad
1422
+
1423
+ Return values
1424
+ (cases: I=only in case of isotopic H atoms the neighbors are different,
1425
+ N=in case of non-isotopic H atoms the neighbors are different)
1426
+
1427
+ -4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, I
1428
+ -3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, I
1429
+ -2 =-AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, I
1430
+ -1 =-AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, I
1431
+ 0 = AB_PARITY_NONE => the atom is not adjacent to a stereogenic bond
1432
+ 1 = AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, N&I
1433
+ 2 = AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, N&I
1434
+ 3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, N&I
1435
+ 4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, N&I
1436
+ 5 = AB_PARITY_IISO => atom constitutionally equivalent to this atom may be adjacent to a stereogenic bond, I
1437
+
1438
+
1439
+ =====================================================================================================*/
1440
+
1441
+ int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo )
1442
+ {
1443
+ double at_coord[MAX_NUM_STEREO_BOND_NEIGH][3], c, s, tmp[3], tmp1, tmp2, min_tmp, max_tmp, z;
1444
+ double temp[3], pnt[3][3];
1445
+ int j, k, p0, p1, p2, next, bValence3=0, num_z, nType, num_either_single, num_either_double;
1446
+ int nNumExplictAttachments;
1447
+ int bond_parity = AB_PARITY_UNDF;
1448
+ int num_H=0, num_iH, num_eH=0, num_nH=0 /* = num_iso_H[0] */;
1449
+ int num_iso_H[NUM_H_ISOTOPES+1];
1450
+ int index_H[5]; /* cannot have more than 4 elements: 1 H, 1 1H, 1 D, 1 T atom(s) */
1451
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
1452
+ const double two_pi = 2.0*one_pi;
1453
+ int bIgnoreIsotopicH = (0 != (at[cur_at].cFlags & AT_FLAG_ISO_H_POINT));
1454
+ AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_BOND_NEIGH];
1455
+
1456
+
1457
+ if ( z_dir && !z_dir[0] && !z_dir[1] && !z_dir[2] ) {
1458
+ z_dir[2]=100;
1459
+ }
1460
+
1461
+ num_H = at[cur_at].num_H;
1462
+ if ( num_H > NUM_H_ISOTOPES )
1463
+ return 0; /* at least 2 H atoms are isotopically identical */
1464
+
1465
+ if ( MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence + num_H ||
1466
+ MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence + num_H )
1467
+ return 0;
1468
+
1469
+ if ( !bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) )
1470
+ return 0;
1471
+ if ( !bIgnoreIsotopicH ) {
1472
+ for ( j = 0, num_nH = num_H; j < NUM_H_ISOTOPES; j ++ ) {
1473
+ if ( (k = (int)at[cur_at].num_iso_H[j]) > 1 ) {
1474
+ return AB_PARITY_IISO; /* two or more identical isotopic H atoms */
1475
+ }
1476
+ num_nH -= k;
1477
+ }
1478
+ }
1479
+ /* at this point num_nH = number of non-isotopic H atoms */
1480
+ if ( num_nH > 1 )
1481
+ return AB_PARITY_IISO; /* two or more identical non-isotopic H atoms */
1482
+ if ( num_nH < 0 )
1483
+ return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
1484
+
1485
+ /********************************************************************
1486
+ * Note. At this point all (implicit and explicit) isotopic
1487
+ * terminal H neighbors are either different or not present.
1488
+ ********************************************************************/
1489
+
1490
+ /* locate explicit hydrogen atoms */
1491
+ /* (at_removed_H are sorted in ascending isotopic H mass order, non-isotopic first) */
1492
+ memset( num_iso_H, 0, sizeof(num_iso_H) );
1493
+ if ( at_removed_H && num_removed_H > 0 ) {
1494
+ for ( j = 0; j < num_removed_H; j ++ ) {
1495
+ if ( at_removed_H[j].neighbor[0] == cur_at ) {
1496
+ k = bIgnoreIsotopicH? 0 : at_removed_H[j].iso_atw_diff;
1497
+ if ( 0 <= k && k <= NUM_H_ISOTOPES ) {
1498
+ if ( ++num_iso_H[k] > 1 ) /* num_iso_H[0] = number of non-isotopic H atoms */
1499
+ return CT_ISO_H_ERR; /* program error in counting hydrogens */ /* <BRKPT> */
1500
+ index_H[num_eH++] = j;
1501
+ } else {
1502
+ return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
1503
+ }
1504
+ }
1505
+ }
1506
+ num_iH = num_H - num_eH; /* number of implicit non-isotopic and isotopic H atoms */
1507
+ if ( num_iH > 1 ) {
1508
+ /* more than one implicit H: cannot reconstruct the geometry */
1509
+ bond_parity = -AB_PARITY_UNDF;
1510
+ goto exit_function;
1511
+ }
1512
+ } else {
1513
+ num_iH = num_H;
1514
+ }
1515
+ /* at this point num_iH = number of implicit non-isotopic and isotopic H atoms */
1516
+ if ( at[cur_at].valence + num_eH < MIN_NUM_STEREO_BOND_NEIGH ) {
1517
+ /* =NH or =CHD when no explicit H is present */
1518
+ return num_H == 1? AB_PARITY_UNDF : -AB_PARITY_UNDF;
1519
+ }
1520
+
1521
+ bValence3 = bAtomHasValence3( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical );
1522
+ /*
1523
+ * Can one explicit hydrogen be added to make asymmetric configuration?
1524
+ * For now we can add 1 H atom in case of an appropriate geometry if:
1525
+ * (a) one non-isotopic H (even if explicit isotopic H atoms are present), or
1526
+ * (b) one isotopic or non-isotopic H if NO explicit isotopic or non-isotopic H atom is present
1527
+ * This makes sense only in case chem. valence = 4. In case of chem. valence = 3, do not check.
1528
+ */
1529
+ if ( at[cur_at].valence + num_eH == MIN_NUM_STEREO_BOND_NEIGH && !bValence3 &&
1530
+ !(/*(a)*/ 1 == num_nH && !num_iso_H[0] ||
1531
+ /*(b)*/ 1 == num_H && !num_eH)
1532
+ ) {
1533
+ goto exit_function;
1534
+ /* return num_H == 1? AB_PARITY_UNDF : -AB_PARITY_UNDF; */
1535
+ }
1536
+
1537
+ /* store neighbors coordinates */
1538
+ num_z = num_either_single = num_either_double = 0;
1539
+ for ( k = nNumExplictAttachments = 0; k < 2; k ++ ) {
1540
+ switch( k ) {
1541
+ case 0:
1542
+ for ( j = 0; j < num_eH; j ++, nNumExplictAttachments ++ ) {
1543
+ next = index_H[j];
1544
+ at_coord[nNumExplictAttachments][0] = at_removed_H[next].x - at[cur_at].x;
1545
+ at_coord[nNumExplictAttachments][1] = at_removed_H[next].y - at[cur_at].y;
1546
+ nSbNeighOrigAtNumb[nNumExplictAttachments] = at_removed_H[next].orig_at_number;
1547
+ /* use the fact that (at_removed_H - at) = (number of atoms except removed explicit H) */
1548
+ z = -get_z_coord( at, (at_removed_H-at)+next, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
1549
+ switch ( nType ) {
1550
+ case ZTYPE_EITHER:
1551
+ num_either_single ++; /* bond in "Either" direction. */
1552
+ break;
1553
+ case ZTYPE_UP:
1554
+ case ZTYPE_DOWN:
1555
+ nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
1556
+ z = len2( at_coord[nNumExplictAttachments] );
1557
+ /*
1558
+ z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
1559
+ + at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
1560
+ */
1561
+ if ( nType == ZTYPE_DOWN )
1562
+ z = -z;
1563
+ /* no break; here */
1564
+ case ZTYPE_3D:
1565
+ num_z ++;
1566
+ }
1567
+ at_coord[nNumExplictAttachments][2] = z;
1568
+ }
1569
+ break;
1570
+ case 1:
1571
+ for ( j = 0; j < at[cur_at].valence; j ++, nNumExplictAttachments ++ ) {
1572
+ next = at[cur_at].neighbor[j];
1573
+ at_coord[nNumExplictAttachments][0] = at[next].x - at[cur_at].x;
1574
+ at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
1575
+ nSbNeighOrigAtNumb[nNumExplictAttachments] = at[next].orig_at_number;
1576
+
1577
+ z = get_z_coord( at, cur_at, j /*neighbor #*/, &nType, bPointedEdgeStereo );
1578
+ switch ( nType ) {
1579
+ case ZTYPE_EITHER:
1580
+ num_either_single ++; /* bond in "Either" direction. */
1581
+ break;
1582
+ case ZTYPE_UP:
1583
+ case ZTYPE_DOWN:
1584
+ z = len2( at_coord[nNumExplictAttachments] );
1585
+ /*
1586
+ z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
1587
+ + at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
1588
+ */
1589
+ if ( nType == ZTYPE_DOWN )
1590
+ z = -z;
1591
+ /* no break; here */
1592
+ case ZTYPE_3D:
1593
+ num_z ++;
1594
+ }
1595
+ at_coord[nNumExplictAttachments][2] = z;
1596
+ }
1597
+ break;
1598
+ }
1599
+ }
1600
+
1601
+ if ( num_either_single ) {
1602
+ bond_parity = AB_PARITY_UNKN; /* single bond is 'unknown' */
1603
+ goto exit_function;
1604
+ }
1605
+
1606
+ /* nNumExplictAttachments is a total number of attachments, including removed explicit terminal hydrogens */
1607
+ if ( nNumExplictAttachments == 2 ) {
1608
+ /* create coordinates of the implicit hydrogen (or a fictitious atom in case of ==N-X ), */
1609
+ /* coord[2][], attached to the cur_at. */
1610
+ for ( j = 0; j < 3; j ++ ) {
1611
+ at_coord[2][j] = - ( at_coord[0][j] + at_coord[1][j] );
1612
+ }
1613
+ nSbNeighOrigAtNumb[nNumExplictAttachments] = 0; /* implicit H or lone pair */
1614
+ }
1615
+ for ( j = 0; j < 3; j ++ ) {
1616
+ tmp[j] = len3( at_coord[j] );
1617
+ }
1618
+ min_tmp = inchi_min( tmp[0], inchi_min(tmp[1], tmp[2]) );
1619
+ max_tmp = inchi_max( tmp[0], inchi_max(tmp[1], tmp[2]) );
1620
+ if ( min_tmp < MIN_BOND_LEN || min_tmp < MIN_SINE*max_tmp ) {
1621
+ /* all bonds or some of bonds are too short */
1622
+ if ( at[cur_at].sb_parity[0] ) {
1623
+ /* use bond psrity; the reconciliation in ReconcileAllCmlBondParities()
1624
+ * has made all ways to calculate parity produce same result
1625
+ */
1626
+ bond_parity = GetHalfStereobond0DParity( at, cur_at, nSbNeighOrigAtNumb,
1627
+ nNumExplictAttachments, bond_parity, FlagSB_0D );
1628
+ }
1629
+
1630
+ goto exit_function;
1631
+ }
1632
+ /* normalize lengths to 1 */
1633
+ for ( j = 0; j < 3; j ++ ) {
1634
+ mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
1635
+ }
1636
+
1637
+ /* find projections of at_coord vector differences on the plane containing their arrowhead ends */
1638
+ for ( j = 0; j < 3; j ++ ) {
1639
+ /* pnt[0..2] = {0-1, 1-2, 2-0} */
1640
+ tmp[j] = len3(diff3( at_coord[j], at_coord[(j+1)%3], pnt[j] ));
1641
+ if ( tmp[j] < MIN_SINE ) {
1642
+ goto exit_function; /* angle #i-cur_at-#j is too small */
1643
+ }
1644
+ mult3( pnt[j], 1.0/tmp[j], pnt[j] ); /* 2003-10-06 */
1645
+ }
1646
+ /* find pnt[p2], a vector perpendicular to the plane, and its length tmp[p2] */
1647
+ /* replace previous pnt[p2], tmp[p2] with new values; the old values do not have any additional */
1648
+ /* information because pnt[p0]+pnt[p1]+pnt[p2]=0 */
1649
+ /* 10-6-2003: a cross-product of one pair pnt[j], pnt[(j+1)%3] can be very small. Find the larges one */
1650
+ tmp1 = len3( cross_prod3( pnt[0], pnt[1], temp ) );
1651
+ for (j = 1, k = 0; j < 3; j ++ ) {
1652
+ tmp2 = len3( cross_prod3( pnt[j], pnt[(j+1)%3], temp ) );
1653
+ if ( tmp2 > tmp1 ) {
1654
+ tmp1 = tmp2;
1655
+ k = j;
1656
+ }
1657
+ }
1658
+ /* previously p0=0, p1=1, p2=2 */
1659
+ p0 = k;
1660
+ p1 = (k+1)%3;
1661
+ p2 = (k+2)%3;
1662
+ tmp[p2] = len3( cross_prod3( pnt[p0], pnt[p1], pnt[p2] ) );
1663
+ if ( tmp[p2] < MIN_SINE*tmp[p0]*tmp[p1] ) {
1664
+ goto exit_function; /* pnt[p0] is almost colinear to pnt[p1] */
1665
+ }
1666
+ /* new basis: pnt[p0], pnt[p1], pnt[p2]; set z-coord sign and make abs(pnt[p2]) = 1 */
1667
+ mult3( pnt[p2], (pnt[p2][2]>0.0? 1.0:-1.0)/tmp[p2], pnt[p2] ); /* unit vector in the new z-axis direction */
1668
+
1669
+ min_tmp = dot_prod3( at_coord[0], pnt[p2] ); /* non-planarity measure (sine): hight of at_coord[] pyramid */
1670
+ mult3( pnt[p2], min_tmp, pnt[p0] ); /* vector height of the pyramid, ideally 0 */
1671
+ /* find new pnt[p0] = projection of at_coord[p0] on plane orthogonal to pnt[p2] */
1672
+ tmp[p0] = len3(diff3( at_coord[0], pnt[p0], pnt[p0] ));
1673
+ mult3( pnt[p0], 1.0/tmp[p0], pnt[p0] ); /* new x axis basis vector */
1674
+ cross_prod3( pnt[p2], pnt[p0], pnt[p1] ); /* new y axis basis vector */
1675
+ /* find at_coord in the new basis of {pnt[p0], pnt[p1], pnt[p2]} */
1676
+ for ( j = 0; j < 3; j ++ ) {
1677
+ copy3( at_coord[j], temp );
1678
+ for ( k = 0; k < 3; k ++ ) {
1679
+ at_coord[j][k] = dot_prod3( temp, pnt[(k+p0)%3] );
1680
+ }
1681
+ /* new xy plane projection length */
1682
+ tmp[j] = sqrt(at_coord[j][0]*at_coord[j][0] + at_coord[j][1]*at_coord[j][1]);
1683
+ /* make new xy plane projection length = 1 */
1684
+ mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
1685
+ }
1686
+
1687
+ s = fabs( at_coord[1][0]*at_coord[2][1] - at_coord[1][1]*at_coord[2][0] ); /* 1-2 sine */
1688
+ c = at_coord[1][0]*at_coord[2][0] + at_coord[1][1]*at_coord[2][1]; /* 1-2 cosine */
1689
+ if ( s < MIN_SINE && c > 0.5 ) {
1690
+ goto exit_function; /* bonds to neigh. 1 and 2 have almost same direction; relative angles are undefined */
1691
+ }
1692
+ c = at_coord[0][0]; /* cosine of the angle between new Ox axis and a bond to the neighbor 0. Should be 1 */
1693
+ s = at_coord[0][1]; /* sine. Should be 0 */
1694
+ /* turn vectors so that vector #1 (at_coord[0]) becomes {1, 0} */
1695
+ for ( j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j ++ ) {
1696
+ tmp1 = c*at_coord[j][0] + s*at_coord[j][1];
1697
+ tmp2 = -s*at_coord[j][0] + c*at_coord[j][1];
1698
+ at_coord[j][0] = tmp1;
1699
+ at_coord[j][1] = tmp2;
1700
+ }
1701
+ /* counterclockwise angles from the direction to neigh 0 to to directions to neighbors 1 and 2: */
1702
+ tmp1 = atan2( at_coord[1][1], at_coord[1][0] ); /* range -pi and +pi */
1703
+ tmp2 = atan2( at_coord[2][1], at_coord[2][0] );
1704
+ if ( tmp1 < 0.0 )
1705
+ tmp1 += two_pi; /* range 0 to 2*pi */
1706
+ if ( tmp2 < 0.0 )
1707
+ tmp2 += two_pi;
1708
+ /*-----------------------------------
1709
+ Example
1710
+ 1 \ case tmp1 < tmp2
1711
+ \ parity is odd
1712
+ \ (counterclockwise)
1713
+ A------- 0
1714
+ /
1715
+ /
1716
+ 2 /
1717
+
1718
+ ------------------------------------*/
1719
+ bond_parity = 2 - ( tmp1 < tmp2 );
1720
+ for ( j = 0; j < 3; j ++ ) {
1721
+ z_dir[j] = (S_CHAR) (pnt[p2][j]>= 0.0? floor(0.5 + 100.0 * pnt[p2][j]) :
1722
+ -floor(0.5 - 100.0 * pnt[p2][j])); /* abs(z_dir) = 100 */
1723
+ }
1724
+ /* check for ambiguity */
1725
+ if ( nNumExplictAttachments > 2 ) {
1726
+ min_tmp = inchi_min( tmp1, tmp2 );
1727
+ max_tmp = inchi_max( tmp1, tmp2 );
1728
+ if ( min_tmp > one_pi-MIN_SINE || max_tmp < one_pi+MIN_SINE || max_tmp-min_tmp > one_pi - MIN_SINE ) {
1729
+ at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
1730
+ } else /* 3D ambiguity 8-28-2002 */
1731
+ if ( fabs(at_coord[0][2]) > MAX_SINE ) { /* all fabs(at_coord[j][2] (j=0..2) must be equal */
1732
+ at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
1733
+ }
1734
+ } else
1735
+ if ( nNumExplictAttachments == 2 ) { /* 10-6-2003: added */
1736
+ min_tmp = fabs(tmp1 - one_pi);
1737
+ if ( min_tmp < MIN_SINE ) {
1738
+ bond_parity = AB_PARITY_UNDF; /* consider as undefined 10-6-2003 */
1739
+ } else
1740
+ if ( min_tmp < MIN_ANGLE_DBOND ) {
1741
+ at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
1742
+ }
1743
+ }
1744
+
1745
+
1746
+ /* for 3 neighbors moving implicit H to the index=0 from index=2 position */
1747
+ /* can be done in 2 transpositions and does not change atom's parity */
1748
+ exit_function:
1749
+ if ( num_H > 1 && bond_parity > 0 && !(bond_parity & AB_PARITY_0D) /*&& PARITY_WELL_DEF(bond_parity)*/ ) {
1750
+ /*
1751
+ * stereo only if isotopes are counted. Do not inverse
1752
+ * Examples: sign for this:
1753
+ * H D
1754
+ * / / H
1755
+ * ==C or ==CH /
1756
+ * \ ==N (bValence3=1)
1757
+ * D
1758
+ * two explicit one explicit H isotope (D),
1759
+ * isotopic H atoms one implicit H
1760
+ */
1761
+ bond_parity = -bond_parity; /* refers to isotopically substituted structure only */
1762
+ }
1763
+ return bond_parity;
1764
+ }
1765
+
1766
+ /*************************************************************/
1767
+ int save_a_stereo_bond( int z_prod, int result_action,
1768
+ 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,
1769
+ 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 )
1770
+ {
1771
+ int i1, i2;
1772
+ for ( i1 = 0; i1 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor1[i1]; i1 ++ )
1773
+ ;
1774
+ for ( i2 = 0; i2 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor2[i2]; i2 ++ )
1775
+ ;
1776
+ if ( i1 == MAX_NUM_STEREO_BONDS || i2 == MAX_NUM_STEREO_BONDS )
1777
+ return 0;
1778
+
1779
+ stereo_bond_parity1[i1] =
1780
+ stereo_bond_parity2[i2] = result_action;
1781
+
1782
+ stereo_bond_neighbor1[i1] = (AT_NUMB) (at2+1);
1783
+ stereo_bond_ord1[i1] = (S_CHAR)ord1;
1784
+ stereo_bond_neighbor2[i2] = (AT_NUMB) (at1+1);
1785
+ stereo_bond_ord2[i2] = (S_CHAR)ord2;
1786
+ stereo_bond_z_prod1[i1] =
1787
+ stereo_bond_z_prod2[i2] = (S_CHAR)z_prod;
1788
+ return 1;
1789
+ }
1790
+ /***************************************************************/
1791
+ int get_allowed_stereo_bond_type( int bond_type )
1792
+ {
1793
+ #if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 0 )
1794
+ if ( (bond_type & ~BOND_MARK_ALL) == BOND_TAUTOM )
1795
+ return 0; /* no tautomer bonds allowed */
1796
+ else
1797
+ #endif
1798
+ #if ( EXCL_ALL_AROM_BOND_PARITY == 1 ) /* { */
1799
+ /* a stereo bond cannot belong to an aromatic atom */
1800
+ if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN )
1801
+ {
1802
+ return 0;
1803
+ }
1804
+ #else /* } { */
1805
+ #if ( ADD_6MEMB_AROM_BOND_PARITY == 1 )
1806
+ /* accept any aromatic bond as a stereo bond */
1807
+ if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN )
1808
+ #else
1809
+ /* accept only aromatic bonds in non-6-member rings */
1810
+ if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN ) )
1811
+ #endif
1812
+ {
1813
+ return BOND_ALTERN;
1814
+ }
1815
+ #endif /* } */
1816
+ else
1817
+ /* at this point BOND_MARK_ALL bits have been removed from bond_type */
1818
+ if ( bond_type == BOND_DOUBLE || bond_type == BOND_SINGLE ) {
1819
+ return bond_type;
1820
+ }
1821
+ #if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 1 )
1822
+ else
1823
+ if ( bond_type == BOND_TAUTOM ) {
1824
+ return BOND_TAUTOM;
1825
+ }
1826
+ #endif
1827
+
1828
+ return 0; /* wrong bond type */
1829
+ }
1830
+
1831
+ /*************************************************************/
1832
+ int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode )
1833
+ {
1834
+ int i, j, next_at, num_stereo_bonds, bFound;
1835
+ int bond_type, num_2s, num_alt;
1836
+ int num_2s_next, num_alt_next, num_wrong_bonds_1, num_wrong_bonds_2;
1837
+ #if( N_V_STEREOBONDS == 1 )
1838
+ int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
1839
+ #endif
1840
+ if ( MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence+at[cur_at].num_H ||
1841
+ MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence+at[cur_at].num_H )
1842
+ return 0;
1843
+ if ( !bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) )
1844
+ return 0;
1845
+ /* count bonds and find the second atom on the stereo bond */
1846
+ num_2s = num_alt = num_wrong_bonds_1 = 0;
1847
+ #if( N_V_STEREOBONDS == 1 )
1848
+ num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
1849
+ if ( 0 == at[cur_at].num_H && 0 == at[cur_at].charge && 0 == at[cur_at].radical &&
1850
+ 3 == get_endpoint_valence( at[cur_at].el_number ) ) {
1851
+ if ( 2 == at[cur_at].valence && 3 == at[cur_at].chem_bonds_valence ) {
1852
+ type_N = 1;
1853
+ } else
1854
+ if ( 3 == at[cur_at].valence && 5 == at[cur_at].chem_bonds_valence ) {
1855
+ type_N = 2; /* unfortunately includes >N# */
1856
+ }
1857
+ }
1858
+ #endif
1859
+ for ( i = 0, num_stereo_bonds = 0; i < at[cur_at].valence; i ++ ) {
1860
+ bFound = 0;
1861
+ next_at = at[cur_at].neighbor[i];
1862
+ bond_type = get_allowed_stereo_bond_type( (int)at[cur_at].bond_type[i] );
1863
+ if ( bond_type == BOND_ALTERN ) {
1864
+ num_alt ++;
1865
+ if ( cur_at > next_at && !(nMode & CMODE_NO_ALT_SBONDS) )
1866
+ bFound = 1;
1867
+ } else
1868
+ if ( bond_type == BOND_DOUBLE ) {
1869
+ num_2s ++;
1870
+ #if( N_V_STEREOBONDS == 1 )
1871
+ if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_at )) ) {
1872
+ num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
1873
+ }
1874
+ #endif
1875
+ if ( cur_at > next_at )
1876
+ bFound = 1;
1877
+ } else
1878
+ if ( bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM ) {
1879
+ num_wrong_bonds_1 ++;
1880
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
1881
+ if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[cur_at].valence ) {
1882
+ return 0; /* wrong bond type */
1883
+ } else {
1884
+ continue;
1885
+ }
1886
+ #else
1887
+ return 0; /* wrong bond type */
1888
+ #endif
1889
+ }
1890
+
1891
+ if ( bFound ) {
1892
+ /* check "next_at" atom on the opposite side of the bond */
1893
+ if ( MAX_NUM_STEREO_BOND_NEIGH < at[next_at].valence+at[next_at].num_H ||
1894
+ MIN_NUM_STEREO_BOND_NEIGH > at[next_at].valence+at[next_at].num_H )
1895
+ continue;
1896
+ if ( !bCanAtomHaveAStereoBond( at[next_at].elname, at[next_at].charge, at[next_at].radical ) )
1897
+ continue;
1898
+ /* next atom neighbors */
1899
+ num_2s_next = num_alt_next = num_wrong_bonds_2 = 0;
1900
+ #if( N_V_STEREOBONDS == 1 )
1901
+ num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
1902
+ if ( 0 == at[next_at].num_H && 0 == at[next_at].charge && 0 == at[next_at].radical &&
1903
+ 3 == get_endpoint_valence( at[next_at].el_number ) ) {
1904
+ if ( 2 == at[next_at].valence && 3 == at[next_at].chem_bonds_valence ) {
1905
+ type_N_next = 1; /* -N= */
1906
+ } else
1907
+ if ( 3 == at[next_at].valence && 5 == at[next_at].chem_bonds_valence ) {
1908
+ type_N_next = 2; /* unfortunately includes >N# */
1909
+ }
1910
+ }
1911
+ #endif
1912
+ for ( j = 0; j < at[next_at].valence; j ++ ) {
1913
+ bond_type = get_allowed_stereo_bond_type( (int)at[next_at].bond_type[j] );
1914
+ if ( bond_type == BOND_ALTERN )
1915
+ num_alt_next ++;
1916
+ else
1917
+ if ( bond_type == BOND_DOUBLE ) {
1918
+ num_2s_next ++;
1919
+ #if( N_V_STEREOBONDS == 1 )
1920
+ next_next_at = at[next_at].neighbor[j];
1921
+ if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_next_at )) ) {
1922
+ num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
1923
+ }
1924
+ #endif
1925
+ } else
1926
+ if ( bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM ) {
1927
+ num_wrong_bonds_2 ++;
1928
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
1929
+ if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[cur_at].valence ) {
1930
+ break; /* wrong bond type */
1931
+ } else {
1932
+ continue;
1933
+ }
1934
+ #else
1935
+ break; /* wrong bond type */
1936
+ #endif
1937
+ }
1938
+ }
1939
+ /* figure out whether the at[cur_at]--at[next_at] bond may not be stereogenic */
1940
+
1941
+ #if( N_V_STEREOBONDS == 1 )
1942
+ if ( 3 == (type_N | type_N_next) &&
1943
+ ( 2 == type_N && !bIsOxide( at, cur_at ) ||
1944
+ 2 == type_N_next && !bIsOxide( at, next_at ) ) ) {
1945
+ bFound = 0;
1946
+ } else
1947
+ #endif
1948
+ if ( j < at[next_at].valence || /* at[next_at] has a wrong bond type*/
1949
+ (num_alt_next>0) + (num_2s_next>0) != 1 /* only one type of stereogenic bond permitted */
1950
+ ) {
1951
+ bFound = 0;
1952
+ } else
1953
+ if ( 2 < num_2s_next ) {
1954
+ bFound = 0;
1955
+ } else
1956
+ if ( 2 == num_2s_next ) {
1957
+ if ( 2 == at[next_at].valence ) {
1958
+ ; /* only one double bond permitted except cumulenes */
1959
+ #if( N_V_STEREOBONDS == 1 )
1960
+ } else
1961
+ if ( 1 == (num_2s_hetero_next[0] | num_2s_hetero_next[1]) &&
1962
+ 3 == at[next_at].valence + at[next_at].num_H &&
1963
+ 5 == at[next_at].chem_bonds_valence + at[next_at].num_H &&
1964
+ 3 == get_endpoint_valence( at[next_at].el_number ) &&
1965
+ (!type_N || bIsOxide( at, next_at )) ) {
1966
+ ; /*
1967
+ * found:
1968
+ *
1969
+ * \ / \ / \ /
1970
+ * \ / \ / \ /
1971
+ * N==C or N==C or N==N
1972
+ * // \ // \ // \
1973
+ * O ^ \ N ^ \ O ^ \
1974
+ * | | |
1975
+ * | | |
1976
+ * at[next_at] at[next_at] at[next_at]
1977
+ */
1978
+ #endif
1979
+ } else {
1980
+ bFound = 0;
1981
+ }
1982
+ }
1983
+
1984
+ }
1985
+ if ( bFound ) {
1986
+ num_stereo_bonds++;
1987
+ }
1988
+ }
1989
+
1990
+ if ( (num_alt>0) + (num_2s>0) != 1 || !num_stereo_bonds )
1991
+ return 0;
1992
+ if ( num_2s > 1 ) {
1993
+ #if( N_V_STEREOBONDS == 1 )
1994
+ if ( 2 == num_2s &&
1995
+ 1 == (num_2s_hetero[0] | num_2s_hetero[1]) &&
1996
+ 3 == at[cur_at].valence + at[cur_at].num_H &&
1997
+ 5 == at[cur_at].chem_bonds_valence + at[cur_at].num_H &&
1998
+ 3 == get_endpoint_valence( at[cur_at].el_number ) ) {
1999
+ ;
2000
+ } else {
2001
+ return 0;
2002
+ }
2003
+ #else
2004
+ return 0;
2005
+ #endif
2006
+ }
2007
+
2008
+ return num_stereo_bonds;
2009
+ }
2010
+ /*************************************************************/
2011
+ int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic )
2012
+ {
2013
+ #define AB_NEGATIVE 0x10
2014
+ #define AB_UNKNOWN 0x20
2015
+ int nAction;
2016
+
2017
+ if ( nParity == AB_PARITY_NONE )
2018
+ return AB_PARITY_NONE;
2019
+
2020
+ /* Unknown (type 1) in the parity value may come from the 'Either' single bond only */
2021
+ /* Treat it as a known single bond geometry and unknown (Either) double bond */
2022
+ if ( nParity == AB_PARITY_UNKN )
2023
+ nParity = AB_PARITY_ODD | AB_UNKNOWN;
2024
+ if ( nParity == -AB_PARITY_UNKN )
2025
+ nParity = AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE;
2026
+
2027
+ /* make positive, replace AB_PARITY_EVEN with AB_PARITY_ODD */
2028
+ if ( nParity < 0 )
2029
+ nParity = ((nParity == -AB_PARITY_EVEN)? AB_PARITY_ODD : (-nParity)) | AB_NEGATIVE;
2030
+ else
2031
+ if (nParity == AB_PARITY_EVEN)
2032
+ nParity = AB_PARITY_ODD;
2033
+
2034
+ /* Unknown (type 2): was detected in the double bond attribute */
2035
+ /* (this 'unknown' came from 'Either' double bond) */
2036
+ /* Treat both unknowns in the same way */
2037
+ if ( bUnknown )
2038
+ nParity |= AB_UNKNOWN;
2039
+
2040
+ if ( bIsotopic ) {
2041
+ switch ( nParity ) {
2042
+ case AB_PARITY_ODD:
2043
+ case AB_PARITY_ODD | AB_NEGATIVE:
2044
+ nAction = AB_PARITY_CALC;
2045
+ break;
2046
+ case AB_PARITY_ODD | AB_UNKNOWN:
2047
+ case AB_PARITY_UNDF | AB_UNKNOWN:
2048
+ case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
2049
+ case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
2050
+ nAction = AB_PARITY_UNKN;
2051
+ break;
2052
+ case AB_PARITY_IISO:
2053
+ case AB_PARITY_IISO | AB_UNKNOWN:
2054
+ nAction = AB_PARITY_NONE;
2055
+ break;
2056
+ case AB_PARITY_UNDF:
2057
+ case AB_PARITY_UNDF | AB_NEGATIVE:
2058
+ nAction = AB_PARITY_UNDF;
2059
+ break;
2060
+ default:
2061
+ nAction = -1; /* program error */
2062
+ }
2063
+ } else {
2064
+ /* Non-isotopic */
2065
+ switch ( nParity ) {
2066
+ case AB_PARITY_ODD:
2067
+ nAction = AB_PARITY_CALC;
2068
+ break;
2069
+ case AB_PARITY_ODD | AB_UNKNOWN:
2070
+ case AB_PARITY_UNDF | AB_UNKNOWN:
2071
+ nAction = AB_PARITY_UNKN;
2072
+ break;
2073
+ /* case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE: */
2074
+ case AB_PARITY_UNDF:
2075
+ nAction = AB_PARITY_UNDF;
2076
+ break;
2077
+ case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
2078
+ case AB_PARITY_ODD | AB_NEGATIVE:
2079
+ case AB_PARITY_IISO:
2080
+ case AB_PARITY_IISO | AB_UNKNOWN:
2081
+ case AB_PARITY_UNDF | AB_NEGATIVE:
2082
+ case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
2083
+ nAction = AB_PARITY_NONE;
2084
+ break;
2085
+ default:
2086
+ nAction = -1; /* program error */
2087
+ }
2088
+ }
2089
+ return nAction;
2090
+ #undef AB_NEGATIVE
2091
+ #undef AB_UNKNOWN
2092
+ }
2093
+ /*************************************************************/
2094
+ int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
2095
+ INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo )
2096
+ {
2097
+ int j, k, next_at_1, i_next_at_1, i_next_at_2, at_2, next_at_2, num_stereo_bonds, bFound, bAllene;
2098
+ int bond_type, num_2s_1, num_alt_1;
2099
+ int num_2s_2, num_alt_2;
2100
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2101
+ int num_wrong_bonds_1, num_wrong_bonds_2;
2102
+ #endif
2103
+ #if( N_V_STEREOBONDS == 1 )
2104
+ int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
2105
+ #endif
2106
+ int num_stored_stereo_bonds, num_stored_isotopic_stereo_bonds;
2107
+ int chain_length, num_chains, cur_chain_length;
2108
+ int all_at_2[MAX_NUM_STEREO_BONDS];
2109
+ int all_pos_1[MAX_NUM_STEREO_BONDS], all_pos_2[MAX_NUM_STEREO_BONDS];
2110
+ S_CHAR all_unkn[MAX_NUM_STEREO_BONDS];
2111
+ int /*at_1_parity, at_2_parity,*/ nUnknown, stop=0;
2112
+
2113
+ /* at_1_parity = AB_PARITY_NONE; */ /* do not know */
2114
+ /* check valence */
2115
+ if ( MAX_NUM_STEREO_BOND_NEIGH < at[at_1].valence+at[at_1].num_H ||
2116
+ MIN_NUM_STEREO_BOND_NEIGH > at[at_1].valence+at[at_1].num_H )
2117
+ return 0;
2118
+ if ( !bCanAtomHaveAStereoBond( at[at_1].elname, at[at_1].charge, at[at_1].radical ) )
2119
+ return 0;
2120
+ if ( at[at_1].c_point )
2121
+ return 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
2122
+
2123
+ /* middle cumulene atoms, for example, =C=, should be ignored here */
2124
+ /* only atoms at the ends of cumulene chains are considered. */
2125
+ if ( !at[at_1].num_H && 2 == at[at_1].valence &&
2126
+ BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_1].bond_type[0] ) &&
2127
+ BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_1].bond_type[1] ) ) {
2128
+ return 0;
2129
+ }
2130
+
2131
+ /* count bonds and find the second atom on the stereo bond */
2132
+ num_2s_1 = num_alt_1 = 0;
2133
+ chain_length = 0;
2134
+ num_chains = 0;
2135
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2136
+ num_wrong_bonds_1 = 0;
2137
+ #endif
2138
+ #if( N_V_STEREOBONDS == 1 )
2139
+ num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
2140
+ if ( 0 == at[at_1].num_H && 0 == at[at_1].charge && 0 == at[at_1].radical &&
2141
+ 3 == get_endpoint_valence( at[at_1].el_number ) ) {
2142
+ if ( 2 == at[at_1].valence && 3 == at[at_1].chem_bonds_valence ) {
2143
+ type_N = 1;
2144
+ } else
2145
+ if ( 3 == at[at_1].valence && 5 == at[at_1].chem_bonds_valence ) {
2146
+ type_N = 2; /* unfortunately includes >N# */
2147
+ }
2148
+ }
2149
+ #endif
2150
+ for ( i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].valence; i_next_at_1 ++ ) {
2151
+ nUnknown = (at[at_1].bond_stereo[i_next_at_1] == STEREO_DBLE_EITHER);
2152
+ bond_type = get_allowed_stereo_bond_type( (int)at[at_1].bond_type[i_next_at_1] );
2153
+ if ( bond_type == BOND_ALTERN ||
2154
+ bond_type == BOND_DOUBLE ) {
2155
+ at_2 = next_at_1 = at[at_1].neighbor[i_next_at_1];
2156
+ next_at_2 = at_1;
2157
+ }
2158
+ switch ( bond_type ) {
2159
+ case BOND_ALTERN:
2160
+ num_alt_1 ++;
2161
+ #if( FIND_RING_SYSTEMS == 1 )
2162
+ if ( at[at_1].nRingSystem != at[at_2].nRingSystem )
2163
+ continue; /* reject alt. bond connecting different ring systems */
2164
+ #endif
2165
+ if ( (nMode & CMODE_NO_ALT_SBONDS) ||
2166
+ !bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
2167
+ continue; /* reject non-stereogenic bond to neighbor ord. #i_next_at_1 */
2168
+ }
2169
+ break;
2170
+ case BOND_DOUBLE:
2171
+ /* check for cumulene/allene */
2172
+ num_2s_1++;
2173
+ cur_chain_length = 0;
2174
+ if ( bCanAtomBeTerminalAllene( at[at_1].elname, at[at_1].charge, at[at_1].radical ) ) {
2175
+ /*
2176
+ * Example of cumulene
2177
+ * chain length = 2: >X=C=C=Y<
2178
+ * | | | |
2179
+ * 1st cumulene atom= at_1 | | at_2 =last cumlene chain atom
2180
+ * next to at_1= next_at_1 next_at_2 =previous to at_2
2181
+ *
2182
+ * chain length odd: stereocenter on the middle atom ( 1=> allene )
2183
+ * chain length even: "long stereogenic bond"
2184
+ */
2185
+ while ((bAllene =
2186
+ !at[at_2].num_H && at[at_2].valence == 2 &&
2187
+ BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_2].bond_type[0] ) &&
2188
+ BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_2].bond_type[1] )) &&
2189
+ bCanAtomBeMiddleAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
2190
+ k = ((int)at[at_2].neighbor[0]==next_at_2); /* opposite neighbor position */
2191
+ next_at_2 = at_2;
2192
+ nUnknown += (at[at_2].bond_stereo[k] == STEREO_DBLE_EITHER);
2193
+ at_2 = (int)at[at_2].neighbor[k];
2194
+ cur_chain_length ++; /* count =C= atoms */
2195
+ }
2196
+ if ( cur_chain_length ) {
2197
+ num_chains ++;
2198
+ if ( bAllene /* at the end of the chain atom Y is =Y=, not =Y< or =Y- */ ||
2199
+ !bCanAtomBeTerminalAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
2200
+ cur_chain_length = 0;
2201
+ continue; /* ignore: does not fit cumulene description; go to check next at_1 neighbor */
2202
+ }
2203
+ chain_length = cur_chain_length; /* accept a stereogenic cumulele */
2204
+ }
2205
+ }
2206
+ #if( N_V_STEREOBONDS == 1 )
2207
+ if ( !cur_chain_length &&
2208
+ 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + at_2 )) ) {
2209
+ num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
2210
+ }
2211
+ #endif
2212
+ if ( !cur_chain_length &&
2213
+ !bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
2214
+ continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
2215
+ }
2216
+
2217
+ break;
2218
+
2219
+ case BOND_SINGLE:
2220
+ case BOND_TAUTOM:
2221
+ continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
2222
+ default:
2223
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2224
+ num_wrong_bonds_1 ++;
2225
+ continue;
2226
+ #else
2227
+ return 0; /* wrong bond type; */
2228
+ #endif
2229
+ }
2230
+
2231
+ /* check atom at the opposite end of possibly stereogenic bond */
2232
+
2233
+ bFound = ( at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
2234
+
2235
+ if ( bFound ) {
2236
+ /* check "at_2" atom on the opposite side of the bond or cumulene chain */
2237
+ if ( MAX_NUM_STEREO_BOND_NEIGH < at[at_2].valence+at[at_2].num_H ||
2238
+ MIN_NUM_STEREO_BOND_NEIGH > at[at_2].valence+at[at_2].num_H )
2239
+ continue;
2240
+
2241
+ /* check at_2 neighbors and bonds */
2242
+ num_2s_2 = num_alt_2 = 0;
2243
+ #if( N_V_STEREOBONDS == 1 )
2244
+ num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
2245
+ if ( 0 == at[at_2].num_H && 0 == at[at_2].charge && 0 == at[at_2].radical &&
2246
+ 3 == get_endpoint_valence( at[at_2].el_number ) ) {
2247
+ if ( 2 == at[at_2].valence && 3 == at[at_2].chem_bonds_valence ) {
2248
+ type_N_next = 1; /* -N= */
2249
+ } else
2250
+ if ( 3 == at[at_2].valence && 5 == at[at_2].chem_bonds_valence ) {
2251
+ type_N_next = 2; /* unfortunately includes >N# */
2252
+ }
2253
+ }
2254
+ #endif
2255
+ i_next_at_2 = -1; /* unassigned mark */
2256
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2257
+ num_wrong_bonds_2 = 0;
2258
+ #endif
2259
+ for ( j = 0; j < at[at_2].valence; j ++ ) {
2260
+ bond_type = get_allowed_stereo_bond_type( (int)at[at_2].bond_type[j] );
2261
+ if ( !bond_type ) {
2262
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2263
+ num_wrong_bonds_2 ++;
2264
+ continue; /* this bond type is not allowed to be adjacent to a stereo bond */
2265
+ #else
2266
+ break;
2267
+ #endif
2268
+ }
2269
+ if ( bond_type == BOND_DOUBLE ) {
2270
+ num_2s_2 ++;
2271
+ #if( N_V_STEREOBONDS == 1 )
2272
+ next_next_at = at[at_2].neighbor[j];
2273
+ if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_next_at )) ) {
2274
+ num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
2275
+ }
2276
+ #endif
2277
+ } else {
2278
+ num_alt_2 += ( bond_type == BOND_ALTERN );
2279
+ }
2280
+ if ( (int)at[at_2].neighbor[j] == next_at_2 )
2281
+ i_next_at_2 = j; /* assigned */
2282
+ }
2283
+ if (
2284
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2285
+ num_wrong_bonds_2 > 1 || num_wrong_bonds_2 && 2 >= at[at_2].valence ||
2286
+ #else
2287
+ j < at[at_2].valence /* "next" has a wrong bond type*/ ||
2288
+ #endif
2289
+ (num_alt_2>0) + (num_2s_2>0) != 1 || /* all double XOR all alt bonds only */
2290
+ /* num_2s_2 > 1 ||*/ /* only one double bond permitted */
2291
+ i_next_at_2 < 0 /* atom next to the opposite atom not found */ ) {
2292
+ bFound = 0;
2293
+ } else
2294
+ if ( at[at_2].c_point ) {
2295
+ bFound = 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
2296
+ } else
2297
+ if ( num_2s_2 > 2 ) {
2298
+ bFound = 0;
2299
+ } else
2300
+ #if( N_V_STEREOBONDS == 1 )
2301
+ if ( 3 == (type_N | type_N_next) &&
2302
+ ( 2 == type_N && !bIsOxide( at, at_1 ) ||
2303
+ 2 == type_N_next && !bIsOxide( at, at_2 ) ) ) {
2304
+ bFound = 0;
2305
+ } else
2306
+ #endif
2307
+ if ( 2 == num_2s_2 ) {
2308
+ #if( N_V_STEREOBONDS == 1 )
2309
+ if ( !chain_length &&
2310
+ 1 == (num_2s_hetero_next[0] | num_2s_hetero_next[1]) &&
2311
+ 3 == at[at_2].valence + at[at_2].num_H &&
2312
+ 5 == at[at_2].chem_bonds_valence + at[at_2].num_H &&
2313
+ 3 == get_endpoint_valence( at[at_2].el_number ) &&
2314
+ (!type_N || bIsOxide( at, at_2 )) ) {
2315
+ /*
2316
+ * found:
2317
+ *
2318
+ * \ / \ / \ /
2319
+ * \ / \ / \ /
2320
+ * N==C or N==C or N==N
2321
+ * // \ // \ // \
2322
+ * O ^ \ N ^ \ O ^ \
2323
+ * | | |
2324
+ * | | |
2325
+ * at[at_2] at[at_2] at[at_2]
2326
+ */
2327
+ ;
2328
+ } else {
2329
+ bFound = 0;
2330
+ }
2331
+ #else
2332
+ bFound = 0;
2333
+ #endif
2334
+ }
2335
+
2336
+
2337
+ if ( chain_length && num_alt_2 )
2338
+ return 0; /* allow no alt bonds in cumulenes */
2339
+ }
2340
+ if ( bFound ) {
2341
+ all_pos_1[num_stereo_bonds] = i_next_at_1; /* neighbor to at_1 position */
2342
+ all_pos_2[num_stereo_bonds] = i_next_at_2; /* neighbor to at_2 position */
2343
+ all_at_2[num_stereo_bonds] = at_2; /* at_2 */
2344
+ all_unkn[num_stereo_bonds] = nUnknown; /* stereogenic bond has Unknown configuration */
2345
+ /*
2346
+ if ( (at[at_1].bUsed0DParity & 2) || (at[at_2].bUsed0DParity & 2) ) {
2347
+ for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k ++ ) {
2348
+ if ( at[at_1].sb_neigh[k] == i_next_at_1 ) {
2349
+ if ( at[at_1].sb_parity[k] == AB_PARITY_UNKN && !nUnknown ) {
2350
+ all_unkn[num_stereo_bonds] = 1;
2351
+ }
2352
+ break;
2353
+ }
2354
+ }
2355
+ }
2356
+ */
2357
+ num_stereo_bonds ++;
2358
+ }
2359
+ }
2360
+ if ( num_chains > 1 ) {
2361
+ return 0; /* cannot be more than 1 cumulene chain. */
2362
+ }
2363
+ #if( ONE_BAD_SB_NEIGHBOR == 1 )
2364
+ if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[at_1].valence ) {
2365
+ return 0; /* wrong bond type */
2366
+ }
2367
+ #endif
2368
+ /* accept only short chains for now */
2369
+ /* chain_length=1: >C=C=C< tetrahedral center, allene */
2370
+ /* chain_length=2: >C=C=C=C< stereogenic bond, cumulene */
2371
+ if ( chain_length && (num_stereo_bonds != 1 || num_alt_1 || chain_length > MAX_CUMULENE_LEN) ) {
2372
+ return 0;
2373
+ }
2374
+
2375
+ /* we need 1 double bond/chain XOR up to 3 arom. bonds */
2376
+ /* to have a stereogenic bond */
2377
+ if ( (num_alt_1>0) + (num_2s_1>0) != 1 || !num_stereo_bonds /*|| num_2s_1 > 1*/ )
2378
+ return 0;
2379
+
2380
+ if ( num_2s_1 > 1 ) {
2381
+ #if( N_V_STEREOBONDS == 1 )
2382
+ if ( 2 == num_2s_1 &&
2383
+ 2 == type_N &&
2384
+ 1 == (num_2s_hetero[0] | num_2s_hetero[1]) &&
2385
+ 3 == at[at_1].valence + at[at_1].num_H &&
2386
+ 5 == at[at_1].chem_bonds_valence + at[at_1].num_H &&
2387
+ 3 == get_endpoint_valence( at[at_1].el_number ) ) {
2388
+ ;
2389
+ } else {
2390
+ return 0;
2391
+ }
2392
+ #else
2393
+ return 0;
2394
+ #endif
2395
+ }
2396
+
2397
+ /* ================== calculate parities ====================== */
2398
+
2399
+
2400
+ /* find possibly stereo bonds and save them */
2401
+ num_stored_isotopic_stereo_bonds = 0;
2402
+ num_stored_stereo_bonds = 0;
2403
+ for ( k = 0; k < num_stereo_bonds; k ++ ) {
2404
+
2405
+ int cur_parity, next_parity, abs_cur_parity, abs_next_parity, dot_prod_z;
2406
+ S_CHAR z_dir1[3], z_dir2[3]; /* 3D vectors for half stereo bond parity direction */
2407
+ int chain_len_bits = MAKE_BITS_CUMULENE_LEN(chain_length);
2408
+ int cur_parity_defined, next_parity_defined;
2409
+ int cur_action, next_action, result_action;
2410
+
2411
+ at_2 = all_at_2[k];
2412
+ i_next_at_1 = all_pos_1[k];
2413
+
2414
+ #if( MIN_SB_RING_SIZE > 0 )
2415
+ if( at[at_1].nRingSystem == at[at_2].nRingSystem ) {
2416
+ /* check min. ring size only if both double bond/cumulene */
2417
+ /* ending atoms belong to the same ring system */
2418
+ j = is_bond_in_Nmax_memb_ring( at, at_1, i_next_at_1, q, nAtomLevel, cSource, min_sb_ring_size );
2419
+ if ( j > 0 ) {
2420
+ continue;
2421
+ } else
2422
+ if ( j < 0 ) {
2423
+ return CT_STEREOBOND_ERROR;
2424
+ }
2425
+ }
2426
+ #endif
2427
+
2428
+ i_next_at_2 = all_pos_2[k];
2429
+ nUnknown = all_unkn[k];
2430
+ memset(z_dir1, 0, sizeof(z_dir1));
2431
+ memset(z_dir2, 0, sizeof(z_dir2));
2432
+
2433
+ /********************************************************************************
2434
+ * find atom parities (negative means parity due to H-isotopes only)
2435
+ * and half stereo bond parity directions z_dir1, z_dir2.
2436
+ *
2437
+ * Bond can have unknown or undefined parity or no parity because of:
2438
+ * 1. Geometry (poorly defined, cannot calculate, for example linear =C-F
2439
+ * or =CHD with no geometry) -- Undefined parity
2440
+ * H
2441
+ * 2. Identical H atoms (no parity in principle, for example =C< )
2442
+ * -- No parity H
2443
+ *
2444
+ * 3. The user said double bond stereo is unknown
2445
+ * or at least one of single bonds is in unknown direction
2446
+ * -- Unknown parity
2447
+ *
2448
+ * These 3 cases (see above) are referred below as 1, 2, 3.
2449
+ * Each of the cases may be present or not (2 possibilities)
2450
+ * Total number of combination is 2*2*2=8
2451
+ *
2452
+ * Since a case when all 3 are not present is a well-defined parity,
2453
+ * we do not consider this case here. Then 2*2*2-1=7 cases are left.
2454
+ *
2455
+ * If several cases are present, list them below separated by "+".
2456
+ * For example, 1+2 means (1) undefined geometry and (2) no parity
2457
+ * is possible because of identical H atoms.
2458
+ *
2459
+ * N) Decision table, Non-isotopic, 2*2*2-1=7 cases:
2460
+ * =================================================
2461
+ * none : 2+any: 1+2(e.g.=CH2); 1+2+3; 2; 2+3 AB_PARITY_NONE=0
2462
+ * undefined: 1 AB_PARITY_UNDF
2463
+ * unknown : 1+3; 3 AB_PARITY_UNKN
2464
+ *
2465
+ * I) Decision table, Isotopic, 2*2*2-1=7 cases:
2466
+ * =============================================
2467
+ * none : none
2468
+ * undefined: 1; 1+2; 1+2+3; 2; 2+3
2469
+ * unknown : 1+3; 3
2470
+ *
2471
+ * Note: When defining identical atoms H atoms in case 2,
2472
+ * Isotopic and Non-isotopic cases are different:
2473
+ * N: do NOT take into account the isotopic composition of H atoms
2474
+ * I: DO take into account the isotopic composition of H atoms
2475
+ * (it is assumed that H isotopes are always different)
2476
+ *
2477
+ * half_stereo_bond_parity() returns:
2478
+ * ==================================
2479
+ * Note: half_stereo_bond_parity() is unaware of case 3.
2480
+ *
2481
+ * can't be a half of a stereo bond AB_PARITY_NONE
2482
+ * 1, isotopic & non-isotopic: AB_PARITY_UNDF
2483
+ * 1, isotopic only -AB_PARITY_UNDF
2484
+ * 2, no parity: identical H isotopes AB_PARITY_IISO
2485
+ * 3, 'Either' single bond(s) AB_PARITY_UNKN ???
2486
+ * 3, 'Either' single bond(s), iso H -AB_PARITY_UNKN ???
2487
+ * defined parity AB_PARITY_ODD, AB_PARITY_EVEN
2488
+ * defined parity for isotopic only: -AB_PARITY_ODD, -AB_PARITY_EVEN
2489
+ *
2490
+ * Resultant value for the stereo bond parity
2491
+ * ---+-------------------+-------+--------+----------------+
2492
+ * 3? | half_stereo_bond_ | N or I| case 1,| bond parity |
2493
+ * | parity()= | | 2 or 3 | |
2494
+ * ---+-------------------+-------+--------+----------------+
2495
+ * ( AB_PARITY_ODD/EVEN) => N&I: - => AB_PARITY_CALC (=6, calc.later)
2496
+ * 3+( AB_PARITY_ODD/EVEN) => N&I: 3 => AB_PARITY_UNKN (=3)
2497
+ * (-AB_PARITY_ODD/EVEN) => N: 2 => AB_PARITY_NONE (=0)
2498
+ * (-AB_PARITY_ODD/EVEN) => I: - => AB_PARITY_CALC
2499
+ * 3+(-AB_PARITY_ODD/EVEN) => N: 2+3 => AB_PARITY_UNDF (=4)
2500
+ * 3+(-AB_PARITY_ODD/EVEN) => I: 3 => AB_PARITY_UNKN
2501
+ * ( AB_PARITY_IISO ) => N: 1+2, 2 => AB_PARITY_NONE (=0)
2502
+ * ( AB_PARITY_IISO ) => I: 1+2, 2 => AB_PARITY_UNDF
2503
+ * 3+( AB_PARITY_IISO ) => N: 1+2+3,2+3=> AB_PARITY_NONE
2504
+ * 3+( AB_PARITY_IISO ) => I: 1+2+3,2+3=> AB_PARITY_UNDF
2505
+ * ( AB_PARITY_UNDF ) => N&I: 1 => AB_PARITY_UNDF
2506
+ * 3+( AB_PARITY_UNDF ) => N&I: 1+3 => AB_PARITY_UNKN
2507
+ * (-AB_PARITY_UNDF ) => N: 1+2 => AB_PARITY_NONE
2508
+ * (-AB_PARITY_UNDF ) => I: 1 => AB_PARITY_UNDF
2509
+ * 3+(-AB_PARITY_UNDF ) => N: 1+2+3 => AB_PARITY_NONE
2510
+ * 3+(-AB_PARITY_UNDF ) => I: 1+3 => AB_PARITY_UNKN
2511
+ * ---+-------------------+-------+--------+----------------+
2512
+
2513
+ * If bond parity is undefined because abs(dot_prod_z) < MIN_DOT_PROD
2514
+ * then replace: AB_PARITY_CALC
2515
+ * with: AB_PARITY_UNDF
2516
+ * Joining two half_bond_parity() results:
2517
+ *
2518
+ *
2519
+ * atom1 \ atom2 | AB_PARITY_NONE AB_PARITY_UNKN AB_PARITY_UNDF AB_PARITY_CALC
2520
+ * ----------------+---------------------------------------------------------------
2521
+ *0=AB_PARITY_NONE | AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE
2522
+ *3=AB_PARITY_UNKN | AB_PARITY_UNKN AB_PARITY_UNKN AB_PARITY_UNKN
2523
+ *4=AB_PARITY_UNDF | AB_PARITY_UNDF AB_PARITY_UNDF
2524
+ *6=AB_PARITY_CALC | AB_PARITY_CALC
2525
+ *
2526
+ * that is, take min out of the two
2527
+ *********************************************************************************/
2528
+
2529
+ cur_parity = half_stereo_bond_parity( at, at_1, at_removed_H, num_removed_H, z_dir1, bPointedEdgeStereo );
2530
+ next_parity = half_stereo_bond_parity( at, at_2, at_removed_H, num_removed_H, z_dir2, bPointedEdgeStereo );
2531
+
2532
+ if ( RETURNED_ERROR(cur_parity) || RETURNED_ERROR(next_parity) ) {
2533
+ return CT_CALC_STEREO_ERR;
2534
+ }
2535
+ if ( (at[at_1].bUsed0DParity & FlagSB_0D) || (at[at_1].bUsed0DParity & FlagSB_0D) ) {
2536
+ FixSb0DParities( at, /* at_removed_H, num_removed_H,*/ chain_length,
2537
+ at_1, i_next_at_1, z_dir1,
2538
+ at_2, i_next_at_2, z_dir2, &cur_parity, &next_parity );
2539
+ }
2540
+
2541
+ if ( cur_parity == AB_PARITY_NONE || abs(cur_parity) == AB_PARITY_IISO ) {
2542
+ continue;
2543
+ }
2544
+ if ( next_parity == AB_PARITY_NONE || abs(next_parity) == AB_PARITY_IISO ) {
2545
+ continue;
2546
+ }
2547
+
2548
+ cur_action = half_stereo_bond_action( cur_parity, nUnknown, 0 ); /* -1 => program error */
2549
+ next_action = half_stereo_bond_action( next_parity, nUnknown, 0 );
2550
+ result_action = inchi_min(cur_action, next_action);
2551
+
2552
+ if ( result_action == -1 ) {
2553
+ stop = 1; /* program error <BRKPT> */
2554
+ }
2555
+
2556
+ abs_cur_parity = abs( cur_parity );
2557
+ abs_next_parity = abs( next_parity );
2558
+ cur_parity_defined = ATOM_PARITY_WELL_DEF(abs_cur_parity);
2559
+ next_parity_defined = ATOM_PARITY_WELL_DEF(abs_next_parity);
2560
+
2561
+
2562
+ if ( cur_parity_defined && next_parity_defined ) {
2563
+ /* find how the whole bond parity depend on geometry */
2564
+ /* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
2565
+ /* can be done only for a well-defined geometry */
2566
+ /*
2567
+ dot_prod_z = (chain_len_bits & BIT_CUMULENE_CHI)?
2568
+ triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
2569
+ dot_prodchar3(z_dir1, z_dir2);
2570
+ */
2571
+ dot_prod_z = (chain_len_bits && BOND_CHAIN_LEN(chain_len_bits)%2)?
2572
+ triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
2573
+ dot_prodchar3(z_dir1, z_dir2);
2574
+
2575
+ if ( abs(dot_prod_z) < MIN_DOT_PROD ) {
2576
+ /* The geometry is not well-defined. Eliminate AB_PARITY_CALC */
2577
+ result_action = inchi_min( result_action, AB_PARITY_UNDF );
2578
+ }
2579
+ } else {
2580
+ dot_prod_z = 0;
2581
+ }
2582
+
2583
+ if ( result_action != AB_PARITY_NONE && result_action != -1 ) {
2584
+ /* stereo, no isotopes (only positive) */
2585
+ if ( cur_parity > 0 && next_parity > 0 ) {
2586
+ if ( save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
2587
+ at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor,
2588
+ out_at[at_1].stereo_bond_ord, out_at[at_1].stereo_bond_z_prod,
2589
+ out_at[at_1].stereo_bond_parity,
2590
+ at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor,
2591
+ out_at[at_2].stereo_bond_ord, out_at[at_2].stereo_bond_z_prod,
2592
+ out_at[at_2].stereo_bond_parity) ) {
2593
+ if ( !out_at[at_1].parity ||
2594
+ cur_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_1].parity)) ) {
2595
+ out_at[at_1].parity = cur_parity;
2596
+ memcpy( out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir) );
2597
+ }
2598
+ if ( !out_at[at_2].parity ||
2599
+ next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity)) ) {
2600
+ out_at[at_2].parity = next_parity;
2601
+ memcpy( out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir) );
2602
+ }
2603
+ out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
2604
+ out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
2605
+ num_stored_stereo_bonds ++;
2606
+ }
2607
+ }
2608
+ }
2609
+
2610
+ /* stereo + isotopic (all non-zero) */
2611
+ cur_action = half_stereo_bond_action( cur_parity, nUnknown, 1 ); /* -1 => program error */
2612
+ next_action = half_stereo_bond_action( next_parity, nUnknown, 1 );
2613
+ result_action = inchi_min(cur_action, next_action);
2614
+ cur_parity = abs_cur_parity;
2615
+ next_parity = abs_next_parity;
2616
+ if ( result_action != AB_PARITY_NONE && result_action != -1 ) {
2617
+ /* stero, isotopic */
2618
+ if ( cur_parity > 0 && next_parity > 0 ) {
2619
+ if( save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
2620
+ at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor2,
2621
+ out_at[at_1].stereo_bond_ord2, out_at[at_1].stereo_bond_z_prod2,
2622
+ out_at[at_1].stereo_bond_parity2,
2623
+ at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor2,
2624
+ out_at[at_2].stereo_bond_ord2, out_at[at_2].stereo_bond_z_prod2,
2625
+ out_at[at_2].stereo_bond_parity2) ) {
2626
+ if ( !out_at[at_1].parity2 ||
2627
+ cur_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_1].parity2)) ) {
2628
+ out_at[at_1].parity2 = cur_parity /*| chain_len_bits*/;
2629
+ if ( !out_at[at_1].parity ) {
2630
+ memcpy( out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir) );
2631
+ }
2632
+ }
2633
+ if ( !out_at[at_2].parity2 ||
2634
+ next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity)) ) {
2635
+ out_at[at_2].parity2 = next_parity /*| chain_len_bits*/;
2636
+ if ( !out_at[at_2].parity ) {
2637
+ memcpy( out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir) );
2638
+ }
2639
+ }
2640
+ out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
2641
+ out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
2642
+ num_stored_isotopic_stereo_bonds ++;
2643
+ }
2644
+ }
2645
+ } else
2646
+ if ( result_action == -1 ) {
2647
+ stop = 1; /* program error? <BRKPT> */
2648
+ }
2649
+
2650
+ }
2651
+ if ( stop ) {
2652
+ return CT_CALC_STEREO_ERR;
2653
+ }
2654
+ return /*num_stored_stereo_bonds+*/ num_stored_isotopic_stereo_bonds;
2655
+ }
2656
+
2657
+
2658
+ /*********************************************************************/
2659
+ /* if isotopic H, D, T added, can the atom be a stereo center? */
2660
+ #if( NEW_STEREOCENTER_CHECK == 1 )
2661
+ /* int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at ) */
2662
+ int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
2663
+ {
2664
+ int nNumNeigh;
2665
+ if ( (nNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at )) &&
2666
+ at[cur_at].valence + at[cur_at].num_H == nNumNeigh &&
2667
+ at[cur_at].num_H <= NUM_H_ISOTOPES
2668
+ ) {
2669
+ return 1;
2670
+ }
2671
+ return 0;
2672
+ }
2673
+ #else
2674
+ int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
2675
+ {
2676
+ int j, ret = 0;
2677
+ if ( bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) &&
2678
+ at[cur_at].valence + at[cur_at].num_H == MAX_NUM_STEREO_ATOM_NEIGH &&
2679
+ at[cur_at].num_H < MAX_NUM_STEREO_ATOM_NEIGH
2680
+ ) {
2681
+
2682
+ for ( j = 0, ret=1; ret && j < at[cur_at].valence; j ++ ) {
2683
+ if ( (at[cur_at].bond_type[j] & ~BOND_MARK_ALL) != BOND_SINGLE ) {
2684
+ ret = 0;
2685
+ }
2686
+ }
2687
+ }
2688
+ return ret;
2689
+ }
2690
+ #endif
2691
+ /***************************************************************/
2692
+ int GetStereocenter0DParity( inp_ATOM *at, int cur_at, int j1, AT_NUMB nSbNeighOrigAtNumb[], int nFlag )
2693
+ {
2694
+ int parity = AB_PARITY_NONE;
2695
+ if ( at[cur_at].p_parity && (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH) ) {
2696
+ int i, num_trans_inp, num_trans_neigh;
2697
+ AT_NUMB nInpNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
2698
+ for ( i = 0; i < MAX_NUM_STEREO_ATOM_NEIGH; i ++ ) {
2699
+ nInpNeighOrigAtNumb[i] = at[cur_at].p_orig_at_num[i];
2700
+ if ( nInpNeighOrigAtNumb[i] == at[cur_at].orig_at_number ) {
2701
+ nInpNeighOrigAtNumb[i] = 0; /* lone pair or explicit H */
2702
+ }
2703
+ }
2704
+ num_trans_inp = insertions_sort( nInpNeighOrigAtNumb, MAX_NUM_STEREO_ATOM_NEIGH, sizeof(nInpNeighOrigAtNumb[0]), comp_AT_NUMB );
2705
+ num_trans_neigh = insertions_sort( nSbNeighOrigAtNumb, j1, sizeof(nSbNeighOrigAtNumb[0]), comp_AT_NUMB );
2706
+ if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2707
+ ; /*num_trans_neigh += j1;*/ /* the lone pair or implicit H is implicitly at the top of the list */
2708
+ }
2709
+ if ( !memcmp( nInpNeighOrigAtNumb + MAX_NUM_STEREO_ATOM_NEIGH-j1, nSbNeighOrigAtNumb, j1*sizeof(AT_NUMB) ) ) {
2710
+ if ( ATOM_PARITY_WELL_DEF(at[cur_at].p_parity) ) {
2711
+ parity = 2 - (num_trans_inp + num_trans_neigh + at[cur_at].p_parity) % 2;
2712
+ } else {
2713
+ parity = at[cur_at].p_parity;
2714
+ }
2715
+ at[cur_at].bUsed0DParity |= nFlag; /* 0D parity used for streocenter parity */
2716
+ }
2717
+ }
2718
+ return parity;
2719
+ }
2720
+
2721
+ /***************************************************************
2722
+ * Get stereo atom parity for the current order of attachments
2723
+ * The result in at[cur_at].parity is valid for previously removed
2724
+ * explicit hydrogen atoms, including isotopic ones, that are located in at_removed_H[]
2725
+ * The return value is a calculated parity.
2726
+ */
2727
+ #define ADD_EXPLICIT_HYDROGEN_NEIGH 1
2728
+ #define ADD_EXPLICIT_LONE_PAIR_NEIGH 2
2729
+ int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H,
2730
+ int num_removed_H, int bPointedEdgeStereo )
2731
+ {
2732
+ int j, k, next_at, num_z, j1, nType, num_explicit_H, tot_num_iso_H, nMustHaveNumNeigh;
2733
+ int num_explicit_iso_H[NUM_H_ISOTOPES+1]; /* numbers of removed hydrogen atoms */
2734
+ int index_H[MAX_NUM_STEREO_ATOM_NEIGH]; /* cannot have more than 4 elements: 1 H, 1 D, 1 T atom(s) */
2735
+ double z, sum_xyz[3], min_sine, triple_product;
2736
+ double at_coord[MAX_NUM_STEREO_ATOM_NEIGH][3];
2737
+ double bond_len_xy[4], rmax, rmin;
2738
+ double at_coord_center[3];
2739
+ int parity, bAmbiguous = 0, bAddExplicitNeighbor = 0, b2D = 0, n2DTetrahedralAmbiguity = 0;
2740
+ int bIgnoreIsotopicH = (0 != (at[cur_at].cFlags & AT_FLAG_ISO_H_POINT));
2741
+ AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
2742
+
2743
+ out_at[cur_at].parity =
2744
+ out_at[cur_at].parity2 =
2745
+ out_at[cur_at].stereo_atom_parity =
2746
+ out_at[cur_at].stereo_atom_parity2 = AB_PARITY_NONE;
2747
+ parity = AB_PARITY_NONE;
2748
+
2749
+ memset(num_explicit_iso_H, 0, sizeof(num_explicit_iso_H));
2750
+ num_explicit_H = 0;
2751
+
2752
+ #if( NEW_STEREOCENTER_CHECK == 1 )
2753
+ if ( !(nMustHaveNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at ) ) ||
2754
+ at[cur_at].num_H > NUM_H_ISOTOPES
2755
+ ) {
2756
+ goto exit_function;
2757
+ }
2758
+ #else
2759
+ nMustHaveNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH;
2760
+ if ( !bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) ||
2761
+ at[cur_at].valence + at[cur_at].num_H != nMustHaveNumNeigh ||
2762
+ at[cur_at].num_H > NUM_H_ISOTOPES
2763
+ ) {
2764
+ goto exit_function;
2765
+ }
2766
+ for ( j = 0; j < at[cur_at].valence; j ++ ) {
2767
+ if ( (at[cur_at].bond_type[j] & ~BOND_MARK_ALL) != BOND_SINGLE ) {
2768
+ goto exit_function;
2769
+ }
2770
+ }
2771
+ #endif
2772
+
2773
+ /* numbers of isotopic H atoms */
2774
+ for ( j = 0, tot_num_iso_H = 0; j < NUM_H_ISOTOPES; j ++ ) {
2775
+ if ( at[cur_at].num_iso_H[j] > 1 ) {
2776
+ goto exit_function; /* two or more identical hydrogen isotopic neighbors */
2777
+ }
2778
+ tot_num_iso_H += at[cur_at].num_iso_H[j];
2779
+ }
2780
+ if ( bIgnoreIsotopicH ) {
2781
+ tot_num_iso_H = 0; /* isotopic H considered subject to exchange => ignore isotopic */
2782
+ }
2783
+ /* number of non-isotopic H atoms */
2784
+ if ( at[cur_at].num_H - tot_num_iso_H > 1 ) {
2785
+ goto exit_function; /* two or more identical hydrogen non-isotopic neighbors */
2786
+ }
2787
+
2788
+ /* count removed explicit terminal hydrogens attached to at[cur_at]. */
2789
+ /* the result is num_explicit_H. */
2790
+ /* Removed hydrogens are sorted in increasing isotopic shift order */
2791
+ if ( at_removed_H && num_removed_H > 0 ) {
2792
+ for ( j = 0; j < num_removed_H; j ++ ) {
2793
+ if ( at_removed_H[j].neighbor[0] == cur_at ) {
2794
+ k = at_removed_H[j].iso_atw_diff;
2795
+ /* iso_atw_diff values: H=>0, 1H=>1, D=2H=>2, T=3H=>3 */
2796
+ if ( k < 0 || k > NUM_H_ISOTOPES || bIgnoreIsotopicH )
2797
+ k = 0; /* treat wrong H isotopes as non-isotopic H */
2798
+ num_explicit_iso_H[k] ++;
2799
+ index_H[num_explicit_H++] = j;
2800
+ }
2801
+ }
2802
+ }
2803
+
2804
+ /* coordinates initialization */
2805
+ num_z = 0;
2806
+ sum_xyz[0] = sum_xyz[1] = sum_xyz[2] = 0.0;
2807
+
2808
+ at_coord_center[0] =
2809
+ at_coord_center[1] =
2810
+ at_coord_center[2] = 0.0;
2811
+
2812
+ /* fill out stereo center neighbors coordinates */
2813
+ /* and obtain the parity from the geometry */
2814
+
2815
+ for ( k = 0, j1 = 0; k < 2; k ++ ) {
2816
+ switch( k ) {
2817
+
2818
+ case 0:
2819
+ /* add coordinates of removed hydrogens */
2820
+ for ( j = 0; j < num_explicit_H; j ++, j1 ++ ) {
2821
+ next_at = index_H[j];
2822
+ /* use bond description located at removed_H atom */
2823
+ /* minus sign at get_z_coord: at_removed_H[] contains bonds TO at[cur_at], not FROM it. */
2824
+ /* Note: &at[(at_removed_H-at)+ next_at] == &at_removed_H[next_at] */
2825
+ z = -get_z_coord( at, (at_removed_H-at)+ next_at, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
2826
+ switch ( nType ) {
2827
+ case ZTYPE_EITHER:
2828
+ parity = AB_PARITY_UNKN; /* no parity: bond in "Either" direction. */
2829
+ goto exit_function;
2830
+ case ZTYPE_UP:
2831
+ case ZTYPE_DOWN:
2832
+ nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
2833
+ b2D ++;
2834
+ /* no break; here */
2835
+ case ZTYPE_3D:
2836
+ num_z ++;
2837
+ }
2838
+
2839
+ nSbNeighOrigAtNumb[j1] = at_removed_H[next_at].orig_at_number;
2840
+ at_coord[j1][0] = at_removed_H[next_at].x-at[cur_at].x;
2841
+ at_coord[j1][1] = at_removed_H[next_at].y-at[cur_at].y;
2842
+ bond_len_xy[j1] = len2(at_coord[j1]);
2843
+ /* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
2844
+ at_coord[j1][2] = (nType==ZTYPE_3D? z :
2845
+ nType==ZTYPE_UP? bond_len_xy[j1] :
2846
+ nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
2847
+ }
2848
+ break;
2849
+ case 1:
2850
+ /* add all coordinates of other neighboring atoms */
2851
+ for ( j = 0; j < at[cur_at].valence; j ++, j1 ++ ) {
2852
+ next_at = at[cur_at].neighbor[j];
2853
+ z = get_z_coord( at, cur_at, j, &nType, bPointedEdgeStereo );
2854
+ switch ( nType ) {
2855
+ case ZTYPE_EITHER:
2856
+ parity = AB_PARITY_UNKN; /* unknown parity: bond in "Either" direction. */
2857
+ goto exit_function;
2858
+ case ZTYPE_UP:
2859
+ case ZTYPE_DOWN:
2860
+ b2D ++;
2861
+ case ZTYPE_3D:
2862
+ num_z ++;
2863
+ }
2864
+
2865
+ nSbNeighOrigAtNumb[j1] = at[next_at].orig_at_number;
2866
+ at_coord[j1][0] = at[next_at].x-at[cur_at].x;
2867
+ at_coord[j1][1] = at[next_at].y-at[cur_at].y;
2868
+ bond_len_xy[j1] = len2(at_coord[j1]);
2869
+ /* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
2870
+ at_coord[j1][2] = (nType==ZTYPE_3D? z :
2871
+ nType==ZTYPE_UP? bond_len_xy[j1] :
2872
+ nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
2873
+ }
2874
+ break;
2875
+ }
2876
+ }
2877
+ /* j1 is the number of explicit neighbors (that is, all neighbors except implicit H) */
2878
+
2879
+ b2D = (b2D == num_z && num_z); /* 1 => two-dimensional */
2880
+
2881
+ if ( MAX_NUM_STEREO_ATOM_NEIGH != at[cur_at].valence+num_explicit_H &&
2882
+ MAX_NUM_STEREO_ATOM_NEIGH-1 != at[cur_at].valence+num_explicit_H ) {
2883
+ /* not enough geometry data to find the central atom parity */
2884
+ if ( nMustHaveNumNeigh == at[cur_at].valence+at[cur_at].num_H &&
2885
+ at[cur_at].num_H > 1 ) {
2886
+ /* only isotopic parity is possible; no non-isotopic parity */
2887
+ if ( parity == AB_PARITY_UNKN ) {
2888
+ parity = -AB_PARITY_UNKN; /* the user marked the center as "unknown" */
2889
+ } else {
2890
+ parity = -AB_PARITY_UNDF; /* not enough geometry; only isotopic parity is possible */
2891
+ }
2892
+ } else {
2893
+ parity = AB_PARITY_NONE; /* not a stereocenter at all */
2894
+ }
2895
+ goto exit_function;
2896
+ }
2897
+ /* make all vector lengths equal to 1; exit if too short. 9-10-2002 */
2898
+ for ( j = 0; j < j1; j ++ ) {
2899
+ z = len3( at_coord[j] );
2900
+ if ( z < MIN_BOND_LEN ) {
2901
+ /* bond length is too small: use 0D parities */
2902
+ if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
2903
+ parity = AB_PARITY_UNDF;
2904
+ }
2905
+ goto exit_function;
2906
+ }
2907
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
2908
+ else {
2909
+ mult3( at_coord[j], 1.0/z, at_coord[j] );
2910
+ }
2911
+ #endif
2912
+ rmax = j? inchi_max( rmax, z) : z;
2913
+ rmin = j? inchi_min( rmin, z) : z;
2914
+ }
2915
+ if ( rmin / rmax < MIN_SINE ) {
2916
+ /* bond ratio is too small: use 0D parities */
2917
+ if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
2918
+ parity = AB_PARITY_UNDF;
2919
+ }
2920
+ goto exit_function;
2921
+ }
2922
+ for ( j = 0; j < j1; j ++ ) {
2923
+ add3( sum_xyz, at_coord[j], sum_xyz );
2924
+ }
2925
+
2926
+
2927
+
2928
+ /* here j1 is a number of neighbors including explicit terminal isotopic H */
2929
+ /* num_explicit_iso_H[0] = number of explicit non-isotopic hydrogen atom neighbors */
2930
+ j = j1;
2931
+ /* Add Explicit Neighbor */
2932
+ if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2933
+ /* add an explicit neighbor if possible */
2934
+ if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2935
+ bAddExplicitNeighbor = ADD_EXPLICIT_LONE_PAIR_NEIGH;
2936
+ } else
2937
+ if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH ) {
2938
+ /* check whether an explicit non-isotopic hydrogen can be added */
2939
+ /* to an atom that is a stereogenic atom */
2940
+ if ( 1 == at[cur_at].num_H - num_explicit_H && /* the atom has only one one implicit hydrogen */
2941
+ 1 == at[cur_at].num_H - tot_num_iso_H ) { /* this hydrogen is non-isotopic */
2942
+ bAddExplicitNeighbor = ADD_EXPLICIT_HYDROGEN_NEIGH;
2943
+ }
2944
+ }
2945
+ }
2946
+
2947
+ if ( bAddExplicitNeighbor ) {
2948
+ /***********************************************************
2949
+ * May happen only if (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1)
2950
+ * 3 neighbors only, no H-neighbors. Create and add coordinates of an implicit H
2951
+ * or a fake 4th neighbor, that is, a lone pair
2952
+ */
2953
+ if ( parity == AB_PARITY_UNKN ) {
2954
+ goto exit_function; /* the user insists the parity is unknown and the isotopic */
2955
+ /* composition of the neighbors does not contradict */
2956
+ } else
2957
+ if ( num_z == 0 || are_3_vect_in_one_plane(at_coord, MIN_SINE) ) {
2958
+ /* "hydrogen down" rule is needed to resolve an ambiguity */
2959
+ if ( num_z > 0 ) {
2960
+ bAmbiguous |= AMBIGUOUS_STEREO;
2961
+ }
2962
+ #if( APPLY_IMPLICIT_H_DOWN_RULE == 1 ) /* { */
2963
+ /* Although H should be at the top of the list, add it to the bottom. */
2964
+ /* This will be taken care of later by inverting parity 1<->2 */
2965
+ at_coord[j][0] = 0.0;
2966
+ at_coord[j][1] = 0.0;
2967
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
2968
+ at_coord[j][2] = -1.0;
2969
+ #else
2970
+ at_coord[j][2] = -(bond_len_xy[0]+bond_len_xy[1]+bond_len_xy[2])/3.0;
2971
+ #endif
2972
+ #else /* } APPLY_IMPLICIT_H_DOWN_RULE { */
2973
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
2974
+ parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
2975
+ #else
2976
+ /* all 3 bonds are in one plain: try to get 0D parities */
2977
+ if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
2978
+ parity = AB_PARITY_UNDF;
2979
+ }
2980
+ /*parity = AB_PARITY_UNDF;*/ /* no parity can be calculated found */
2981
+ #endif
2982
+ goto exit_function;
2983
+ #endif /* } APPLY_IMPLICIT_H_DOWN_RULE */
2984
+ } else {
2985
+ /* we have enough information to find implicit hydrogen coordinates */
2986
+ /*
2987
+ at_coord[j][0] = -sum_x;
2988
+ at_coord[j][1] = -sum_y;
2989
+ at_coord[j][2] = -sum_z;
2990
+ */
2991
+ copy3( sum_xyz, at_coord[j] );
2992
+ change_sign3( at_coord[j], at_coord[j] );
2993
+ z = len3( at_coord[j] );
2994
+ rmax = inchi_max( rmax, z );
2995
+ rmin = inchi_min( rmin, z );
2996
+ if ( z < MIN_BOND_LEN || rmin/rmax < MIN_SINE ) {
2997
+ /* the new 4th bond is too short: try to get 0D parities */
2998
+ if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
2999
+ parity = AB_PARITY_UNDF;
3000
+ }
3001
+ goto exit_function;
3002
+ }
3003
+ #if( STEREO_CENTER_BOND4_NORM == 1 )
3004
+ else {
3005
+ mult3( at_coord[j], 1.0/z, at_coord[j] );
3006
+ }
3007
+ #endif
3008
+ }
3009
+ } else
3010
+ if ( j1 != MAX_NUM_STEREO_ATOM_NEIGH ) {
3011
+ if ( parity == AB_PARITY_UNKN ) {
3012
+ parity = -AB_PARITY_UNDF; /* isotopic composition of H-neighbors contradicts 'unknown' */
3013
+ }
3014
+ goto exit_function;
3015
+ } else /* j1 == MAX_NUM_STEREO_ATOM_NEIGH */
3016
+ if ( num_z == 0 || are_4at_in_one_plane(at_coord, MIN_SINE) ) {
3017
+ /* all four neighours in xy plane: undefined geometry. */
3018
+ if ( num_z > 0 ) {
3019
+ bAmbiguous |= AMBIGUOUS_STEREO;
3020
+ }
3021
+ if ( parity != AB_PARITY_UNKN ) {
3022
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
3023
+ parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
3024
+ #else
3025
+ /* all 4 bonds are in one plain: try to get 0D parities */
3026
+ if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
3027
+ parity = AB_PARITY_UNDF;
3028
+ } else
3029
+ if ( ATOM_PARITY_WELL_DEF( parity ) ) {
3030
+ bAmbiguous &= ~AMBIGUOUS_STEREO; /* 0D parity has resolved the ambiguity */
3031
+ }
3032
+ #endif
3033
+ }
3034
+ goto exit_function;
3035
+ }
3036
+ /***********************************************************
3037
+ * At this point we have 4 neighboring atoms.
3038
+ * check for tetrahedral ambiguity in 2D case
3039
+ */
3040
+ if ( b2D ) {
3041
+ if ( 0 < (n2DTetrahedralAmbiguity = Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor )) ) {
3042
+ if ( T2D_WARN & n2DTetrahedralAmbiguity ) {
3043
+ bAmbiguous |= AMBIGUOUS_STEREO;
3044
+ }
3045
+ if ( T2D_UNDF & n2DTetrahedralAmbiguity ) {
3046
+ if ( parity != AB_PARITY_UNKN ) {
3047
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
3048
+ parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
3049
+ #else
3050
+ parity = AB_PARITY_UNDF; /* no parity */
3051
+ #endif
3052
+ }
3053
+ goto exit_function;
3054
+ }
3055
+ } else
3056
+ if ( n2DTetrahedralAmbiguity < 0 ) {
3057
+ bAmbiguous |= AMBIGUOUS_STEREO_ERROR; /* error */
3058
+ parity = AB_PARITY_UNDF;
3059
+ goto exit_function;
3060
+ }
3061
+ }
3062
+
3063
+ /************************************************************/
3064
+ /* Move coordinates origin to the neighbor #0 */
3065
+ for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
3066
+ diff3(at_coord[j], at_coord[0], at_coord[j]);
3067
+ }
3068
+ diff3(at_coord_center, at_coord[0], at_coord_center);
3069
+
3070
+ /*
3071
+ for ( k = 0; k < 3; k++ ) {
3072
+ for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
3073
+ at_coord[j][k] -= at_coord[0][k];
3074
+ }
3075
+ at_coord_center[k] -= at_coord[0][k];
3076
+ }
3077
+ */
3078
+ /********************************************************
3079
+ * find the central (cur_at) atom's parity
3080
+ * (orientation of atoms #1-3 when looking from #0)
3081
+ ********************************************************/
3082
+ triple_product = triple_prod_and_min_abs_sine2(&at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous);
3083
+ /*
3084
+ *triple_product = triple_prod_and_min_abs_sine( &at_coord[1], &min_sine);
3085
+ * check for tetrahedral ambiguity -- leave it out for now
3086
+ *triple_product = sp3_triple_prod_and_min_abs_sine( &at_coord[1], at_coord_center, &min_sine, &bAmbiguous);
3087
+ */
3088
+ if ( fabs(triple_product) > ZERO_FLOAT && (min_sine > MIN_SINE || fabs(min_sine) > ZERO_FLOAT && (n2DTetrahedralAmbiguity & T2D_OKAY ) ) ) {
3089
+ /* Even => sorted in correct order, Odd=>transposed */
3090
+ parity = triple_product > 0.0? AB_PARITY_EVEN : AB_PARITY_ODD;
3091
+ /* if ( num_explicit_H && at[cur_at].removed_H_parity % 2 ) */
3092
+ /* odd transposition of the removed implicit H */
3093
+ /* out_at[cur_at].parity = 3 - out_at[cur_at].parity; */
3094
+
3095
+ /* moved; see below */
3096
+ /* out_at[cur_at].bAmbiguousStereo |= bAmbiguous; */
3097
+ /* at[cur_at].bAmbiguousStereo |= bAmbiguous; */
3098
+
3099
+ /* for 4 attached atoms, moving the implicit H from index=3 to index=0 */
3100
+ /* can be done in odd number (3) transpositions: (23)(12)(01), which inverts the parity */
3101
+ if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
3102
+ parity = 3 - parity;
3103
+ }
3104
+ } else {
3105
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
3106
+ parity = AT_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
3107
+ #else
3108
+ if ( num_z > 0 ) {
3109
+ bAmbiguous |= AMBIGUOUS_STEREO;
3110
+ }
3111
+ parity = AB_PARITY_UNDF; /* no parity: 4 bonds are in one plane. */
3112
+ #endif
3113
+ }
3114
+ exit_function:
3115
+
3116
+ if ( parity ) {
3117
+ out_at[cur_at].bAmbiguousStereo |= bAmbiguous;
3118
+ at[cur_at].bAmbiguousStereo |= bAmbiguous;
3119
+ }
3120
+
3121
+
3122
+ /* non-isotopic parity */
3123
+ if ( at[cur_at].num_H > 1 || parity <= 0 )
3124
+ ; /* no non-isotopic parity */
3125
+ else
3126
+ out_at[cur_at].parity = parity;
3127
+
3128
+ /* isotopic parity */
3129
+ if ( parity == -AB_PARITY_UNDF || parity == -AB_PARITY_UNKN )
3130
+ parity = -parity;
3131
+ if ( parity < 0 )
3132
+ parity = AB_PARITY_NONE;
3133
+ out_at[cur_at].parity2 = parity;
3134
+
3135
+
3136
+ parity = PARITY_VAL(out_at[cur_at].parity);
3137
+ out_at[cur_at].stereo_atom_parity = ATOM_PARITY_WELL_DEF( parity )? AB_PARITY_CALC : parity;
3138
+ parity = PARITY_VAL(out_at[cur_at].parity2);
3139
+ out_at[cur_at].stereo_atom_parity2 = ATOM_PARITY_WELL_DEF( parity )? AB_PARITY_CALC : parity;
3140
+ /*
3141
+ out_at[cur_at].parity2 = out_at[cur_at].parity; // save for stereo + isotopic canon.
3142
+ if ( out_at[cur_at].parity ) {
3143
+ if ( num_explicit_H > 1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 && num_explicit_H ) {
3144
+ // X H X
3145
+ // for example, >C< or >C-D
3146
+ // Y D Y
3147
+ // parity exists for stereo + isotopic atoms canonicalization only
3148
+ out_at[cur_at].parity = 0;
3149
+ }
3150
+ }
3151
+ // returning 0 means this can be an adjacent to a stereogenic bond atom
3152
+ */
3153
+ return (int)out_at[cur_at].parity2;
3154
+
3155
+ }
3156
+ #undef ADD_EXPLICIT_HYDROGEN_NEIGH
3157
+ #undef ADD_EXPLICIT_LONE_PAIR_NEIGH
3158
+
3159
+ /*************************************************************/
3160
+ int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_removed_H,
3161
+ int *nMaxNumStereoAtoms, int *nMaxNumStereoBonds, INCHI_MODE nMode,
3162
+ int bPointedEdgeStereo )
3163
+ {
3164
+ int num_3D_stereo_atoms=0;
3165
+
3166
+ int i, is_stereo, num_stereo, max_stereo_atoms=0, max_stereo_bonds=0;
3167
+ QUEUE *q = NULL;
3168
+ AT_RANK *nAtomLevel = NULL;
3169
+ S_CHAR *cSource = NULL;
3170
+ AT_RANK min_sb_ring_size = 0;
3171
+
3172
+ /**********************************************************
3173
+ *
3174
+ * Note: this parity reflects only relative positions of
3175
+ * the atoms-neighbors and their ordering in the
3176
+ * lists of neighbors.
3177
+ *
3178
+ * To obtain the actual parity, the parity of a number
3179
+ * of neighbors transpositions (to obtain a sorted
3180
+ * list of numbers assigned to the atoms) should be
3181
+ * added.
3182
+ *
3183
+ **********************************************************/
3184
+
3185
+ /*********************************************************************************
3186
+
3187
+ An example of parity=1 for stereogenic center, tetrahedral asymmetric atom
3188
+
3189
+
3190
+
3191
+ (1)
3192
+ |
3193
+ |
3194
+ [C] |
3195
+ |
3196
+ (2)------(0)
3197
+ /
3198
+ /
3199
+ /
3200
+ /
3201
+ (3)
3202
+
3203
+
3204
+ Notation: (n) is a tetrahedral atom neighbor; n is an index of a neighbor in
3205
+ the central_at->neighbor[] array : neighbor atom number is central_at->neighbor[n].
3206
+
3207
+ (0)-(1), (0)-(2), (0)-(3) are lines connecting atom [C] neighbors to neighbor (0)
3208
+ (0), (1) and (2) are in the plane
3209
+ (0)-(3) is directed from the plain to the viewer
3210
+ [C] is somewhere between (0), (1), (2), (3)
3211
+ Since (1)-(2)-(3) are in a clockwise order when looking from (0), parity is 2, or even;
3212
+ otherwise parity would be 1, or odd.
3213
+
3214
+ **********************************************************************************
3215
+
3216
+ Examples of a stereogenic bond.
3217
+
3218
+ Notation: [atom number], (index of a neighbor):
3219
+ [1] and [2] are atoms connected by the stereogenic bond
3220
+ numbers in () are indexes of neighbors of [1] or [2].
3221
+ (12 x 16)z = z-component of [1]-[2] and [1]-[6] cross-product
3222
+
3223
+ atom [1] atom [2]
3224
+ [8] [4] prod01 = (12 x 16)z < 0 prod01 = (21 x 24)z < 0
3225
+ \ / prod02 = (12 x 18)z > 0 prod02 = (21 x 25)z > 0
3226
+ (2) (1) 0 transpositions because 0 transpositions because
3227
+ \ / double bond is in 0 posit. double bond is in 0 position
3228
+ [1]==(0)(0)==[2] 0 = (prod01 > prod02) 0 = (prod01 > prod02)
3229
+ / \
3230
+ (1) (2) result: parity = 2, even result: parity=2, even
3231
+ / \
3232
+ [6] [5]
3233
+
3234
+
3235
+
3236
+ atom [1] atom [2]
3237
+ [8] [5] prod01 = (12 x 18)z > 0 prod01 = (21 x 24)z > 0
3238
+ \ / prod02 = (12 x 16)z < 0 prod02 = (21 x 25)z < 0
3239
+ (0) (2) 2 transpositions to move 1 transposition to move
3240
+ \ / at [2] from 2 to 0 pos. at [1] from 1 to 0 position
3241
+ [1]==(2)(1)==[2] 1 = (prod01 > prod02) 1 = (prod01 > prod02)
3242
+ / \
3243
+ (1) (0) result: parity = (1+2) result: parity=(1+1)
3244
+ / \ 2-(1+2)%2 = 1, odd 2-(1+1)%2 = 2, even
3245
+ [6] [4]
3246
+
3247
+
3248
+ ***********************************************************************************
3249
+ Note: atoms' numbers [1], [2], [4],... are not used to calculate parity at this
3250
+ point. They will be used for each numbering in the canonicalization.
3251
+ Note: parity=3 for a stereo atom means entered undefined bond direction
3252
+ parity=4 for an atom means parity cannot be determined from the given geometry
3253
+ ***********************************************************************************/
3254
+
3255
+ if ( !at_output || !at ) {
3256
+ return -1;
3257
+ }
3258
+
3259
+ /* clear stereo descriptors */
3260
+
3261
+ for( i = 0; i < num_at; i ++ ) {
3262
+ at_output[i].parity = 0;
3263
+ at_output[i].parity2 = 0;
3264
+ memset(&at_output[i].stereo_bond_neighbor[0], 0, sizeof(at_output[0].stereo_bond_neighbor) );
3265
+ memset(&at_output[i].stereo_bond_neighbor2[0], 0, sizeof(at_output[0].stereo_bond_neighbor2) );
3266
+ memset(&at_output[i].stereo_bond_ord[0], 0, sizeof(at_output[0].stereo_bond_ord) );
3267
+ memset(&at_output[i].stereo_bond_ord2[0], 0, sizeof(at_output[0].stereo_bond_ord2) );
3268
+ memset(&at_output[i].stereo_bond_z_prod[0], 0, sizeof(at_output[0].stereo_bond_z_prod) );
3269
+ memset(&at_output[i].stereo_bond_z_prod2[0], 0, sizeof(at_output[0].stereo_bond_z_prod2) );
3270
+ memset(&at_output[i].stereo_bond_parity[0], 0, sizeof(at_output[0].stereo_bond_parity) );
3271
+ memset(&at_output[i].stereo_bond_parity2[0], 0, sizeof(at_output[0].stereo_bond_parity2) );
3272
+ }
3273
+ /* estimate max numbers of stereo atoms and bonds if isotopic H are added */
3274
+ if ( nMaxNumStereoAtoms || nMaxNumStereoBonds ) {
3275
+ for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
3276
+ int num;
3277
+ num = can_be_a_stereo_atom_with_isotopic_H( at, i );
3278
+ if ( num ) {
3279
+ max_stereo_atoms += num;
3280
+ } else
3281
+ if ( (num = can_be_a_stereo_bond_with_isotopic_H( at, i, nMode ) ) ) { /* accept cumulenes */
3282
+ max_stereo_bonds += num;
3283
+ }
3284
+ }
3285
+ if ( nMaxNumStereoAtoms )
3286
+ *nMaxNumStereoAtoms = max_stereo_atoms;
3287
+ if ( nMaxNumStereoBonds )
3288
+ *nMaxNumStereoBonds = max_stereo_bonds;
3289
+ }
3290
+ /* calculate stereo descriptors */
3291
+ #if( MIN_SB_RING_SIZE > 0 )
3292
+ min_sb_ring_size = (AT_RANK)(((nMode & REQ_MODE_MIN_SB_RING_MASK) >> REQ_MODE_MIN_SB_RING_SHFT) & AT_RANK_MASK);
3293
+ if ( min_sb_ring_size >= 3 ) {
3294
+ /* create BFS data structure for finding for each stereo bond its min. ring sizes */
3295
+ q = QueueCreate( num_at+1, sizeof(qInt) );
3296
+ nAtomLevel = (AT_RANK*)inchi_calloc(sizeof(nAtomLevel[0]),num_at);
3297
+ cSource = (S_CHAR *)inchi_calloc(sizeof(cSource[0]),num_at);
3298
+ if ( !q || !cSource || !nAtomLevel ) {
3299
+ num_3D_stereo_atoms = CT_OUT_OF_RAM;
3300
+ goto exit_function;
3301
+ }
3302
+ } else {
3303
+ min_sb_ring_size = 2;
3304
+ }
3305
+ #endif
3306
+ /* main cycle: set stereo parities */
3307
+ for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
3308
+
3309
+ if ( is_stereo = set_stereo_atom_parity( at_output, at, i, at+num_at, num_removed_H, bPointedEdgeStereo ) ) {
3310
+ num_3D_stereo_atoms += ATOM_PARITY_WELL_DEF( is_stereo );
3311
+ } else {
3312
+ is_stereo = set_stereo_bonds_parity( at_output, at, i, at+num_at, num_removed_H, nMode,
3313
+ q, nAtomLevel, cSource, min_sb_ring_size, bPointedEdgeStereo );
3314
+ if ( RETURNED_ERROR( is_stereo ) ) {
3315
+ num_3D_stereo_atoms = is_stereo;
3316
+ break;
3317
+ }
3318
+ }
3319
+ num_stereo += (is_stereo != 0);
3320
+ }
3321
+ /*
3322
+ if ( (nMode & REQ_MODE_SC_IGN_ALL_UU )
3323
+ REQ_MODE_SC_IGN_ALL_UU
3324
+ REQ_MODE_SB_IGN_ALL_UU
3325
+ */
3326
+
3327
+ #if( MIN_SB_RING_SIZE > 0 )
3328
+ if ( q ) {
3329
+ q = QueueDelete( q );
3330
+ }
3331
+ if ( nAtomLevel )
3332
+ inchi_free( nAtomLevel );
3333
+ if ( cSource )
3334
+ inchi_free( cSource );
3335
+ exit_function:
3336
+ #endif
3337
+
3338
+
3339
+ return num_3D_stereo_atoms;
3340
+ }
3341
+ /*****************************************************************
3342
+ * Functions that disconnect bonds
3343
+ *
3344
+ *=== During Preprocessing ===
3345
+ *
3346
+ * RemoveInpAtBond
3347
+ * DisconnectMetalSalt (is not aware of bond parities)
3348
+ * DisconnectAmmoniumSalt
3349
+ *
3350
+ *=== Before Normalization ===
3351
+ *
3352
+ * remove_terminal_HDT
3353
+ *
3354
+ *=== During the Normalization ===
3355
+ *
3356
+ * AddOrRemoveExplOrImplH
3357
+ *
3358
+ *****************************************************************/
3359
+ int ReconcileAllCmlBondParities( inp_ATOM *at, int num_atoms, int bDisconnected )
3360
+ {
3361
+ int i, ret = 0;
3362
+ S_CHAR *visited = (S_CHAR*) inchi_calloc( num_atoms, sizeof(*visited) );
3363
+ if ( !visited )
3364
+ return -1; /* out of RAM */
3365
+ for ( i = 0; i < num_atoms; i ++ ) {
3366
+ if ( at[i].sb_parity[0] && !visited[i] && !(bDisconnected && is_el_a_metal(at[i].el_number)) ) {
3367
+ if ( ret = ReconcileCmlIncidentBondParities( at, i, -1, visited, bDisconnected ) ) {
3368
+ break; /* error */
3369
+ }
3370
+ }
3371
+ }
3372
+ inchi_free ( visited );
3373
+ return ret;
3374
+ }
3375
+ /*****************************************************************/
3376
+ int ReconcileCmlIncidentBondParities( inp_ATOM *at, int cur_atom, int prev_atom, S_CHAR *visited, int bDisconnected )
3377
+ {
3378
+ /* visited = 0 or parity => atom has not been visited
3379
+ 10 + parity => currently is on the stack + its final parity
3380
+ 20 + parity => has been visited; is not on the stack anymore + its final parity */
3381
+ int i, j, nxt_atom, ret = 0, len;
3382
+ int icur2nxt, icur2neigh; /* cur atom neighbors */
3383
+ int inxt2cur, inxt2neigh; /* next atom neighbors */
3384
+ int cur_parity, nxt_parity;
3385
+ int cur_order_parity, nxt_order_parity, cur_sb_parity, nxt_sb_parity, bCurMask, bNxtMask;
3386
+ /* !(bDisconnected && is_el_a_metal(at[i].el_number) */
3387
+
3388
+ if ( at[cur_atom].valence > MAX_NUM_STEREO_BONDS )
3389
+ return 0; /* ignore */
3390
+
3391
+ if ( !at[cur_atom].sb_parity[0] )
3392
+ return 1; /* wrong call */
3393
+
3394
+ if ( visited[cur_atom] >= 10 )
3395
+ return 2; /* program error */
3396
+
3397
+ cur_parity = visited[cur_atom] % 10;
3398
+
3399
+ visited[cur_atom] += 10;
3400
+
3401
+ for ( i = 0; i < MAX_NUM_STEREO_BONDS && at[cur_atom].sb_parity[i]; i ++ ) {
3402
+ icur2nxt = (int)at[cur_atom].sb_ord[i];
3403
+ len = get_opposite_sb_atom( at, cur_atom, icur2nxt, &nxt_atom, &inxt2cur, &j );
3404
+ if ( !len ) {
3405
+ return 4; /* could not find the opposite atom: bond parity data error */
3406
+ }
3407
+ if ( nxt_atom == prev_atom )
3408
+ continue;
3409
+ if ( visited[nxt_atom] >= 20 )
3410
+ continue; /* back edge, second visit: ignore */
3411
+ if ( at[nxt_atom].valence > MAX_NUM_STEREO_BONDS )
3412
+ continue; /* may be treated only after metal disconnection */
3413
+
3414
+ if ( bDisconnected && (at[cur_atom].sb_parity[i] & SB_PARITY_FLAG) ) {
3415
+ cur_sb_parity = (at[cur_atom].sb_parity[i] >> SB_PARITY_SHFT);
3416
+ bCurMask = 3 << SB_PARITY_SHFT;
3417
+ } else {
3418
+ cur_sb_parity = (at[cur_atom].sb_parity[i] & SB_PARITY_MASK);
3419
+ bCurMask = 3;
3420
+ }
3421
+ if ( bDisconnected && (at[nxt_atom].sb_parity[j] & SB_PARITY_FLAG) ) {
3422
+ nxt_sb_parity = (at[nxt_atom].sb_parity[j] >> SB_PARITY_SHFT);
3423
+ bNxtMask = 3 << SB_PARITY_SHFT;
3424
+ } else {
3425
+ nxt_sb_parity = (at[nxt_atom].sb_parity[j] & SB_PARITY_MASK);
3426
+ bNxtMask = 3;
3427
+ }
3428
+
3429
+
3430
+
3431
+ if ( !ATOM_PARITY_WELL_DEF(cur_sb_parity) ||
3432
+ !ATOM_PARITY_WELL_DEF(nxt_sb_parity) ) {
3433
+ if ( cur_sb_parity == nxt_sb_parity ) {
3434
+ continue;
3435
+ /*goto move_forward;*/ /* bypass unknown/undefined */
3436
+ }
3437
+ return 3; /* sb parities do not match: bond parity data error */
3438
+ }
3439
+
3440
+ icur2neigh = (int)at[cur_atom].sn_ord[i];
3441
+ inxt2neigh = (int)at[nxt_atom].sn_ord[j];
3442
+ /* parity of at[cur_atom].neighbor[] premutation to reach this order: { next_atom, neigh_atom, ...} */
3443
+
3444
+ /* 1. move next_atom from position=icur2nxt to position=0 =>
3445
+ * icur2nxt permutations
3446
+ * 2. move neigh_atom from position=inxt2neigh+(inxt2cur > inxt2neigh) to position=1 =>
3447
+ * inxt2neigh+(inxt2cur > inxt2neigh)-1 permutations.
3448
+ * Note if (inxt2cur > inxt2neigh) then move #1 increments neigh_atom position
3449
+ * Note add 4 because icur2neigh may be negative due to isotopic H removal
3450
+ */
3451
+ cur_order_parity = (4+icur2nxt + icur2neigh + (icur2neigh > icur2nxt)) % 2;
3452
+ /* same for next atom: */
3453
+ /* parity of at[nxt_atom].neighbor[] premutation to reach this order: { cur_atom, neigh_atom, ...} */
3454
+ nxt_order_parity = (4+inxt2cur + inxt2neigh + (inxt2neigh > inxt2cur)) % 2;
3455
+
3456
+ nxt_parity = visited[nxt_atom] % 10;
3457
+
3458
+ if ( !cur_parity ) {
3459
+ cur_parity = 2 - (cur_order_parity + cur_sb_parity) % 2;
3460
+ visited[cur_atom] += cur_parity;
3461
+ } else
3462
+ if ( cur_parity != 2 - (cur_order_parity + cur_sb_parity) % 2 ) {
3463
+
3464
+ /***** reconcile bond parities *****/
3465
+
3466
+ /* Each bond parity is split into two values located at the end atoms.
3467
+ For T (trans) the values are (1,1) or (2,2)
3468
+ For C (cis) the values are (1,2) or (2,1)
3469
+ The fact that one pair = another with inverted parities, namely
3470
+ Inv(1,1) = (2,2) and Inv(1,2) = (2,1), allows to
3471
+ simultaneouly invert parities of the current bond end atoms
3472
+ (at[cur_atom].sb_parity[i], at[nxt_atom].sb_parity[j])
3473
+ so that the final current atom parity cur_parity
3474
+ calculated later in stereochemical canonicalization for
3475
+ each stereobond incident with the current atomis same.
3476
+ Achieving this is called here RECONCILIATION.
3477
+ If at the closure of an aromatic circuit the parities of
3478
+ next atom cannot be reconciled with already calculated then
3479
+ this function returns 5 (error).
3480
+ */
3481
+
3482
+ at[cur_atom].sb_parity[i] ^= bCurMask;
3483
+ at[nxt_atom].sb_parity[j] ^= bNxtMask;
3484
+ cur_sb_parity ^= 3;
3485
+ nxt_sb_parity ^= 3;
3486
+ }
3487
+
3488
+ if ( !nxt_parity ) {
3489
+ nxt_parity = 2 - (nxt_order_parity + nxt_sb_parity) % 2;
3490
+ visited[nxt_atom] += nxt_parity;
3491
+ } else
3492
+ if ( nxt_parity != 2 - (nxt_order_parity + nxt_sb_parity) % 2 ) {
3493
+ return 5; /* algorithm does not work for Mebius-like structures */
3494
+ }
3495
+
3496
+ /* move_forward: */
3497
+ if ( visited[nxt_atom] < 10 ) {
3498
+ ret = ReconcileCmlIncidentBondParities( at, nxt_atom, cur_atom, visited, bDisconnected );
3499
+ if ( ret ) {
3500
+ break;
3501
+ }
3502
+ }
3503
+ }
3504
+ visited[cur_atom] += 10; /* all bonds incident to the current atom have
3505
+ been processed or an error occurred. */
3506
+ return ret;
3507
+ }
3508
+ /*****************************************************************/
3509
+ int get_opposite_sb_atom( inp_ATOM *at, int cur_atom, int icur2nxt, int *pnxt_atom, int *pinxt2cur, int *pinxt_sb_parity_ord )
3510
+ {
3511
+ AT_NUMB nxt_atom;
3512
+ int j, len;
3513
+
3514
+ len = 0;
3515
+ while ( len ++ < 20 ) { /* arbitrarily set cumulene length limit to avoid infinite loop */
3516
+ nxt_atom = at[cur_atom].neighbor[icur2nxt];
3517
+ for ( j = 0; j < MAX_NUM_STEREO_BONDS && at[nxt_atom].sb_parity[j]; j ++ ) {
3518
+ if ( cur_atom == at[nxt_atom].neighbor[(int)at[nxt_atom].sb_ord[j]] ) {
3519
+ /* found the opposite atom */
3520
+ *pnxt_atom = nxt_atom;
3521
+ *pinxt2cur = at[nxt_atom].sb_ord[j];
3522
+ *pinxt_sb_parity_ord = j;
3523
+ return len;
3524
+ }
3525
+ }
3526
+ if ( j ) {
3527
+ return 0; /* reached atom(s) with stereobond (sb) parity, the opposite atom has not been found */
3528
+ }
3529
+ if ( at[nxt_atom].valence == 2 && 2*BOND_TYPE_DOUBLE == at[nxt_atom].chem_bonds_valence ) {
3530
+ /* follow cumulene =X= path */
3531
+ icur2nxt = (at[nxt_atom].neighbor[0] == cur_atom);
3532
+ cur_atom = nxt_atom;
3533
+ } else {
3534
+ return 0; /* neither atom with a sb parity not middle cumulene could be reached */
3535
+ }
3536
+ }
3537
+ return 0; /* too long chain of cumulene was found */
3538
+ }