rino 0.1.0

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