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,1625 @@
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 <string.h>
13
+
14
+ #include "mode.h"
15
+
16
+ #include "comdef.h"
17
+ #include "extr_ct.h"
18
+ #include "ichitaut.h"
19
+ #include "ichicant.h"
20
+ #include "ichicomn.h"
21
+ #include "ichister.h"
22
+
23
+ #include "ichicomp.h"
24
+
25
+
26
+
27
+
28
+ typedef struct tagStereoBondNeighbor { /* *n = sort key */
29
+ AT_RANK nRank; /* *1 opposite atom rank; equal ranks mean constit. equivalence */
30
+ AT_RANK nNeighRank1; /* rank of the neighbor in the direction to the opposite atom */
31
+ AT_RANK nNeighRank2; /* rank of the opposite atom neighbor in the direction to the current atom */
32
+ AT_RANK num; /* number of same type bonds to constitutionally equivalent neighbors */
33
+ AT_RANK num_any_parity; /* at least one atom has parity in 1..4 range */
34
+ AT_RANK num_defined_parity; /* number of neighbors with defined parity <= num */
35
+ /* AT_RANK num_undef_parity; */
36
+ /* AT_RANK num_unkn_parity; */
37
+ AT_RANK what2do;
38
+ U_CHAR cumulene_len; /* high nimble bits: (cumulene length - 1) */
39
+ U_CHAR bond_type; /* *2 all same, not a real bond type */
40
+ } STEREO_BOND_NEIGH;
41
+
42
+ /* local prototypes */
43
+ int SetHalfStereoBondIllDefPariy( sp_ATOM *at, int jn, /* atom number*/ int k1 /* stereo bond number*/, int new_parity );
44
+ int RemoveHalfStereoBond( sp_ATOM *at, int jn, /* atom number*/ int k1 /* stereo bond number*/ );
45
+ int SetKnownStereoBondParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
46
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber );
47
+ int MarkKnownEqualStereoBondParities( sp_ATOM *at, int num_atoms,
48
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber );
49
+ int GetNextNeighborAndRank( sp_ATOM *at, AT_RANK cur, AT_RANK prev, AT_RANK *n, AT_RANK *cr, const AT_RANK *nCanonRank );
50
+ int GetAndCheckNextNeighbors( sp_ATOM *at, AT_RANK cur1, AT_RANK prev1, AT_RANK cur2, AT_RANK prev2,
51
+ AT_RANK *n1, AT_RANK *n2, AT_RANK *nVisited1, AT_RANK *nVisited2,
52
+ const AT_RANK *nRank, const AT_RANK *nCanonRank );
53
+ AT_RANK PathsHaveIdenticalKnownParities( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
54
+ AT_RANK *nVisited1, AT_RANK *nVisited2,
55
+ const AT_RANK *nRank, const AT_RANK *nCanonRank, AT_RANK nLength );
56
+ int RemoveKnownNonStereoBondParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
57
+ const AT_RANK *nRank, CANON_STAT *pCS);
58
+ int SetKnownStereoCenterParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
59
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber );
60
+ int RemoveKnownNonStereoCenterParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
61
+ const AT_RANK *nRank, CANON_STAT *pCS);
62
+ int MarkKnownEqualStereoCenterParities( sp_ATOM *at, int num_atoms,
63
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber );
64
+
65
+ /**********************************************************************************/
66
+ /* Depth First Search for an atom with parity */
67
+ int find_atoms_with_parity( sp_ATOM *at, S_CHAR *visited, int from_atom, int cur_atom )
68
+ {
69
+ int i, next_atom;
70
+ if ( visited[cur_atom] )
71
+ return 0;
72
+ if ( at[cur_atom].parity )
73
+ return 1;
74
+ visited[cur_atom] = 1;
75
+ for ( i = 0; i < at[cur_atom].valence; i ++ ) {
76
+ next_atom = at[cur_atom].neighbor[i];
77
+ if ( next_atom != from_atom && find_atoms_with_parity( at, visited, cur_atom, next_atom ) )
78
+ return 1;
79
+ }
80
+ return 0;
81
+ }
82
+ /**********************************************************************************/
83
+ int SetHalfStereoBondIllDefPariy( sp_ATOM *at, int jn, /* atom number*/ int k1 /* stereo bond number*/, int new_parity )
84
+ {
85
+ int parity;
86
+ if ( k1 < MAX_NUM_STEREO_BOND_NEIGH && at[jn].stereo_bond_neighbor[k1] ) {
87
+ parity = at[jn].stereo_bond_parity[k1] ^ PARITY_VAL(at[jn].stereo_bond_parity[k1]);
88
+ at[jn].stereo_bond_parity[k1] = parity | PARITY_VAL(new_parity);
89
+ at[jn].parity = PARITY_VAL(new_parity);
90
+ return 1; /* success */
91
+ }
92
+ return 0; /* failed */
93
+ }
94
+
95
+ /**********************************************************************************/
96
+ int RemoveHalfStereoBond( sp_ATOM *at, int jn, /* atom number*/ int k1 /* stereo bond number*/ )
97
+ {
98
+ int k2;
99
+ if ( k1 < MAX_NUM_STEREO_BOND_NEIGH && at[jn].stereo_bond_neighbor[k1] ) {
100
+ for ( k2 = k1; k2+1 < MAX_NUM_STEREO_BOND_NEIGH; k2++ ) {
101
+ at[jn].stereo_bond_neighbor[k2] = at[jn].stereo_bond_neighbor[k2+1];
102
+ at[jn].stereo_bond_ord[k2] = at[jn].stereo_bond_ord[k2+1];
103
+ at[jn].stereo_bond_z_prod[k2] = at[jn].stereo_bond_z_prod[k2+1];
104
+ at[jn].stereo_bond_parity[k2] = at[jn].stereo_bond_parity[k2+1];
105
+ }
106
+ at[jn].stereo_bond_neighbor[k2] = 0;
107
+ at[jn].stereo_bond_ord[k2] = 0;
108
+ at[jn].stereo_bond_z_prod[k2] = 0;
109
+ at[jn].stereo_bond_parity[k2] = 0;
110
+
111
+ if ( !at[jn].stereo_bond_neighbor[0] ) { /* curled braces added 6-6-2002 */
112
+ at[jn].parity = 0;
113
+ at[jn].stereo_atom_parity = 0;
114
+ at[jn].final_parity = 0;
115
+ /* at[jn].bHasStereoOrEquToStereo = 0; */
116
+ }
117
+ return 1; /* success */
118
+ }
119
+ return 0; /* failed */
120
+ }
121
+
122
+ /**********************************************************************************/
123
+ int SetOneStereoBondIllDefParity( sp_ATOM *at, int jc, /* atom number*/ int k /* stereo bond ord. number*/, int new_parity )
124
+ {
125
+ int k1, ret=0, kn, jn = (int)at[jc].stereo_bond_neighbor[k]-1;
126
+
127
+ /* opposite end */
128
+ for ( k1 = kn = ret = 0; k1 < MAX_NUM_STEREO_BOND_NEIGH && (kn=at[jn].stereo_bond_neighbor[k1]); k1++ ) {
129
+ if ( kn - 1 == jc ) {
130
+ ret = SetHalfStereoBondIllDefPariy( at, jn, /* atom number*/ k1 /* stereo bond number*/, new_parity );
131
+ break;
132
+ }
133
+ }
134
+ if ( ret ) {
135
+ ret = SetHalfStereoBondIllDefPariy( at, jc, k, new_parity );
136
+ }
137
+ return ret;
138
+ }
139
+
140
+ /**********************************************************************************/
141
+ int RemoveOneStereoBond( sp_ATOM *at, int jc, /* atom number*/ int k /* stereo bond number*/ )
142
+ {
143
+ int k1, ret=0, kn, jn = (int)at[jc].stereo_bond_neighbor[k]-1;
144
+
145
+ /* opposite end */
146
+ for ( k1 = kn = ret = 0; k1 < MAX_NUM_STEREO_BOND_NEIGH && (kn=at[jn].stereo_bond_neighbor[k1]); k1++ ) {
147
+ if ( kn - 1 == jc ) {
148
+ ret = RemoveHalfStereoBond( at, jn, k1 );
149
+ break;
150
+ }
151
+ }
152
+ if ( ret ) {
153
+ ret = RemoveHalfStereoBond( at, jc, k );
154
+ }
155
+ return ret;
156
+ }
157
+ /**********************************************************************************/
158
+ int RemoveOneStereoCenter( sp_ATOM *at, int jc /* atom number*/ )
159
+ {
160
+ if ( at[jc].parity ) {
161
+ at[jc].parity = 0; /* remove parity */
162
+ at[jc].stereo_atom_parity = 0;
163
+ at[jc].final_parity = 0;
164
+ /* at[jc].bHasStereoOrEquToStereo = 0; */
165
+ return 1;
166
+ }
167
+ return 0; /* failed: not a stereo center */
168
+ }
169
+ /**********************************************************************************/
170
+ /* Remove stereo parity from centers having constitutionally equivalent */
171
+ /* cut-vertex neighbors whose attachments do not have stereogenic elements. */
172
+ /* Currently checks ALL constitutionally equivalent neighbors. */
173
+ /* To optimize, check only one. */
174
+ int UnmarkNonStereo( sp_ATOM *at, int num_atoms, const AT_RANK *nRank, const AT_RANK *nAtomNumber, int bIsotopic )
175
+ {
176
+ int i, i1, i2, j, k, k1, k2, kn /* neigh*/, val, ic/* center*/, jc, num_implicit_H;
177
+ int num_neighbors_with_parity, num_no_parity_atoms, num_removed_parities=-1, num_removed_parities0;
178
+ AT_RANK nNeighborNumber[MAX_NUM_STEREO_ATOM_NEIGH];
179
+ AT_RANK nPrevAtomRank, nPrevNeighRank;
180
+ S_CHAR *visited = (S_CHAR *)inchi_malloc(num_atoms * sizeof(visited[0]));
181
+ if ( !visited )
182
+ goto exit_function;
183
+ num_removed_parities = 0;
184
+ num_no_parity_atoms = 0;
185
+
186
+ do {
187
+ num_removed_parities0 = num_removed_parities;
188
+ for ( i = i1 = 0, nPrevAtomRank = 0; i <= num_atoms; i++ ) {
189
+ /* bounds violation check (i!=num_atoms) added 6-21-2002 */
190
+ if ( i == num_atoms || nPrevAtomRank != nRank[j = nAtomNumber[i]]
191
+ /* at[j].parity && 1 < at[j].valence && at[j].valence < MAX_NUM_STEREO_ATOM_NEIGH*/ ) {
192
+
193
+ /* end of constitutionally equivalent atoms sequence */
194
+
195
+ /* nPrevRank = nRank[j]; */
196
+ i2 = i;
197
+ if ( i2 - i1 > num_no_parity_atoms /*&& at[jc = nAtomNumber[i1]].parity*/ ) {
198
+ /* at[nAtomNumber[i1]]..at[nAtomNumber[i2-1]] are constitutionally equivalent and some of them have parity */
199
+ jc = nAtomNumber[i1];
200
+ num_no_parity_atoms = 0;
201
+ val = at[jc].valence; /* all equivalent atoms have equal valences, etc. (except parities) */
202
+ num_implicit_H = at[jc].endpoint? 0 : at[jc].num_H;
203
+ /* Only atoms with valence <= MAX_NUM_STEREO_ATOM_NEIGH may have parity. However, check: */
204
+ if ( val + num_implicit_H > MAX_NUM_STEREO_ATOM_NEIGH ) {
205
+ continue; /* program error ??? */ /* <BRKPT> */
206
+ }
207
+ for ( k = 0; k < val; k ++ ) {
208
+ nNeighborNumber[k] = k; /* initialize an array of indexes for sorting */
209
+ }
210
+ /* check parities */
211
+ for ( ic = i1; ic < i2; ic ++ ) {
212
+ jc = nAtomNumber[ic];
213
+ /* sort neighbors according to their canon. equivalence ranks */
214
+ pNeighborsForSort = at[jc].neighbor;
215
+ pn_RankForSort = nRank;
216
+ insertions_sort( nNeighborNumber, val, sizeof(nNeighborNumber[0]), CompNeighborsAT_NUMBER );
217
+ num_neighbors_with_parity = -1; /* non-zero */
218
+ for ( k = k1 = 0, nPrevNeighRank = 0; k <= val; k ++ ) {
219
+ if ( k == val || nPrevNeighRank != nRank[at[jc].neighbor[nNeighborNumber[k]]] ) {
220
+ k2 = k;
221
+ if ( k2 - k1 > 1 ) {
222
+ /* found 2 or more constitutionally equivalent neighbors */
223
+ /* Check if they have only non-stereogenic neighbors */
224
+ for ( kn = k1, num_neighbors_with_parity = 0; kn < k2; kn ++ ) {
225
+ memset( visited, 0, num_atoms * sizeof(visited[0]));
226
+ visited[jc] = 1; /* starting point; the only atom with parity */
227
+ num_neighbors_with_parity +=
228
+ find_atoms_with_parity( at, visited, jc, (int)at[jc].neighbor[nNeighborNumber[kn]] );
229
+ }
230
+ }
231
+ if ( !num_neighbors_with_parity ) {
232
+ break; /* at[jc] cannot have defined parity */
233
+ }
234
+ if ( k + 1 < val ) {
235
+ k1 = k; /* at least 2 more neighbors left */
236
+ nPrevNeighRank = nRank[at[jc].neighbor[nNeighborNumber[k]]];
237
+ } else {
238
+ break;
239
+ }
240
+ }
241
+ }
242
+ if ( num_implicit_H > 1 ) {
243
+ if ( bIsotopic && (at[jc].num_iso_H[0] > 1 ||
244
+ at[jc].num_iso_H[1] > 1 ||
245
+ at[jc].num_iso_H[2] > 1 ) ||
246
+ num_implicit_H > NUM_H_ISOTOPES ||
247
+ !bIsotopic
248
+ ) {
249
+ num_neighbors_with_parity = 0;
250
+ }
251
+ }
252
+ /* increment if: */
253
+ /* (a) constitutionally equivalent neighbors do exist, and */
254
+ /* (b) all constitutionally equivalent neighbors do not have parity, and */
255
+ /* (c) all constitutionally equivalent neighbors are not connected to atoms with parity */
256
+ num_no_parity_atoms += !num_neighbors_with_parity;
257
+ }
258
+ if ( num_no_parity_atoms == i2 - i1 ) {
259
+ /* all atoms at[nAtomNumber[i1]]..at[nAtomNumber[i2-1]] cannot be */
260
+ /* stereo centers or belong to stereo bonds */
261
+ for ( ic = i1; ic < i2; ic ++ ) {
262
+ int jn;
263
+ jc = nAtomNumber[ic];
264
+ at[jc].parity = 0; /* remove parity */
265
+ at[jc].stereo_atom_parity = 0;
266
+ at[jc].final_parity = 0;
267
+ at[jc].bHasStereoOrEquToStereo = 0;
268
+ /* remove stereo bonds */
269
+ for ( k = 0; k < MAX_NUM_STEREO_BOND_NEIGH && (jn=at[jc].stereo_bond_neighbor[k]); k++ ) {
270
+ jn--; /* stereo bond neighbor */
271
+ /* opposite end */
272
+ for ( k1 = 0; k1 < MAX_NUM_STEREO_BOND_NEIGH && (kn=at[jn].stereo_bond_neighbor[k1]); k1++ ) {
273
+ if ( kn - 1 == jc ) {
274
+ RemoveHalfStereoBond( at, jn, k1 );
275
+ break;
276
+ }
277
+ }
278
+ /* at at[jc] stereo bond end; since references to all at[jc] */
279
+ /* stereo bond neighbors are to be removed, do not shift them */
280
+ at[jc].stereo_bond_neighbor[k] = 0;
281
+ at[jc].stereo_bond_ord[k] = 0;
282
+ at[jc].stereo_bond_z_prod[k] = 0;
283
+ at[jc].stereo_bond_parity[k] = 0;
284
+
285
+ }
286
+
287
+ }
288
+ num_removed_parities += num_no_parity_atoms;
289
+ }
290
+
291
+ }
292
+ if ( i < num_atoms ) {
293
+ nPrevAtomRank = nRank[j];
294
+ i1 = i;
295
+ }
296
+ num_no_parity_atoms = 0;
297
+ }
298
+ num_no_parity_atoms += (i < num_atoms && !at[j].parity);
299
+ }
300
+ } while ( num_removed_parities != num_removed_parities0 );
301
+
302
+ exit_function:
303
+ if ( visited )
304
+ inchi_free( visited );
305
+ return num_removed_parities;
306
+ }
307
+ /**********************************************************************************
308
+ *
309
+ * Add stereo descriptor(s) for atom #i
310
+ *
311
+ **********************************************************************************/
312
+ int FillSingleStereoDescriptors(sp_ATOM *at, int i, int num_trans, const AT_RANK *nRank
313
+ , AT_STEREO_CARB *LinearCTStereoCarb, int *nStereoCarbLen, int nMaxStereoCarbLen
314
+ , AT_STEREO_DBLE *LinearCTStereoDble, int *nStereoDbleLen, int nMaxStereoDbleLen
315
+ , int bAllene )
316
+ {
317
+ if ( !LinearCTStereoDble && !LinearCTStereoCarb ) {
318
+ return 0; /* return immediately if no stereo have been requested */
319
+ }
320
+
321
+ /***************************************************
322
+ add stereo centers and stereo bonds to the CT
323
+ ***************************************************/
324
+ if ( at[i].parity || at[i].stereo_bond_neighbor[0] ) {
325
+ AT_RANK r_neigh, rank = nRank[i];
326
+ AT_NUMB nNeighborNumber2[MAXVAL];
327
+ unsigned parity;
328
+ int k;
329
+ int num_allene = 0;
330
+ if ( ATOM_PARITY_WELL_DEF(at[i].parity) && num_trans < 0 ) {
331
+ /* number of neighbors transpositions to the sorted order is unknown. Find it. */
332
+ /* If parity is not well-defined then doing this is a waste of time */
333
+ int num_neigh = at[i].valence;
334
+ for ( k = 0; k < num_neigh; k ++) {
335
+ nNeighborNumber2[k] = k;
336
+ }
337
+ pNeighborsForSort = at[i].neighbor;
338
+ pn_RankForSort = nRank;
339
+ num_trans=insertions_sort( nNeighborNumber2, num_neigh, sizeof(nNeighborNumber2[0]), CompNeighborsAT_NUMBER );
340
+ #ifndef CT_NEIGH_INCREASE
341
+ num_trans += ((num_neigh*(num_neigh-1))/2)%2; /* get correct parity for ascending order */
342
+ #endif
343
+ }
344
+
345
+ /* stereo bonds */
346
+ if ( LinearCTStereoDble && at[i].stereo_bond_neighbor[0] ) {
347
+
348
+ /* HalfStereoBondParity( sp_ATOM *at, int at_no1, int i_sb_neigh, AT_RANK *nRank ) */
349
+ AT_NUMB nStereoNeighNumber[MAX_NUM_STEREO_BONDS], nStereoNeigh[MAX_NUM_STEREO_BONDS], n;
350
+ int num_stereo, stereo_neigh, stereo_neigh_ord, stereo_bond_parity;
351
+ for ( num_stereo = 0;
352
+ num_stereo < MAX_NUM_STEREO_BONDS &&
353
+ (n=at[i].stereo_bond_neighbor[num_stereo]); num_stereo ++ ) {
354
+ nStereoNeighNumber[num_stereo] = num_stereo;
355
+ nStereoNeigh[num_stereo] = n-1;
356
+ num_allene += IS_ALLENE_CHAIN(at[i].stereo_bond_parity[num_stereo]);
357
+ }
358
+ if ( bAllene > 0 && !num_allene || bAllene == 0 && num_allene ) {
359
+ return 0;
360
+ }
361
+ /* sort stereo bonds according to the ranks of the neighbors */
362
+ pNeighborsForSort = nStereoNeigh;
363
+ pn_RankForSort = nRank;
364
+ insertions_sort( nStereoNeighNumber, num_stereo, sizeof(nStereoNeighNumber[0]), CompNeighborsAT_NUMBER );
365
+
366
+ /* process stereo bonds one by one */
367
+ for ( k = 0; k < num_stereo; k ++ ) {
368
+ stereo_neigh = nStereoNeigh[stereo_neigh_ord=(int)nStereoNeighNumber[k]];
369
+ if ( (r_neigh = (AT_NUMB)nRank[stereo_neigh]) CT_NEIGH_SMALLER_THAN rank ) {
370
+ /* accept only neighbors that have smaller ranks */
371
+ stereo_bond_parity = PARITY_VAL(at[i].stereo_bond_parity[stereo_neigh_ord]);
372
+ if ( stereo_bond_parity == AB_PARITY_NONE )
373
+ continue;
374
+
375
+ /* stereo_neigh = at[i].stereo_bond_neighbor[nStereoNeighNumber[k]]-1; */
376
+ if ( ATOM_PARITY_KNOWN(stereo_bond_parity) ) {
377
+ parity = stereo_bond_parity;
378
+ } else
379
+ if ( ATOM_PARITY_WELL_DEF(at[i].parity) &&
380
+ ATOM_PARITY_WELL_DEF(at[stereo_neigh].parity) &&
381
+ MIN_DOT_PROD <= abs(at[i].stereo_bond_z_prod[stereo_neigh_ord]) ) {
382
+ /* bond parity can be calculated */
383
+ int half_parity1, half_parity2, j, nn, stereo_neigh_ord2;
384
+ stereo_neigh_ord2 = -1;
385
+ for ( j = 0; j < MAX_NUM_STEREO_BONDS &&
386
+ (nn=(int)at[stereo_neigh].stereo_bond_neighbor[j]); j++ ) {
387
+ if ( i+1 == nn ) {
388
+ /* found the opposite end of the stereo bond */
389
+ stereo_neigh_ord2 = j;
390
+ break;
391
+ }
392
+ }
393
+ if ( stereo_neigh_ord2 >= 0 ) {
394
+ half_parity1 = HalfStereoBondParity( at, i, stereo_neigh_ord, nRank );
395
+ half_parity2 = HalfStereoBondParity( at, stereo_neigh, stereo_neigh_ord2, nRank );
396
+ if ( ATOM_PARITY_WELL_DEF(half_parity1) &&
397
+ ATOM_PARITY_WELL_DEF(half_parity2) ) {
398
+ parity = 2 - ( half_parity1 + half_parity2
399
+ + (at[i].stereo_bond_z_prod[stereo_neigh_ord] < 0))%2;
400
+ } else {
401
+ return CT_STEREOBOND_ERROR; /* <BRKPT> */
402
+ }
403
+ } else {
404
+ return CT_STEREOBOND_ERROR; /* <BRKPT> */
405
+ }
406
+ } else {
407
+ /* parity cannot be calculated: not enough info or 'unknown' */
408
+ if ( AB_PARITY_NONE == (parity = inchi_max(at[i].parity, at[stereo_neigh].parity)) )
409
+ continue;
410
+ if ( ATOM_PARITY_WELL_DEF(parity) )
411
+ parity = AB_PARITY_UNDF; /* should not happen */
412
+ }
413
+ if ( CHECK_OVERFLOW(*nStereoDbleLen, nMaxStereoDbleLen) )
414
+ return CT_OVERFLOW; /* <BRKPT> */
415
+ /* first stereo bond atom */
416
+ LinearCTStereoDble[*nStereoDbleLen].at_num1 = rank;
417
+ /* second stereo bond atom (opposite end) */
418
+ LinearCTStereoDble[*nStereoDbleLen].at_num2 = r_neigh;
419
+ /* bond parity */
420
+ LinearCTStereoDble[*nStereoDbleLen].parity = parity;
421
+ (*nStereoDbleLen) ++;
422
+ }
423
+ }
424
+ }
425
+
426
+
427
+ /* stereo carbon */
428
+ if ( bAllene > 0 ) {
429
+ return 0;
430
+ }
431
+ if ( LinearCTStereoCarb && !at[i].stereo_bond_neighbor[0] ) {
432
+ if ( CHECK_OVERFLOW(*nStereoCarbLen, nMaxStereoCarbLen) )
433
+ return CT_OVERFLOW; /* <BRKPT> */
434
+ /* stereo atom rank */
435
+ LinearCTStereoCarb[*nStereoCarbLen].at_num = rank;
436
+ /* stereo atom parity */
437
+ parity = ATOM_PARITY_WELL_DEF(at[i].parity)? (2 - (at[i].parity + num_trans)%2) : at[i].parity;
438
+ LinearCTStereoCarb[*nStereoCarbLen].parity = parity;
439
+ (*nStereoCarbLen) ++;
440
+ }
441
+
442
+ }
443
+
444
+ return 0;
445
+ }
446
+ /**********************************************************************************/
447
+ void SwitchAtomStereoAndIsotopicStereo( sp_ATOM *at, int num_atoms, int *bSwitched )
448
+ {
449
+ int i;
450
+ /* switch atom stereo data */
451
+ for ( i = 0; i < num_atoms; i ++ ) {
452
+ swap( (char*)&at[i].parity, (char*)&at[i].parity2, sizeof( at[i].parity ) );
453
+ swap( (char*)&at[i].final_parity, (char*)&at[i].final_parity2, sizeof( at[i].final_parity ) );
454
+ swap( (char*)&at[i].stereo_atom_parity, (char*)&at[i].stereo_atom_parity2, sizeof( at[i].stereo_atom_parity ) );
455
+ swap( (char*)&at[i].bHasStereoOrEquToStereo, (char*)&at[i].bHasStereoOrEquToStereo2, sizeof( at[i].bHasStereoOrEquToStereo ) );
456
+
457
+ swap( (char*)at[i].stereo_bond_neighbor, (char*)at[i].stereo_bond_neighbor2, sizeof( at[i].stereo_bond_neighbor ) );
458
+ swap( (char*)at[i].stereo_bond_ord, (char*)at[i].stereo_bond_ord2, sizeof( at[i].stereo_bond_ord ) );
459
+ swap( (char*)at[i].stereo_bond_z_prod, (char*)at[i].stereo_bond_z_prod2, sizeof( at[i].stereo_bond_z_prod ) );
460
+ swap( (char*)at[i].stereo_bond_parity, (char*)at[i].stereo_bond_parity2, sizeof( at[i].stereo_bond_parity ) );
461
+ }
462
+ *bSwitched = !*bSwitched;
463
+ }
464
+ /**********************************************************************************/
465
+ void SetCtToIsotopicStereo( CANON_STAT *pCS, CANON_STAT *pCS2 )
466
+ {
467
+ pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble; /* enable stereo */
468
+ pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
469
+
470
+ pCS->LinearCTStereoDbleInv = pCS2->LinearCTIsotopicStereoDbleInv; /* enable inv. stereo */
471
+ pCS->LinearCTStereoCarbInv = pCS2->LinearCTIsotopicStereoCarbInv;
472
+ pCS->nMaxLenLinearCTStereoDble = pCS2->nMaxLenLinearCTIsotopicStereoDble;
473
+ pCS->nMaxLenLinearCTStereoCarb = pCS2->nMaxLenLinearCTIsotopicStereoCarb;
474
+
475
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
476
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
477
+ }
478
+ /**********************************************************************************/
479
+ void SetCtToNonIsotopicStereo( CANON_STAT *pCS, CANON_STAT *pCS2 )
480
+ {
481
+ pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble; /* enable stereo */
482
+ pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
483
+
484
+ pCS->LinearCTStereoDbleInv = pCS2->LinearCTStereoDbleInv; /* enable inv. stereo */
485
+ pCS->LinearCTStereoCarbInv = pCS2->LinearCTStereoCarbInv;
486
+ pCS->nMaxLenLinearCTStereoDble = pCS2->nMaxLenLinearCTStereoDble;
487
+ pCS->nMaxLenLinearCTStereoCarb = pCS2->nMaxLenLinearCTStereoCarb;
488
+
489
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
490
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
491
+
492
+ pCS->nLenLinearCTIsotopicStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
493
+ pCS->nLenLinearCTIsotopicStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
494
+ }
495
+
496
+ /**********************************************************************************/
497
+ int FillAllStereoDescriptors( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank, const AT_RANK *nAtomNumberCanon, CANON_STAT *pCS )
498
+ {
499
+ int ret=0, i;
500
+ /* initialize zero lengths */
501
+ pCS->nLenLinearCTStereoCarb = 0;
502
+ pCS->nLenLinearCTStereoDble = 0;
503
+
504
+ /* fill atom by atom */
505
+ for ( i = 0; !ret && i < num_atoms; i ++ ) {
506
+ ret = FillSingleStereoDescriptors( at, (int)nAtomNumberCanon[i], -1, nCanonRank
507
+ , pCS->LinearCTStereoCarb, &pCS->nLenLinearCTStereoCarb, pCS->nMaxLenLinearCTStereoCarb
508
+ , pCS->LinearCTStereoDble, &pCS->nLenLinearCTStereoDble, pCS->nMaxLenLinearCTStereoDble
509
+ , 0 /* bAllene */ );
510
+ }
511
+ for ( i = 0; !ret && i < num_atoms; i ++ ) {
512
+ ret = FillSingleStereoDescriptors( at, (int)nAtomNumberCanon[i], -1, nCanonRank
513
+ , pCS->LinearCTStereoCarb, &pCS->nLenLinearCTStereoCarb, pCS->nMaxLenLinearCTStereoCarb
514
+ , pCS->LinearCTStereoDble, &pCS->nLenLinearCTStereoDble, pCS->nMaxLenLinearCTStereoDble
515
+ , 1 /* bAllene */);
516
+ }
517
+
518
+ return ret;
519
+ }
520
+ /**********************************************************************************/
521
+ /* Find stereo bond parities known in advance */
522
+ int SetKnownStereoBondParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
523
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber )
524
+ {
525
+ int i, j, n, m, j1, k, num_neigh1, num_neigh2, iMax1, parity;
526
+ int trans_i1, trans_i2, trans_k1, trans_k2, prev_trans, trans_k, num_set;
527
+ int i1, i2, k1, k2, n1, n2, m1, m2, /*stereo_bond_parity,*/ cumulene_len;
528
+ AT_RANK nAtomRank1, nAtomRank2, nAtom1NeighRank;
529
+ AT_RANK nNeighRank1[MAX_NUM_STEREO_BONDS], nNeighRank2[MAX_NUM_STEREO_BONDS];
530
+ AT_RANK nNeighCanonRank1[MAX_NUM_STEREO_BONDS], nNeighCanonRank2[MAX_NUM_STEREO_BONDS];
531
+ for ( i1 = 0, num_set = 0; i1 < num_atoms; i1 ++ ) {
532
+ if ( !at[i1].parity || !at[i1].stereo_bond_neighbor[0] ) {
533
+ continue;
534
+ }
535
+
536
+ if ( !PARITY_WELL_DEF(at[i1].parity) ) {
537
+ continue;
538
+ }
539
+ nAtomRank1 = nRank[i1];
540
+ iMax1 = (int)nAtomRank1-1;
541
+ num_neigh1 = at[i1].valence;
542
+ for ( n1 = 0; n1 < MAX_NUM_STEREO_BONDS && (i2=(int)at[i1].stereo_bond_neighbor[n1]); n1++ ) {
543
+ i2 --;
544
+ /* found a stereo bond at[i1]-at[i2] adjacent to at[i1] */
545
+ for ( n2 = 0, m=0; n2 < MAX_NUM_STEREO_BONDS && (m=(int)at[i2].stereo_bond_neighbor[n2]) && m-1 != i1; n2++ )
546
+ ; /* locate stereo bond (#n2) at the opposite atom at[i2] */
547
+ if ( m-1 != i1 || at[i1].stereo_bond_parity[n1] != at[i2].stereo_bond_parity[n2] ) {
548
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
549
+ }
550
+ if ( i1 < i2 ) {
551
+ continue; /* do not process same bond 2 times */
552
+ }
553
+
554
+ if ( PARITY_KNOWN(at[i1].stereo_bond_parity[n1]) || !PARITY_VAL(at[i1].stereo_bond_parity[n1]) ) {
555
+ continue;
556
+ }
557
+ if ( !PARITY_WELL_DEF(at[i1].parity) || !PARITY_WELL_DEF(at[i2].parity) ) {
558
+ continue;
559
+ }
560
+ if ( PARITY_VAL(at[i1].stereo_bond_parity[n1]) != AB_PARITY_CALC ) {
561
+ continue; /* ?? program error ?? should not happen */ /* <BRKPT> */
562
+ }
563
+ /*stereo_bond_parity = PARITY_VAL(at[i1].stereo_bond_parity[n1]);*/
564
+ cumulene_len = BOND_CHAIN_LEN(at[i1].stereo_bond_parity[n1]);
565
+ nAtomRank2 = nRank[i2];
566
+ nAtom1NeighRank = nRank[(int)at[i1].neighbor[(int)at[i1].stereo_bond_ord[n1]]];
567
+ num_neigh2 = at[i2].valence;
568
+ /* store ranks of at[i1] stereo bond neighbors except one connected by a stereo bond */
569
+ k = (int)at[i1].stereo_bond_ord[n1];
570
+ trans_i1 = 0;
571
+ for ( i = j = 0; i < num_neigh1; i ++ ) {
572
+ if ( i != k ) {
573
+ nNeighRank1[j] = nRank[(int)at[i1].neighbor[i]];
574
+ j ++;
575
+ }
576
+ }
577
+ if ( j == 2 ) {
578
+ if ( nNeighRank1[0] == nNeighRank1[1] ) {
579
+ /* neighbors are constitutionally identical, can't find bond parity */
580
+ continue;
581
+ }
582
+ trans_i1 = insertions_sort(nNeighRank1, j, sizeof(nNeighRank1[0]), comp_AT_RANK);
583
+ }
584
+ /* store ranks of at[i2] stereo bond neighbors except one connected by a stereo bond */
585
+ k = (int)at[i2].stereo_bond_ord[n2];
586
+ trans_i2 = 0;
587
+ for ( i = j = 0; i < num_neigh2; i ++ ) {
588
+ if ( i != k ) {
589
+ nNeighRank2[j] = nRank[(int)at[i2].neighbor[i]];
590
+ j ++;
591
+ }
592
+ }
593
+ if ( j == 2 ) {
594
+ if ( nNeighRank2[0] == nNeighRank2[1] ) {
595
+ /* neighbors are constitutionally identical, can't find bond parity */
596
+ continue;
597
+ }
598
+ trans_i2 = insertions_sort(nNeighRank2, j, sizeof(nNeighRank2[0]), comp_AT_RANK);
599
+ }
600
+ prev_trans = -1;
601
+ trans_k1 = -2;
602
+ trans_k = -4; /* 2004-04-28 */
603
+ /* find all pairs of atoms that can be mapped on at[i1], at[i2] pair */
604
+ for ( j1 = 0; j1 <= iMax1 && nAtomRank1==nRank[k1=(int)nAtomNumber[iMax1-j1]]; j1 ++ ) {
605
+ /* at[k1] is constitutionally equivalent to at[i1] */
606
+ /* find all at[k1] neighbors that have rank nAtomRank2; */
607
+ /* then find at[k2] constitutionally equivalent at at[i2] */
608
+ if ( at[k1].valence != num_neigh1 ) {
609
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
610
+ }
611
+ for ( m1 = 0; m1 < num_neigh1; m1 ++ ) {
612
+ int prev, next, len;
613
+ if ( nAtom1NeighRank != nRank[k2=(int)at[k1].neighbor[m1]] ) {
614
+ continue;
615
+ }
616
+ m2 = -1; /* undefined yet */
617
+ prev = k1;
618
+ len = 0;
619
+ if ( cumulene_len ) {
620
+ for ( len=0, next = (int)at[k1].neighbor[m1]; len < cumulene_len; len ++ ) {
621
+ if ( at[next].valence == 2 && !at[next].num_H ) {
622
+ j = ((int)at[next].neighbor[0] == prev);
623
+ prev = next;
624
+ next = at[next].neighbor[j];
625
+ } else {
626
+ break; /* cannot continue */
627
+ }
628
+ }
629
+ if ( len != cumulene_len || nAtomRank2 != nRank[next] ) {
630
+ continue; /* not found */
631
+ }
632
+ k2 = next;
633
+ }
634
+ if ( at[k2].valence != num_neigh2 ) {
635
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
636
+ }
637
+ /* store canon. ranks of at[k1] neighbors */ /* use i,j,k,m,n */
638
+ for ( n = j = 0; n < num_neigh1; n ++ ) {
639
+ if ( n != m1 ) {
640
+ i=(int)at[k1].neighbor[n];
641
+ for ( m = 0; m < num_neigh1-1; m ++ ) {
642
+ if ( nRank[i] == nNeighRank1[m] ) {
643
+ nNeighCanonRank1[m] = nCanonRank[i];
644
+ j ++;
645
+ break;
646
+ }
647
+ }
648
+ }
649
+ }
650
+ if ( j != num_neigh1-1 ) {
651
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
652
+ }
653
+ if ( j == 2 ) {
654
+ trans_k1 = insertions_sort(nNeighCanonRank1, j, sizeof(nNeighCanonRank1[0]), comp_AT_RANK);
655
+ } else {
656
+ trans_k1 = 0;
657
+ }
658
+ /* store canon. ranks of at[k2] neighbors */ /* use i,j,k,m,n */
659
+ for ( n = j = 0; n < num_neigh2; n ++ ) {
660
+ i=(int)at[k2].neighbor[n];
661
+ if ( i == prev ) { /* neighbor belongs to the stereobond */
662
+ m2 = n;
663
+ } else {
664
+ for ( m = 0; m < num_neigh2-1; m ++ ) {
665
+ if ( nRank[i] == nNeighRank2[m] ) {
666
+ nNeighCanonRank2[m] = nCanonRank[i];
667
+ j ++;
668
+ break;
669
+ }
670
+ }
671
+ }
672
+ }
673
+ if ( j != num_neigh2-1 || m2 < 0 ) {
674
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
675
+ }
676
+ if ( j == 2 ) {
677
+ trans_k2 = insertions_sort(nNeighCanonRank2, j, sizeof(nNeighCanonRank2[0]), comp_AT_RANK);
678
+ } else {
679
+ trans_k2 = 0;
680
+ }
681
+ trans_k = (trans_k1 + trans_k2)%2;
682
+ if ( prev_trans < 0 ) {
683
+ prev_trans = trans_k;
684
+ } else
685
+ if ( prev_trans != trans_k ) { /* was != trans_k1, changed 9-23-2003 */
686
+ break; /* different number of transpositions */
687
+ }
688
+ } /* end of the second atom mapping cycle */
689
+ if ( prev_trans >= 0 && prev_trans != trans_k ) { /* was != trans_k1, changed 9-23-2003 */
690
+ break;
691
+ }
692
+ } /* end of the first atom mapping cycle */
693
+ if ( prev_trans == trans_k ) { /* was == trans_k1, changed 9-23-2003 */
694
+ int z_prod;
695
+ /* all mappings of canonical numbers on the */
696
+ /* stereo bond at[i1]-at[i2] produce equivalent numberings. */
697
+ /* Therefore the stereo bond parity is known at this time. */
698
+ /* parity_1 = at[i1].parity + (trans_i1 + trans_k1 + num_neigh1 - 1) + (int)at[i1].stereo_bond_ord[n1] */
699
+ /* expression in parentheses is equivalent to rank[first neigh] > rank[second neigh] */
700
+ /* same for parity_2. */
701
+ /* parity_2 = at[i2].parity + (trans_i2 + trans_k2 + num_neigh2 - 1) + (int)at[i2].stereo_bond_ord[n2] */
702
+ /* Sum of the two parities (without stereo_bond_z_prod) is: */
703
+ parity = (at[i1].parity + at[i2].parity + prev_trans + trans_i1 + trans_i2
704
+ + num_neigh1 + num_neigh2
705
+ + (int)at[i1].stereo_bond_ord[n1] + (int)at[i2].stereo_bond_ord[n2] ) %2;
706
+ z_prod = at[i1].stereo_bond_z_prod[n1];
707
+ if ( MIN_DOT_PROD > abs(z_prod)) {
708
+ parity = AB_PARITY_UNDF; /* undefined because of geometry */
709
+ } else {
710
+ parity = (z_prod > 0)? 2 - parity : 1 + parity;
711
+ }
712
+ at[i1].stereo_bond_parity[n1] = ALL_BUT_PARITY(at[i1].stereo_bond_parity[n1]) | parity;
713
+ at[i2].stereo_bond_parity[n2] = ALL_BUT_PARITY(at[i2].stereo_bond_parity[n2]) | parity;
714
+ num_set ++;
715
+ }
716
+ }
717
+ }
718
+ return num_set;
719
+ }
720
+ /**********************************************************************************/
721
+ /* Find stereo center parities known in advance */
722
+ int MarkKnownEqualStereoBondParities( sp_ATOM *at, int num_atoms,
723
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber )
724
+ {
725
+ int j, n, m, j1, num_neigh1, num_neigh2, iMax1;
726
+ int num_set, /*num_sb1, num_sb2,*/ bDifferentParities;
727
+ int i1, i2, k1, k2, n1, n2, m1, m2, s1, s2, stereo_bond_parity, stereo_bond_parity2, cumulene_len;
728
+ AT_RANK nAtomRank1, nAtomRank2, nAtom1NeighRank, nAtom2NeighRank;
729
+ num_set = 0;
730
+ for ( i1 = 0, num_set = 0; i1 < num_atoms; i1 ++ ) {
731
+ if ( !at[i1].parity || !at[i1].stereo_bond_neighbor[0] ) {
732
+ continue;
733
+ }
734
+ nAtomRank1 = nRank[i1];
735
+ iMax1 = (int)nAtomRank1-1;
736
+ num_neigh1 = at[i1].valence;
737
+ /* count stereogenic bonds adjacent to at[i1] */
738
+ for ( n1 = 0; n1 < MAX_NUM_STEREO_BONDS && at[i1].stereo_bond_neighbor[n1]; n1++ )
739
+ ;
740
+ /*num_sb1 = n1;*/
741
+ /* search for bonds possibly constitutionally equivalent to each of the adjacent bonds */
742
+ /* and find if all of them have same already known parity */
743
+ for ( n1 = 0, i2 = 0; n1 < MAX_NUM_STEREO_BONDS && (i2=(int)at[i1].stereo_bond_neighbor[n1]); n1++ ) {
744
+ i2 --;
745
+ nAtomRank2 = nRank[i2];
746
+ if ( nAtomRank2 < nAtomRank1 || nAtomRank2 == nAtomRank1 && i1 < i2 ) {
747
+ /* An attempt to reduce unnecessary repetitions. */
748
+ /* We still have repetitions because we do not accumulate a list of */
749
+ /* processed (nAtomRank2, nAtomRank1) pairs. */
750
+ continue;
751
+ }
752
+ bDifferentParities = -1; /* parities have not been compared yet */
753
+ /* found a stereo bond at[i1]-at[i2] (adjacent to at[i1]) */
754
+ /*
755
+ if ( !PARITY_KNOWN(at[i1].stereo_bond_parity[n1]) || (at[i1].stereo_bond_parity[n1] & KNOWN_PARITIES_EQL) ) {
756
+ continue;
757
+ }
758
+ */
759
+ if ( at[i1].stereo_bond_parity[n1] & KNOWN_PARITIES_EQL ) {
760
+ continue;
761
+ }
762
+ /* stereo bond has known or unknown parity; we have not checked it yet */
763
+ for ( n2 = 0; n2 < MAX_NUM_STEREO_BONDS && at[i2].stereo_bond_neighbor[n2]; n2++ )
764
+ ;
765
+ /*num_sb2 = n2;*/
766
+ for ( n2 = 0, m = 0; n2 < MAX_NUM_STEREO_BONDS && (m=(int)at[i2].stereo_bond_neighbor[n2]) && m-1 != i1; n2++ )
767
+ ;
768
+ if ( m-1 != i1 || at[i1].stereo_bond_parity[n1] != at[i2].stereo_bond_parity[n2] ) {
769
+ return CT_STEREOCOUNT_ERR; /* program error: stereo bonds data in two directions are different */ /* <BRKPT> */
770
+ }
771
+ stereo_bond_parity = PARITY_VAL(at[i1].stereo_bond_parity[n1]);
772
+ cumulene_len = BOND_CHAIN_LEN(at[i1].stereo_bond_parity[n1]);
773
+ nAtom1NeighRank = nRank[(int)at[i1].neighbor[(int)at[i1].stereo_bond_ord[n1]]];
774
+ nAtom2NeighRank = nRank[(int)at[i2].neighbor[(int)at[i2].stereo_bond_ord[n2]]];
775
+ num_neigh2 = at[i2].valence;
776
+ /* find all pairs of atoms that possibly can be mapped on at[i1], at[i2] pair */
777
+ /* (we may also find pairs that cannot be mapped, but we cannot miss any pair */
778
+ /* that can be mapped) */
779
+ for ( j1 = 0; j1 <= iMax1 && nAtomRank1==nRank[k1=(int)nAtomNumber[iMax1-j1]]; j1 ++ ) {
780
+ /* at[k1] is constitutionally equivalent to at[i1] */
781
+ /* find all at[k1] stereo bond neighbors at[k2] that have rank nAtomRank2; */
782
+ /* then find at[k2] constitutionally equivalent at at[i2] */
783
+ if ( at[k1].valence != num_neigh1 ) {
784
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
785
+ }
786
+ if ( !at[k1].bHasStereoOrEquToStereo ) {
787
+ at[k1].bHasStereoOrEquToStereo = 1;
788
+ }
789
+ /* -- do not check number of stereo bonds, check bonds themselves --
790
+ for ( s1 = 0; s1 < MAX_NUM_STEREO_BONDS && at[k1].stereo_bond_neighbor[s1]; s1++ )
791
+ ;
792
+ if ( num_sb1 != s1 ) {
793
+ bDifferentParities = 1;
794
+ }
795
+ */
796
+ for ( m1 = 0; m1 < num_neigh1; m1 ++ ) {
797
+ /* Looking for at[k1] neighbor with nRank=nAtom1NeighRank. */
798
+ /* This neighbor may be on the bond constit. equivalent to at[i1]-at[i2] stereo bond */
799
+ /* (or may be constit. equivalent an adjacent to at[i1] atom in a stereogenic cumulene chain) */
800
+ int prev, next, len;
801
+ if ( nAtom1NeighRank != nRank[k2=(int)at[k1].neighbor[m1]] ) {
802
+ continue;
803
+ }
804
+ /* found at[k1] neighbor with nRank=nAtom1NeighRank */
805
+ m2 = -1; /* undefined yet */
806
+ prev = k1;
807
+ len = 0;
808
+ /* if cumulene then bypass the cumulene chain */
809
+ if ( cumulene_len ) {
810
+ for ( len=0, next = (int)at[k1].neighbor[m1]; len < cumulene_len; len ++ ) {
811
+ if ( at[next].valence == 2 && !at[next].num_H ) {
812
+ j = ((int)at[next].neighbor[0] == prev);
813
+ prev = next;
814
+ next = at[next].neighbor[j];
815
+ } else {
816
+ break; /* cannot continue: end of cumulene chain */
817
+ }
818
+ }
819
+ if ( len != cumulene_len || nAtomRank2 != nRank[next] ) {
820
+ continue; /* cumulene chain not found at this neighbor */
821
+ }
822
+ if ( nAtom2NeighRank != nRank[prev] ) {
823
+ /* continue; */ /* ??? program error ??? If not, must be a very rare event */
824
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
825
+ }
826
+ k2 = next;
827
+ }
828
+
829
+ /* a connected pair of constit. equivalent atoms found */
830
+ if ( at[k2].valence != num_neigh2 ) {
831
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
832
+ }
833
+ for ( n = 0; n < num_neigh2; n ++ ) {
834
+ if ( prev == (int)at[k2].neighbor[n] ) {
835
+ m2 = n; /* found bond from the opposite end of a possibly stereogenic bond */
836
+ break;
837
+ }
838
+ }
839
+ if ( m2 < 0 ) {
840
+ return CT_STEREOCOUNT_ERR; /* program error: opposite direction bond not found */ /* <BRKPT> */
841
+ }
842
+ if ( !at[k2].bHasStereoOrEquToStereo ) {
843
+ at[k2].bHasStereoOrEquToStereo = 1;
844
+ }
845
+
846
+ /* check if atoms at[k1] and at[k2] are connected by a stereo bond */
847
+ for ( s1 = 0, m = 0; s1 < MAX_NUM_STEREO_BONDS && (m=(int)at[k1].stereo_bond_neighbor[s1]) && m-1 != k2; s1++ )
848
+ ;
849
+ if ( m-1 != k2 ) {
850
+ bDifferentParities = 1; /* cannot find the stereo bond */
851
+ at[k1].bHasStereoOrEquToStereo =
852
+ at[k2].bHasStereoOrEquToStereo = 2;
853
+ continue;
854
+ }
855
+ /* -- do not check number of stereo bonds, check bonds themselves --
856
+ for ( s2 = 0; s2 < MAX_NUM_STEREO_BONDS && at[k2].stereo_bond_neighbor[s2]; s2++ )
857
+ ;
858
+ if ( num_sb2 != s2 ) {
859
+ bDifferentParities = 1;
860
+ continue;
861
+ }
862
+ */
863
+ for ( s2 = 0, m = 0; s2 < MAX_NUM_STEREO_BONDS && (m=(int)at[k2].stereo_bond_neighbor[s2]) && m-1 != k1; s2++ )
864
+ ;
865
+ if ( m-1 != k1 ) {
866
+ /*
867
+ bDifferentParities = 1; // cannot find the stereo bond
868
+ continue;
869
+ */
870
+ return CT_STEREOCOUNT_ERR; /* program error: opposite direction bond not found */ /* <BRKPT> */
871
+ }
872
+ if ( at[k1].stereo_bond_parity[s1] != at[k2].stereo_bond_parity[s2] ) {
873
+ bDifferentParities = 1;
874
+ continue;
875
+ }
876
+ stereo_bond_parity2 = PARITY_VAL(at[k1].stereo_bond_parity[s1]);
877
+ if ( stereo_bond_parity2 != stereo_bond_parity ) {
878
+ bDifferentParities = 1;
879
+ continue;
880
+ }
881
+ if ( stereo_bond_parity2 == stereo_bond_parity && bDifferentParities < 0 ) {
882
+ bDifferentParities = 0;
883
+ }
884
+ }
885
+ }
886
+ /* mark equal parities */
887
+ if ( 0 == bDifferentParities && PARITY_KNOWN( stereo_bond_parity ) ) {
888
+ for ( j1 = 0; j1 <= iMax1 && nAtomRank1==nRank[k1=(int)nAtomNumber[iMax1-j1]]; j1 ++ ) {
889
+ /* at[k1] is constitutionally equivalent to at[i1] */
890
+ for ( s1 = 0, k2 = 0; s1 < MAX_NUM_STEREO_BONDS && (k2=(int)at[k1].stereo_bond_neighbor[s1]); s1++ ) {
891
+ k2--;
892
+ if ( nRank[k2] == nAtomRank2 ) {
893
+ int b1, b2;
894
+ for ( s2 = 0, m = 0; s2 < MAX_NUM_STEREO_BONDS && (m=(int)at[k2].stereo_bond_neighbor[s2])
895
+ && m-1 != k1; s2++ )
896
+ ;
897
+ if ( m-1 != k1 ) {
898
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
899
+ }
900
+ /* mark the stereo bonds */
901
+ b1 = !(at[k1].stereo_bond_parity[s1] & KNOWN_PARITIES_EQL);
902
+ b2 = !(at[k2].stereo_bond_parity[s2] & KNOWN_PARITIES_EQL);
903
+ if ( 2 == b1 + b2 ) {
904
+ at[k1].stereo_bond_parity[s1] |= KNOWN_PARITIES_EQL;
905
+ at[k2].stereo_bond_parity[s2] |= KNOWN_PARITIES_EQL;
906
+ num_set ++;
907
+ } else
908
+ if ( b1 || b2 ) {
909
+ return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
910
+ }
911
+ }
912
+ }
913
+ }
914
+ }
915
+ }
916
+ }
917
+ return num_set;
918
+ }
919
+ #if ( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
920
+ /**********************************************************************************/
921
+ /* Return next atom number (and its canon. rank) on the path prev->cur->next */
922
+ /* in order of ascending canonical ranks of the next atoms: *cr(output) > *cr(input) */
923
+ /* To start the sequence let *cr=0 */
924
+ /* If no more neighbors available the return value = 0; if successgul then the return value = 1. */
925
+ int GetNextNeighborAndRank( sp_ATOM *at, AT_RANK cur, AT_RANK prev, AT_RANK *n, AT_RANK *cr, const AT_RANK *nCanonRank )
926
+ {
927
+ int i, val;
928
+ AT_RANK cr1 = MAX_ATOMS+1, j, j1=MAX_ATOMS+1, crj;
929
+
930
+ for ( i = 0, val = at[(int)cur].valence; i < val; i ++ ) {
931
+ if ( (j=at[cur].neighbor[i]) != prev &&
932
+ cr1 > (crj=nCanonRank[(int)j]) && crj > *cr ) {
933
+ cr1 = crj;
934
+ j1 = j;
935
+ }
936
+ }
937
+ if ( cr1 <= MAX_ATOMS ) {
938
+ *cr = cr1;
939
+ *n = (AT_RANK)j1;
940
+ return 1;
941
+ }
942
+ return 0; /* program error */ /* <BRKPT> */
943
+ }
944
+
945
+ /**********************************************************************************/
946
+ /* Find next pair of neighbors having the next greater canon. rank */
947
+ /* The neighbors should be constitutionally identical and traversed simultaneouly or not traversed at all */
948
+ /* If a bond cur1-*n1 or cur2-*n2 is a stereo bond then reject if their stereo bond parities are different or */
949
+ /* cannot be calculated without breaking ties. */
950
+ int GetAndCheckNextNeighbors( sp_ATOM *at, AT_RANK cur1, AT_RANK prev1, AT_RANK cur2, AT_RANK prev2,
951
+ AT_RANK *n1, AT_RANK *n2, AT_RANK *nVisited1, AT_RANK *nVisited2,
952
+ const AT_RANK *nRank, const AT_RANK *nCanonRank )
953
+ {
954
+ AT_RANK cr1, cr2, s1, s2;
955
+ int i1, i2, k1, k2;
956
+ cr1 = ( *n1 > MAX_ATOMS )? 0 : nCanonRank[(int)*n1];
957
+ cr2 = ( *n2 > MAX_ATOMS )? 0 : nCanonRank[(int)*n2];
958
+ if ( !GetNextNeighborAndRank( at, cur1, prev1, n1, &cr1, nCanonRank ) ||
959
+ !GetNextNeighborAndRank( at, cur2, prev2, n2, &cr2, nCanonRank ) ||
960
+ nRank[(int)*n1] != nRank[(int)*n2] || nVisited1[(int)*n1] != nVisited2[(int)*n2] ) {
961
+ return 0; /* program error; no breakpoint here */ /* <BRKPT> */
962
+ }
963
+
964
+ /* Even though the bond or cumulene might have already been checked, check it: this is */
965
+ /* the only place we can check stereo bonds and cumulenes that are not edges of the DFS tree */
966
+ /* The code works both for a stereo bond and a stereogenic cumulene. */
967
+ for ( i1 = 0, k1 = 0; i1 < MAX_NUM_STEREO_BONDS &&
968
+ (s1=at[cur1].stereo_bond_neighbor[i1]) &&
969
+ !(k1=(at[cur1].neighbor[(int)at[cur1].stereo_bond_ord[i1]] == *n1)); i1 ++ )
970
+ ;
971
+ for ( i2 = 0, k2 = 0; i2 < MAX_NUM_STEREO_BONDS &&
972
+ (s2=at[cur2].stereo_bond_neighbor[i2]) &&
973
+ !(k2=(at[cur2].neighbor[(int)at[cur2].stereo_bond_ord[i2]] == *n2)); i2 ++ )
974
+ ;
975
+ if ( k1 != k2 ) {
976
+ return 0; /* possibly not an error: constit. equivalent atoms on a stereo bond and not on a stereo bond */
977
+ }
978
+ if ( k1 /* yes, it is a stero bond */ &&
979
+ ( at[cur1].stereo_bond_parity[i1] != at[cur2].stereo_bond_parity[i2] ||
980
+ /* PARITY_KNOWN (at[cur1].stereo_bond_parity[i1] ) */ /* replaced 08-13-2002 with the next: */
981
+ !PARITY_WELL_DEF (at[cur1].stereo_bond_parity[i1] ) /* it suffices to check only one parity */
982
+ ) ) {
983
+ return 0; /* different or (currently) unknown stereo bond parities */
984
+ }
985
+ return 1; /* stereo bonds have known parities */
986
+ }
987
+
988
+ /**********************************************************************************/
989
+ /* Simultaneously DFS-traverse 2 paths starting at the bonds prev1->cur1 and prev2->cur2 */
990
+ /* The two paths MUST go through the pairs of constitutionally identical atoms, each atom being on one path. */
991
+ /* Reject if encountered atoms having currently unknown (without breaking ties) */
992
+ /* parities or having different known or unknown or undefined parities. */
993
+ /* Save length of the path into nVisited[cur. atom number]. */
994
+ /* Only one nVisited[] array is sufficient because the paths from the beginning are in different ring systems. */
995
+ AT_RANK PathsHaveIdenticalKnownParities( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
996
+ AT_RANK *nVisited1, AT_RANK *nVisited2,
997
+ const AT_RANK *nRank, const AT_RANK *nCanonRank, AT_RANK nLength )
998
+ {
999
+ int k;
1000
+ AT_RANK n1, n2;
1001
+
1002
+ nLength ++; /* number of successfully traversed pairs of atoms */
1003
+ nVisited1[cur1] = nLength;
1004
+ nVisited2[cur2] = nLength;
1005
+ /* the atoms must be either both stereogenic and have well-defined parities or non-stereogenic at all. */
1006
+ if ( at[cur1].stereo_atom_parity != at[cur2].stereo_atom_parity ||
1007
+ at[cur1].stereo_atom_parity && !PARITY_WELL_DEF (at[cur1].stereo_atom_parity)
1008
+ ) {
1009
+ return 0; /* Reject: Different or unknown in advance parities */
1010
+ }
1011
+
1012
+ if ( at[cur1].valence != at[cur2].valence ) {
1013
+ return 0; /* program error */ /* <BRKPT> */
1014
+ }
1015
+ if ( at[cur1].valence == 1 ) {
1016
+ return nLength; /* so far success */
1017
+ }
1018
+
1019
+
1020
+ for ( k = 1, n1 = MAX_ATOMS+1, n2=MAX_ATOMS+1; k < at[cur1].valence; k ++ ) {
1021
+ /* start from 1: since we do not go back, we have only (at[cur1].valence-1) bonds to try */
1022
+ if ( !GetAndCheckNextNeighbors( at, cur1, prev1, cur2, prev2,
1023
+ &n1, &n2, nVisited1, nVisited2, nRank, nCanonRank ) ) {
1024
+ return 0; /* different neighbors */
1025
+ }
1026
+ /* In a DFS we do not traverse already visited atoms */
1027
+ if ( !nVisited1[n1] ) { /* recursion */
1028
+ if ( ! (nLength = PathsHaveIdenticalKnownParities( at, cur1, n1, cur2, n2, nVisited1, nVisited2, nRank, nCanonRank, nLength ) ) ) {
1029
+ return 0;
1030
+ }
1031
+ }
1032
+ }
1033
+ /* To be on a safe side, recheck after all nVisited[] have been set */
1034
+ for ( k = 1, n1 = MAX_ATOMS+1, n2=MAX_ATOMS+1; k < at[cur1].valence; k ++ ) {
1035
+ /* start from 1: since we do not go back, we have only (at[cur1].valence-1) bonds to try */
1036
+ if ( !GetAndCheckNextNeighbors( at, cur1, prev1, cur2, prev2,
1037
+ &n1, &n2, nVisited1, nVisited2, nRank, nCanonRank ) ) {
1038
+ return 0; /* different neighbors */
1039
+ }
1040
+ }
1041
+
1042
+
1043
+ return nLength;
1044
+
1045
+ }
1046
+
1047
+ /**********************************************************************************/
1048
+ /* Remove stereo marks from the bonds that are known to be non-stereo */
1049
+ /* (compare neighbors if they are attached by cut-edges) */
1050
+ int RemoveKnownNonStereoBondParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
1051
+ const AT_RANK *nRank, CANON_STAT *pCS)
1052
+ {
1053
+ int j, n, m, ret;
1054
+
1055
+ int i1, n1, s2;
1056
+ AT_RANK nAtomRank1, nAtomRank2, neigh[3], opposite_atom, *nVisited = NULL;
1057
+ ret = 0;
1058
+ for ( i1 = 0; i1 < num_atoms; i1 ++ ) {
1059
+ if ( at[i1].valence != 3 || !at[i1].stereo_bond_neighbor[0] ) {
1060
+ continue;
1061
+ }
1062
+ for ( n1 = 0; n1 < MAX_NUM_STEREO_BONDS && (s2=at[i1].stereo_bond_neighbor[n1]); n1++ ) {
1063
+ if ( !PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) && PARITY_WELL_DEF(at[i1].stereo_bond_parity[n1]) ) {
1064
+ continue;
1065
+ }
1066
+ opposite_atom = (AT_RANK)(s2-1);
1067
+ /* s2 = at[i1].neighbor[m=(int)at[i1].stereo_bond_ord[n1]]; */
1068
+ m=(int)at[i1].stereo_bond_ord[n1];
1069
+ for ( j = 0, n = 0; j < at[i1].valence; j ++ ) {
1070
+ /* if ( at[i1].neighbor[j] != s2 ) */
1071
+ if ( j != m )
1072
+ {
1073
+ neigh[n++] = at[i1].neighbor[j];
1074
+ }
1075
+ }
1076
+ if ( n > 2 ) {
1077
+ ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
1078
+ goto exit_function;
1079
+ }
1080
+ if ( n != 2 || nRank[(int)neigh[0]] != nRank[(int)neigh[1]] ) {
1081
+ continue; /* may happen if another half-bond has not a defined parity */
1082
+ }
1083
+ if ( at[i1].nRingSystem == at[(int)neigh[0]].nRingSystem ) {
1084
+ continue; /* no more ring system membership check is necessary because */
1085
+ } /* the two neighbors are to be constitutionally equivalent atoms */
1086
+ if ( !nVisited && !(nVisited = (AT_RANK*)inchi_malloc( sizeof(nVisited[0])*num_atoms ) ) ) {
1087
+ ret = CT_OUT_OF_RAM; /* <BRKPT> */
1088
+ goto exit_function;
1089
+ }
1090
+ memset( nVisited, 0, sizeof(nVisited[0])*num_atoms );
1091
+ nVisited[i1] = 1;
1092
+ if ( PathsHaveIdenticalKnownParities( at, (AT_RANK)i1, neigh[0], (AT_RANK)i1, neigh[1], nVisited, nVisited, nRank, nCanonRank, 1 ) ) {
1093
+ if ( !RemoveOneStereoBond( at, i1, /* atom number*/ n1 /* stereo bond number*/ ) ) {
1094
+ ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
1095
+ goto exit_function;
1096
+ }
1097
+ n1 --; /* cycle counter may temporarily become negative */
1098
+ /* Remove from pCS */
1099
+ nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom]);
1100
+ nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom]);
1101
+ for ( n = 0, m = pCS->nLenLinearCTStereoDble-1; n <= m; n ++ ) {
1102
+ if ( pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
1103
+ pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2 ) {
1104
+ if ( n < m ) { /* remove pCS->LinearCTStereoDble[n] */
1105
+ memmove( pCS->LinearCTStereoDble + n,
1106
+ pCS->LinearCTStereoDble + n + 1,
1107
+ (m-n)*sizeof(pCS->LinearCTStereoDble[0]) );
1108
+ }
1109
+ pCS->nLenLinearCTStereoDble --;
1110
+ #if( bRELEASE_VERSION == 0 )
1111
+ pCS->bExtract |= EXTR_KNOWN_USED_TO_REMOVE_PARITY;
1112
+ #endif
1113
+ m = -1; /* set flag "found" */
1114
+ break;
1115
+ }
1116
+ }
1117
+ if ( m >= 0) {
1118
+ ret = CT_STEREOCOUNT_ERR; /* bond not found <BRKPT> */
1119
+ goto exit_function;
1120
+ }
1121
+ ret ++; /* number of removed known in advance non-stereo bonds */
1122
+ }
1123
+ }
1124
+ }
1125
+
1126
+ exit_function:
1127
+
1128
+ if ( nVisited ) {
1129
+ inchi_free( nVisited );
1130
+ }
1131
+ return ret;
1132
+ }
1133
+ #endif /* } REMOVE_KNOWN_NONSTEREO */
1134
+ /**********************************************************************************/
1135
+ /* Find stereo center parities known in advance */
1136
+ int SetKnownStereoCenterParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
1137
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber )
1138
+ {
1139
+ int i, j, n, m, j1, k, num_neigh, iMax, trans_i, trans_k, prev_trans, num_set;
1140
+ AT_RANK nAtomRank;
1141
+ AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
1142
+ AT_RANK nNeighCanonRank[MAX_NUM_STEREO_ATOM_NEIGH];
1143
+ for ( i = 0, num_set = 0; i < num_atoms; i ++ ) {
1144
+ if ( !at[i].parity || at[i].stereo_bond_neighbor[0] ) {
1145
+ continue;
1146
+ }
1147
+ if ( at[i].stereo_atom_parity != AB_PARITY_CALC || !PARITY_WELL_DEF(at[i].parity) ) {
1148
+ continue;
1149
+ }
1150
+ num_neigh = at[i].valence;
1151
+ for ( j = 0; j < num_neigh; j ++ ) {
1152
+ nNeighRank[j] = nRank[(int)at[i].neighbor[j]];
1153
+ }
1154
+ nAtomRank = nRank[i];
1155
+ if ( num_neigh == 1 ) { /* other neighbors must be implicit H */
1156
+ at[i].stereo_atom_parity = at[i].parity;
1157
+ trans_i = 0;
1158
+ } else {
1159
+ /* sort constitutional equivalence ranks of the neighbors */
1160
+ trans_i = insertions_sort(nNeighRank, num_neigh, sizeof(nNeighRank[0]), comp_AT_RANK);
1161
+ for ( j = 1; j < num_neigh; j ++ ) {
1162
+ if ( nNeighRank[j-1] == nNeighRank[j] )
1163
+ break; /* at[i] has consitutionally identical neighbors */
1164
+ }
1165
+ if ( j < num_neigh ) {
1166
+ /* at least 2 neighbors are const. identical; parity cannot be calculated at this time */
1167
+ continue; /* try next stereo atom */
1168
+ }
1169
+ }
1170
+ prev_trans = -1;
1171
+ trans_k = 0;
1172
+ /* find neighbors of constitutionally equivalent stereo centers */
1173
+ /* and at[i] parities in case those centers are mapped on at[i] */
1174
+ for ( iMax = (int)nAtomRank-1, j1 = 0; j1 <= iMax && nAtomRank==nRank[k=(int)nAtomNumber[iMax-j1]]; j1 ++ ) {
1175
+ /* at[k] is constitutionally equivalent to at[i] */
1176
+ if ( (int)at[k].valence != num_neigh ) {
1177
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1178
+ }
1179
+ /* -- commented out to accept non-stereogenic atoms since --
1180
+ -- they may participate in mapping stereocenters 12-16-2003 --
1181
+ if ( !PARITY_VAL(at[k].parity) ) {
1182
+ continue; // not a stereogenic atom
1183
+ }
1184
+ */
1185
+ for ( j = 0, m = 0; m < num_neigh; m ++ ) {
1186
+ for ( n = 0; n < num_neigh; n ++ ) {
1187
+ if ( nRank[(int)at[k].neighbor[n]] == nNeighRank[m] ) {
1188
+ /* save canonical numbers (ranks) of the neighbors in
1189
+ * order of increasing constit. equivalence ranks */
1190
+ nNeighCanonRank[m] = nCanonRank[(int)at[k].neighbor[n]];
1191
+ j ++;
1192
+ break;
1193
+ }
1194
+ }
1195
+ }
1196
+ if ( j != num_neigh ) {
1197
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1198
+ }
1199
+ trans_k = insertions_sort(nNeighCanonRank, num_neigh, sizeof(nNeighCanonRank[0]), comp_AT_RANK);
1200
+ trans_k %= 2;
1201
+ if ( prev_trans < 0 ) {
1202
+ prev_trans = trans_k;
1203
+ } else
1204
+ if ( trans_k != prev_trans ) {
1205
+ /* different mappings may produce different parities. Cannot find the parity at this time */
1206
+ /* this may happen when a set of constit. equivalent atoms has non-contiguous canonical numbers */
1207
+ break;
1208
+ }
1209
+ }
1210
+ if ( trans_k == prev_trans ) {
1211
+ at[i].stereo_atom_parity = 2 - (at[i].parity + trans_i + prev_trans ) % 2;
1212
+ num_set ++;
1213
+ }
1214
+ }
1215
+ return num_set;
1216
+ }
1217
+
1218
+ #if( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
1219
+ /**********************************************************************************/
1220
+ /* DFS along paths starting from the stereocenter through pairs of cut-edges */
1221
+ int RemoveKnownNonStereoCenterParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank,
1222
+ const AT_RANK *nRank, CANON_STAT *pCS)
1223
+ {
1224
+ int i, j, n, m, k, num_neigh, ret = 0;
1225
+ /*AT_RANK nAtomRank;*/
1226
+ AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH], nNeighOrd[MAX_NUM_STEREO_ATOM_NEIGH];
1227
+
1228
+ AT_RANK *nVisited = NULL;
1229
+
1230
+ for ( i = 0; i < num_atoms; i ++ ) {
1231
+ if ( !at[i].parity || at[i].stereo_bond_neighbor[0] ) {
1232
+ continue;
1233
+ }
1234
+ if ( !PARITY_CALCULATE(at[i].stereo_atom_parity) && PARITY_WELL_DEF(at[i].stereo_atom_parity) ) {
1235
+ continue;
1236
+ }
1237
+ num_neigh = at[i].valence;
1238
+ for ( j = 0; j < num_neigh; j ++ ) {
1239
+ nNeighRank[j] = nRank[(int)at[i].neighbor[j]];
1240
+ nNeighOrd[j] = j;
1241
+ }
1242
+ /*nAtomRank = nRank[i];*/
1243
+ if ( num_neigh == 1 ) {
1244
+ continue;
1245
+ }
1246
+ pn_RankForSort = nNeighRank;
1247
+ insertions_sort(nNeighOrd, num_neigh, sizeof(nNeighRank[0]), CompRanksOrd);
1248
+ for ( j = k = 1; k && j < num_neigh; j ++ ) {
1249
+ if ( at[i].nRingSystem != at[(int)at[i].neighbor[(int)nNeighOrd[j]]].nRingSystem &&
1250
+ /* no more ring system membership check is necessary because */
1251
+ /* the two neighbors are to be constitutionally equivalent atoms: */
1252
+ nNeighRank[nNeighOrd[j-1]] == nNeighRank[nNeighOrd[j]] ) {
1253
+ k = j;
1254
+ do {
1255
+ if ( !nVisited && !(nVisited = (AT_RANK*)inchi_malloc( sizeof(nVisited[0])*num_atoms ) ) ) {
1256
+ ret = CT_OUT_OF_RAM; /* <BRKPT> */
1257
+ goto exit_function;
1258
+ }
1259
+ memset( nVisited, 0, sizeof(nVisited[0])*num_atoms );
1260
+ nVisited[i] = 1;
1261
+ if ( PathsHaveIdenticalKnownParities( at, (AT_RANK)i, at[i].neighbor[(int)nNeighOrd[j-1]],
1262
+ (AT_RANK)i, at[i].neighbor[(int)nNeighOrd[k]],
1263
+ nVisited, nVisited, nRank, nCanonRank, 1 ) ) {
1264
+ at[i].parity = 0; /* remove parity */
1265
+ at[i].stereo_atom_parity = 0;
1266
+ at[i].final_parity = 0;
1267
+ /* at[i].bHasStereoOrEquToStereo = 0; */
1268
+ for ( n = 0, m = pCS->nLenLinearCTStereoCarb-1; n <= m; n ++ ) {
1269
+ if ( pCS->LinearCTStereoCarb[n].at_num == nCanonRank[i] ) {
1270
+ if ( n < m ) { /* remove pCS->LinearCTStereoCarb[n] */
1271
+ memmove( pCS->LinearCTStereoCarb + n,
1272
+ pCS->LinearCTStereoCarb + n + 1,
1273
+ (m-n)*sizeof(pCS->LinearCTStereoCarb[0]) );
1274
+ }
1275
+ pCS->nLenLinearCTStereoCarb --;
1276
+ k = 0;
1277
+ #if( bRELEASE_VERSION == 0 )
1278
+ pCS->bExtract |= EXTR_KNOWN_USED_TO_REMOVE_PARITY;
1279
+ #endif
1280
+ break;
1281
+ }
1282
+ }
1283
+ if ( k ) {
1284
+ ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1285
+ goto exit_function;
1286
+ }
1287
+ ret ++;
1288
+ break;
1289
+ }
1290
+ } while ( ++k < num_neigh && nNeighRank[nNeighOrd[j-1]] == nNeighRank[nNeighOrd[k]] );
1291
+ }
1292
+ }
1293
+ }
1294
+
1295
+ exit_function:
1296
+
1297
+ if ( nVisited ) {
1298
+ inchi_free( nVisited );
1299
+ }
1300
+
1301
+ return ret;
1302
+ }
1303
+ #endif /* } REMOVE_KNOWN_NONSTEREO */
1304
+ /**********************************************************************************/
1305
+ /* Find stereo center parities known in advance */
1306
+ int MarkKnownEqualStereoCenterParities( sp_ATOM *at, int num_atoms,
1307
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber )
1308
+ {
1309
+ int i, j1, k, num_centers, iMax, bDifferentParities;
1310
+ AT_RANK nAtomRank;
1311
+ int parity, parity_k;
1312
+ num_centers = 0;
1313
+ for ( i = 0; i < num_atoms; i ++ ) {
1314
+ if ( !at[i].parity || at[i].stereo_bond_neighbor[0] ) {
1315
+ continue;
1316
+ }
1317
+ if ( at[i].bHasStereoOrEquToStereo ) {
1318
+ continue; /* already marked */
1319
+ }
1320
+ if ( /*!PARITY_KNOWN(at[i].stereo_atom_parity) ||*/ (at[i].stereo_atom_parity & KNOWN_PARITIES_EQL) ) {
1321
+ continue;
1322
+ }
1323
+ parity = PARITY_VAL(at[i].stereo_atom_parity);
1324
+ if ( parity == AB_PARITY_NONE ) {
1325
+ continue;
1326
+ }
1327
+ nAtomRank = nRank[i];
1328
+ bDifferentParities = -1;
1329
+ /* find constitutionally equivalent stereo centers and compare their known at this time parities */
1330
+ for ( iMax = (int)nAtomRank-1, j1 = 0; j1 <= iMax && nAtomRank==nRank[k=(int)nAtomNumber[iMax-j1]]; j1 ++ ) {
1331
+ /* at[k] is constitutionally equivalent to at[i] */
1332
+ parity_k = PARITY_VAL(at[k].stereo_atom_parity);
1333
+ if ( parity_k != parity ) {
1334
+ bDifferentParities = 1;
1335
+ } else
1336
+ if ( parity_k == parity && bDifferentParities < 0 ) {
1337
+ bDifferentParities = 0;
1338
+ }
1339
+ if ( !parity_k ) {
1340
+ at[k].bHasStereoOrEquToStereo = 2;
1341
+ } else
1342
+ if ( !at[k].bHasStereoOrEquToStereo ) {
1343
+ at[k].bHasStereoOrEquToStereo = 1;
1344
+ }
1345
+ }
1346
+ if ( 0 == bDifferentParities && PARITY_KNOWN( parity ) ) {
1347
+ for ( iMax = (int)nAtomRank-1, j1 = 0; j1 <= iMax && nAtomRank==nRank[k=(int)nAtomNumber[iMax-j1]]; j1 ++ ) {
1348
+ /* at[k] is constitutionally equivalent to at[i] */
1349
+ at[k].stereo_atom_parity |= KNOWN_PARITIES_EQL;
1350
+ num_centers ++;
1351
+ }
1352
+ }
1353
+ }
1354
+ return num_centers;
1355
+ }
1356
+ /*****************************************************************************/
1357
+ /* invert known parities in at[] and in pCS->LinearCTStereoDble */
1358
+ /* pCS->LinearCTStereoCarb */
1359
+ /* nCanonRank[] contains canonical ranks used to fill pCS->LinearCTStereo... */
1360
+ /* nAtomNumberCanon[] will be filled with atom numbers in canonical order */
1361
+ /*****************************************************************************/
1362
+ int InvertStereo( sp_ATOM *at, int num_at_tg,
1363
+ AT_RANK *nCanonRank, AT_RANK *nAtomNumberCanon,
1364
+ CANON_STAT *pCS, int bInvertLinearCTStereo )
1365
+ {
1366
+ int i, j, j1, j2, num_changes, parity, cumulene_len;
1367
+ num_changes = 0;
1368
+ for ( i = 0; i < num_at_tg; i ++ ) {
1369
+ nAtomNumberCanon[(int)nCanonRank[i]-1] = i;
1370
+ }
1371
+ for ( i = 0; i < pCS->nLenLinearCTStereoCarb; i ++ ) {
1372
+ parity = pCS->LinearCTStereoCarb[i].parity;
1373
+ if ( ATOM_PARITY_WELL_DEF( parity ) ) {
1374
+ j = nAtomNumberCanon[(int)pCS->LinearCTStereoCarb[i].at_num-1];
1375
+ if ( PARITY_WELL_DEF(at[j].parity) ) {
1376
+ at[j].parity ^= AB_INV_PARITY_BITS;
1377
+ } else {
1378
+ goto exit_error; /* inconsistency */
1379
+ }
1380
+ if ( bInvertLinearCTStereo ) {
1381
+ pCS->LinearCTStereoCarb[i].parity ^= AB_INV_PARITY_BITS;
1382
+ }
1383
+ num_changes ++;
1384
+ if ( PARITY_WELL_DEF(at[j].stereo_atom_parity) ) {
1385
+ at[j].stereo_atom_parity ^= AB_INV_PARITY_BITS;
1386
+ }
1387
+ if ( PARITY_WELL_DEF(at[j].final_parity) ) {
1388
+ at[j].final_parity ^= AB_INV_PARITY_BITS;
1389
+ }
1390
+ }
1391
+ }
1392
+ for ( i = 0; i < pCS->nLenLinearCTStereoDble; i ++ ) {
1393
+ parity = pCS->LinearCTStereoDble[i].parity;
1394
+ if ( ATOM_PARITY_WELL_DEF( parity ) ) {
1395
+ j1 = nAtomNumberCanon[(int)pCS->LinearCTStereoDble[i].at_num1-1];
1396
+ cumulene_len = BOND_CHAIN_LEN(at[j1].stereo_bond_parity[0]);
1397
+ if ( cumulene_len % 2 ) {
1398
+ /* invert only in case of allene */
1399
+ j2 = nAtomNumberCanon[(int)pCS->LinearCTStereoDble[i].at_num2-1];
1400
+ /* checks for debug only */
1401
+ if ( 1 < MAX_NUM_STEREO_BONDS ) {
1402
+ if ( at[j1].stereo_bond_neighbor[1] ||
1403
+ at[j2].stereo_bond_neighbor[1] ) {
1404
+ goto exit_error; /* inconsitency: atom has more than one cumulene bond */
1405
+ }
1406
+ }
1407
+ if ( cumulene_len != BOND_CHAIN_LEN(at[j2].stereo_bond_parity[0]) ||
1408
+ j1+1 != at[j2].stereo_bond_neighbor[0] ||
1409
+ j2+1 != at[j1].stereo_bond_neighbor[0] ) {
1410
+ goto exit_error; /* inconsitency: atoms should refer to each other */
1411
+ }
1412
+ /* invert parities */
1413
+ if ( PARITY_WELL_DEF(at[j1].parity) && PARITY_WELL_DEF(at[j2].parity) ) {
1414
+ j = inchi_min( j1, j2 );
1415
+ at[j].parity ^= AB_INV_PARITY_BITS; /* for reversability always invert only atom with the smaller number */
1416
+ } else {
1417
+ goto exit_error; /* inconsistency */
1418
+ }
1419
+ if ( bInvertLinearCTStereo ) {
1420
+ pCS->LinearCTStereoDble[i].parity ^= AB_INV_PARITY_BITS;
1421
+ }
1422
+ num_changes ++;
1423
+ if ( PARITY_WELL_DEF(at[j1].stereo_bond_parity[0]) ) {
1424
+ at[j1].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
1425
+ }
1426
+ if ( PARITY_WELL_DEF(at[j2].stereo_bond_parity[0]) ) {
1427
+ at[j2].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
1428
+ }
1429
+ }
1430
+ }
1431
+ }
1432
+
1433
+ return num_changes;
1434
+
1435
+ exit_error:
1436
+
1437
+ return CT_STEREOCOUNT_ERR;
1438
+ }
1439
+ /**********************************************************************************/
1440
+ /* Make sure atoms stereo descriptors fit molecular symmetry and remove */
1441
+ /* parity from obviously non-stereo atoms and bonds */
1442
+ int FillOutStereoParities( sp_ATOM *at, int num_atoms, const AT_RANK *nCanonRank, const AT_RANK *nAtomNumberCanon,
1443
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber, CANON_STAT *pCS, int bIsotopic )
1444
+ {
1445
+ int ret;
1446
+ /* unmark atoms with 2 or more constitutionally equivalent neighbors */
1447
+ /* such that there is no path through them to an atom with parity */
1448
+ ret = UnmarkNonStereo( at, num_atoms, nRank, nAtomNumber, bIsotopic );
1449
+ if ( ret < 0 )
1450
+ return ret; /* program error? */ /* <BRKPT> */
1451
+ ret = FillAllStereoDescriptors( at, num_atoms, nCanonRank, nAtomNumberCanon, pCS ); /* ret<0: error */
1452
+ if ( !ret ) {
1453
+ ret = pCS->nLenLinearCTStereoCarb + pCS->nLenLinearCTStereoDble;
1454
+ }
1455
+ if ( ret < 0 ) {
1456
+ return ret; /* program error? */ /* <BRKPT> */
1457
+ }
1458
+
1459
+ if ( ret >= 0 ) {
1460
+ int ret2;
1461
+ ret2 = SetKnownStereoCenterParities( at, num_atoms, nCanonRank, nRank, nAtomNumber );
1462
+ if ( ret2 >= 0 ) {
1463
+ ret2 = MarkKnownEqualStereoCenterParities( at, num_atoms, nRank, nAtomNumber );
1464
+ }
1465
+ if ( ret2 >= 0 ) {
1466
+ ret2 = SetKnownStereoBondParities( at, num_atoms, nCanonRank, nRank, nAtomNumber );
1467
+ if ( ret2 >= 0 ) {
1468
+ ret2 = MarkKnownEqualStereoBondParities( at, num_atoms, nRank, nAtomNumber);
1469
+ }
1470
+ }
1471
+ #if( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
1472
+ if ( ret2 >= 0 ) {
1473
+ int ret3;
1474
+ do {
1475
+ ret2 = RemoveKnownNonStereoCenterParities( at, num_atoms, nCanonRank, nRank, pCS);
1476
+ if ( ret2 >= 0 ) {
1477
+ ret3 = RemoveKnownNonStereoBondParities( at, num_atoms, nCanonRank, nRank, pCS);
1478
+ ret2 = ret3 >= 0? ret2+ret3 : ret3;
1479
+ }
1480
+ }
1481
+ while( ret2 > 0 );
1482
+ }
1483
+ if ( RETURNED_ERROR( ret2 ) ) {
1484
+ ret = ret2;
1485
+ }
1486
+ #endif /* } REMOVE_KNOWN_NONSTEREO */
1487
+ }
1488
+
1489
+ return ret; /* non-zero means error */
1490
+ }
1491
+ /**********************************************************************************/
1492
+ int GetStereoNeighborPos( sp_ATOM *at, int iAt1, int iAt2 )
1493
+ {
1494
+ int k1;
1495
+ AT_RANK sNeigh = (AT_RANK)(iAt2+1);
1496
+ AT_RANK s;
1497
+ for ( k1 = 0; k1 < MAX_NUM_STEREO_BONDS && (s = at[iAt1].stereo_bond_neighbor[k1]); k1 ++ ) {
1498
+ if ( s == sNeigh ) {
1499
+ return k1;
1500
+ }
1501
+ }
1502
+ return -1; /* neighbor not found */
1503
+ }
1504
+
1505
+ /**********************************************************************************/
1506
+ /* Extracted from FillSingleStereoDescriptors(...) */
1507
+ /**********************************************************************************/
1508
+ int GetStereoBondParity(sp_ATOM *at, int i, int n, AT_RANK *nRank )
1509
+ {
1510
+ int k1, k2, s, parity;
1511
+
1512
+ if ( at[i].stereo_bond_neighbor[0] ) {
1513
+ for ( k1 = 0; k1 < MAX_NUM_STEREO_BONDS && (s = (int)at[i].stereo_bond_neighbor[k1]); k1 ++ ) {
1514
+ if ( --s == n ) {
1515
+ goto neigh1_found;
1516
+ }
1517
+ }
1518
+ return -1; /* error: not a stereo neighbor */
1519
+ neigh1_found:
1520
+ if ( PARITY_KNOWN( at[i].stereo_bond_parity[k1] ) ) {
1521
+ return PARITY_VAL( at[i].stereo_bond_parity[k1] );
1522
+ }
1523
+ for ( k2 = 0; k2 < MAX_NUM_STEREO_BONDS && (s = (int)at[n].stereo_bond_neighbor[k2]); k2 ++ ) {
1524
+ if ( --s == i ) {
1525
+ goto neigh2_found;
1526
+ }
1527
+ }
1528
+ return -1; /* error: not a stereo neighbor */
1529
+ neigh2_found:;
1530
+ } else {
1531
+ return -1; /* error: not a stereo bond */
1532
+ }
1533
+
1534
+ if ( ATOM_PARITY_WELL_DEF(at[i].parity) &&
1535
+ ATOM_PARITY_WELL_DEF(at[n].parity) &&
1536
+ MIN_DOT_PROD <= abs(at[i].stereo_bond_z_prod[k1]) ) {
1537
+ /* bond parity can be calculated */
1538
+ int half_parity1, half_parity2;
1539
+ /* check whether all neighbors are defined */
1540
+
1541
+
1542
+ half_parity1 = HalfStereoBondParity( at, i, k1, nRank );
1543
+ half_parity2 = HalfStereoBondParity( at, n, k2, nRank );
1544
+ if ( !half_parity1 || !half_parity2 )
1545
+ return 0; /* ranks undefined or not a stereo bond */
1546
+ if ( ATOM_PARITY_WELL_DEF(half_parity1) &&
1547
+ ATOM_PARITY_WELL_DEF(half_parity2) ) {
1548
+ parity = 2 - ( half_parity1 + half_parity2
1549
+ + (at[i].stereo_bond_z_prod[k1] < 0))%2;
1550
+ } else {
1551
+ return CT_STEREOBOND_ERROR; /* <BRKPT> */
1552
+ }
1553
+ } else {
1554
+ /* parity cannot be calculated: not enough info or 'unknown' */
1555
+ if ( AB_PARITY_NONE != (parity = inchi_max(at[i].parity, at[n].parity)) ) {
1556
+ parity = AB_PARITY_UNDF; /* should not happen */
1557
+ }
1558
+ }
1559
+ return parity;
1560
+ }
1561
+
1562
+
1563
+
1564
+
1565
+ /**********************************************************************************/
1566
+ /* Extracted from FillSingleStereoDescriptors(...) */
1567
+ /**********************************************************************************/
1568
+ int GetPermutationParity( sp_ATOM *at, AT_RANK nAvoidNeighbor, AT_RANK *nCanonRank )
1569
+ {
1570
+ AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
1571
+ int j, k, parity;
1572
+ if ( at->valence > MAX_NUM_STEREO_ATOM_NEIGH ) {
1573
+ parity = -1; /* error */
1574
+ } else {
1575
+ for ( j = k = 0; j < at->valence; j ++ ) {
1576
+ if ( at->neighbor[j] != nAvoidNeighbor ) {
1577
+ nNeighRank[k++] = nCanonRank[(int)at->neighbor[j]];
1578
+ }
1579
+ }
1580
+ parity = insertions_sort( nNeighRank, k, sizeof(nNeighRank[0]), comp_AT_RANK);
1581
+ if ( nNeighRank[0] ) {
1582
+ parity = 2 - parity % 2;
1583
+ } else {
1584
+ parity = 0; /* not all ranks are known */
1585
+ }
1586
+ }
1587
+ return parity;
1588
+ }
1589
+ /**********************************************************************************/
1590
+ int GetStereoCenterParity(sp_ATOM *at, int i, AT_RANK *nRank )
1591
+ {
1592
+ AT_NUMB nNeighborNumber2[MAXVAL];
1593
+ int parity;
1594
+ int k, num_trans;
1595
+
1596
+ if ( !at[i].parity ) {
1597
+ return 0; /* not a stereo center */
1598
+ }
1599
+ if ( at[i].stereo_bond_neighbor[0] ) {
1600
+ return -1; /* a stereo bond atom, not a stereo center */
1601
+ }
1602
+
1603
+ if ( ATOM_PARITY_WELL_DEF(at[i].parity) ) {
1604
+ /* number of neighbors transpositions to the sorted order is unknown. Find it. */
1605
+ /* If parity is not well-defined then doing this is a waste of time */
1606
+ int num_neigh = at[i].valence;
1607
+ for ( k = 0; k < num_neigh; k ++) {
1608
+ if ( !nRank[(int)at[i].neighbor[k]] )
1609
+ return 0; /* stereo at[i] does not belong to the traversed part of the structure */
1610
+ nNeighborNumber2[k] = k;
1611
+ }
1612
+ pNeighborsForSort = at[i].neighbor;
1613
+ pn_RankForSort = nRank;
1614
+ num_trans=insertions_sort( nNeighborNumber2, num_neigh, sizeof(nNeighborNumber2[0]), CompNeighborsAT_NUMBER );
1615
+ #ifndef CT_NEIGH_INCREASE
1616
+ num_trans += ((num_neigh*(num_neigh-1))/2)%2; /* get correct parity for ascending order */
1617
+ #endif
1618
+ parity = 2 - (at[i].parity + num_trans)%2;
1619
+ } else {
1620
+ parity = at[i].parity;
1621
+ }
1622
+
1623
+ return parity;
1624
+ }
1625
+