rino 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/ichicano.c
ADDED
@@ -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
|
+
}
|