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,2195 @@
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
+ #include <ctype.h>
14
+
15
+ #include "mode.h"
16
+
17
+ #include "ichitime.h"
18
+ #include "ichi.h"
19
+ #include "util.h"
20
+ #include "extr_ct.h"
21
+ #include "ichitaut.h"
22
+ #include "inpdef.h"
23
+ #include "ichinorm.h"
24
+ #include "ichicant.h"
25
+ #include "ichicano.h"
26
+ #include "ichicomn.h"
27
+
28
+ #include "ichicomp.h"
29
+
30
+ /****************************************************************************
31
+ *
32
+ * Globals for sorting
33
+ */
34
+
35
+ const NEIGH_LIST *pNeighList_RankForSort;
36
+ const ATOM_INVARIANT2 *pAtomInvariant2ForSort;
37
+ const AT_NUMB *pNeighborsForSort;
38
+ const AT_RANK *pn_RankForSort;
39
+
40
+ AT_RANK nMaxAtNeighRankForSort;
41
+
42
+ int nNumCompNeighborsRanksCountEql;
43
+
44
+
45
+ #define tsort insertions_sort
46
+
47
+ /* local prototypes */
48
+
49
+
50
+ void FillOutAtomInvariant( sp_ATOM* at, int num_atoms, int num_at_tg, ATOM_INVARIANT* pAtomInvariant, CANON_STAT* pCS );
51
+
52
+ int Canon_INChI1( int num_atoms, int num_at_tg, sp_ATOM* at, CANON_STAT* pCS, INCHI_MODE nMode);
53
+ int Canon_INChI2( int num_atoms, int num_at_tg, sp_ATOM* at, CANON_STAT* pCS, INCHI_MODE nMode);
54
+ int Canon_INChI3( int num_atoms, int num_at_tg, sp_ATOM* at, CANON_STAT* pCS, INCHI_MODE nMode, int bTautFtcn);
55
+
56
+
57
+ #ifdef INCHI_ANSI_ONLY
58
+
59
+ static clock_t InchiClock(void);
60
+
61
+ #ifdef INCHI_USETIMES
62
+ static clock_t InchiClock(void)
63
+ {
64
+ struct tms buf;
65
+ clock_t c = times( &buf );
66
+ if ( c != (clock_t)-1 ) {
67
+ return buf.tms_utime;
68
+ }
69
+ return 0;
70
+ }
71
+ #else
72
+ static clock_t InchiClock(void)
73
+ {
74
+ clock_t c = clock();
75
+ if ( c != (clock_t)-1 ) {
76
+ return c;
77
+ }
78
+ return 0;
79
+ }
80
+ #endif
81
+
82
+ #define INCHI_MSEC(X) (long)((1000.0/(double)CLOCKS_PER_SEC)*(X))
83
+ #define INCHI_CLOCK_T(X) (clock_t)( (double)(X) / 1000.0 * (double)CLOCKS_PER_SEC )
84
+ const clock_t FullMaxClock = (clock_t)(-1);
85
+ const clock_t HalfMaxClock = (clock_t)(-1) / 2;
86
+ clock_t MaxPositiveClock = 0;
87
+ clock_t MinNegativeClock = 0;
88
+ clock_t HalfMaxPositiveClock = 0;
89
+ clock_t HalfMinNegativeClock = 0;
90
+
91
+ static void FillMaxMinClock(void); /* keep compiler happy */
92
+
93
+ static void FillMaxMinClock(void)
94
+ {
95
+ if ( !MaxPositiveClock ) {
96
+ clock_t valPos, val1 = 1;
97
+ while ( 0 < ((val1 <<= 1), (val1 |= 1)) ) {
98
+ valPos = val1;
99
+ }
100
+ MaxPositiveClock = valPos;
101
+ MinNegativeClock = -valPos;
102
+ HalfMaxPositiveClock = MaxPositiveClock / 2;
103
+ HalfMinNegativeClock = MinNegativeClock / 2;
104
+ }
105
+ }
106
+
107
+
108
+ /******** get current process time ****************************************/
109
+ void InchiTimeGet( inchiTime *TickEnd )
110
+ {
111
+ TickEnd->clockTime = InchiClock();
112
+ }
113
+ /******** returns difference TickEnd - TickStart in milliseconds **********/
114
+ long InchiTimeMsecDiff( inchiTime *TickEnd, inchiTime *TickStart )
115
+ {
116
+ if ( FullMaxClock > 0 ) {
117
+ clock_t delta;
118
+ if ( !TickEnd || !TickStart )
119
+ return 0;
120
+ /* clock_t is unsigned */
121
+ if ( TickEnd->clockTime > TickStart->clockTime ) {
122
+ if ( TickEnd->clockTime > HalfMaxClock &&
123
+ TickEnd->clockTime - TickStart->clockTime > HalfMaxClock ) {
124
+ /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
125
+ delta = (FullMaxClock - TickEnd->clockTime) + TickStart->clockTime;
126
+ return -INCHI_MSEC(delta);
127
+ }
128
+ delta = TickEnd->clockTime - TickStart->clockTime;
129
+ return INCHI_MSEC(delta);
130
+ } else
131
+ if ( TickEnd->clockTime < TickStart->clockTime ) {
132
+ if ( TickStart->clockTime > HalfMaxClock &&
133
+ TickStart->clockTime - TickEnd->clockTime > HalfMaxClock ) {
134
+ /* overflow in TickEnd->clockTime, actually TickEnd->clockTime was later */
135
+ delta = (FullMaxClock - TickStart->clockTime) + TickEnd->clockTime;
136
+ return INCHI_MSEC(delta);
137
+ }
138
+ delta = TickStart->clockTime - TickEnd->clockTime;
139
+ return -INCHI_MSEC(delta);
140
+ }
141
+ return 0; /* TickEnd->clockTime == TickStart->clockTime */
142
+ } else {
143
+ /* may happen under Win32 only where clock_t is SIGNED long */
144
+ clock_t delta;
145
+ FillMaxMinClock( );
146
+ if ( !TickEnd || !TickStart )
147
+ return 0;
148
+ if ( TickEnd->clockTime >= 0 && TickStart->clockTime >= 0 ||
149
+ TickEnd->clockTime <= 0 && TickStart->clockTime <= 0) {
150
+ delta = TickEnd->clockTime - TickStart->clockTime;
151
+ } else
152
+ if ( TickEnd->clockTime >= HalfMaxPositiveClock &&
153
+ TickStart->clockTime <= HalfMinNegativeClock ) {
154
+ /* end is earlier than start */
155
+ delta = (MaxPositiveClock - TickEnd->clockTime) + (TickStart->clockTime - MinNegativeClock);
156
+ delta = -delta;
157
+ } else
158
+ if ( TickEnd->clockTime <= HalfMinNegativeClock &&
159
+ TickStart->clockTime >= HalfMaxPositiveClock ) {
160
+ /* start was earlier than end */
161
+ delta = (MaxPositiveClock - TickStart->clockTime) + (TickEnd->clockTime - MinNegativeClock);
162
+ } else {
163
+ /* there was no overflow, clock passed zero */
164
+ delta = TickEnd->clockTime - TickStart->clockTime;
165
+ }
166
+ return INCHI_MSEC(delta);
167
+ }
168
+ }
169
+ /******************* get elapsed time from TickStart ************************/
170
+ long InchiTimeElapsed( inchiTime *TickStart )
171
+ {
172
+ inchiTime TickEnd;
173
+ if ( !TickStart )
174
+ return 0;
175
+ InchiTimeGet( &TickEnd );
176
+ return InchiTimeMsecDiff( &TickEnd, TickStart );
177
+ }
178
+ /******************* add number of milliseconds to time *********************/
179
+ void InchiTimeAddMsec( inchiTime *TickEnd, unsigned long nNumMsec )
180
+ {
181
+ clock_t delta;
182
+ if ( !TickEnd )
183
+ return;
184
+ if ( FullMaxClock > 0 ) {
185
+ /* clock_t is unsigned */
186
+ delta = INCHI_CLOCK_T(nNumMsec);
187
+ TickEnd->clockTime += delta;
188
+ } else {
189
+ /* may happen under Win32 only where clock_t is SIGNED long */
190
+ /* clock_t is unsigned */
191
+ FillMaxMinClock( );
192
+ delta = INCHI_CLOCK_T(nNumMsec);
193
+ TickEnd->clockTime += delta;
194
+ }
195
+ }
196
+ /******************* check whether time has expired *********************/
197
+ int bInchiTimeIsOver( inchiTime *TickStart )
198
+ {
199
+ if ( FullMaxClock > 0 ) {
200
+ clock_t clockCurrTime;
201
+ if ( !TickStart )
202
+ return 0;
203
+ clockCurrTime = InchiClock();
204
+ /* clock_t is unsigned */
205
+ if ( TickStart->clockTime > clockCurrTime ) {
206
+ if ( TickStart->clockTime > HalfMaxClock &&
207
+ TickStart->clockTime - clockCurrTime > HalfMaxClock ) {
208
+ /* overflow in clockCurrTime, actually clockCurrTime was later */
209
+ return 1;
210
+ }
211
+ return 0;
212
+ } else
213
+ if ( TickStart->clockTime < clockCurrTime ) {
214
+ if ( clockCurrTime > HalfMaxClock &&
215
+ clockCurrTime - TickStart->clockTime > HalfMaxClock ) {
216
+ /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
217
+ return 0;
218
+ }
219
+ return 1;
220
+ }
221
+ return 0; /* TickStart->clockTime == clockCurrTime */
222
+ } else {
223
+ /* may happen under Win32 only where clock_t is SIGNED long */
224
+ clock_t clockCurrTime;
225
+ FillMaxMinClock( );
226
+ if ( !TickStart )
227
+ return 0;
228
+ clockCurrTime = InchiClock();
229
+ if ( clockCurrTime >= 0 && TickStart->clockTime >= 0 ||
230
+ clockCurrTime <= 0 && TickStart->clockTime <= 0) {
231
+ return (clockCurrTime > TickStart->clockTime);
232
+ } else
233
+ if ( clockCurrTime >= HalfMaxPositiveClock &&
234
+ TickStart->clockTime <= HalfMinNegativeClock ) {
235
+ /* curr is earlier than start */
236
+ return 0;
237
+ } else
238
+ if ( clockCurrTime <= HalfMinNegativeClock &&
239
+ TickStart->clockTime >= HalfMaxPositiveClock ) {
240
+ /* start was earlier than curr */
241
+ return 1;
242
+ } else {
243
+ /* there was no overflow, clock passed zero */
244
+ return (clockCurrTime > TickStart->clockTime);
245
+ }
246
+ }
247
+ }
248
+
249
+ #else
250
+
251
+ /******** get current process time ****************************************/
252
+ void InchiTimeGet( inchiTime *TickEnd )
253
+ {
254
+ if ( TickEnd ) {
255
+ struct _timeb timeb;
256
+ _ftime( &timeb );
257
+ TickEnd->clockTime = (unsigned long)timeb.time;
258
+ TickEnd->millitime = (long)timeb.millitm;
259
+ }
260
+ }
261
+ /******** returns difference TickEnd - TickStart in milliseconds **********/
262
+ long InchiTimeMsecDiff( inchiTime *TickEnd, inchiTime *TickStart )
263
+ {
264
+ long delta;
265
+ if ( !TickEnd || !TickStart ) {
266
+ return 0;
267
+ }
268
+ if ( TickEnd->clockTime >= TickStart->clockTime ) {
269
+ delta = (long)(TickEnd->clockTime - TickStart->clockTime);
270
+ delta *= 1000;
271
+ delta += TickEnd->millitime - TickStart->millitime;
272
+ } else {
273
+ delta = -(long)(TickStart->clockTime - TickEnd->clockTime);
274
+ delta *= 1000;
275
+ delta += TickEnd->millitime - TickStart->millitime;
276
+ }
277
+ return delta;
278
+ }
279
+ /******************* get elapsed time from TickStart ************************/
280
+ long InchiTimeElapsed( inchiTime *TickStart )
281
+ {
282
+ inchiTime TickEnd;
283
+ if ( !TickStart )
284
+ return 0;
285
+ InchiTimeGet( &TickEnd );
286
+ return InchiTimeMsecDiff( &TickEnd, TickStart );
287
+ }
288
+ /******************* add number of milliseconds to time *********************/
289
+ void InchiTimeAddMsec( inchiTime *TickEnd, unsigned long nNumMsec )
290
+ {
291
+ long delta;
292
+ if ( !TickEnd )
293
+ return;
294
+ TickEnd->clockTime += nNumMsec / 1000;
295
+ delta = nNumMsec % 1000 + TickEnd->millitime;
296
+ TickEnd->clockTime += delta / 1000;
297
+ TickEnd->millitime = delta % 1000;
298
+ }
299
+ /******************* check whether time has expired *********************/
300
+ int bInchiTimeIsOver( inchiTime *TickEnd )
301
+ {
302
+ struct _timeb timeb;
303
+ if ( !TickEnd )
304
+ return 0;
305
+ _ftime( &timeb );
306
+ if ( TickEnd->clockTime > (unsigned long)timeb.time )
307
+ return 0;
308
+ if ( TickEnd->clockTime < (unsigned long)timeb.time ||
309
+ TickEnd->millitime < (long)timeb.millitm ) {
310
+ return 1;
311
+ }
312
+ return 0;
313
+ }
314
+ #endif
315
+
316
+
317
+ /****************************************************************************/
318
+ /* length of canonic representation in sizeof(AT_NUMB) units */
319
+ int GetCanonLengths( int num_at, sp_ATOM* at, ATOM_SIZES *s, T_GROUP_INFO *t_group_info )
320
+ { /* include taut. groups as additional "atoms" to the connection table 07-22-2002 */
321
+ int i, nNumCT, nNumBonds, nNumTBonds=0, nNumDblBondsStereo=0, nNumAsymCarbStereo=0, nNumIsotopic=0;
322
+ T_GROUP *t_group = (s->nLenLinearCTTautomer && t_group_info)? t_group_info->t_group : NULL;
323
+ for (nNumBonds = 0, i = 0; i < num_at; i ++ ) {
324
+ nNumBonds += at[i].valence;
325
+ if ( at[i].iso_sort_key ) {
326
+ nNumIsotopic ++; /* not including tautomeric endpoints that are isotopic only due to mobile atoms */
327
+ }
328
+
329
+ if ( at[i].parity > 0 ) { /* ignore hydrogen isotope parities in at[i].parity2 */
330
+ int j = 0, nStereoBondsToAtom=0; /* number of stereo double bonds at this atom */
331
+ int k;
332
+ for ( ; j < MAX_NUM_STEREO_BONDS && (k=at[i].stereo_bond_neighbor[j]); j ++ ) {
333
+ nStereoBondsToAtom += (at[k-1].parity > 0);
334
+ }
335
+ nNumDblBondsStereo += nStereoBondsToAtom;
336
+ nNumAsymCarbStereo += !j;
337
+ }
338
+ }
339
+ nNumDblBondsStereo /= 2;
340
+ nNumBonds /= 2;
341
+
342
+ s->nLenBonds = inchi_max( s->nLenBonds, nNumBonds );
343
+ nNumCT = nNumBonds; /* total number of neighbors in the CT */
344
+
345
+ #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
346
+ nNumCT += num_at;
347
+ #endif
348
+
349
+ s->nLenCTAtOnly = inchi_max(s->nLenCTAtOnly, nNumCT);
350
+
351
+ if ( t_group ) {
352
+ for ( i = 0; i < t_group_info->num_t_groups; i ++ ) {
353
+ nNumTBonds += t_group[i].nNumEndpoints;
354
+ }
355
+ nNumCT += nNumTBonds;
356
+ #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
357
+ nNumCT += t_group_info->num_t_groups;
358
+ #endif
359
+ }
360
+
361
+ nNumCT = inchi_max( 1, nNumCT ); /* keep GetBaseCanonRanking() happy */
362
+ s->nLenCT = inchi_max(s->nLenCT, nNumCT);
363
+ s->nLenIsotopic = inchi_max(s->nLenIsotopic, nNumIsotopic);
364
+ s->nLenLinearCTStereoDble = inchi_max(s->nLenLinearCTStereoDble, nNumDblBondsStereo);
365
+ s->nLenLinearCTStereoCarb = inchi_max(s->nLenLinearCTStereoCarb, nNumAsymCarbStereo);
366
+ if ( t_group_info )
367
+ s->nLenIsotopicEndpoints = inchi_max(s->nLenIsotopicEndpoints, t_group_info->nNumIsotopicEndpoints);
368
+
369
+ return 0;
370
+ }
371
+ /****************************************************************************/
372
+ int DeAllocateCS( CANON_STAT *pCS )
373
+ {
374
+ #define LOCAL_FREE(X) do{if(X){inchi_free(X); X=NULL;}}while(0)
375
+
376
+ /* connection table */
377
+ LOCAL_FREE( pCS->LinearCT );
378
+ LOCAL_FREE( pCS->nCanonOrd );
379
+ LOCAL_FREE( pCS->nSymmRank );
380
+ LOCAL_FREE( pCS->nNum_H );
381
+ LOCAL_FREE( pCS->nNum_H_fixed );
382
+ LOCAL_FREE( pCS->nExchgIsoH );
383
+ /* isotopic */
384
+ LOCAL_FREE( pCS->LinearCTIsotopic );
385
+ LOCAL_FREE( pCS->nSymmRankIsotopic );
386
+ LOCAL_FREE( pCS->nCanonOrdIsotopic );
387
+ /* isotopic tautomeric */
388
+ LOCAL_FREE( pCS->LinearCTIsotopicTautomer );
389
+ LOCAL_FREE( pCS->nCanonOrdIsotopicTaut );
390
+ LOCAL_FREE( pCS->nSymmRankIsotopicTaut );
391
+ /* stereo */
392
+ LOCAL_FREE( pCS->LinearCTStereoDble );
393
+ LOCAL_FREE( pCS->LinearCTStereoCarb );
394
+ LOCAL_FREE( pCS->LinearCTStereoDbleInv );
395
+ LOCAL_FREE( pCS->LinearCTStereoCarbInv );
396
+ LOCAL_FREE( pCS->nCanonOrdStereo );
397
+ LOCAL_FREE( pCS->nCanonOrdStereoInv );
398
+ LOCAL_FREE( pCS->nCanonOrdStereoTaut );
399
+ /* isotopic stereo */
400
+ LOCAL_FREE( pCS->LinearCTIsotopicStereoDble );
401
+ LOCAL_FREE( pCS->LinearCTIsotopicStereoCarb );
402
+ LOCAL_FREE( pCS->LinearCTIsotopicStereoDbleInv );
403
+ LOCAL_FREE( pCS->LinearCTIsotopicStereoCarbInv );
404
+ LOCAL_FREE( pCS->bRankUsedForStereo );
405
+ LOCAL_FREE( pCS->bAtomUsedForStereo );
406
+
407
+ LOCAL_FREE( pCS->nCanonOrdIsotopicStereo );
408
+ LOCAL_FREE( pCS->nCanonOrdIsotopicStereoInv );
409
+ LOCAL_FREE( pCS->nCanonOrdIsotopicStereoTaut );
410
+ /* tautomeric part of the connection table */
411
+ LOCAL_FREE( pCS->LinearCTTautomer );
412
+ LOCAL_FREE( pCS->nCanonOrdTaut );
413
+ LOCAL_FREE( pCS->nSymmRankTaut );
414
+
415
+ LOCAL_FREE( pCS->LinearCT2 );
416
+
417
+ /* for establishing constitutional equivalence */
418
+ LOCAL_FREE( pCS->nPrevAtomNumber );
419
+
420
+ FreeNeighList( pCS->NeighList );
421
+ pCS->NeighList = NULL;
422
+
423
+ /* set zero lengths */
424
+ pCS->nMaxLenLinearCTStereoDble = 0;
425
+ pCS->nLenLinearCTStereoDble = 0;
426
+ pCS->nMaxLenLinearCTStereoCarb = 0;
427
+ pCS->nLenLinearCTStereoCarb = 0;
428
+ pCS->nMaxLenLinearCTIsotopicStereoDble = 0;
429
+ pCS->nLenLinearCTIsotopicStereoDble = 0;
430
+ pCS->nMaxLenLinearCTIsotopicStereoCarb = 0;
431
+ pCS->nLenLinearCTIsotopicStereoCarb = 0;
432
+ pCS->nMaxLenLinearCTTautomer = 0;
433
+ pCS->nLenLinearCTTautomer = 0;
434
+ pCS->nMaxLenLinearCTIsotopic = 0;
435
+ pCS->nLenLinearCTIsotopic = 0;
436
+ pCS->nMaxLenLinearCTIsotopicTautomer = 0;
437
+ pCS->nLenLinearCTIsotopicTautomer = 0;
438
+
439
+ /* set canon numbering lengths to zero */
440
+ pCS->nLenCanonOrd = 0;
441
+ pCS->nLenCanonOrdIsotopic = 0;
442
+ pCS->nLenCanonOrdIsotopicTaut = 0;
443
+ pCS->nLenCanonOrdStereo = 0;
444
+ pCS->nLenCanonOrdStereoTaut = 0;
445
+ pCS->nLenCanonOrdIsotopicStereo = 0;
446
+ pCS->nLenCanonOrdIsotopicStereoTaut = 0;
447
+ pCS->nLenCanonOrdTaut = 0;
448
+
449
+ return 0;
450
+
451
+ #undef LOCAL_FREE
452
+ }
453
+ /****************************************************************************/
454
+ int AllocateCS( CANON_STAT *pCS, int num_at, int num_at_tg, int nLenCT, int nLenCTAtOnly,
455
+ int nLenLinearCTStereoDble, int nLenLinearCTIsotopicStereoDble,
456
+ int nLenLinearCTStereoCarb, int nLenLinearCTIsotopicStereoCarb,
457
+ int nLenLinearCTTautomer, int nLenLinearCTIsotopicTautomer,
458
+ int nLenIsotopic, INCHI_MODE nMode, BCN *pBCN )
459
+ {
460
+ #define pCS_CALLOC(PTR,TYPE,LEN) (pCS->PTR=(TYPE*)inchi_calloc((size_t)(LEN),sizeof(*pCS->PTR)))
461
+
462
+ int num_err = 0;
463
+ int num_t_groups = num_at_tg - num_at;
464
+
465
+ pCS->nMode = nMode;
466
+ /* connection table */
467
+ if ( (nMode & CMODE_CT) && nLenCT > 0 ) {
468
+ num_err += !pCS_CALLOC(LinearCT, AT_NUMB, nLenCT);
469
+ pCS->nMaxLenLinearCT =
470
+ pCS->nLenLinearCT = nLenCT;
471
+ pCS->nLenLinearCTAtOnly = nLenCTAtOnly;
472
+ num_err += !pCS_CALLOC(nCanonOrd, AT_RANK, num_at_tg);
473
+ num_err += !pCS_CALLOC(nSymmRank, AT_RANK, num_at_tg);
474
+ if ( pBCN ) {
475
+ num_err += !pCS_CALLOC(nNum_H, S_CHAR, num_at);
476
+ num_err += !pCS_CALLOC(nNum_H_fixed, S_CHAR, num_at);
477
+ num_err += !pCS_CALLOC(nExchgIsoH, S_CHAR, num_at);
478
+ }
479
+ }
480
+ /* isotopic */
481
+ if ( (nMode & CMODE_ISO) && nLenIsotopic > 0 ) {
482
+ num_err += !pCS_CALLOC(LinearCTIsotopic, AT_ISOTOPIC, nLenIsotopic);
483
+ pCS->nMaxLenLinearCTIsotopic =
484
+ pCS->nLenLinearCTIsotopic = nLenIsotopic;
485
+ }
486
+ /* isotopic tautomeric */
487
+ if ( (nMode & CMODE_ISO) && CANON_MODE_TAUT == (nMode & CANON_MODE_TAUT) ) {
488
+ if ( nLenLinearCTIsotopicTautomer > 0 ) {
489
+ num_err += !pCS_CALLOC(LinearCTIsotopicTautomer, AT_ISO_TGROUP, nLenLinearCTIsotopicTautomer);
490
+ pCS->nMaxLenLinearCTIsotopicTautomer =
491
+ pCS->nLenLinearCTIsotopicTautomer = nLenLinearCTIsotopicTautomer;
492
+ }
493
+ if ( num_t_groups > 0 ) {
494
+ num_err += !pCS_CALLOC(nCanonOrdIsotopicTaut, AT_RANK, num_t_groups);
495
+ num_err += !pCS_CALLOC(nSymmRankIsotopicTaut, AT_RANK, num_t_groups);
496
+ }
497
+ }
498
+ /* isotopic atoms & t-groups */
499
+ if ( (nMode & CMODE_ISO) /*&& nLenIsotopic > 0*/ ||
500
+ (nMode & CMODE_ISO) && CANON_MODE_TAUT == (nMode & CANON_MODE_TAUT) && nLenLinearCTIsotopicTautomer > 0
501
+ ) {
502
+ num_err += !pCS_CALLOC(nSymmRankIsotopic, AT_RANK, num_at_tg);
503
+ num_err += !pCS_CALLOC(nCanonOrdIsotopic, AT_RANK, num_at_tg);
504
+ }
505
+ /* stereo */
506
+ if ( (nMode & CMODE_STEREO) && nLenLinearCTStereoDble > 0 ) {
507
+ num_err += !pCS_CALLOC(LinearCTStereoDble, AT_STEREO_DBLE, nLenLinearCTStereoDble);
508
+ num_err += !pCS_CALLOC(LinearCTStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTStereoDble);
509
+ pCS->nLenLinearCTStereoDbleInv =
510
+ pCS->nMaxLenLinearCTStereoDble =
511
+ pCS->nLenLinearCTStereoDble = nLenLinearCTStereoDble;
512
+ }
513
+ if ( (nMode & CMODE_STEREO) && nLenLinearCTStereoCarb > 0 ) {
514
+ num_err += !pCS_CALLOC(LinearCTStereoCarb, AT_STEREO_CARB, nLenLinearCTStereoCarb);
515
+ num_err += !pCS_CALLOC(LinearCTStereoCarbInv, AT_STEREO_CARB, nLenLinearCTStereoCarb);
516
+ pCS->nLenLinearCTStereoCarbInv =
517
+ pCS->nMaxLenLinearCTStereoCarb =
518
+ pCS->nLenLinearCTStereoCarb = nLenLinearCTStereoCarb;
519
+ }
520
+ if ( (nMode & CMODE_STEREO) && (nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 ) ) {
521
+ num_err += !pCS_CALLOC(nCanonOrdStereo, AT_RANK, num_at_tg);
522
+ num_err += !pCS_CALLOC(nCanonOrdStereoInv, AT_RANK, num_at_tg);
523
+ if ( (nMode & CMODE_TAUT) && nLenLinearCTTautomer > 0 && num_t_groups > 0 ) {
524
+ num_err += !pCS_CALLOC(nCanonOrdStereoTaut, AT_RANK, num_t_groups);
525
+ }
526
+ }
527
+ /* isotopic stereo */
528
+ if ( (nMode & CMODE_ISO_STEREO) && nLenLinearCTIsotopicStereoDble > 0 ) {
529
+ num_err += !pCS_CALLOC(LinearCTIsotopicStereoDble, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble);
530
+ num_err += !pCS_CALLOC(LinearCTIsotopicStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble);
531
+ pCS->nLenLinearCTIsotopicStereoDbleInv =
532
+ pCS->nMaxLenLinearCTIsotopicStereoDble =
533
+ pCS->nLenLinearCTIsotopicStereoDble = nLenLinearCTIsotopicStereoDble;
534
+ }
535
+ if ( (nMode & CMODE_ISO_STEREO) && nLenLinearCTIsotopicStereoCarb > 0 ) {
536
+ num_err += !pCS_CALLOC(LinearCTIsotopicStereoCarb, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb);
537
+ num_err += !pCS_CALLOC(LinearCTIsotopicStereoCarbInv, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb);
538
+ pCS->nLenLinearCTIsotopicStereoCarbInv =
539
+ pCS->nMaxLenLinearCTIsotopicStereoCarb =
540
+ pCS->nLenLinearCTIsotopicStereoCarb = nLenLinearCTIsotopicStereoCarb;
541
+ }
542
+ if ( (nMode & CMODE_ISO_STEREO) && (nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ) ) {
543
+ num_err += !pCS_CALLOC(nCanonOrdIsotopicStereo, AT_RANK, num_at_tg);
544
+ num_err += !pCS_CALLOC(nCanonOrdIsotopicStereoInv, AT_RANK, num_at_tg);
545
+ if ( (nMode & CMODE_TAUT) && nLenLinearCTTautomer > 0 && num_t_groups > 0 ) {
546
+ num_err += !pCS_CALLOC(nCanonOrdIsotopicStereoTaut, AT_RANK, num_t_groups);
547
+ }
548
+ }
549
+ if ( (nMode & CMODE_STEREO) && (nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 ) ||
550
+ (nMode & CMODE_ISO_STEREO) && (nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ) ) {
551
+ num_err += !pCS_CALLOC(bRankUsedForStereo, S_CHAR, num_at);
552
+ num_err += !pCS_CALLOC(bAtomUsedForStereo, S_CHAR, num_at);
553
+ }
554
+ /* tautomeric part of the connection table */
555
+ if ( (nMode & CMODE_CT) && (nMode & CMODE_TAUT) && nLenLinearCTTautomer > 0 ) {
556
+ num_err += !pCS_CALLOC(LinearCTTautomer, AT_TAUTOMER, nLenLinearCTTautomer);
557
+ pCS->nMaxLenLinearCTTautomer =
558
+ pCS->nLenLinearCTTautomer = nLenLinearCTTautomer;
559
+ if ( num_t_groups > 0 ) {
560
+ num_err += !pCS_CALLOC(nCanonOrdTaut, AT_RANK, num_t_groups);
561
+ num_err += !pCS_CALLOC(nSymmRankTaut, AT_RANK, num_t_groups);
562
+ }
563
+ }
564
+
565
+ if ( nMode & CMODE_CT )
566
+ num_err += !pCS_CALLOC(LinearCT2, AT_NUMB, nLenCT);
567
+
568
+ /* for establishing constitutional equivalence */
569
+ num_err += !pCS_CALLOC(nPrevAtomNumber, AT_RANK, num_at_tg);
570
+
571
+ /* set canon numbering lengths to zero */
572
+ pCS->nLenCanonOrd = 0;
573
+ pCS->nLenCanonOrdIsotopic = 0;
574
+ pCS->nLenCanonOrdIsotopicTaut = 0;
575
+ pCS->nLenCanonOrdStereo = 0;
576
+ pCS->nLenCanonOrdStereoTaut = 0;
577
+ pCS->nLenCanonOrdIsotopicStereo = 0;
578
+ pCS->nLenCanonOrdIsotopicStereoTaut = 0;
579
+ pCS->nLenCanonOrdTaut = 0;
580
+
581
+
582
+ if ( num_err ) {
583
+ DeAllocateCS( pCS );
584
+ return CT_OUT_OF_RAM; /* <BRKPT> */
585
+ }
586
+ return 0;
587
+
588
+ #undef pCS_CALLOC
589
+ }
590
+ /****************************************************************************/
591
+ #define COMPARE_WITH_CT(CT, CTLEN, VALUE, CONDITION) \
592
+ if ( CONDITION ) { \
593
+ if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) \
594
+ return 1; /* not a minimal CT */ \
595
+ (CONDITION) = (VALUE) == (CT)[CTLEN]; \
596
+ } \
597
+ (CT)[CTLEN] = VALUE; \
598
+ (CTLEN)++
599
+
600
+ #define COMPARE_WITH_CTVAL(CTVAL, VALUE, CONDITION) \
601
+ if ( CONDITION ) { \
602
+ if ( (VALUE) CT_GREATER_THAN (CTVAL) ) \
603
+ return 1; /* not a minimal CT */ \
604
+ (CONDITION) = (VALUE) == (CTVAL); \
605
+ } \
606
+ (CTVAL) = VALUE
607
+
608
+ #define COMPARE_WITH_CT2(CT, CTLEN, VALUE, CONDITION, OPER) \
609
+ if ( CONDITION ) { \
610
+ if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) { \
611
+ (OPER); \
612
+ return 1; /* not a minimal CT */ \
613
+ } \
614
+ (CONDITION) = (VALUE) == (CT)[CTLEN]; \
615
+ } \
616
+ (CT)[CTLEN] = VALUE; \
617
+ (CTLEN)++
618
+
619
+ /****************************************************************************/
620
+ int FillIsotopicAtLinearCT( int num_atoms, sp_ATOM* at, const AT_RANK *nAtomNumber,
621
+ AT_ISOTOPIC *LinearCTIsotopic, int nMaxLenLinearCTIsotopic, int *pnLenLinearCTIsotopic )
622
+ {
623
+ /* at[i].init_rank = initial ranks before canonizing */
624
+ /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
625
+ /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
626
+ /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
627
+ /* nAtomNumber[nRank[i]-1] = i; */
628
+
629
+ int i, k, rank;
630
+ int nLinearCTIsotopicLen=0;
631
+
632
+ /* the following parts of the "name" should be compared */
633
+ /* after the connection table comparison is done */
634
+ /* to avoid wrong difference sign. So, these parts */
635
+ /* go to a separate buffers. */
636
+ if ( LinearCTIsotopic && nMaxLenLinearCTIsotopic > 0 ) {
637
+ memset( LinearCTIsotopic, 0, nMaxLenLinearCTIsotopic * sizeof(LinearCTIsotopic[0]) );
638
+ } else {
639
+ return 0;
640
+ }
641
+
642
+ /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
643
+ for ( rank = 1; rank <= num_atoms; rank ++ ) {
644
+
645
+ i = (int)nAtomNumber[rank-1]; /* current atom */
646
+
647
+ /****************************************************
648
+ add isotopic atom info to LinearCTIsotopic
649
+ *****************************************************/
650
+
651
+ /* if the atom itself is not isotopic then add it only if */
652
+ /* the atom is not an endpoint AND has attached T or D or 1H. */
653
+ k = ( !at[i].endpoint && !(at[i].cFlags & AT_FLAG_ISO_H_POINT) && (at[i].num_iso_H[0] || at[i].num_iso_H[1] || at[i].num_iso_H[2]) );
654
+ if ( at[i].iso_atw_diff || k ) {
655
+ if ( CHECK_OVERFLOW(nLinearCTIsotopicLen, nMaxLenLinearCTIsotopic) )
656
+ return CT_OVERFLOW; /* <BRKPT> */
657
+ LinearCTIsotopic[nLinearCTIsotopicLen].at_num = (AT_RANK)rank;
658
+ LinearCTIsotopic[nLinearCTIsotopicLen].iso_atw_diff = at[i].iso_atw_diff;
659
+ LinearCTIsotopic[nLinearCTIsotopicLen].num_1H = (NUM_H)(k? at[i].num_iso_H[0] : 0);
660
+ LinearCTIsotopic[nLinearCTIsotopicLen].num_D = (NUM_H)(k? at[i].num_iso_H[1] : 0);
661
+ LinearCTIsotopic[nLinearCTIsotopicLen].num_T = (NUM_H)(k? at[i].num_iso_H[2] : 0);
662
+ nLinearCTIsotopicLen ++;
663
+ }
664
+
665
+ } /* end of cycle over all atoms. */
666
+
667
+ if ( LinearCTIsotopic ) {
668
+ if ( *pnLenLinearCTIsotopic ) {
669
+ if ( *pnLenLinearCTIsotopic != nLinearCTIsotopicLen )
670
+ return CT_LEN_MISMATCH; /* <BRKPT> */
671
+ }else
672
+ *pnLenLinearCTIsotopic = nLinearCTIsotopicLen;
673
+ }
674
+
675
+ /* Return value: >0 => OK */
676
+ return nLinearCTIsotopicLen;
677
+ }
678
+ /****************************************************************************/
679
+ int FillTautLinearCT2( int num_atoms, int num_at_tg, int bIsoTaut,
680
+ const AT_RANK *nRank, const AT_RANK *nAtomNumber, const AT_RANK *nSymmRank,
681
+ const AT_RANK *nRankIso, const AT_RANK *nAtomNumberIso, const AT_RANK *nSymmRankIso,
682
+ AT_TAUTOMER *LinearCTTautomer, int nMaxLenLinearCTTautomer, int *pnLenLinearCTTautomer,
683
+ AT_ISO_TGROUP *LinearCTIsotopicTautomer, int nMaxLenLinearCTIsotopicTautomer, int *pnLenLinearCTIsotopicTautomer,
684
+ T_GROUP_INFO *t_group_info )
685
+ {
686
+ /* nRank[i] = Canonical numbers of atoms,.. */
687
+ /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
688
+ /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
689
+ /* nAtomNumber[nRank[i]-1] = i; */
690
+
691
+ T_GROUP *t_group;
692
+
693
+ int i, j, len=0, g, num_num, offset, max_len = 0, len_iso=0;
694
+ const static int max_num_num = sizeof(t_group->num)/sizeof(t_group->num[0]);
695
+ const static int max_num_iso = sizeof(LinearCTIsotopicTautomer->num)/sizeof(LinearCTIsotopicTautomer->num[0])+T_NUM_NO_ISOTOPIC;
696
+
697
+ /****************************************************************************
698
+
699
+ Tautomeric groups 07-22-2002, modified 12-2003
700
+
701
+ ****************************************************************************/
702
+
703
+ if ( num_at_tg > num_atoms && t_group_info && t_group_info->num_t_groups ) {
704
+ int num_t_groups = t_group_info->num_t_groups;
705
+ AT_NUMB *tGroupNumber = t_group_info->tGroupNumber;
706
+ AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups; /* equivalence */
707
+ AT_NUMB *tPrevGroupNumber = tGroupNumber + TGSO_PREV_ORDER*num_t_groups; /* prev. order or symm rank sort order */
708
+ AT_NUMB *tSortRank = tGroupNumber + TGSO_SORT_RANK*num_t_groups; /* ranks */
709
+ AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups;
710
+ AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*num_t_groups;
711
+ AT_NUMB *tiSortRank = tGroupNumber + TGSO_SORT_IRANK*num_t_groups;
712
+ AT_RANK nOffset = (AT_RANK)num_atoms;
713
+ /* Fill Canonical ranks and Symmetry Ranks */
714
+ memcpy( tPrevGroupNumber, tGroupNumber, num_t_groups*sizeof(tPrevGroupNumber[0]));
715
+ for ( i = num_atoms, j = 0; i < num_at_tg; i ++, j ++ ) {
716
+ tPrevGroupNumber[j] =
717
+ tGroupNumber[j] = nAtomNumber[i] - nOffset;
718
+ tSymmRank[j] = nSymmRank[i] - nOffset;
719
+ tSortRank[j] = nRank[i] - nOffset;
720
+ if ( bIsoTaut /*nMaxLenLinearCTIsotopicTautomer*/ ) {
721
+ tiGroupNumber[j] = nAtomNumberIso[i] - nOffset;
722
+ tiSymmRank[j] = nSymmRankIso[i] - nOffset;
723
+ tiSortRank[j] = nRankIso[i] - nOffset;
724
+ }
725
+ }
726
+ /* Sort enpoints within each tautomeric group according to the canonical ranks */
727
+ pn_RankForSort = nRank;
728
+ for ( i = 0; i < num_t_groups; i ++ ) {
729
+ qsort( t_group_info->nEndpointAtomNumber + (int)t_group_info->t_group[i].nFirstEndpointAtNoPos,
730
+ t_group_info->t_group[i].nNumEndpoints,
731
+ sizeof(t_group_info->nEndpointAtomNumber[0]),
732
+ CompRank );
733
+ }
734
+ /* fill out LinearCTTautomer */
735
+ if ( nMaxLenLinearCTTautomer ) {
736
+ max_len = T_GROUP_HDR_LEN * t_group_info->num_t_groups + t_group_info->nNumEndpoints+1;
737
+ if ( max_len > nMaxLenLinearCTTautomer )
738
+ return CT_OVERFLOW; /* <BRKPT> */
739
+ }
740
+
741
+ /****************************************************************
742
+ * tautomer group format (#: is an offset)
743
+ ****************************************************************
744
+ * HEADER (T_GROUP_HDR_LEN=3+3iso)
745
+ * 0: N = number of endpoints ( t_group->nNumEndpoints )
746
+ * 1: number of mobile groups ( t_group->num[0] )
747
+ * 2: number of neg. charges ( t_group->num[1] ) {note: T_NUM_NO_ISOTOPIC=2}
748
+ * ENDPOINT RANKS
749
+ * 3..N+2: sorted tautomer group endpoint ranks; the sorting order is in
750
+ * t_group_info->nEndpointAtomNumber[t_group->nFirstEndpointAtNoPos+j], j=0..N-1
751
+ *
752
+ * End mark : N==0
753
+ ****************************************************************/
754
+ /* num_num = t_group_info->bIgnoreIsotopic? T_NUM_NO_ISOTOPIC : max_num_num; */
755
+ num_num = max_num_num; /* always include isotopic info; ignore it at the CT comparison step. */
756
+ for ( i = 0; i < t_group_info->num_t_groups; i ++ ) {
757
+ g = tGroupNumber[i]; /* ith tautomeric group number in canonical order */
758
+ t_group = t_group_info->t_group + g;
759
+ /*******************************************************
760
+ * Tautomer non-isotopic part: LinearCTTautomer
761
+ *******************************************************/
762
+ /* check length */
763
+ if ( CHECK_OVERFLOW(len + T_GROUP_HDR_LEN + t_group->nNumEndpoints, max_len) )
764
+ return CT_OVERFLOW; /* <BRKPT> */
765
+
766
+ /* t_group header: number of endpoints */
767
+ LinearCTTautomer[len++] = t_group->nNumEndpoints;
768
+ /* t_group header: */
769
+ /* (a) number of mobile groups in the t_group and */
770
+ /* (b) number of mobile negative charges in the t_group, currently = 0 always */
771
+ for ( j = 0; j < T_NUM_NO_ISOTOPIC; j ++ ) {
772
+ LinearCTTautomer[len++] = t_group->num[j];
773
+ }
774
+ /* t_group endpoint ranks link the group to the tautomeric endpoint atoms in the structure */
775
+ /* according to their ranks */
776
+ for ( j = 0, offset = t_group->nFirstEndpointAtNoPos; j < t_group->nNumEndpoints; j ++ ) {
777
+ LinearCTTautomer[len++] = nRank[(int)t_group_info->nEndpointAtomNumber[offset+j]];
778
+ }
779
+ }
780
+ if ( nMaxLenLinearCTTautomer ) {
781
+ LinearCTTautomer[len++] = 0; /* or CT_INITVALUE ??? */
782
+ if ( len != max_len ) {
783
+ len = -len; /* program error */ /* <BRKPT> */
784
+ } else
785
+ if ( *pnLenLinearCTTautomer && *pnLenLinearCTTautomer != len ) {
786
+ return CT_LEN_MISMATCH;
787
+ } else {
788
+ *pnLenLinearCTTautomer = len;
789
+ }
790
+ } else {
791
+ *pnLenLinearCTTautomer = 0;
792
+ }
793
+ /******************************************************************
794
+ * Isotopic Tautomeric mobile groups part: LinearCTIsotopicTautomer
795
+ ******************************************************************/
796
+ if ( nMaxLenLinearCTIsotopicTautomer && !t_group_info->nNumIsotopicEndpoints ) {
797
+ for ( i = 0; i < t_group_info->num_t_groups; i ++ ) {
798
+ g = tiGroupNumber[i]; /* ith tautomeric group number in canonical order */
799
+ t_group = t_group_info->t_group + g;
800
+ /* find if mobile hydrogens are isotopic */
801
+ if ( !t_group->iWeight ) {
802
+ continue; /* no isotopic H */
803
+ }
804
+ if ( CHECK_OVERFLOW(len_iso, nMaxLenLinearCTIsotopicTautomer) )
805
+ return CT_OVERFLOW; /* <BRKPT> */
806
+ for ( j = T_NUM_NO_ISOTOPIC; j < max_num_num && j < max_num_iso; j ++ ) {
807
+ /* num_T, num_D, num_1H */
808
+ LinearCTIsotopicTautomer[len_iso].num[j-T_NUM_NO_ISOTOPIC] = t_group->num[j];
809
+ }
810
+ /* link to tautomer group LinearCTTautomer[i]: */
811
+ LinearCTIsotopicTautomer[len_iso++].tgroup_num = (AT_NUMB)(i + 1); /* t_group isotopic rank */
812
+ }
813
+ }
814
+ if ( nMaxLenLinearCTIsotopicTautomer ) {
815
+ if ( *pnLenLinearCTIsotopicTautomer && *pnLenLinearCTIsotopicTautomer != len_iso ) {
816
+ return CT_LEN_MISMATCH;
817
+ }
818
+ *pnLenLinearCTIsotopicTautomer = len_iso;
819
+ } else {
820
+ *pnLenLinearCTIsotopicTautomer = 0;
821
+ }
822
+
823
+ }
824
+ return len;
825
+ }
826
+ /****************************************************************************
827
+ *
828
+ * Update a linear connection table out of final ranks
829
+ */
830
+ int UpdateFullLinearCT( int num_atoms, int num_at_tg, sp_ATOM* at, AT_RANK *nRank, AT_RANK *nAtomNumber,
831
+ CANON_STAT* pCS, int bFirstTime )
832
+ {
833
+ /* at[i].init_rank = initial ranks before canonizing */
834
+ /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
835
+ /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
836
+ /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
837
+ /* nAtomNumber[nRank[i]-1] = i; */
838
+
839
+ AT_NUMB nNeighborNumber[MAXVAL];
840
+ int i, j, k, num_neigh, rank, bCompare; /*, nRetVal; */
841
+
842
+ T_GROUP_INFO *t_group_info = NULL;
843
+ T_GROUP *t_group = NULL;
844
+ AT_NUMB *nEndpointAtomNumber = NULL;
845
+
846
+ int nCTLen=0, nCTLenAtOnly=0;
847
+
848
+ AT_NUMB r_neigh;
849
+ AT_NUMB *LinearCT = pCS->LinearCT;
850
+
851
+ /* the following parts of the "name" should be compared */
852
+ /* after the connection table comparison is done */
853
+ /* to avoid wrong difference sign. So, these parts */
854
+ /* go to a separate buffers. */
855
+ /* -- currently not used at all at all -- */
856
+
857
+ #if CT_ATOMID != CT_ATOMID_DONTINCLUDE
858
+ AT_NUMB r0_at_type;
859
+ #endif
860
+
861
+ bCompare = bFirstTime? 0 : 1;
862
+
863
+ if ( num_at_tg > num_atoms ) {
864
+ t_group_info = pCS->t_group_info;
865
+ t_group = t_group_info->t_group;
866
+ } else {
867
+ t_group_info = NULL;
868
+ t_group = NULL;
869
+ }
870
+
871
+ /**********************************************************************/
872
+ /* */
873
+ /* CYCLE 1: FILL OUT CONNECTION TABLE(S) FOR ALL ATOMS */
874
+ /* ** NOT INCLUDING ISOTOPIC ATOMS AND 1H, 2H(D), 3H(T) ** */
875
+ /* */
876
+ /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
877
+ /**********************************************************************/
878
+ for ( rank = 1; rank <= num_atoms; rank ++ ) {
879
+ i = (int)nAtomNumber[rank-1]; /* current atom */
880
+ #if( CT_ATOMID == CT_ATOMID_IS_CURRANK )
881
+ r0_at_type = (AT_NUMB)rank; /* current Rank */
882
+ #else
883
+ #if( CT_ATOMID == CT_ATOMID_IS_INITRANK )
884
+ r0_at_type = (AT_NUMB)at[i].init_rank; /* chemical + neighborhood ID */
885
+ #else
886
+ #if( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
887
+ #else
888
+ #error Undefined or wrong definition of CT_ATOMID
889
+ #endif
890
+ #endif
891
+ #endif
892
+
893
+ /* add atom to the CT */
894
+ #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
895
+ if ( CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT) )
896
+ return CT_OVERFLOW; /* <BRKPT> */
897
+ COMPARE_WITH_CT(LinearCT, nCTLen, r0_at_type, bCompare);
898
+ #endif
899
+ /*******************************************************
900
+ add neighbors and (if required) bonds to CT
901
+ ********************************************************/
902
+
903
+ /* sort neighbors */
904
+ num_neigh = at[i].valence;
905
+ for ( k = 0; k < num_neigh; k ++) {
906
+ nNeighborNumber[k] = (AT_NUMB)k;
907
+ }
908
+ pNeighborsForSort = at[i].neighbor;
909
+ pn_RankForSort = nRank;
910
+ insertions_sort( nNeighborNumber, (size_t)num_neigh, sizeof(nNeighborNumber[0]), CompNeighborsAT_NUMBER );
911
+
912
+ for ( k = 0; k < num_neigh; k ++) {
913
+ /* rank = (new current atom Rank) */
914
+ if ( (int)(r_neigh = (AT_NUMB)nRank[(int)at[i].neighbor[(int)nNeighborNumber[k]]])
915
+ CT_NEIGH_SMALLER_THAN rank ) {
916
+ if ( CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT) )
917
+ return CT_OVERFLOW; /* <BRKPT> */
918
+ COMPARE_WITH_CT( LinearCT, nCTLen, r_neigh, bCompare);
919
+ }
920
+ }
921
+
922
+ /* add CT row delimiter */
923
+
924
+ } /* end of cycle over all atoms. */
925
+
926
+ nCTLenAtOnly = nCTLen;
927
+
928
+ /**************************************************************
929
+
930
+ Tautomeric groups 07-22-2002
931
+
932
+ ***************************************************************/
933
+
934
+ for ( rank = num_atoms + 1; rank <= num_at_tg; rank ++ ) {
935
+ j = (int)nAtomNumber[rank-1]; /* current "atom" */
936
+ i = j - num_atoms; /* current t-group */
937
+ #if( CT_ATOMID == CT_ATOMID_IS_CURRANK )
938
+ r0_at_type = (AT_NUMB)rank; /* current Rank */
939
+ #else
940
+ #if( CT_ATOMID == CT_ATOMID_IS_INITRANK )
941
+ r0_at_type = (AT_NUMB)rank; /* current Rank or (AT_NUMB)at[i].init_rank; ==> chemical + neighborhood ID */
942
+ #else
943
+ #if ( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
944
+ #else
945
+ #error Undefined or wrong definition of CT_ATOMID
946
+ #endif
947
+ #endif
948
+ #endif
949
+
950
+ /* add atom to the CT */
951
+ #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
952
+ if ( CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT) )
953
+ return CT_OVERFLOW; /* <BRKPT> */
954
+ COMPARE_WITH_CT(LinearCT, nCTLen, r0_at_type, bCompare);
955
+ #endif
956
+
957
+ /*******************************************************
958
+ add neighbors and (if required) bonds to CT
959
+ ********************************************************/
960
+
961
+ /* sort endpoints */
962
+ nEndpointAtomNumber = t_group_info->nEndpointAtomNumber+(int)t_group[i].nFirstEndpointAtNoPos;
963
+ pn_RankForSort = nRank;
964
+ num_neigh = (int)t_group[i].nNumEndpoints;
965
+ insertions_sort( nEndpointAtomNumber, (size_t)num_neigh, sizeof(nEndpointAtomNumber[0]), CompRank);
966
+
967
+ for ( k = 0; k < num_neigh; k ++) {
968
+ /* rank = (new current atom Rank) */
969
+ if ( (int)(r_neigh = (AT_NUMB)nRank[(int)nEndpointAtomNumber[k]])
970
+ CT_NEIGH_SMALLER_THAN rank ) {
971
+ if ( CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT) )
972
+ return CT_OVERFLOW; /* <BRKPT> */
973
+ COMPARE_WITH_CT( LinearCT, nCTLen, r_neigh, bCompare);
974
+ }
975
+ }
976
+ } /* end of cycle over all tautomeric groups. */
977
+
978
+ /* compare bonds types */
979
+ /* compare elements */
980
+
981
+ if ( LinearCT ) {
982
+
983
+ if ( pCS->nLenLinearCT ) {
984
+ if ( pCS->nLenLinearCT != nCTLen )
985
+ return CT_LEN_MISMATCH; /* <BRKPT> */
986
+ } else {
987
+ pCS->nLenLinearCT = nCTLen;
988
+ }
989
+
990
+ if ( pCS->nLenLinearCT ) {
991
+ if ( pCS->nLenLinearCTAtOnly != nCTLenAtOnly )
992
+ return CT_LEN_MISMATCH; /* <BRKPT> */
993
+ } else {
994
+ pCS->nLenLinearCTAtOnly = nCTLenAtOnly;
995
+ }
996
+
997
+ }
998
+
999
+ /* Return: 0=> identical CT; -1=> new CT is smaller than the previous one */
1000
+ return (bCompare-1);
1001
+ }
1002
+
1003
+ /*********************************************************************************************/
1004
+ /* if (*bChanged & 1) then nSymmRank has been rearranged because for some r
1005
+ min{i: r=nSymmRank[nAtomNumber[i]]}+1 != r
1006
+ if (*bChanged & 2) then ranks nTempRank[] from nSymmRank[] differ from input nCurrRank[]
1007
+
1008
+ on exit:
1009
+
1010
+ nSymmRank[] have been updated if (*bChanged & 1)
1011
+ nCurrRank[] have been updated if (*bChanged & 1)
1012
+ nTempRank[] is always same as nCurrRank[]
1013
+ nAtomNumber[] have been sorted so that
1014
+ (i < j) <=> (nSymmRank[nAtomNumber[i]] <= nSymmRank[nAtomNumber[j]])
1015
+ */
1016
+ int FixCanonEquivalenceInfo( int num_at_tg, AT_RANK *nSymmRank, AT_RANK *nCurrRank,
1017
+ AT_RANK *nTempRank, AT_NUMB *nAtomNumber, int *bChanged)
1018
+ {
1019
+ int nNumDiffRanks, bChangeSymmRank, bChangeCurrRank=0;
1020
+ /* sort equivalence information */
1021
+ /*
1022
+ int i;
1023
+ for ( i = 0; i < num_at_tg; i ++ ) {
1024
+ nAtomNumber[i] = i;
1025
+ }
1026
+ */
1027
+ pn_RankForSort = nSymmRank; /* minimal class representatives: min ranks for equiv. atoms */
1028
+ qsort( nAtomNumber, num_at_tg, sizeof(nAtomNumber[0]), CompRanksOrd );
1029
+
1030
+ /* convert equivalence information nSymmRank[] into ranks array nTempRank[] */
1031
+ /* eq. info contains min. possible ranks for eq. atoms; nCurrRank contains max. possible ranks */
1032
+ nNumDiffRanks = SortedEquInfoToRanks( nSymmRank/*inp*/, nTempRank/*out*/, nAtomNumber, num_at_tg, &bChangeSymmRank );
1033
+ /* check whether nCurrRank is same as new initial ranks calculated from nSymmRank[] */
1034
+ bChangeCurrRank = memcmp( nCurrRank, nTempRank, num_at_tg*sizeof(nTempRank[0]));
1035
+
1036
+ /*-----------------------------------------------------------------------
1037
+ if ( bChangeSymmRank || bChangeCurrRank ) {
1038
+ This is the case when the initial equitable partitioning does not produce
1039
+ constitutionally equivalent classes of atoms.
1040
+ Rebuild nSymmRank[] according to the new nCurrRank[] := nTempRank[]
1041
+ For such structures the found canonical numbers of the constitutionally equivalent atoms
1042
+ are not contiguous (see nCanonRank and nSymmRank examples below). Here arrays
1043
+ nCurrRank, nAtomNumber, and nSymmRank are changed so that later the
1044
+ contiguous canonical numbers for equivalent atoms can be obtained
1045
+ (see GetCanonRanking under
1046
+ "III. Get final canonical numbering (no stereo, no isotopic)".
1047
+
1048
+ Example: for CAS=37520-11-9 (ID=21247: Ethane, 1,2-dicyclopropyl-),
1049
+
1050
+ the numbers are the "final canon. numbers, nCanonRank"
1051
+ 1
1052
+
1053
+ HC 7 5 3
1054
+ | \
1055
+ | >CH--CH2 CH
1056
+ | / \ / |
1057
+ HC H2C--CH< |
1058
+ \ |
1059
+ 2 6 8 CH
1060
+
1061
+ 4
1062
+
1063
+ the arrays (arranged according to ordering in nAtomNumberTemp) are:
1064
+ before SortedEquInfoToRanks after SortedRanksToEquInfo
1065
+ orig. atom nos.,nAtomNumberTemp: {4 5 6 7 0 1 2 3} {4 5 6 7 0 1 2 3}
1066
+ order numbers for sorted ranks: {0 1 2 3 4 5 6 7} {0 1 2 3 4 5 6 7}
1067
+ canonical numbering, nCanonRank: {1 2 5 6 3 4 7 8} {1 2 5 6 3 4 7 8}
1068
+ constit. equivalence, nSymmRank: {1 1 1 1 3 3 7 7} {1 1 1 1 5 5 7 7} used later
1069
+ initial equivalence, nCurrRank: {6 6 6 6 6 6 8 8} {4 4 4 4 6 6 8 8} used later
1070
+ initial numbering, nAtomNumber: {2 3 4 7 0 1 6 7} {0 1 2 3 4 5 6 7} used later
1071
+ final, no stereo, no isotopic, after III. GetCanonRanking:
1072
+ final canon. numbers, nCanonRank: {1 2 3 4 5 6 7 8} final
1073
+ }
1074
+ ----------------------------------------------------------------------------------*/
1075
+ if ( bChangeCurrRank ) {
1076
+ memcpy( nCurrRank, nTempRank, num_at_tg*sizeof(nCurrRank[0]) );
1077
+ }
1078
+ if ( bChangeSymmRank ) {
1079
+ SortedRanksToEquInfo( nSymmRank/*out*/, nTempRank/*inp*/, nAtomNumber, num_at_tg );
1080
+ }
1081
+ if ( bChanged ) {
1082
+ *bChanged = (0 != bChangeSymmRank) | 2*(0 != bChangeCurrRank);
1083
+ }
1084
+ return nNumDiffRanks;
1085
+ }
1086
+ /* isotopic canonicalization */
1087
+ /***********************************************************************
1088
+ *
1089
+ * Canon_INChI (former GetCanonRankingUsingEquivInfo)
1090
+ *
1091
+ */
1092
+ int Canon_INChI3( int num_atoms, int num_at_tg, sp_ATOM* at, CANON_STAT* pCS, INCHI_MODE nMode, int bTautFtcn)
1093
+ {
1094
+ /****************************************************************
1095
+
1096
+ 0. Initiation, Prepare initial ranks for GetCanonRanking()
1097
+
1098
+ I. Find constitutionally equivalent atoms and possibly canonical numbering
1099
+ I.1 Set tautomer=On, stereo=isotopic=Off
1100
+ I.2 GetCanonRanking(): Find constitutionally equivalent atoms and possibly canonical numbering
1101
+ 1.3 Fix canonical equivalence info if needed (if the fix is needed then the numbering is not canonical)
1102
+
1103
+ II. Get final non-isotopic canonical numbering. Simultaneously obtain non-minimal isotopic and stereo CTs
1104
+ GetCanonRanking() with pCS->bKeepSymmRank = 1
1105
+ FillOutStereoParities() (create initial stereo descriptors)
1106
+ save non-isotopic canonicalization final results
1107
+ hide isotopic and tautomeric results (for historical reasons only)
1108
+
1109
+
1110
+ III. Find constitutionally equivalent isotopic atoms (for isotopic stereo canonicalization)
1111
+ III.1 Allocate more memory
1112
+ III.2 fill allocated memory with the initial data
1113
+ III.3 duplicate, save old and add isotopic info to the new pCS->t_group_info
1114
+ III.4 Prepare initial isotopic ranks for GetCanonRanking()
1115
+ III.5 GetCanonRanking() to Find constitutionally equivalent ISOTOPIC atoms and tautomer groups
1116
+ III.6 Fix canonical isotopic equivalence information and derive ranks out of it
1117
+
1118
+ IV. Prepare a second Rank/AtomNumber Stack for mapping.
1119
+
1120
+ V. Optimize isotopic part (optimized)
1121
+ map_isotopic_atoms2()
1122
+ save isotopic canonical numbering
1123
+
1124
+ VI. Optimize stereo descriptors (optimized)
1125
+ map_stereo_bonds4()
1126
+
1127
+
1128
+ VII. Optimize isotopic stereo descriptors (optimized)
1129
+ SwitchAtomStereoAndIsotopicStereo()
1130
+ SetCtToIsotopicStereo()
1131
+ FillOutStereoParities()
1132
+ SetUseAtomForStereo()
1133
+ map_stereo_bonds4()
1134
+
1135
+ SwitchAtomStereoAndIsotopicStereo()
1136
+ SetCtToNonIsotopicStereo()
1137
+
1138
+
1139
+
1140
+
1141
+ *****************************************************************/
1142
+
1143
+ int nRet = 0, i, n;
1144
+
1145
+
1146
+ /********************************************************
1147
+ input non-stereo canonical info
1148
+ ********************************************************/
1149
+ BCN *pBCN = pCS->pBCN;
1150
+ FTCN *ftcn = pBCN->ftcn + bTautFtcn;
1151
+
1152
+ /********************************************************
1153
+ set mode flags
1154
+ ********************************************************/
1155
+ /* tautomeric structure */
1156
+ int bTaut = (num_at_tg > num_atoms) && pCS->t_group_info && pCS->t_group_info->num_t_groups && pCS->t_group_info->t_group;
1157
+ /* special case: induced by exchangable isotopic H inequivalence of atoms in formally non-tautomeric structure */
1158
+ int bIsoXchgH = pCS->t_group_info && pCS->t_group_info->nNumIsotopicEndpoints > 1 &&
1159
+ pCS->t_group_info->nIsotopicEndpointAtomNumber && pCS->t_group_info->nIsotopicEndpointAtomNumber[0] &&
1160
+ (pCS->t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE))
1161
+ /* && (ftcn->nCanonFlags & CANON_FLAG_ISO_TAUT_DIFF)*/;
1162
+ int bHasIsotopicCanonData = (ftcn->PartitionCtIso.AtNumber && ftcn->PartitionCtIso.Rank && ftcn->nSymmRankCtIso);
1163
+ /* bHasIsotopicCanonData==0 means
1164
+ * (1) No isotopic atoms in the component OR
1165
+ * (2) the component has only exchangable isotopic H that do not change canonical numbering and equivalence.
1166
+ */
1167
+ T_GROUP_INFO *t_group_info1 = bTaut? pCS->t_group_info : NULL;
1168
+ /*int bIsoXchgH = t_group_info1 && t_group_info1->nNumIsotopicEndpoints && t_group_info1->nIsotopicEndpointAtomNumber;*/
1169
+ /* isotopic canonicalization */
1170
+ int bCanonIsotopic = bHasIsotopicCanonData && ( nMode & CMODE_ISO ) && ( pCS->LinearCTIsotopic || pCS->LinearCTIsotopicTautomer || bIsoXchgH );
1171
+ /* stereo canonicalization */
1172
+ int bCanonStereo = ( nMode & CMODE_STEREO ) && ( pCS->LinearCTStereoDble || pCS->LinearCTStereoCarb );
1173
+ /* stereo isotopic canonicalization */
1174
+ int bCanonIsoStereo = bHasIsotopicCanonData && ( nMode & CMODE_ISO_STEREO ) && (pCS->LinearCTIsotopicStereoDble || pCS->LinearCTIsotopicStereoCarb) && bCanonIsotopic;
1175
+ int bIsoTaut = (bTaut && bCanonIsotopic);
1176
+
1177
+ int bIgnoreIsotopicInputGroups;
1178
+ int bIgnoreIsotopicInputAtoms;
1179
+
1180
+ AT_RANK **pRankStack1 = pBCN->pRankStack;
1181
+ int nRankStackLen = pBCN->nMaxLenRankStack;
1182
+ int num_max = pBCN->num_max; /* allocation lengths in *pRankStack1[] */
1183
+ NEIGH_LIST *NeighList = ftcn->NeighList;
1184
+
1185
+ int nNumCurrRanks = 0;
1186
+ AT_RANK *nTempRank = NULL;
1187
+
1188
+ AT_RANK *nSymmRank = NULL;
1189
+
1190
+ AT_RANK *nAtomNumber = NULL;
1191
+ AT_RANK *nRank = NULL;
1192
+
1193
+ AT_RANK **pRankStack2 = NULL;
1194
+ AT_RANK *nCanonRankStereo = NULL;
1195
+ AT_RANK *nCanonRankStereoInv = NULL;
1196
+ AT_RANK *nSymmStereo = NULL;
1197
+
1198
+ AT_RANK *nCanonRankIsotopicStereo = NULL;
1199
+ AT_RANK *nCanonRankIsotopicStereoInv = NULL;
1200
+
1201
+ CUR_TREE *cur_tree = NULL;
1202
+ CUR_TREE CurrentTree;
1203
+
1204
+
1205
+ /*AT_ISO_TGROUP *LinearCTIsotopicTautomer = NULL; */
1206
+
1207
+
1208
+ CANON_STAT CS2;
1209
+ CANON_STAT* pCS2 = &CS2;
1210
+
1211
+ inchiTime ulStartTime, ulEndTime;
1212
+ /*=========== Mode Bits (low 8 bits, bit 0 is Least Significant Bit) ===========
1213
+
1214
+ Mode Bits Description
1215
+ '0' c 0 Only one connection table canonicalization
1216
+ '1' C 1 Recalculate CT using fixed nSymmRank
1217
+ '2' i 1|2 Isotopic canonicalization (internal)
1218
+ '3' I 1|2|4 Isotopic canonicalization (output)
1219
+ '4' s 1|8 Stereo canonicalization
1220
+ '5' S 1|2|4|16 Stereo isotopic canonicalization
1221
+ '6' A 1|2|4|8|16 Output All
1222
+
1223
+ --- high 8 bits ----
1224
+ --- obsolete, only historical interest. ------
1225
+ 1-2 : 0 => at[i].init_rank from Morgan+NeighList
1226
+ 1 => at[i].init_rank from Atom Invariants
1227
+ 2 => at[i].init_rank from nSymmRank[]
1228
+ (at[i].init_rank is included in LinearCT
1229
+ depending on CT_ATOMID definition)
1230
+ 3 : 1 => Get Stereo canonical info
1231
+ 4 : 1 => Get Isotopic canonical info
1232
+ 5 : 1 => Get Charge/Radical canonical info
1233
+ ==================================================================*/
1234
+ /*int nOutputMode = 0;*/ /* obsolete */
1235
+
1236
+ int bSwitchedAtomToIsotopic = 0;
1237
+
1238
+ InchiTimeGet( &ulStartTime );
1239
+
1240
+ *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1241
+
1242
+ /* set "ignore isotopic differences in tautomer groups" true */
1243
+ if ( bTaut ) {
1244
+ /* save request for isotopic tautomeric groups */
1245
+ bIgnoreIsotopicInputGroups = pCS->t_group_info->bIgnoreIsotopic;
1246
+ pCS->t_group_info->bIgnoreIsotopic = 1;
1247
+ } else {
1248
+ bIgnoreIsotopicInputGroups = 1;
1249
+ }
1250
+ /* save request for isotopic name */
1251
+ bIgnoreIsotopicInputAtoms = pCS->bIgnoreIsotopic;
1252
+ /* set "ignore isotopic differences in atoms" true */
1253
+ pCS->bIgnoreIsotopic = 1;
1254
+
1255
+
1256
+ /* save non-isotopic and isotopic canonicalization results */
1257
+ pCS->nCanonFlags = ftcn->nCanonFlags;
1258
+ /* 1. non-isotopic */
1259
+
1260
+ /* linear CT, H */
1261
+ memcpy( pCS->LinearCT, ftcn->LinearCt, ftcn->nLenLinearCt * sizeof(pCS->LinearCT[0]) );
1262
+ if ( pCS->nNum_H && ftcn->nNumH ) {
1263
+ for ( i = 0; i < num_atoms; i ++ ) {
1264
+ pCS->nNum_H[i] = /*(S_CHAR)*/(CHAR_MASK & ftcn->nNumH[i]);
1265
+ }
1266
+ }
1267
+ if ( pCS->nNum_H_fixed && ftcn->nNumHFixH ) {
1268
+ for ( i = 0; i < num_atoms; i ++ ) {
1269
+ pCS->nNum_H_fixed[i] = /*(S_CHAR)*/(CHAR_MASK & ftcn->nNumHFixH[i]);
1270
+ }
1271
+ }
1272
+ pCS->nLenLinearCT = ftcn->nLenLinearCt;
1273
+ pCS->nLenLinearCTAtOnly = ftcn->nLenLinearCtAtOnly;
1274
+
1275
+ /* save non-isotopic atoms equivalence and numbering */
1276
+ if ( pCS->nSymmRank ) {
1277
+ memcpy( pCS->nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(pCS->nSymmRank[0]) );
1278
+ }
1279
+ if ( pCS->nCanonOrd ) {
1280
+ memcpy( pCS->nCanonOrd, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(pCS->nCanonOrd[0]) );
1281
+ pCS->nLenCanonOrd = num_atoms;
1282
+ }
1283
+ if ( ftcn->iso_exchg_atnos && pCS->nExchgIsoH ) {
1284
+ for ( i = 0; i < num_atoms; i ++ ) {
1285
+ pCS->nExchgIsoH[i] = !ftcn->iso_exchg_atnos[i]; /* (pCS->nExchgIsoH[i]==1) => tautomeric or hetero atoms that may exchange isotopic H */
1286
+ }
1287
+ }
1288
+ /* 2. isotopic */
1289
+
1290
+ if ( bCanonIsotopic ) {
1291
+ /* linear CT, num_H are same as non-isotopic */
1292
+ /* save atoms equivalence and numbering */
1293
+ if ( pCS->nSymmRankIsotopic ) {
1294
+ memcpy( pCS->nSymmRankIsotopic, ftcn->nSymmRankCtIso, num_at_tg * sizeof(pCS->nSymmRankIsotopic[0]));
1295
+ }
1296
+ if ( pCS->nCanonOrdIsotopic ) {
1297
+ memcpy( pCS->nCanonOrdIsotopic, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(pCS->nCanonOrdIsotopic[0]) );
1298
+ pCS->nLenCanonOrdIsotopic = num_at_tg;
1299
+ }
1300
+ nRet = FillIsotopicAtLinearCT( num_atoms, at, ftcn->PartitionCtIso.AtNumber,
1301
+ pCS->LinearCTIsotopic, pCS->nMaxLenLinearCTIsotopic, &pCS->nLenLinearCTIsotopic );
1302
+ if ( RETURNED_ERROR(nRet) ) {
1303
+ goto exit_function;
1304
+ }
1305
+ if ( nRet < 0 ) {
1306
+ nRet = CT_TAUCOUNT_ERR;
1307
+ goto exit_function;
1308
+ }
1309
+ } else {
1310
+ pCS->nMaxLenLinearCTIsotopic = 0;
1311
+ pCS->nMaxLenLinearCTIsotopicTautomer = 0;
1312
+ }
1313
+
1314
+ /* fill out tautomeric groups, isotopic and non-isotopic tautomeric CT and t_group_info1->tGroupNumber */
1315
+ if ( bTaut ) {
1316
+ bIsoTaut = bIsoTaut && ftcn->PartitionCtIso.Rank &&
1317
+ ftcn->PartitionCtIso.AtNumber && ftcn->nSymmRankCtIso;
1318
+ nRet = FillTautLinearCT2( num_atoms, num_at_tg, bIsoTaut,
1319
+ ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber, ftcn->nSymmRankCt,
1320
+ ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber, ftcn->nSymmRankCtIso,
1321
+ pCS->LinearCTTautomer, pCS->nMaxLenLinearCTTautomer, &pCS->nLenLinearCTTautomer,
1322
+ pCS->LinearCTIsotopicTautomer, pCS->nMaxLenLinearCTIsotopicTautomer, &pCS->nLenLinearCTIsotopicTautomer,
1323
+ t_group_info1 );
1324
+
1325
+ if ( RETURNED_ERROR(nRet) ) {
1326
+ goto exit_function;
1327
+ }
1328
+ if ( nRet <= 0 ) {
1329
+ nRet = CT_TAUCOUNT_ERR;
1330
+ goto exit_function;
1331
+ } else {
1332
+ /* tautomeric groups: save non-isotopic symmetry & t_group order */
1333
+ int num_t_groups = t_group_info1->num_t_groups;
1334
+ AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1335
+ AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups;
1336
+ if ( pCS->nSymmRankTaut ) {
1337
+ memcpy( pCS->nSymmRankTaut, tSymmRank, num_t_groups * sizeof(pCS->nSymmRank[0]) ); /* fixed 5-23-02 */
1338
+ }
1339
+ if ( pCS->nCanonOrdTaut ) {
1340
+ memcpy( pCS->nCanonOrdTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdTaut[0]) );
1341
+ pCS->nLenCanonOrdTaut = num_t_groups;
1342
+ }
1343
+ if ( bCanonIsotopic /*&& pCS->nLenLinearCTIsotopicTautomer*/ ) {
1344
+ /* tautomeric groups: save isotopic symmetry & t_group order */
1345
+ /*AT_NUMB ntRankOffset = (AT_RANK)num_atoms;*/
1346
+ AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups;
1347
+ AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*num_t_groups;
1348
+ if ( pCS->nSymmRankIsotopicTaut ) {
1349
+ memcpy( pCS->nSymmRankIsotopicTaut, tiSymmRank, num_t_groups * sizeof(pCS->nSymmRankIsotopicTaut[0]) );
1350
+ }
1351
+ memcpy( pCS->nCanonOrdIsotopicTaut, tiGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdIsotopicTaut[0]) );
1352
+ pCS->nLenCanonOrdIsotopicTaut = num_t_groups;
1353
+ }
1354
+ }
1355
+ }
1356
+ /* save connection table if requested */
1357
+ if ( pCS->LinearCT2 ) {
1358
+ memcpy( pCS->LinearCT2, pCS->LinearCT, sizeof(pCS->LinearCT2[0])*pCS->nLenLinearCT );
1359
+ pCS->nLenLinearCT2 = pCS->nLenLinearCT;
1360
+ pCS->nLenLinearCTAtOnly2 = pCS->nLenLinearCTAtOnly;
1361
+ }
1362
+
1363
+ if ( num_atoms <= 1 ) {
1364
+ bCanonStereo = 0; /* a sinle atom + possibly terminal hydrogen atoms */
1365
+ if ( num_atoms < 1 || !at[0].parity2 ) {
1366
+ bCanonIsoStereo = 0; /* structure; for example Cl- or CH4 */
1367
+ }
1368
+ }
1369
+
1370
+ if ( !bCanonStereo && !(bCanonIsotopic && bCanonIsoStereo) ) {
1371
+ goto exit_function; /* skip stereo canonicalization */
1372
+ }
1373
+
1374
+
1375
+
1376
+ /**********************************************************
1377
+ Mode
1378
+ ***********************************************************/
1379
+ nMode = nMode & CANON_MODE_MASK;
1380
+
1381
+ /* memory allocation */
1382
+
1383
+ nAtomNumber = (AT_RANK *)qmalloc(num_max*sizeof(*nAtomNumber));
1384
+ nRank = (AT_RANK *)qmalloc(num_max*sizeof(*nRank));
1385
+ nTempRank = (AT_RANK *)qmalloc(num_max*sizeof(*nTempRank));
1386
+ nSymmRank = (AT_RANK *)qmalloc(num_max*sizeof(*nSymmRank));
1387
+ /***********************************************
1388
+ 0.1 Initialization
1389
+ ************************************************/
1390
+
1391
+
1392
+ if ( !NeighList || !nAtomNumber || !nTempRank ||
1393
+ !nRank || !pCS->LinearCT ) {
1394
+ nRet = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
1395
+ goto exit_function;
1396
+ }
1397
+
1398
+ pCS->NeighList = NeighList;
1399
+
1400
+ *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1401
+
1402
+ if ( !(nMode & CMODE_NOEQ_STEREO) && (bCanonStereo || bCanonIsoStereo ) ) {
1403
+ /* will be used to discover vertex equivalences in stereo canonicalization */
1404
+ memset( &CurrentTree, 0, sizeof(CurrentTree) );
1405
+ cur_tree = &CurrentTree;
1406
+ }
1407
+
1408
+
1409
+ pCS->bCmpStereo = 0;
1410
+ pCS->bCmpIsotopicStereo = 0;
1411
+
1412
+
1413
+ if ( bCanonStereo || bCanonIsoStereo ) {
1414
+ int ii, nn;
1415
+
1416
+ /* stereo or isotopic canonicalization: we need a second set of ranks for mapping */
1417
+ /* (isotopic atoms or stereo can only increase nNumCurrRanks) */
1418
+ pRankStack2 = (AT_RANK **) inchi_calloc( nRankStackLen, sizeof(AT_RANK *) );
1419
+ if ( pRankStack2 ) {
1420
+ /* prepare for ranks reuse */
1421
+ for ( nn = 2; nn < nRankStackLen && pRankStack1[nn]; nn ++ ) {
1422
+ pRankStack1[nn][0] = 0; /* means ranks have to be calculated */
1423
+ }
1424
+ /* reuse memory to reduce number of allocations: */
1425
+ /* move last half of pointers from pRankStack1 to pRankStack2 */
1426
+ /* The first 2 elements will be assigned separately */
1427
+ if ( (nn = (nn-2)/2) > 0 ) {
1428
+ for ( ii = 2+nn; ii < nRankStackLen && pRankStack1[ii]; ii ++ ) {
1429
+ pRankStack2[ii-nn] = pRankStack1[ii];
1430
+ pRankStack1[ii] = NULL;
1431
+ }
1432
+ }
1433
+ } else {
1434
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1435
+ goto exit_function; /* program error */
1436
+ }
1437
+ }
1438
+
1439
+ if ( bCanonStereo ) {
1440
+
1441
+ /* *pCS2 = *pCS; */ /* save input information and pointers to allocated memory */
1442
+
1443
+ /* initial ranking for non-isotopic mapping */
1444
+ memcpy( nAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]) );
1445
+ memcpy( nRank, ftcn->PartitionCt.Rank, num_at_tg * sizeof(nRank[0]) );
1446
+ memcpy( nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(nSymmRank[0]) );
1447
+
1448
+ /* nSymmRank changes if canonical numbers of constitutionally equivalent atoms are not contiguous */
1449
+ nNumCurrRanks = FixCanonEquivalenceInfo( num_at_tg, nSymmRank /* in&out*/,
1450
+ nRank, nTempRank /* out */, nAtomNumber /* in&out */, NULL);
1451
+ /* atom numbers in canonical order */
1452
+ memcpy( pCS->nPrevAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]) );
1453
+
1454
+ /* fill stereo part of the connection table with initial (not optimized) parities */
1455
+ /* input
1456
+ pCS->LinearCTStereoDble
1457
+ pCS->LinearCTStereoCarb
1458
+ pCS->nMaxLenLinearCTStereoCarb
1459
+ pCS->nMaxLenLinearCTStereoDble
1460
+ */
1461
+ nRet = FillOutStereoParities( at, num_atoms, ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1462
+ nRank, nAtomNumber, pCS, 0 /* bIsotopic */ );
1463
+ /* output
1464
+ pCS->LinearCTStereoDble
1465
+ pCS->LinearCTStereoCarb
1466
+ pCS2->nLenLinearCTStereoCarb
1467
+ pCS2->nLenLinearCTStereoDble
1468
+ */
1469
+ if ( RETURNED_ERROR( nRet ) ) {
1470
+ goto exit_function;
1471
+ }
1472
+ if ( nRet < 0 ) {
1473
+ nRet = CT_STEREOCOUNT_ERR;
1474
+ goto exit_function;
1475
+ }
1476
+
1477
+ /***************************************************************
1478
+ *
1479
+ * VI. Optimize non-isotopic stereo descriptors (optimized)
1480
+ *
1481
+ ***************************************************************/
1482
+
1483
+ /* allocate memory for stereo canonicalization */
1484
+
1485
+ if ( !nCanonRankStereo )
1486
+ nCanonRankStereo = (AT_RANK *) qmalloc(num_max*sizeof(*nCanonRankStereo));
1487
+ if ( !nSymmStereo && !(nMode & CMODE_NOEQ_STEREO) )
1488
+ nSymmStereo = (AT_RANK *) qmalloc((num_max+1)*sizeof(*nSymmStereo));
1489
+ if ( !(nMode & CMODE_NOEQ_STEREO) && 0 > CurTreeAlloc( cur_tree, num_at_tg ) ) {
1490
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1491
+ goto exit_function;
1492
+ }
1493
+ /* check allocations and assign first 2 elements of pRankStack2 */
1494
+ if ( pRankStack1 && pRankStack2 &&
1495
+ nCanonRankStereo &&
1496
+ /* nCurrRankStereo && nAtomNumberCurrStereo &&*/
1497
+ (nSymmStereo || (nMode & CMODE_NOEQ_STEREO)) ) {
1498
+ pRankStack1[0] = pRankStack2[0] = nRank;
1499
+ pRankStack1[1] = pRankStack2[1] = nAtomNumber;
1500
+ } else {
1501
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1502
+ goto exit_function;
1503
+ }
1504
+
1505
+ /****************************************************************
1506
+ *
1507
+ * VI-A. Optimize non-isotopic non-inverted stereo descriptors
1508
+ *
1509
+ ****************************************************************/
1510
+
1511
+ /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
1512
+ for ( n = 2; n < nRankStackLen && pRankStack1[n]; n ++ ) {
1513
+ pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
1514
+ }
1515
+ /* set the 1st ranks to zero: prepare for ranks reuse */
1516
+ for ( n = 2; n < nRankStackLen && pRankStack2[n]; n ++ ) {
1517
+ pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
1518
+ }
1519
+
1520
+ /* for debugging or statistics */
1521
+ pCS->lNumBreakTies =
1522
+ pCS->lNumNeighListIter=
1523
+ pCS->lNumTotCT =
1524
+ pCS->lNumDecreasedCT =
1525
+ pCS->lNumRejectedCT =
1526
+ pCS->lNumEqualCT = 0;
1527
+ pCS->bKeepSymmRank = 0;
1528
+ pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
1529
+
1530
+ /******************************************************************************
1531
+ nCanonRank contains input canonical numbering
1532
+ nCanonRankStereo will be filled with a transposition of canonical numbering
1533
+ which (1) keeps connection table unchanged and
1534
+ (2) provides minimal stereo descriptors in
1535
+ pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
1536
+ pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
1537
+ */
1538
+ nRet = map_stereo_bonds4
1539
+ ( at, num_atoms, num_at_tg, num_max, 0, ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1540
+ nCanonRankStereo, nSymmRank,
1541
+ pRankStack1, pRankStack2, nTempRank, nNumCurrRanks,
1542
+ nSymmStereo, NeighList, pCS, cur_tree, 0 /* nNumMappedBonds */);
1543
+
1544
+ if ( RETURNED_ERROR( nRet ) ) {
1545
+ if ( nRet == CT_TIMEOUT_ERR )
1546
+ goto exit_function;
1547
+ else
1548
+ goto exit_function; /* program error */
1549
+ } else {
1550
+ int bFailed = 0;
1551
+ if ( !nRet ) {
1552
+ bFailed = 1; /* progrm error */
1553
+ pCS2->nLenLinearCTStereoCarb =
1554
+ pCS->nLenLinearCTStereoCarb = -abs(pCS->nLenLinearCTStereoCarb);
1555
+ pCS2->nLenLinearCTStereoDble =
1556
+ pCS->nLenLinearCTStereoDble = -abs(pCS->nLenLinearCTStereoDble);
1557
+ nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1558
+ goto exit_function; /* program error */
1559
+ } else {
1560
+ /* save non-isotopic lengths */
1561
+ pCS2->nLenLinearCTStereoDble = pCS->nLenLinearCTStereoDble;
1562
+ pCS2->nLenLinearCTStereoCarb = pCS->nLenLinearCTStereoCarb;
1563
+ nRet = 0;
1564
+ }
1565
+
1566
+ /* save stereo canonical numbering */
1567
+ if ( pCS->nCanonOrdStereo ) {
1568
+ for ( i = n = 0; i < num_at_tg; i ++ ) {
1569
+ if ( nCanonRankStereo[i] && (int)nCanonRankStereo[i] <= num_at_tg ) {
1570
+ pCS->nCanonOrdStereo[ (int)nCanonRankStereo[i] - 1 ] = (AT_NUMB)i;
1571
+ } else {
1572
+ bFailed ++;
1573
+ }
1574
+ }
1575
+ pCS->nLenCanonOrdStereo = ( bFailed )? -num_atoms : num_atoms;
1576
+ }
1577
+ /* save stereo tautomer groups numbering */
1578
+ if ( bTaut && pCS->nCanonOrdStereoTaut ) {
1579
+ if ( 0 < (nRet = SortTautomerGroupsAndEndpoints( t_group_info1, num_atoms, num_at_tg, nCanonRankStereo ) ) ) {
1580
+ /*non-isotopic contains symmetry ranks */
1581
+ int num_t_groups = t_group_info1->num_t_groups;
1582
+ AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1583
+ /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
1584
+ memcpy( pCS->nCanonOrdStereoTaut, tGroupNumber, num_t_groups*sizeof(pCS->nCanonOrdStereoTaut[0]) );
1585
+ pCS->nLenCanonOrdStereoTaut = ( bFailed ) ?
1586
+ -num_t_groups : num_t_groups;
1587
+ } else
1588
+ if ( RETURNED_ERROR( nRet ) ) {
1589
+ goto exit_function;
1590
+ } else {
1591
+ nRet = 0;
1592
+ }
1593
+ /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
1594
+ }
1595
+ }
1596
+
1597
+ /****************************************************
1598
+ *
1599
+ * VI-B. Optimize INVERTED stereo descriptors
1600
+ *
1601
+ ****************************************************/
1602
+ if ( !nCanonRankStereoInv )
1603
+ nCanonRankStereoInv = (AT_RANK *) qmalloc(num_max*sizeof(*nCanonRankStereoInv));
1604
+ if ( !nCanonRankStereoInv ) {
1605
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1606
+ goto exit_function;
1607
+ }
1608
+ /* copy previous non-isotopic stereo canonicalization results to Inv initial data */
1609
+ /* assign pointers */
1610
+ pCS->LinearCTStereoDble = pCS2->LinearCTStereoDbleInv;
1611
+ pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarbInv;
1612
+
1613
+ /* copy the lengths */
1614
+ pCS2->nLenLinearCTStereoDbleInv =
1615
+ pCS->nLenLinearCTStereoDbleInv =
1616
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
1617
+
1618
+ pCS2->nLenLinearCTStereoCarbInv =
1619
+ pCS->nLenLinearCTStereoCarbInv =
1620
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
1621
+
1622
+ if ( pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0 ) {
1623
+ /* copy previous results, the canonical stereo CT */
1624
+ memcpy( pCS->LinearCTStereoDble, pCS2->LinearCTStereoDble, pCS->nLenLinearCTStereoDble*sizeof(pCS->LinearCTStereoDble[0]) );
1625
+ memcpy( pCS->LinearCTStereoCarb, pCS2->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb*sizeof(pCS->LinearCTStereoCarb[0]) );
1626
+ }
1627
+ memcpy( nCanonRankStereoInv, nCanonRankStereo, num_max * sizeof(nCanonRankStereoInv[0]) );
1628
+ if ( pCS->nCanonOrdStereoInv && pCS->nCanonOrdStereo ) {
1629
+ /* in case there is nothing to invert */
1630
+ memcpy( pCS->nCanonOrdStereoInv, pCS->nCanonOrdStereo, num_at_tg*sizeof(pCS->nCanonOrdStereoInv[0]));
1631
+ }
1632
+
1633
+ /******************************
1634
+ *
1635
+ * Invert stereo
1636
+ *
1637
+ ******************************/
1638
+
1639
+ /*********************************************************************************
1640
+ * Create initial approximation for the minimization of the stereo descriptors:
1641
+ * invert stereogenic atom parities, one parity in each allene, all parities in
1642
+ * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
1643
+ */
1644
+ nRet = InvertStereo( at, num_at_tg, nCanonRankStereo, nTempRank, pCS, 1 /* bInvertLinearCTStereo */ );
1645
+ if ( RETURNED_ERROR( nRet ) ) {
1646
+ goto exit_function;
1647
+ } else
1648
+ if ( nRet > 0 ) {
1649
+ /* InvertStereo() has done some changes */
1650
+ nRet = 0;
1651
+ /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
1652
+
1653
+ /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
1654
+ for ( n = 2; n < nRankStackLen && pRankStack1[n]; n ++ ) {
1655
+ pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
1656
+ }
1657
+ /* set the 1st ranks to zero: prepare for ranks reuse */
1658
+ for ( n = 2; n < nRankStackLen && pRankStack2[n]; n ++ ) {
1659
+ pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
1660
+ }
1661
+
1662
+ /* for debugging or statistics */
1663
+ pCS->lNumBreakTies =
1664
+ pCS->lNumNeighListIter=
1665
+ pCS->lNumTotCT =
1666
+ pCS->lNumDecreasedCT =
1667
+ pCS->lNumRejectedCT =
1668
+ pCS->lNumEqualCT = 0;
1669
+ pCS->bKeepSymmRank = 0;
1670
+ pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
1671
+
1672
+ /******************************************************************************
1673
+ ftcn->PartitionCt.Rank contains input canonical numbering
1674
+ nCanonRankStereoInv will be filled with a transposition of canonical numbering
1675
+ which (1) keeps connection table unchanged and
1676
+ (2) provides minimal stereo descriptors in
1677
+ pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
1678
+ pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
1679
+ ******************************************************************************/
1680
+ nRet = map_stereo_bonds4
1681
+ ( at, num_atoms, num_at_tg, num_max, 0, ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1682
+ nCanonRankStereoInv, nSymmRank,
1683
+ pRankStack1, pRankStack2, nTempRank, nNumCurrRanks, nSymmStereo,
1684
+ NeighList, pCS, cur_tree, 0 );
1685
+ if ( RETURNED_ERROR( nRet ) ) {
1686
+ if ( nRet == CT_TIMEOUT_ERR )
1687
+ goto exit_function;
1688
+ else
1689
+ goto exit_function; /* program error */
1690
+ } else {
1691
+ int bFailed = 0;
1692
+ if ( !nRet ) {
1693
+ bFailed = 1; /* progrm error */
1694
+ pCS2->nLenLinearCTStereoCarb =
1695
+ pCS->nLenLinearCTStereoCarb = -abs(pCS->nLenLinearCTStereoCarb);
1696
+ pCS2->nLenLinearCTStereoDble =
1697
+ pCS->nLenLinearCTStereoDble = -abs(pCS->nLenLinearCTStereoDble);
1698
+ nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1699
+ goto exit_function; /* program error */
1700
+ }
1701
+
1702
+ /* save non-isotopic pointers & lengths for INVERTED stereo */
1703
+ pCS->nLenLinearCTStereoDbleInv =
1704
+ pCS2->nLenLinearCTStereoDbleInv = pCS->nLenLinearCTStereoDble;
1705
+ pCS->nLenLinearCTStereoCarbInv =
1706
+ pCS2->nLenLinearCTStereoCarbInv = pCS->nLenLinearCTStereoCarb;
1707
+
1708
+ /* restore pointers and lengths to non-inverted stereo */
1709
+ /* -- this is needed for InvertStereo() back, see below */
1710
+ pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
1711
+ pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
1712
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
1713
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
1714
+ /* consistency check */
1715
+ if ( pCS->nLenLinearCTStereoDbleInv != pCS->nLenLinearCTStereoDble ||
1716
+ pCS->nLenLinearCTStereoCarbInv != pCS->nLenLinearCTStereoCarb ) {
1717
+ nRet = CT_CALC_STEREO_ERR;
1718
+ goto exit_function; /* program error */
1719
+ }
1720
+ /******************************
1721
+ *
1722
+ * Invert stereo back
1723
+ *
1724
+ ******************************
1725
+ * (make sure that pointers
1726
+ * pCS->LinearCTStereoCarb,
1727
+ * pCS->LinearCTStereoDble
1728
+ * and corresponding lengths
1729
+ * have been restored)
1730
+ ******************************/
1731
+ /*********************************************************************************
1732
+ * invert only stereogenic atom parities and one parity in each allene, DO NOT
1733
+ * change parities in pCS->LinearCTStereoCarb and pCS->nLenLinearCTStereoDble
1734
+ */
1735
+ nRet = InvertStereo( at, num_at_tg, nCanonRankStereo, nTempRank, pCS, 0 );
1736
+ if ( RETURNED_ERROR( nRet ) ) {
1737
+ goto exit_function;
1738
+ }
1739
+ nRet = 0;
1740
+
1741
+
1742
+ /* save stereo canonical numbering */
1743
+ if ( pCS->nCanonOrdStereoInv ) {
1744
+ for ( i = n = 0; i < num_at_tg; i ++ ) {
1745
+ if ( nCanonRankStereoInv[i] && (int)nCanonRankStereoInv[i] <= num_at_tg ) {
1746
+ pCS->nCanonOrdStereoInv[ (int)nCanonRankStereoInv[i] - 1 ] = (AT_NUMB)i;
1747
+ } else {
1748
+ bFailed ++;
1749
+ }
1750
+ }
1751
+ pCS->nLenCanonOrdStereo = ( bFailed )? -num_atoms : num_atoms;
1752
+ }
1753
+
1754
+ /* compare inverted and non-inverted stereo */
1755
+ pCS->bCmpStereo = 2 + CompareLinCtStereo(
1756
+ pCS->LinearCTStereoDbleInv, pCS->nLenLinearCTStereoDbleInv,
1757
+ pCS->LinearCTStereoCarbInv, pCS->nLenLinearCTStereoCarbInv,
1758
+ pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble,
1759
+ pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb
1760
+ );
1761
+
1762
+ }
1763
+ } else
1764
+ if ( 0 == nRet ) {
1765
+ /* nothing has been done, restore pointers and lengths for stereo */
1766
+ pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
1767
+ pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
1768
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
1769
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
1770
+ }
1771
+
1772
+
1773
+ }
1774
+ /* restore "ignore isotopic differences in tautomer groups" */
1775
+ if ( bTaut ) {
1776
+ /* save request for isotopic tautomeric groups */
1777
+ pCS->t_group_info->bIgnoreIsotopic = bIgnoreIsotopicInputGroups;
1778
+ }
1779
+ /* restore request for isotopic name */
1780
+ pCS->bIgnoreIsotopic = bIgnoreIsotopicInputAtoms;
1781
+
1782
+ if ( bCanonIsoStereo && bCanonIsotopic ) {
1783
+
1784
+ /****************************************************************
1785
+ *
1786
+ * VII. Optimize isotopic stereo descriptors (optimized)
1787
+ *
1788
+ ****************************************************************/
1789
+ /*
1790
+ pCS->LinearCTIsotopic = NULL;
1791
+ */
1792
+
1793
+ /* initial ranking for isotopic mapping */
1794
+ memcpy( nAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]) );
1795
+ memcpy( nRank, ftcn->PartitionCtIso.Rank, num_at_tg * sizeof(nRank[0]) );
1796
+ memcpy( nSymmRank, ftcn->nSymmRankCtIso, num_at_tg * sizeof(nSymmRank[0]) );
1797
+
1798
+ /* nSymmRank will change if canonical numbers of of constitutionally equivalent atoms are not contiguous */
1799
+ nNumCurrRanks = FixCanonEquivalenceInfo( num_at_tg, nSymmRank /* in&out*/,
1800
+ nRank, nTempRank /* out */, nAtomNumber /* in&out */, NULL);
1801
+
1802
+ memcpy( pCS->nPrevAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]) );
1803
+
1804
+ /* allocate memory for optimized stereo canonicalization */
1805
+ /* for stereo canonical numbering to be found. */
1806
+ if ( !nCanonRankIsotopicStereo )
1807
+ nCanonRankIsotopicStereo = (AT_RANK *) qmalloc(num_max*sizeof(*nCanonRankIsotopicStereo));
1808
+ if ( !nSymmStereo && !(nMode & CMODE_NOEQ_STEREO) )
1809
+ nSymmStereo = (AT_RANK *) qmalloc((num_max+1)*sizeof(*nSymmStereo));
1810
+
1811
+ if ( !(nMode & CMODE_NOEQ_STEREO) && CurTreeAlloc( cur_tree, num_at_tg ) ) {
1812
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1813
+ goto exit_function;
1814
+ }
1815
+ /* check allocations and assign first 2 elements of pRankStack2 */
1816
+ if ( pRankStack1 && pRankStack2 &&
1817
+ nCanonRankIsotopicStereo &&
1818
+ (nSymmStereo || (nMode & CMODE_NOEQ_STEREO)) ) {
1819
+
1820
+ pRankStack1[0] = pRankStack2[0] = nRank; /* pRankStack1[0,1] shall be unchanged */
1821
+ pRankStack1[1] = pRankStack2[1] = nAtomNumber;
1822
+ } else {
1823
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1824
+ goto exit_function;
1825
+ }
1826
+
1827
+ /******************************************************************
1828
+ Important: fill out a list of stereo atoms and bonds including
1829
+ those which are stereo due to isotopic atoms only and create
1830
+ LinearCT stereo descriptors for the canonical numbering
1831
+ ******************************************************************/
1832
+
1833
+
1834
+ /* at[] has certain members for non-isotopic and isotopic stereo; switch them */
1835
+ SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
1836
+ /* prepare stereo connection tables' pointers */
1837
+ SetCtToIsotopicStereo( pCS, pCS2 );
1838
+
1839
+ nRet = FillOutStereoParities( at, num_atoms, ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber,
1840
+ nRank, nAtomNumber, pCS, 1 /* bIsotopic */);
1841
+ if (RETURNED_ERROR(nRet)) {
1842
+ goto exit_function; /* program error */
1843
+ } else
1844
+ if ( !nRet ) {
1845
+ /* no isotopic stereo */
1846
+ pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTIsotopicStereoDble = 0;
1847
+ pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTIsotopicStereoCarb = 0;
1848
+ pCS->nLenCanonOrdIsotopicStereo = 0;
1849
+ pCS->nLenCanonOrdIsotopicStereoTaut = 0;
1850
+ pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTIsotopicStereoDbleInv = 0;
1851
+ pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTIsotopicStereoCarbInv = 0;
1852
+ goto bypass_isotopic_stereo;
1853
+ } else {
1854
+ nRet = 0; /* not an error */
1855
+ }
1856
+
1857
+
1858
+
1859
+ /*************************************************************
1860
+ *
1861
+ * VII-A. Optimize non-inverted isotopic stereo descriptors
1862
+ *
1863
+ *************************************************************/
1864
+
1865
+ /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
1866
+ for ( n = 2; n < nRankStackLen && pRankStack1[n]; n ++ ) {
1867
+ pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
1868
+ }
1869
+ /* set the 1st ranks to zero: prepare for ranks reuse */
1870
+ for ( n = 2; n < nRankStackLen && pRankStack2[n]; n ++ ) {
1871
+ pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
1872
+ }
1873
+
1874
+ /* for debugging or statistics */
1875
+ pCS->lNumBreakTies =
1876
+ pCS->lNumNeighListIter=
1877
+ pCS->lNumTotCT =
1878
+ pCS->lNumDecreasedCT =
1879
+ pCS->lNumRejectedCT =
1880
+ pCS->lNumEqualCT = 0;
1881
+ pCS->bKeepSymmRank = 0;
1882
+ pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
1883
+
1884
+ /**************************************************************************************
1885
+ nCanonRankIsotopic contains input canonical numbering
1886
+ nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
1887
+ that (1) keeps connection table unchanged and
1888
+ (2) provides minimal stereo descriptors in
1889
+ pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
1890
+ pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
1891
+ ***************************************************************************************/
1892
+ nRet = map_stereo_bonds4
1893
+ ( at, num_atoms, num_at_tg, num_max, 0, ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber,
1894
+ nCanonRankIsotopicStereo, nSymmRank,
1895
+ pRankStack1, pRankStack2, nTempRank, nNumCurrRanks,
1896
+ nSymmStereo, NeighList, pCS, cur_tree, 0 );
1897
+ if ( RETURNED_ERROR( nRet ) ) {
1898
+ goto exit_function;
1899
+ } else {
1900
+ int bFailed = 0;
1901
+
1902
+ if ( !nRet ) {
1903
+ bFailed = 1; /* program error */
1904
+ pCS2->nLenLinearCTIsotopicStereoDble =
1905
+ pCS->nLenLinearCTIsotopicStereoDble = -abs(pCS->nLenLinearCTStereoDble);
1906
+ pCS2->nLenLinearCTIsotopicStereoCarb =
1907
+ pCS->nLenLinearCTIsotopicStereoCarb = -abs(pCS->nLenLinearCTStereoCarb);
1908
+ nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1909
+ goto exit_function; /* program error */
1910
+ } else {
1911
+ /* save isotopic lengths */
1912
+ pCS->nLenLinearCTIsotopicStereoDble =
1913
+ pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTStereoDble;
1914
+ pCS->nLenLinearCTIsotopicStereoCarb =
1915
+ pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTStereoCarb;
1916
+
1917
+ /* save stereo canonical numbering */
1918
+ if ( pCS->nCanonOrdIsotopicStereo ) {
1919
+ for ( i = n = 0; i < num_at_tg; i ++ ) {
1920
+ if ( nCanonRankIsotopicStereo[i] && (int)nCanonRankIsotopicStereo[i] <= num_at_tg ) {
1921
+ pCS->nCanonOrdIsotopicStereo[ (int)nCanonRankIsotopicStereo[i] - 1 ] = (AT_NUMB)i;
1922
+ } else {
1923
+ bFailed ++;
1924
+ }
1925
+ }
1926
+ pCS->nLenCanonOrdIsotopicStereo = bFailed? -num_atoms : num_atoms;
1927
+ }
1928
+ /* save stereo tautomer groups numbering */
1929
+ if ( pCS->nCanonOrdIsotopicStereoTaut ) {
1930
+ if ( 0 < (nRet=SortTautomerGroupsAndEndpoints( t_group_info1, num_atoms, num_at_tg, nCanonRankIsotopicStereo ) ) ) {
1931
+ /*non-isotopic contains symmetry ranks */
1932
+ int num_t_groups = t_group_info1->num_t_groups;
1933
+ AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1934
+ /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
1935
+ memcpy( pCS->nCanonOrdIsotopicStereoTaut, tGroupNumber, num_t_groups*sizeof(pCS->nCanonOrdIsotopicStereoTaut[0]) );
1936
+ pCS->nLenCanonOrdIsotopicStereoTaut = bFailed? -num_t_groups:num_t_groups;
1937
+
1938
+ /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
1939
+ } else
1940
+ if ( RETURNED_ERROR( nRet ) ) {
1941
+ goto exit_function;
1942
+ } else {
1943
+ nRet = 0;
1944
+ }
1945
+ }
1946
+ }
1947
+ }
1948
+
1949
+ /**********************************************************
1950
+ *
1951
+ * VII-B. Optimize INVERTED isotopic stereo descriptors
1952
+ *
1953
+ **********************************************************/
1954
+ if ( !nCanonRankIsotopicStereoInv )
1955
+ nCanonRankIsotopicStereoInv = (AT_RANK *) qmalloc(num_max*sizeof(*nCanonRankIsotopicStereoInv));
1956
+ if ( !nCanonRankIsotopicStereoInv ) {
1957
+ nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1958
+ goto exit_function;
1959
+ }
1960
+ /* copy previous isotopic stereo canonicalization results to Inv initial data */
1961
+ /* assign pointers */
1962
+ pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDbleInv; /* enable stereo */
1963
+ pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarbInv;
1964
+
1965
+
1966
+ /* copy the lengths */
1967
+ pCS2->nLenLinearCTIsotopicStereoDbleInv =
1968
+ pCS->nLenLinearCTStereoDbleInv =
1969
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
1970
+
1971
+ pCS2->nLenLinearCTIsotopicStereoCarbInv =
1972
+ pCS->nLenLinearCTStereoCarbInv =
1973
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
1974
+
1975
+ if ( pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0 ) {
1976
+ /* copy previous results, the canonical stereo CT */
1977
+ memcpy( pCS->LinearCTStereoDble, pCS2->LinearCTIsotopicStereoDble, pCS->nLenLinearCTStereoDble*sizeof(pCS->LinearCTStereoDble[0]) );
1978
+ memcpy( pCS->LinearCTStereoCarb, pCS2->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTStereoCarb*sizeof(pCS->LinearCTStereoCarb[0]) );
1979
+ }
1980
+ memcpy( nCanonRankIsotopicStereoInv, nCanonRankIsotopicStereo, num_max * sizeof(nCanonRankIsotopicStereoInv[0]) );
1981
+ if ( pCS->nCanonOrdIsotopicStereoInv && pCS->nCanonOrdIsotopicStereo ) {
1982
+ /* in case there is nothing to invert */
1983
+ memcpy( pCS->nCanonOrdIsotopicStereoInv, pCS->nCanonOrdIsotopicStereo, num_at_tg*sizeof(pCS->nCanonOrdIsotopicStereoInv[0]));
1984
+ }
1985
+
1986
+ /******************************
1987
+ *
1988
+ * Invert isotopic stereo
1989
+ *
1990
+ ******************************/
1991
+
1992
+ /*********************************************************************************
1993
+ * Create initial approximation for the minimization of the stereo descriptors:
1994
+ * invert stereogenic atom parities, one parity in each allene, all parities in
1995
+ * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
1996
+ */
1997
+ nRet = InvertStereo( at, num_at_tg, nCanonRankIsotopicStereo, nTempRank, pCS, 1 );
1998
+ if ( RETURNED_ERROR( nRet ) ) {
1999
+ goto exit_function;
2000
+ } else
2001
+ if ( nRet > 0 ) {
2002
+ /* InvertStereo() has done some changes */
2003
+ nRet = 0;
2004
+ /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
2005
+
2006
+ /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2007
+ for ( n = 2; n < nRankStackLen && pRankStack1[n]; n ++ ) {
2008
+ pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2009
+ }
2010
+ /* set the 1st ranks to zero: prepare for ranks reuse */
2011
+ for ( n = 2; n < nRankStackLen && pRankStack2[n]; n ++ ) {
2012
+ pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2013
+ }
2014
+
2015
+ /* for debugging or statistics */
2016
+ pCS->lNumBreakTies =
2017
+ pCS->lNumNeighListIter=
2018
+ pCS->lNumTotCT =
2019
+ pCS->lNumDecreasedCT =
2020
+ pCS->lNumRejectedCT =
2021
+ pCS->lNumEqualCT = 0;
2022
+ pCS->bKeepSymmRank = 0;
2023
+ pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2024
+
2025
+ /**************************************************************************************
2026
+ nCanonRankIsotopic contains input canonical numbering
2027
+ nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
2028
+ that (1) keeps connection table unchanged and
2029
+ (2) provides minimal stereo descriptors in
2030
+ pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2031
+ pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2032
+ */
2033
+ nRet = map_stereo_bonds4
2034
+ ( at, num_atoms, num_at_tg, num_max, 0, ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber,
2035
+ nCanonRankIsotopicStereoInv, nSymmRank,
2036
+ pRankStack1, pRankStack2, nTempRank, nNumCurrRanks,
2037
+ nSymmStereo, NeighList, pCS, cur_tree, 0 );
2038
+ if ( RETURNED_ERROR( nRet ) ) {
2039
+ if ( nRet == CT_TIMEOUT_ERR )
2040
+ goto exit_function;
2041
+ else
2042
+ goto exit_function; /* program error */
2043
+ } else {
2044
+ int bFailed = 0;
2045
+
2046
+ if ( !nRet ) {
2047
+ bFailed = 1; /* program error */
2048
+ pCS2->nLenLinearCTIsotopicStereoDble =
2049
+ pCS->nLenLinearCTIsotopicStereoDble = -abs(pCS->nLenLinearCTStereoDble);
2050
+ pCS2->nLenLinearCTIsotopicStereoCarb =
2051
+ pCS->nLenLinearCTIsotopicStereoCarb = -abs(pCS->nLenLinearCTStereoCarb);
2052
+ nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2053
+ goto exit_function; /* program error */
2054
+ }
2055
+ /* save isotopic pointers & lengths for INVERTED stereo */
2056
+
2057
+ /* save isotopic lengths */
2058
+ pCS->nLenLinearCTIsotopicStereoDbleInv =
2059
+ pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTStereoDble;
2060
+ pCS->nLenLinearCTIsotopicStereoCarbInv =
2061
+ pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTStereoCarb;
2062
+
2063
+ /* restore pointers and lengths to non-inverted isotopic stereo */
2064
+ /* -- this is needed for InvertStereo() back, see below */
2065
+ pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2066
+ pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2067
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2068
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2069
+
2070
+ /* consistency check */
2071
+ if ( pCS->nLenLinearCTIsotopicStereoDbleInv != pCS->nLenLinearCTIsotopicStereoDble ||
2072
+ pCS->nLenLinearCTIsotopicStereoCarbInv != pCS->nLenLinearCTIsotopicStereoCarb ) {
2073
+ nRet = CT_CALC_STEREO_ERR;
2074
+ goto exit_function; /* program error */
2075
+ }
2076
+ /******************************
2077
+ *
2078
+ * Invert stereo back
2079
+ *
2080
+ ******************************
2081
+ * (make sure that pointers
2082
+ * pCS->LinearCTStereoCarb,
2083
+ * pCS->LinearCTStereoDble
2084
+ * and corresponding lengths
2085
+ * have been restored)
2086
+ ******************************/
2087
+ nRet = InvertStereo( at, num_at_tg, nCanonRankIsotopicStereo, nTempRank, pCS, 0 );
2088
+ if ( RETURNED_ERROR( nRet ) ) {
2089
+ goto exit_function;
2090
+ }
2091
+ nRet = 0;
2092
+
2093
+ /* save stereo canonical numbering */
2094
+ if ( pCS->nCanonOrdIsotopicStereoInv ) {
2095
+ for ( i = n = 0; i < num_at_tg; i ++ ) {
2096
+ if ( nCanonRankIsotopicStereoInv[i] && (int)nCanonRankIsotopicStereoInv[i] <= num_at_tg ) {
2097
+ pCS->nCanonOrdIsotopicStereoInv[ (int)nCanonRankIsotopicStereoInv[i] - 1 ] = (AT_NUMB)i;
2098
+ } else {
2099
+ bFailed ++;
2100
+ }
2101
+ }
2102
+ pCS->nLenCanonOrdIsotopicStereo = bFailed? -num_atoms : num_atoms;
2103
+ }
2104
+ /* compare inverted and non-inverted isotopic stereo */
2105
+ pCS->bCmpIsotopicStereo = 2 + CompareLinCtStereo(
2106
+ pCS->LinearCTIsotopicStereoDbleInv, pCS->nLenLinearCTIsotopicStereoDbleInv,
2107
+ pCS->LinearCTIsotopicStereoCarbInv, pCS->nLenLinearCTIsotopicStereoCarbInv,
2108
+ pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble,
2109
+ pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb
2110
+ );
2111
+
2112
+ }
2113
+ } else
2114
+ if ( 0 == nRet ) {
2115
+ /* nothing has been done, restore pointers and lengths for stereo */
2116
+ pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2117
+ pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2118
+ pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2119
+ pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2120
+ }
2121
+
2122
+ bypass_isotopic_stereo:; /* ??? */
2123
+
2124
+ pCS->LinearCTIsotopic = pCS2->LinearCTIsotopic;
2125
+ }
2126
+
2127
+
2128
+
2129
+ exit_function:
2130
+
2131
+ if ( bSwitchedAtomToIsotopic ) {
2132
+ SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
2133
+ SetCtToNonIsotopicStereo( pCS, pCS2 ); /* ??? */
2134
+ }
2135
+
2136
+ /* restore non-isotopic connection table */
2137
+ if ( pCS->LinearCT2 ) {
2138
+ swap( (char*)&pCS->LinearCT, (char*)&pCS->LinearCT2, sizeof(pCS->LinearCT) );
2139
+ swap( (char*)&pCS->nLenLinearCT, (char*)&pCS->nLenLinearCT2, sizeof(pCS->nLenLinearCT) );
2140
+ swap( (char*)&pCS->nLenLinearCTAtOnly, (char*)&pCS->nLenLinearCTAtOnly2, sizeof(pCS->nLenLinearCTAtOnly) );
2141
+ }
2142
+
2143
+ /* free memory */
2144
+ i = 2;
2145
+ if ( pRankStack1 ) {
2146
+ pRankStack1[0] =
2147
+ pRankStack1[1] = NULL; /* deallocated separately */
2148
+ for ( ; i < nRankStackLen && pRankStack1[i]; i ++ )
2149
+ ;
2150
+ }
2151
+ if ( pRankStack1 && pRankStack2 ) {
2152
+ for ( n = 2; n < nRankStackLen && pRankStack2[n]; n ++ ) {
2153
+ if ( i < nRankStackLen - 1 ) {
2154
+ pRankStack1[i++] = pRankStack2[n];
2155
+ } else {
2156
+ inchi_free( pRankStack2[n] );
2157
+ }
2158
+ }
2159
+ inchi_free( pRankStack2 );
2160
+ }
2161
+
2162
+ pCS->NeighList = NULL; /* keep the pointer in pBCN->ftcn[bTaut].NeighList for further deallocation */
2163
+ qfree ( nAtomNumber );
2164
+ qfree ( nTempRank );
2165
+ qfree ( nRank );
2166
+ qfree ( nSymmRank );
2167
+
2168
+ qfree( nSymmStereo );
2169
+ CurTreeFree( cur_tree );
2170
+ /* memory leak fix */
2171
+ /*
2172
+ qfree ( nCurrRankIsotopicStereo );
2173
+ qfree ( nAtomNumberCurrIsotopicStereo);
2174
+ */
2175
+ qfree ( nCanonRankIsotopicStereo );
2176
+ qfree ( nCanonRankIsotopicStereoInv );
2177
+
2178
+ qfree( nCanonRankStereo );
2179
+ qfree( nCanonRankStereoInv );
2180
+
2181
+ InchiTimeGet( &ulEndTime );
2182
+ pCS->lTotalTime = InchiTimeMsecDiff(&ulEndTime, &ulStartTime);
2183
+ return (nRet >= -1)? num_atoms : nRet; /* cannot easily get number of ranks for now */
2184
+
2185
+ }
2186
+
2187
+ /**************************************************************************************/
2188
+ int Canon_INChI( int num_atoms, int num_at_tg, sp_ATOM* at, CANON_STAT* pCS, INCHI_MODE nMode, int bTautFtcn)
2189
+ {
2190
+ if ( pCS->pBCN && !pCS->NeighList ) {
2191
+ /* new version */
2192
+ return Canon_INChI3( num_atoms, num_at_tg, at, pCS, nMode, bTautFtcn);
2193
+ }
2194
+ return CT_CANON_ERR;
2195
+ }