rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }