rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,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
+