rino 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|