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/ichimak2.c
ADDED
@@ -0,0 +1,1189 @@
|
|
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
|
+
#include <math.h>
|
15
|
+
|
16
|
+
#include "mode.h"
|
17
|
+
|
18
|
+
#include "inpdef.h"
|
19
|
+
#include "ichi.h"
|
20
|
+
#include "strutil.h"
|
21
|
+
#include "util.h"
|
22
|
+
#include "extr_ct.h"
|
23
|
+
#include "ichitaut.h"
|
24
|
+
#include "ichinorm.h"
|
25
|
+
#include "ichicant.h"
|
26
|
+
#include "ichicano.h"
|
27
|
+
#include "ichicomn.h"
|
28
|
+
|
29
|
+
#include "ichicomp.h"
|
30
|
+
#include "ichimain.h"
|
31
|
+
#include "ichimake.h"
|
32
|
+
|
33
|
+
int GetHillFormulaCounts( U_CHAR *nAtom, S_CHAR *nNum_H, int num_atoms,
|
34
|
+
AT_NUMB *nTautomer, int lenTautomer,
|
35
|
+
int *pnum_C, int *pnum_H, int *pnLen, int *pnNumNonHAtoms );
|
36
|
+
int MakeHillFormula( U_CHAR *nAtom, int num_atoms,
|
37
|
+
char *szLinearCT, int nLen_szLinearCT, int num_C, int num_H, int *bOverflow );
|
38
|
+
|
39
|
+
char *AllocateAndFillHillFormula( INChI *pINChI );
|
40
|
+
|
41
|
+
int AddElementAndCount( const char *szElement, int mult, char *szLinearCT, int nLenLinearCT, int *bOverflow );
|
42
|
+
|
43
|
+
int Copy2StereoBondOrAllene( INChI_Stereo *Stereo, int *nNumberOfStereoCenters, int *nNumberOfStereoBonds,
|
44
|
+
AT_STEREO_DBLE *LinearCTStereoDble,
|
45
|
+
AT_NUMB *pCanonOrd, AT_RANK *pCanonRank, sp_ATOM *at, int bIsotopic );
|
46
|
+
|
47
|
+
int CopyLinearCTStereoToINChIStereo( INChI_Stereo *Stereo,
|
48
|
+
AT_STEREO_CARB *LinearCTStereoCarb, int nLenLinearCTStereoCarb,
|
49
|
+
AT_STEREO_DBLE *LinearCTStereoDble, int nLenLinearCTStereoDble
|
50
|
+
, AT_NUMB *pCanonOrd, AT_RANK *pCanonRank, sp_ATOM *at, int bIsotopic
|
51
|
+
, AT_STEREO_CARB *LinearCTStereoCarbInv
|
52
|
+
, AT_STEREO_DBLE *LinearCTStereoDbleInv
|
53
|
+
, AT_NUMB *pCanonOrdInv, AT_RANK *pCanonRankInv );
|
54
|
+
int GetHillFormulaIndexLength( int count );
|
55
|
+
|
56
|
+
int MarkAmbiguousStereo( sp_ATOM *at, inp_ATOM *norm_at, int bIsotopic, AT_NUMB *pCanonOrd,
|
57
|
+
AT_STEREO_CARB *LinearCTStereoCarb, int nLenLinearCTStereoCarb,
|
58
|
+
AT_STEREO_DBLE *LinearCTStereoDble, int nLenLinearCTStereoDble );
|
59
|
+
|
60
|
+
INCHI_MODE UnmarkAllUndefinedUnknownStereo( INChI_Stereo *Stereo, INCHI_MODE nUserMode );
|
61
|
+
|
62
|
+
int CleanCoord( MOL_COORD szCoord, int delim );
|
63
|
+
|
64
|
+
/**********************************************************************************************/
|
65
|
+
int MakeHillFormulaString( char *szHillFormula, char *szLinearCT, int nLen_szLinearCT, int *bOverflow)
|
66
|
+
{
|
67
|
+
int nLen;
|
68
|
+
if ( szHillFormula && !*bOverflow ) {
|
69
|
+
if ( nLen_szLinearCT > ( nLen = strlen(szHillFormula) ) ) {
|
70
|
+
memcpy( szLinearCT, szHillFormula, nLen+1 );
|
71
|
+
return nLen;
|
72
|
+
}
|
73
|
+
*bOverflow |= 1;
|
74
|
+
return nLen_szLinearCT+1;
|
75
|
+
}
|
76
|
+
return 0;
|
77
|
+
}
|
78
|
+
/**********************************************************************************************
|
79
|
+
* MS Windows dependent: sprintf() is supposed to return the length of the output string
|
80
|
+
* Carbon atoms are always first
|
81
|
+
* Bridging hydrogen atoms are always last
|
82
|
+
**********************************************************************************************/
|
83
|
+
int GetHillFormulaIndexLength( int count )
|
84
|
+
{
|
85
|
+
char szCount[16];
|
86
|
+
if ( count > 1 ) {
|
87
|
+
return sprintf( szCount, "%d", count );
|
88
|
+
}
|
89
|
+
return 0;
|
90
|
+
}
|
91
|
+
/**********************************************************************************************/
|
92
|
+
int GetHillFormulaCounts( U_CHAR *nAtom, S_CHAR *nNum_H, int num_atoms,
|
93
|
+
AT_NUMB *nTautomer, int lenTautomer,
|
94
|
+
int *pnum_C, int *pnum_H, int *pnLen, int *pnNumNonHAtoms )
|
95
|
+
{
|
96
|
+
char szElement[4];
|
97
|
+
U_CHAR nPrevAtom = (U_CHAR)-1;
|
98
|
+
int bCarbon, bHydrogen, nElemLen, nFormLen, nNumNonHAtoms;
|
99
|
+
int mult, i, num_H, num_C;
|
100
|
+
|
101
|
+
num_H = 0;
|
102
|
+
num_C = 0;
|
103
|
+
bCarbon = 0;
|
104
|
+
bHydrogen = 0;
|
105
|
+
nElemLen = 0;
|
106
|
+
nFormLen = 0;
|
107
|
+
mult = 0;
|
108
|
+
nNumNonHAtoms = num_atoms;
|
109
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
110
|
+
if ( nPrevAtom != nAtom[i] ) {
|
111
|
+
if ( mult ) {
|
112
|
+
if ( bHydrogen ) {
|
113
|
+
num_H += mult;
|
114
|
+
}else
|
115
|
+
if ( bCarbon ) {
|
116
|
+
num_C += mult;
|
117
|
+
} else {
|
118
|
+
nFormLen += nElemLen;
|
119
|
+
nFormLen += GetHillFormulaIndexLength( mult );
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
if ( GetElementFormulaFromAtNum((int)nAtom[i], szElement ) ) {
|
124
|
+
return -1; /* wrong element */
|
125
|
+
}
|
126
|
+
mult = 1;
|
127
|
+
|
128
|
+
nElemLen = strlen(szElement);
|
129
|
+
nPrevAtom = nAtom[i];
|
130
|
+
bCarbon = !strcmp( szElement, "C" );
|
131
|
+
bHydrogen = !strcmp( szElement, "H" );
|
132
|
+
if ( bHydrogen ) {
|
133
|
+
nNumNonHAtoms = i;
|
134
|
+
}
|
135
|
+
} else {
|
136
|
+
mult ++;
|
137
|
+
}
|
138
|
+
|
139
|
+
num_H += nNum_H[i];
|
140
|
+
}
|
141
|
+
/* NumGroups; ((NumAt+1, NumH, At1..AtNumAt),...) */
|
142
|
+
if ( nTautomer && lenTautomer > 0 ) {
|
143
|
+
int num_groups = nTautomer[0];
|
144
|
+
for ( i = 1; i < lenTautomer && num_groups > 0; i += nTautomer[i]+1, num_groups -- ) {
|
145
|
+
num_H += nTautomer[i+1];
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
if ( mult ) {
|
150
|
+
if ( bHydrogen ) {
|
151
|
+
num_H += mult;
|
152
|
+
} else
|
153
|
+
if ( bCarbon ) {
|
154
|
+
num_C += mult;
|
155
|
+
} else {
|
156
|
+
nFormLen += nElemLen;
|
157
|
+
nFormLen += GetHillFormulaIndexLength( mult );
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
if ( num_C ) {
|
162
|
+
nFormLen += strlen( "C" );
|
163
|
+
nFormLen += GetHillFormulaIndexLength( num_C );
|
164
|
+
}
|
165
|
+
|
166
|
+
if ( num_H ) {
|
167
|
+
nFormLen += strlen( "H" );
|
168
|
+
nFormLen += GetHillFormulaIndexLength( num_H );
|
169
|
+
}
|
170
|
+
*pnum_C = num_C;
|
171
|
+
*pnum_H = num_H;
|
172
|
+
*pnLen = nFormLen;
|
173
|
+
*pnNumNonHAtoms = nNumNonHAtoms;
|
174
|
+
|
175
|
+
return 0;
|
176
|
+
}
|
177
|
+
/**********************************************************************************************/
|
178
|
+
int AddElementAndCount( const char *szElement, int mult, char *szLinearCT, int nLenLinearCT, int *bOverflow )
|
179
|
+
{
|
180
|
+
char szMult[16];
|
181
|
+
int len1, len2;
|
182
|
+
if ( mult > 0 && !*bOverflow && 0 < (len1 = strlen( szElement )) ) {
|
183
|
+
if ( mult > 1 ) {
|
184
|
+
len2 = sprintf( szMult, "%d", mult );
|
185
|
+
} else {
|
186
|
+
len2 = 0;
|
187
|
+
szMult[0] = '\0';
|
188
|
+
}
|
189
|
+
if ( len1 + len2 < nLenLinearCT ) {
|
190
|
+
memcpy( szLinearCT, szElement, len1 );
|
191
|
+
memcpy( szLinearCT+len1, szMult, len2+1 ); /* adding zero termination */
|
192
|
+
return len1+len2;
|
193
|
+
} else {
|
194
|
+
(*bOverflow) ++;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
return 0;
|
198
|
+
}
|
199
|
+
/**********************************************************************************************/
|
200
|
+
/* if num_C > 0 then nAtom does not contain C or H */
|
201
|
+
/* otherwise all elements are in alphabetic order */
|
202
|
+
int MakeHillFormula( U_CHAR *nAtom, int num_atoms,
|
203
|
+
char *szLinearCT, int nLen_szLinearCT, int num_C, int num_H, int *bOverflow )
|
204
|
+
{
|
205
|
+
char szElement[4];
|
206
|
+
int mult, compare2H;
|
207
|
+
int i, nLen, bOvfl;
|
208
|
+
U_CHAR nPrevAtom;
|
209
|
+
|
210
|
+
nLen = 0;
|
211
|
+
mult = 0;
|
212
|
+
bOvfl = 0;
|
213
|
+
nPrevAtom = (U_CHAR)-1; /* non-existent number */
|
214
|
+
|
215
|
+
|
216
|
+
if ( num_C ) {
|
217
|
+
nLen += AddElementAndCount( "C", num_C, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
218
|
+
if ( num_H ) {
|
219
|
+
nLen += AddElementAndCount( "H", num_H, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
220
|
+
num_H = 0;
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
225
|
+
|
226
|
+
if ( nPrevAtom != nAtom[i] ) {
|
227
|
+
if ( mult ) {
|
228
|
+
nLen += AddElementAndCount( szElement, mult, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
229
|
+
}
|
230
|
+
mult = 1;
|
231
|
+
if ( GetElementFormulaFromAtNum((int)nAtom[i], szElement ) ) {
|
232
|
+
return -1; /* wrong element */
|
233
|
+
}
|
234
|
+
nPrevAtom = nAtom[i];
|
235
|
+
if ( !strcmp( "C", szElement ) ) {
|
236
|
+
return -1;
|
237
|
+
}
|
238
|
+
compare2H = strcmp( "H", szElement );
|
239
|
+
if ( !compare2H ) {
|
240
|
+
return -1;
|
241
|
+
}
|
242
|
+
if ( compare2H < 0 && num_H ) {
|
243
|
+
/* H-atom should be located in front of szElement */
|
244
|
+
nLen += AddElementAndCount( "H", num_H, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
245
|
+
num_H = 0;
|
246
|
+
}
|
247
|
+
} else {
|
248
|
+
mult ++;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
if ( mult ) {
|
252
|
+
/* the last element if any */
|
253
|
+
nLen += AddElementAndCount( szElement, mult, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
254
|
+
}
|
255
|
+
if ( num_H ) {
|
256
|
+
/* if H has not been output... */
|
257
|
+
nLen += AddElementAndCount( "H", num_H, szLinearCT+nLen, nLen_szLinearCT-nLen, &bOvfl );
|
258
|
+
}
|
259
|
+
*bOverflow |= (0 != bOvfl);
|
260
|
+
return bOvfl? nLen_szLinearCT+1: nLen;
|
261
|
+
}
|
262
|
+
/**********************************************************************************************/
|
263
|
+
char *AllocateAndFillHillFormula( INChI *pINChI )
|
264
|
+
{
|
265
|
+
int num_C, num_H, nLen, nNumNonHAtoms, ret, bOverflow;
|
266
|
+
char *pHillFormula = NULL;
|
267
|
+
bOverflow = 0;
|
268
|
+
if ( !GetHillFormulaCounts( pINChI->nAtom, pINChI->nNum_H, pINChI->nNumberOfAtoms,
|
269
|
+
pINChI->nTautomer, pINChI->lenTautomer,
|
270
|
+
&num_C, &num_H, &nLen, &nNumNonHAtoms ) ) {
|
271
|
+
if ( pHillFormula = (char*)inchi_malloc( nLen+1 ) ) {
|
272
|
+
ret = MakeHillFormula( pINChI->nAtom+num_C, nNumNonHAtoms-num_C,
|
273
|
+
pHillFormula, nLen+1, num_C, num_H, &bOverflow );
|
274
|
+
if ( ret != nLen || bOverflow ) {
|
275
|
+
inchi_free( pHillFormula );
|
276
|
+
pHillFormula = NULL;
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}
|
280
|
+
return pHillFormula;
|
281
|
+
}
|
282
|
+
|
283
|
+
/************************************************************************************/
|
284
|
+
/* return value: 0 => copied to stereo bonds; 1=> Allene copied to stereocenters */
|
285
|
+
/* on input nNumberOfStereoBonds==NULL means second call, use Stereo->...Inv */
|
286
|
+
/************************************************************************************/
|
287
|
+
int Copy2StereoBondOrAllene( INChI_Stereo *Stereo, int *nNumberOfStereoCenters, int *nNumberOfStereoBonds,
|
288
|
+
AT_STEREO_DBLE *LinearCTStereoDble,
|
289
|
+
AT_NUMB *pCanonOrd, AT_RANK *pCanonRank, sp_ATOM *at, int bIsotopic )
|
290
|
+
{
|
291
|
+
int cumulene_len, j, next_j /* ordering number of the central allene atom */, next_neigh;
|
292
|
+
AT_RANK at_num;
|
293
|
+
int parity;
|
294
|
+
if ( pCanonOrd && pCanonRank ) {
|
295
|
+
j = pCanonOrd[(int)LinearCTStereoDble->at_num1-1];
|
296
|
+
/* if allene then find the central atom, at[next_j] */
|
297
|
+
if ( bIsotopic ) {
|
298
|
+
cumulene_len = BOND_CHAIN_LEN(at[j].stereo_bond_parity2[0]);
|
299
|
+
if ( cumulene_len % 2 && (1 >= MAX_NUM_STEREO_BONDS || !at[j].stereo_bond_neighbor2[1]) ) {
|
300
|
+
next_j = at[j].neighbor[(int)at[j].stereo_bond_ord2[0]];
|
301
|
+
for ( cumulene_len = (cumulene_len-1)/2; cumulene_len && 2==at[next_j].valence; cumulene_len -- ) {
|
302
|
+
next_neigh = (j == at[next_j].neighbor[0]);
|
303
|
+
j = next_j;
|
304
|
+
next_j = at[next_j].neighbor[next_neigh];
|
305
|
+
}
|
306
|
+
/* next_j is the central atom */
|
307
|
+
} else {
|
308
|
+
cumulene_len = -1; /* not an allene */
|
309
|
+
}
|
310
|
+
|
311
|
+
} else {
|
312
|
+
cumulene_len = BOND_CHAIN_LEN(at[j].stereo_bond_parity[0]);
|
313
|
+
if ( cumulene_len % 2 && (1 >= MAX_NUM_STEREO_BONDS || !at[j].stereo_bond_neighbor[1]) ) {
|
314
|
+
next_j = at[j].neighbor[(int)at[j].stereo_bond_ord[0]];
|
315
|
+
for ( cumulene_len = (cumulene_len-1)/2; cumulene_len && 2==at[next_j].valence; cumulene_len -- ) {
|
316
|
+
next_neigh = (j == at[next_j].neighbor[0]);
|
317
|
+
j = next_j;
|
318
|
+
next_j = at[next_j].neighbor[next_neigh];
|
319
|
+
}
|
320
|
+
} else {
|
321
|
+
cumulene_len = -1; /* not an allene */
|
322
|
+
}
|
323
|
+
}
|
324
|
+
if ( !cumulene_len ) {
|
325
|
+
/* allene has been found; insert new stereocenter and parity */
|
326
|
+
AT_NUMB *nNumber;
|
327
|
+
S_CHAR *t_parity;
|
328
|
+
nNumber = nNumberOfStereoBonds? Stereo->nNumber : Stereo->nNumberInv;
|
329
|
+
t_parity = nNumberOfStereoBonds? Stereo->t_parity : Stereo->t_parityInv;
|
330
|
+
at_num = pCanonRank[next_j];
|
331
|
+
parity = LinearCTStereoDble->parity;
|
332
|
+
/* free room for the new stereocenter */
|
333
|
+
for ( j = 0; j < *nNumberOfStereoCenters && Stereo->nNumber[j] < at_num; j ++ )
|
334
|
+
;
|
335
|
+
if ( j < *nNumberOfStereoCenters ) {
|
336
|
+
memmove( nNumber + j + 1, nNumber + j, (*nNumberOfStereoCenters-j)*sizeof(nNumber[0]) );
|
337
|
+
memmove( t_parity + j + 1, t_parity + j, (*nNumberOfStereoCenters-j)*sizeof(t_parity[0]) );
|
338
|
+
}
|
339
|
+
/* fill the new stereo center info */
|
340
|
+
|
341
|
+
nNumber[j] = at_num;
|
342
|
+
t_parity[j] = parity;
|
343
|
+
(*nNumberOfStereoCenters) ++;
|
344
|
+
return 1;
|
345
|
+
}
|
346
|
+
}
|
347
|
+
/* save the stereo bond info */
|
348
|
+
if ( nNumberOfStereoBonds ) {
|
349
|
+
j = *nNumberOfStereoBonds;
|
350
|
+
Stereo->b_parity[j] = LinearCTStereoDble->parity;
|
351
|
+
Stereo->nBondAtom1[j] = LinearCTStereoDble->at_num1;
|
352
|
+
Stereo->nBondAtom2[j] = LinearCTStereoDble->at_num2;
|
353
|
+
(*nNumberOfStereoBonds) ++;
|
354
|
+
}
|
355
|
+
return 0;
|
356
|
+
}
|
357
|
+
/***************************************************************************/
|
358
|
+
int CopyLinearCTStereoToINChIStereo( INChI_Stereo *Stereo,
|
359
|
+
AT_STEREO_CARB *LinearCTStereoCarb, int nLenLinearCTStereoCarb,
|
360
|
+
AT_STEREO_DBLE *LinearCTStereoDble, int nLenLinearCTStereoDble
|
361
|
+
, AT_NUMB *pCanonOrd, AT_RANK *pCanonRank, sp_ATOM *at, int bIsotopic
|
362
|
+
, AT_STEREO_CARB *LinearCTStereoCarbInv
|
363
|
+
, AT_STEREO_DBLE *LinearCTStereoDbleInv
|
364
|
+
, AT_NUMB *pCanonOrdInv, AT_RANK *pCanonRankInv )
|
365
|
+
{
|
366
|
+
int n, i, nErrorCode = 0, len;
|
367
|
+
int bAllene;
|
368
|
+
int diff;
|
369
|
+
int lenInv, bAlleneInv;
|
370
|
+
/* stereo centers */
|
371
|
+
n = Stereo->nNumberOfStereoCenters = nLenLinearCTStereoCarb;
|
372
|
+
for ( i = 0; i < n; i ++ ) {
|
373
|
+
Stereo->nNumber[i] = LinearCTStereoCarb[i].at_num;
|
374
|
+
Stereo->t_parity[i] = LinearCTStereoCarb[i].parity;
|
375
|
+
Stereo->nNumberInv[i] = LinearCTStereoCarbInv[i].at_num;
|
376
|
+
Stereo->t_parityInv[i] = LinearCTStereoCarbInv[i].parity;
|
377
|
+
}
|
378
|
+
/* stereo bonds */
|
379
|
+
n = nLenLinearCTStereoDble;
|
380
|
+
lenInv = Stereo->nNumberOfStereoCenters;
|
381
|
+
for ( i = len = 0; i < n; i ++ ) {
|
382
|
+
bAllene =
|
383
|
+
Copy2StereoBondOrAllene( Stereo, &Stereo->nNumberOfStereoCenters,
|
384
|
+
&len, LinearCTStereoDble+i, pCanonOrd, pCanonRank, at, bIsotopic );
|
385
|
+
bAlleneInv =
|
386
|
+
Copy2StereoBondOrAllene( Stereo, &lenInv,
|
387
|
+
NULL, LinearCTStereoDbleInv+i, pCanonOrdInv, pCanonRankInv, at, bIsotopic );
|
388
|
+
/* make sure double bond stereo is identical in original and inverted geometry */
|
389
|
+
/* Note: all allenes are AFTER double bonds in LinearCTStereoDble... */
|
390
|
+
if ( bAllene != bAlleneInv || !bAllene &&
|
391
|
+
CompareLinCtStereoDble ( LinearCTStereoDble+i, 1,
|
392
|
+
LinearCTStereoDbleInv+i, 1 ) ) {
|
393
|
+
nErrorCode = -4; /* double bond stereo Inv is NOT identical to Abs */
|
394
|
+
goto exit_function;
|
395
|
+
}
|
396
|
+
}
|
397
|
+
Stereo->nNumberOfStereoBonds = len;
|
398
|
+
|
399
|
+
if ( lenInv != Stereo->nNumberOfStereoCenters ) {
|
400
|
+
nErrorCode = -5; /* different number of stereo centers in Abs and Inv */
|
401
|
+
goto exit_function;
|
402
|
+
}
|
403
|
+
/* compare inverted stereocenters to absolute */
|
404
|
+
n = Stereo->nNumberOfStereoCenters;
|
405
|
+
diff = 0;
|
406
|
+
for ( i = 0, diff = 0; i < n; i ++ ) {
|
407
|
+
if ( Stereo->nNumberInv[i] != Stereo->nNumber[i] ) {
|
408
|
+
diff = (Stereo->nNumberInv[i] > Stereo->nNumber[i])? 2 : -2;
|
409
|
+
break; /* Abs != Inv */
|
410
|
+
}
|
411
|
+
if ( Stereo->t_parityInv[i] != Stereo->t_parity[i] ) {
|
412
|
+
diff = (Stereo->t_parityInv[i] > Stereo->t_parity[i])? 1 : -1;
|
413
|
+
break; /* Abs != Inv */
|
414
|
+
}
|
415
|
+
}
|
416
|
+
Stereo->nCompInv2Abs = (diff > 0)? 1 : (diff < 0)? -1 : 0;
|
417
|
+
if ( diff == -1 || diff == 1 ) {
|
418
|
+
/* the first found difference was in parities */
|
419
|
+
for ( i = 0, diff = 0; i < n; i ++ ) {
|
420
|
+
if ( Stereo->nNumberInv[i] != Stereo->nNumber[i] ) {
|
421
|
+
diff = 2; /* difference in stereo center numbering */
|
422
|
+
break;
|
423
|
+
}
|
424
|
+
/* parities can be only 1, 2, 3, 4. Therefore only mutually inverted pairs
|
425
|
+
* (t_parityInv, t_parity) = (1,2) or (2,1) statisfy conditions
|
426
|
+
* (t_parityInv != t_parity) && (t_parityInv + t_parity == 3)
|
427
|
+
*/
|
428
|
+
if ( Stereo->t_parityInv[i] == Stereo->t_parity[i] ||
|
429
|
+
Stereo->t_parityInv[i] + Stereo->t_parity[i] != 3 ) {
|
430
|
+
diff = 1; /* parities are same or different and cannot be obtained by simple inversion */
|
431
|
+
break;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
Stereo->bTrivialInv = !diff;
|
435
|
+
} else {
|
436
|
+
Stereo->bTrivialInv = 0;
|
437
|
+
}
|
438
|
+
exit_function:
|
439
|
+
|
440
|
+
return nErrorCode;
|
441
|
+
}
|
442
|
+
/***************************************************************************/
|
443
|
+
int MarkAmbiguousStereo( sp_ATOM *at, inp_ATOM *norm_at, int bIsotopic, AT_NUMB *pCanonOrd,
|
444
|
+
AT_STEREO_CARB *LinearCTStereoCarb, int nLenLinearCTStereoCarb,
|
445
|
+
AT_STEREO_DBLE *LinearCTStereoDble, int nLenLinearCTStereoDble )
|
446
|
+
{
|
447
|
+
int n, i, j1, j2, num, mark_atom, mark_bond;
|
448
|
+
|
449
|
+
if ( !pCanonOrd )
|
450
|
+
return -1;
|
451
|
+
num = 0;
|
452
|
+
n = nLenLinearCTStereoCarb;
|
453
|
+
mark_atom = bIsotopic? AMBIGUOUS_STEREO_ATOM_ISO : AMBIGUOUS_STEREO_ATOM;
|
454
|
+
for ( i = 0; i < n; i ++ ) {
|
455
|
+
/* mark ambiguous stereo centers (for displaying and "Ambiguous stereo" message) */
|
456
|
+
if ( ATOM_PARITY_NOT_UNKN(LinearCTStereoCarb[i].parity) &&
|
457
|
+
at[j1=pCanonOrd[(int)LinearCTStereoCarb[i].at_num-1]].bAmbiguousStereo ) {
|
458
|
+
at[j1].bAmbiguousStereo |= mark_atom;
|
459
|
+
norm_at[j1].bAmbiguousStereo |= mark_atom;
|
460
|
+
num ++;
|
461
|
+
}
|
462
|
+
}
|
463
|
+
|
464
|
+
n = nLenLinearCTStereoDble;
|
465
|
+
mark_bond = bIsotopic? AMBIGUOUS_STEREO_BOND_ISO : AMBIGUOUS_STEREO_BOND;
|
466
|
+
for ( i = 0; i < n; i ++ ) {
|
467
|
+
/* mark ambiguous stereo bonds or allenes (for displaying and "Ambiguous stereo" message) */
|
468
|
+
if ( ATOM_PARITY_WELL_DEF(LinearCTStereoDble[i].parity) ) {
|
469
|
+
j1=pCanonOrd[(int)LinearCTStereoDble[i].at_num1-1];
|
470
|
+
j2=pCanonOrd[(int)LinearCTStereoDble[i].at_num2-1];
|
471
|
+
if ( at[j1].bAmbiguousStereo || at[j2].bAmbiguousStereo ) {
|
472
|
+
/* if it is an allene then mark the central atom only
|
473
|
+
because the bonds should not be marked to avoid misleading
|
474
|
+
message "Ambiguous stereo: bond(s)": Allene makes a stereocenter
|
475
|
+
*/
|
476
|
+
int j1_parity = bIsotopic? at[j1].stereo_bond_parity2[0] :
|
477
|
+
at[j1].stereo_bond_parity[0];
|
478
|
+
int cumulene_len = BOND_CHAIN_LEN(j1_parity); /* 0 => double bond, 1 => allene, 2 => cumulene,..*/
|
479
|
+
if ( cumulene_len % 2 && (1 >= MAX_NUM_STEREO_BONDS ||
|
480
|
+
!(bIsotopic? at[j1].stereo_bond_neighbor2[1] :
|
481
|
+
at[j1].stereo_bond_neighbor[1] )) ) {
|
482
|
+
/* found an allene; locate its central atom */
|
483
|
+
int next_j, next_neigh;
|
484
|
+
int j = j1;
|
485
|
+
next_j = at[j].neighbor[bIsotopic? at[j].stereo_bond_ord2[0] :
|
486
|
+
at[j].stereo_bond_ord[0] ];
|
487
|
+
for ( cumulene_len = (cumulene_len-1)/2;
|
488
|
+
cumulene_len && 2==at[next_j].valence;
|
489
|
+
cumulene_len -- ) {
|
490
|
+
next_neigh = (j == at[next_j].neighbor[0]);
|
491
|
+
j = next_j;
|
492
|
+
next_j = at[next_j].neighbor[next_neigh];
|
493
|
+
}
|
494
|
+
/* next_j is the central atom */
|
495
|
+
if ( 2==at[next_j].valence ) {
|
496
|
+
at[next_j].bAmbiguousStereo |= mark_atom;
|
497
|
+
norm_at[next_j].bAmbiguousStereo |= mark_atom;
|
498
|
+
num ++;
|
499
|
+
continue; /* do not mark the cumulene "bond" endpoints */
|
500
|
+
}
|
501
|
+
}
|
502
|
+
/* not an allene, mark double bond or cumulene end atoms */
|
503
|
+
if ( at[j1].bAmbiguousStereo ) {
|
504
|
+
at[j1].bAmbiguousStereo |= mark_bond; /* ??? */
|
505
|
+
norm_at[j1].bAmbiguousStereo |= mark_bond;
|
506
|
+
num ++;
|
507
|
+
}
|
508
|
+
if ( at[j2].bAmbiguousStereo ) {
|
509
|
+
at[j2].bAmbiguousStereo |= mark_bond; /* ??? */
|
510
|
+
norm_at[j2].bAmbiguousStereo |= mark_bond;
|
511
|
+
num ++;
|
512
|
+
}
|
513
|
+
}
|
514
|
+
}
|
515
|
+
}
|
516
|
+
return num;
|
517
|
+
|
518
|
+
}
|
519
|
+
/**********************************************************************************************/
|
520
|
+
INCHI_MODE UnmarkAllUndefinedUnknownStereo( INChI_Stereo *Stereo, INCHI_MODE nUserMode )
|
521
|
+
{
|
522
|
+
INCHI_MODE nRet = 0;
|
523
|
+
int i, n;
|
524
|
+
if ( !Stereo || Stereo && !Stereo->nNumberOfStereoCenters && !Stereo->nNumberOfStereoBonds) {
|
525
|
+
return nRet;
|
526
|
+
}
|
527
|
+
|
528
|
+
/* stereocenters */
|
529
|
+
if ( !Stereo->nCompInv2Abs &&
|
530
|
+
(n=Stereo->nNumberOfStereoCenters) > 0 && (nUserMode & REQ_MODE_SC_IGN_ALL_UU) ) {
|
531
|
+
|
532
|
+
for ( i = 0; i < n && !ATOM_PARITY_WELL_DEF(Stereo->t_parity[i]); i ++ )
|
533
|
+
;
|
534
|
+
if ( i == n ) {
|
535
|
+
Stereo->nNumberOfStereoCenters = 0;
|
536
|
+
for ( i = 0; i < n; i ++ ) {
|
537
|
+
Stereo->t_parity[i] = 0;
|
538
|
+
Stereo->nNumber[i] = 0;
|
539
|
+
Stereo->t_parityInv[i] = 0;
|
540
|
+
Stereo->nNumberInv[i] = 0;
|
541
|
+
}
|
542
|
+
nRet |= REQ_MODE_SC_IGN_ALL_UU;
|
543
|
+
}
|
544
|
+
}
|
545
|
+
/* stereobonds */
|
546
|
+
if ( (n=Stereo->nNumberOfStereoBonds) > 0 && (nUserMode & REQ_MODE_SB_IGN_ALL_UU) ) {
|
547
|
+
for ( i = 0; i < n && !ATOM_PARITY_WELL_DEF(Stereo->b_parity[i]); i ++ )
|
548
|
+
;
|
549
|
+
if ( i == n ) {
|
550
|
+
Stereo->nNumberOfStereoBonds = 0;
|
551
|
+
for ( i = 0; i < n; i ++ ) {
|
552
|
+
Stereo->b_parity[i] = 0;
|
553
|
+
Stereo->nBondAtom1[i] = 0;
|
554
|
+
Stereo->nBondAtom2[i] = 0;
|
555
|
+
}
|
556
|
+
nRet |= REQ_MODE_SB_IGN_ALL_UU;
|
557
|
+
}
|
558
|
+
}
|
559
|
+
|
560
|
+
return nRet;
|
561
|
+
}
|
562
|
+
#if( defined(INCHI_LIBRARY) || ADD_CMLPP==1 )
|
563
|
+
/**********************************************************************************************/
|
564
|
+
void WriteCoord( char *str, double x )
|
565
|
+
{
|
566
|
+
if ( x < -9999999.9 ) {
|
567
|
+
sprintf( str, "%10.2e", x );
|
568
|
+
} else
|
569
|
+
if ( x < -999999.99 ) {
|
570
|
+
sprintf( str, "%10.2f", x );
|
571
|
+
} else
|
572
|
+
if ( x < -99999.999 ) {
|
573
|
+
sprintf( str, "%10.3f", x );
|
574
|
+
} else
|
575
|
+
if ( x < 99999.9999 ) {
|
576
|
+
sprintf( str, "%10.4f", x );
|
577
|
+
} else
|
578
|
+
if ( x < 999999.999 ) {
|
579
|
+
sprintf( str, "%10.3f", x );
|
580
|
+
} else
|
581
|
+
if ( x < 9999999.99 ) {
|
582
|
+
sprintf( str, "%10.2f", x );
|
583
|
+
} else
|
584
|
+
if ( x < 99999999.9 ) {
|
585
|
+
sprintf( str, "%10.1f", x );
|
586
|
+
} else {
|
587
|
+
sprintf( str, "%10.3e", x );
|
588
|
+
}
|
589
|
+
}
|
590
|
+
#endif
|
591
|
+
/* used CANON_STAT members
|
592
|
+
|
593
|
+
pCS->LinearCT
|
594
|
+
pCS->LinearCTIsotopic
|
595
|
+
pCS->LinearCTIsotopicStereoCarb
|
596
|
+
pCS->LinearCTIsotopicStereoCarbInv
|
597
|
+
pCS->LinearCTIsotopicStereoDble
|
598
|
+
pCS->LinearCTIsotopicStereoDbleInv
|
599
|
+
pCS->LinearCTIsotopicTautomer
|
600
|
+
pCS->LinearCTStereoCarb
|
601
|
+
pCS->LinearCTStereoCarbInv
|
602
|
+
pCS->LinearCTStereoDble
|
603
|
+
pCS->LinearCTStereoDbleInv
|
604
|
+
pCS->nCanonOrd
|
605
|
+
pCS->nCanonOrdIsotopic
|
606
|
+
pCS->nCanonOrdIsotopicStereo
|
607
|
+
pCS->nCanonOrdIsotopicStereoInv
|
608
|
+
pCS->nCanonOrdIsotopicStereoTaut
|
609
|
+
pCS->nCanonOrdIsotopicTaut
|
610
|
+
pCS->nCanonOrdStereo
|
611
|
+
pCS->nCanonOrdStereoInv
|
612
|
+
pCS->nCanonOrdStereoTaut
|
613
|
+
pCS->nCanonOrdTaut
|
614
|
+
pCS->nLenCanonOrd
|
615
|
+
pCS->nLenCanonOrdIsotopic
|
616
|
+
pCS->nLenCanonOrdIsotopicStereo
|
617
|
+
pCS->nLenCanonOrdIsotopicStereoTaut
|
618
|
+
pCS->nLenCanonOrdIsotopicTaut
|
619
|
+
pCS->nLenCanonOrdStereo
|
620
|
+
pCS->nLenCanonOrdStereoTaut
|
621
|
+
pCS->nLenCanonOrdTaut
|
622
|
+
pCS->nLenLinearCTAtOnly
|
623
|
+
pCS->nLenLinearCTIsotopic
|
624
|
+
pCS->nLenLinearCTIsotopicStereoCarb
|
625
|
+
pCS->nLenLinearCTIsotopicStereoDble
|
626
|
+
pCS->nLenLinearCTIsotopicTautomer
|
627
|
+
pCS->nLenLinearCTStereoCarb
|
628
|
+
pCS->nLenLinearCTStereoDble
|
629
|
+
pCS->nNum_H
|
630
|
+
pCS->nNum_H_fixed
|
631
|
+
pCS->nSymmRank
|
632
|
+
pCS->nSymmRankIsotopic
|
633
|
+
pCS->nSymmRankIsotopicTaut
|
634
|
+
pCS->nSymmRankTaut
|
635
|
+
pCS->t_group_info
|
636
|
+
pCS->t_group_info->num_t_groups
|
637
|
+
|
638
|
+
*/
|
639
|
+
/**********************************************************************************************/
|
640
|
+
int FillOutINChI( INChI *pINChI, INChI_Aux *pINChI_Aux,
|
641
|
+
int num_atoms, int num_at_tg, int num_removed_H,
|
642
|
+
sp_ATOM *at, inp_ATOM *norm_at, CANON_STAT *pCS, int bTautomeric,
|
643
|
+
INCHI_MODE nUserMode, char *pStrErrStruct )
|
644
|
+
{
|
645
|
+
int i, j, m, n, g, len, ii, ret=0;
|
646
|
+
|
647
|
+
AT_NUMB *pSymmRank, *pOrigNosInCanonOrd, *pConstitEquNumb, *pCanonOrd=NULL, *pCanonOrdInv=NULL, *pCanonOrdTaut;
|
648
|
+
T_GROUP_INFO *t_group_info = pCS->t_group_info;
|
649
|
+
T_GROUP *t_group;
|
650
|
+
int nErrorCode = 0;
|
651
|
+
AT_NUMB *pCanonRank, *pCanonRankInv; /* canonical ranks of the atoms or tautomeric groups */
|
652
|
+
AT_NUMB *pCanonRankAtoms=NULL, *pSortOrd = NULL;
|
653
|
+
AT_RANK nMinOrd;
|
654
|
+
INChI_Stereo *Stereo;
|
655
|
+
int bUseNumberingInv = 0, bUseIsotopicNumberingInv = 0;
|
656
|
+
INCHI_MODE nStereoUnmarkMode;
|
657
|
+
|
658
|
+
/*AT_NUMB *pCanonOrdNonIso = NULL, *pCanonOrdIso = NULL;*/
|
659
|
+
/*AT_NUMB *nOrigAtNosInCanonOrdNonIso = NULL, *nOrigAtNosInCanonOrdIso = NULL;*/
|
660
|
+
|
661
|
+
/* Check for warnings */
|
662
|
+
if ( pCS->nLenLinearCTStereoCarb < 0 || pCS->nLenLinearCTStereoDble < 0 ||
|
663
|
+
pCS->nLenCanonOrdStereo < 0 || pCS->nLenCanonOrdStereoTaut < 0) {
|
664
|
+
nErrorCode |= WARN_FAILED_STEREO;
|
665
|
+
}
|
666
|
+
if ( pCS->nLenLinearCTIsotopic < 0 || pCS->nLenLinearCTIsotopicTautomer < 0 ||
|
667
|
+
pCS->nLenCanonOrdIsotopic < 0 || pCS->nLenCanonOrdIsotopicTaut < 0 ) {
|
668
|
+
nErrorCode |= WARN_FAILED_ISOTOPIC;
|
669
|
+
}
|
670
|
+
if ( pCS->nLenLinearCTIsotopicStereoCarb < 0 || pCS->nLenLinearCTIsotopicStereoDble < 0 ||
|
671
|
+
pCS->nLenCanonOrdIsotopicStereo < 0 || pCS->nLenCanonOrdIsotopicStereoTaut < 0) {
|
672
|
+
nErrorCode |= WARN_FAILED_ISOTOPIC_STEREO;
|
673
|
+
}
|
674
|
+
pCanonRankAtoms = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pCanonRankAtoms[0]) );
|
675
|
+
pSortOrd = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pSortOrd[0]) ); /* must have more than num_atoms */
|
676
|
+
|
677
|
+
if ( !pCanonRankAtoms || !pSortOrd ) {
|
678
|
+
nErrorCode = 0;
|
679
|
+
ret = CT_OUT_OF_RAM; /* <BRKPT> */
|
680
|
+
pINChI->nErrorCode = pINChI_Aux->nErrorCode = CT_OUT_OF_RAM;
|
681
|
+
goto exit_function;
|
682
|
+
}
|
683
|
+
|
684
|
+
/* total charge */
|
685
|
+
for ( i = 0, n = 0; i < num_atoms+num_removed_H; i ++ ) {
|
686
|
+
n += at[i].charge;
|
687
|
+
}
|
688
|
+
pINChI->nTotalCharge = n;
|
689
|
+
|
690
|
+
/* number of atoms */
|
691
|
+
pINChI->nNumberOfAtoms = num_atoms;
|
692
|
+
pINChI_Aux->nNumberOfAtoms = num_atoms;
|
693
|
+
|
694
|
+
/* removed protons and detachable isotopic H */
|
695
|
+
if ( bTautomeric && t_group_info ) {
|
696
|
+
pINChI_Aux->nNumRemovedProtons = t_group_info->tni.nNumRemovedProtons;
|
697
|
+
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
|
698
|
+
pINChI_Aux->nNumRemovedIsotopicH[i] = t_group_info->num_iso_H[i]
|
699
|
+
+ t_group_info->tni.nNumRemovedProtonsIsotopic[i];
|
700
|
+
}
|
701
|
+
if ( pINChI_Aux->bNormalizationFlags & FLAG_FORCE_SALT_TAUT ) {
|
702
|
+
pINChI->nFlags |= INCHI_FLAG_HARD_ADD_REM_PROTON;
|
703
|
+
}
|
704
|
+
if ( pINChI_Aux->bNormalizationFlags & (FLAG_NORM_CONSIDER_TAUT &~FLAG_PROTON_CHARGE_CANCEL) ) {
|
705
|
+
AddMOLfileError(pStrErrStruct, "Proton(s) added/removed");
|
706
|
+
}
|
707
|
+
if ( pINChI_Aux->bNormalizationFlags & FLAG_PROTON_CHARGE_CANCEL ) {
|
708
|
+
AddMOLfileError(pStrErrStruct, "Charges neutralized");
|
709
|
+
}
|
710
|
+
}
|
711
|
+
|
712
|
+
/* abs or rel stereo may establish one of two canonical numberings */
|
713
|
+
if ( (pCS->nLenLinearCTStereoCarb > 0 || pCS->nLenLinearCTStereoDble > 0) &&
|
714
|
+
pCS->nLenCanonOrdStereo > 0 &&
|
715
|
+
(pCS->LinearCTStereoCarb && pCS->LinearCTStereoCarbInv ||
|
716
|
+
pCS->LinearCTStereoDble && pCS->LinearCTStereoDbleInv) &&
|
717
|
+
pCS->nCanonOrdStereo && pCS->nCanonOrdStereoInv
|
718
|
+
) {
|
719
|
+
|
720
|
+
pCanonRank = pCanonRankAtoms;
|
721
|
+
pCanonOrd = pCS->nCanonOrdStereo;
|
722
|
+
pCanonRankInv = pSortOrd;
|
723
|
+
pCanonOrdInv = pCS->nCanonOrdStereoInv;
|
724
|
+
Stereo = pINChI->Stereo;
|
725
|
+
for ( i = 0; i < num_at_tg; i ++ ) {
|
726
|
+
pCanonRankInv[pCanonOrdInv[i]] =
|
727
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
728
|
+
}
|
729
|
+
/********************************************************************/
|
730
|
+
/* copy stereo bonds and stereo centers; compare Inv and Abs stereo */
|
731
|
+
/********************************************************************/
|
732
|
+
nErrorCode = CopyLinearCTStereoToINChIStereo( Stereo,
|
733
|
+
pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb,
|
734
|
+
pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble
|
735
|
+
, pCanonOrd, pCanonRank, at, 0 /* non-isotopic */
|
736
|
+
, pCS->LinearCTStereoCarbInv
|
737
|
+
, pCS->LinearCTStereoDbleInv
|
738
|
+
, pCanonOrdInv, pCanonRankInv );
|
739
|
+
|
740
|
+
if ( Stereo->t_parityInv && Stereo->nNumberInv ) {
|
741
|
+
if ( nUserMode & REQ_MODE_RELATIVE_STEREO ) {
|
742
|
+
pINChI->nFlags |= INCHI_FLAG_REL_STEREO;
|
743
|
+
}
|
744
|
+
if ( nUserMode & REQ_MODE_RACEMIC_STEREO ) {
|
745
|
+
pINChI->nFlags |= INCHI_FLAG_RAC_STEREO;
|
746
|
+
}
|
747
|
+
if ( Stereo->nCompInv2Abs ) {
|
748
|
+
if ( Stereo->nCompInv2Abs == -1 ) {
|
749
|
+
/* switch pointers in Stereo so that the stereo becomes the smallest (relative) */
|
750
|
+
/* flag Stereo->nCompInv2Abs == -1 will keep track of this exchange */
|
751
|
+
AT_NUMB *nNumberInv = Stereo->nNumberInv;
|
752
|
+
S_CHAR *t_parityInv = Stereo->t_parityInv;
|
753
|
+
Stereo->nNumberInv = Stereo->nNumber;
|
754
|
+
Stereo->t_parityInv = Stereo->t_parity;
|
755
|
+
Stereo->nNumber = nNumberInv;
|
756
|
+
Stereo->t_parity = t_parityInv;
|
757
|
+
/* switch pointers to set rel. stereo to pINChI_Aux->nOrigAtNosInCanonOrd
|
758
|
+
and inv. stereo to pINChI_Aux->nOrigAtNosInCanonOrdInv */
|
759
|
+
switch_ptrs( &pCanonRank, &pCanonRankInv );
|
760
|
+
switch_ptrs( &pCanonOrd, &pCanonOrdInv );
|
761
|
+
bUseNumberingInv = 1; /* use inverted stereo numbering instead of normal */
|
762
|
+
}
|
763
|
+
}
|
764
|
+
}
|
765
|
+
|
766
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
767
|
+
pINChI_Aux->nOrigAtNosInCanonOrdInv[i] = at[pCanonOrdInv[i]].orig_at_number;
|
768
|
+
pINChI_Aux->nOrigAtNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
|
769
|
+
}
|
770
|
+
if ( bUseNumberingInv ) {
|
771
|
+
/* switch ptrs back to avoid confusion */
|
772
|
+
switch_ptrs( &pCanonRank, &pCanonRankInv );
|
773
|
+
switch_ptrs( &pCanonOrd, &pCanonOrdInv );
|
774
|
+
/* save inverted stereo ranks & order because it represents the smallest (relative) */
|
775
|
+
memcpy( pCanonRank, pCanonRankInv, num_at_tg * sizeof(pCanonRank[0]) );
|
776
|
+
/* change pCS->nCanonOrdStereo[] to inverted: */
|
777
|
+
memcpy( pCanonOrd, pCanonOrdInv, num_at_tg * sizeof(pCanonOrd[0]) );
|
778
|
+
}
|
779
|
+
pCanonRankInv = NULL;
|
780
|
+
pCanonOrdInv = NULL;
|
781
|
+
pOrigNosInCanonOrd = NULL;
|
782
|
+
|
783
|
+
} else { /*------------------------------ no stereo */
|
784
|
+
|
785
|
+
pCanonOrd = pCS->nLenCanonOrdStereo > 0? pCS->nCanonOrdStereo :
|
786
|
+
pCS->nLenCanonOrd > 0? pCS->nCanonOrd : NULL;
|
787
|
+
pCanonRank = pCanonRankAtoms;
|
788
|
+
pOrigNosInCanonOrd = pINChI_Aux->nOrigAtNosInCanonOrd;
|
789
|
+
if ( pCanonOrd && pCanonRank ) {
|
790
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
791
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
792
|
+
pOrigNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
|
793
|
+
}
|
794
|
+
for ( ; i < num_at_tg; i ++ ) {
|
795
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
796
|
+
}
|
797
|
+
}
|
798
|
+
}
|
799
|
+
/*pCanonOrdNonIso = pCanonOrd;*/ /* save for aux info */
|
800
|
+
|
801
|
+
|
802
|
+
if ( pINChI_Aux->OrigInfo ) {
|
803
|
+
/* charges, radicals, valences */
|
804
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
805
|
+
ii = pCanonOrd[i];
|
806
|
+
if ( norm_at[ii].valence || norm_at[ii].num_H ) {
|
807
|
+
pINChI_Aux->OrigInfo[i].cCharge = norm_at[ii].charge;
|
808
|
+
pINChI_Aux->OrigInfo[i].cRadical = (norm_at[ii].radical==RADICAL_SINGLET)? 0 :
|
809
|
+
(norm_at[ii].radical==RADICAL_DOUBLET)? 1 :
|
810
|
+
(norm_at[ii].radical==RADICAL_TRIPLET)? 2 :
|
811
|
+
norm_at[ii].radical? 3 : 0 ;
|
812
|
+
pINChI_Aux->OrigInfo[i].cUnusualValence =
|
813
|
+
get_unusual_el_valence( norm_at[ii].el_number, norm_at[ii].charge, norm_at[ii].radical,
|
814
|
+
norm_at[ii].chem_bonds_valence, norm_at[ii].num_H, norm_at[ii].valence );
|
815
|
+
} else {
|
816
|
+
/* charge of a single atom component is in the INChI; valence = 0 is standard */
|
817
|
+
pINChI_Aux->OrigInfo[i].cRadical = (norm_at[ii].radical==RADICAL_SINGLET)? 0 :
|
818
|
+
(norm_at[ii].radical==RADICAL_DOUBLET)? 1 :
|
819
|
+
(norm_at[ii].radical==RADICAL_TRIPLET)? 2 :
|
820
|
+
norm_at[ii].radical? 3 : 0 ;
|
821
|
+
}
|
822
|
+
|
823
|
+
}
|
824
|
+
}
|
825
|
+
|
826
|
+
/* non-isotopic canonical numbers and equivalence of atoms (Aux) */
|
827
|
+
pConstitEquNumb = pINChI_Aux->nConstitEquNumbers; /* contitutional equivalence */
|
828
|
+
pSymmRank = pCS->nSymmRank;
|
829
|
+
if ( pCanonOrd && pCanonRank && pSymmRank && pConstitEquNumb ) {
|
830
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
831
|
+
pConstitEquNumb[i] = pSymmRank[pCanonOrd[i]]; /* constit. equ. ranks in order of canonical numbers */
|
832
|
+
pSortOrd[i] = i;
|
833
|
+
}
|
834
|
+
for ( ; i < num_at_tg; i ++ ) {
|
835
|
+
pSortOrd[i] = MAX_ATOMS; /* for debugging only */
|
836
|
+
}
|
837
|
+
pn_RankForSort = pConstitEquNumb;
|
838
|
+
qsort( pSortOrd, num_atoms, sizeof(pSortOrd[0]), CompRanksOrd );
|
839
|
+
for ( i = 0, nMinOrd = pSortOrd[0], j = 1; j <= num_atoms; j ++ ) {
|
840
|
+
if ( j == num_atoms || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]] ) {
|
841
|
+
nMinOrd ++;
|
842
|
+
if ( j - i > 1 ) {
|
843
|
+
/* found a sequence of equivalent atoms: i..j-1 */
|
844
|
+
while ( i < j ) {
|
845
|
+
pConstitEquNumb[pSortOrd[i++]] = nMinOrd; /* = min. canon. rank in the group of equ. atoms */
|
846
|
+
}
|
847
|
+
/* at this point j == i */
|
848
|
+
} else {
|
849
|
+
pConstitEquNumb[pSortOrd[i++]] = 0; /* means the atom is not equivalent to any other */
|
850
|
+
}
|
851
|
+
nMinOrd = pSortOrd[j]; /* at the end j = num_atoms */
|
852
|
+
}
|
853
|
+
}
|
854
|
+
} else {
|
855
|
+
nErrorCode |= ERR_NO_CANON_RESULTS;
|
856
|
+
ret = -1; /* program error; no breakpoint here */
|
857
|
+
goto exit_function;
|
858
|
+
}
|
859
|
+
/* atomic numbers from the Periodic Table */
|
860
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
861
|
+
pINChI->nAtom[i] = (int)at[pCanonOrd[i]].el_number;
|
862
|
+
}
|
863
|
+
/* connection table: atoms only (before 7-29-2003 pCS->LinearCT2 contained non-isotopic CT) */
|
864
|
+
if ( pCS->nLenLinearCTAtOnly <= 0 || !pCS->LinearCT || !pINChI->nConnTable ) {
|
865
|
+
nErrorCode |= ERR_NO_CANON_RESULTS;
|
866
|
+
ret = -2;
|
867
|
+
goto exit_function;
|
868
|
+
}
|
869
|
+
memcpy( pINChI->nConnTable, pCS->LinearCT, sizeof(pINChI->nConnTable[0])*pCS->nLenLinearCTAtOnly);
|
870
|
+
pINChI->lenConnTable = pCS->nLenLinearCTAtOnly;
|
871
|
+
|
872
|
+
/* tautomeric group(s) canonical representation */
|
873
|
+
len = 0;
|
874
|
+
if ( bTautomeric && 0 < (n = SortTautomerGroupsAndEndpoints( t_group_info, num_atoms, num_at_tg, pCanonRank )) ) {
|
875
|
+
/* SortTautomerGroupsAndEndpoints() produces canonically ordered t-groups */
|
876
|
+
pINChI->nFlags |= (t_group_info->bTautFlagsDone & TG_FLAG_ALL_SALT_DONE)? INCHI_FLAG_ACID_TAUT : 0;
|
877
|
+
/* number of tautomeric groups */
|
878
|
+
pINChI->nTautomer[len ++] = (AT_NUMB)n;
|
879
|
+
/* store each tautomeric group, one by one */
|
880
|
+
for ( i = 0; i < n; i ++ ) {
|
881
|
+
g = (int)t_group_info->tGroupNumber[i]; /* original group numbers in sorted order */
|
882
|
+
t_group = t_group_info->t_group + g; /* pointer to the tautomeric group */
|
883
|
+
/* NumAt+INCHI_T_NUM_MOVABLE (group length excluding this number) */
|
884
|
+
pINChI->nTautomer[len ++] = t_group->nNumEndpoints+INCHI_T_NUM_MOVABLE;
|
885
|
+
/* Num(H), Num(-) */
|
886
|
+
for ( j = 0; j < INCHI_T_NUM_MOVABLE && j < T_NUM_NO_ISOTOPIC; j ++ )
|
887
|
+
pINChI->nTautomer[len ++] = t_group->num[j];
|
888
|
+
for ( j = T_NUM_NO_ISOTOPIC; j < INCHI_T_NUM_MOVABLE; j ++ )
|
889
|
+
pINChI->nTautomer[len ++] = 0; /* should not happen */
|
890
|
+
/* tautomeric group endpoint canonical numbers, pre-sorted in ascending order */
|
891
|
+
for ( j = (int)t_group->nFirstEndpointAtNoPos,
|
892
|
+
m = j + (int)t_group->nNumEndpoints; j < m; j ++ ) {
|
893
|
+
pINChI->nTautomer[len ++] = pCanonRank[(int)t_group_info->nEndpointAtomNumber[j]]; /* At[j] */
|
894
|
+
}
|
895
|
+
}
|
896
|
+
pINChI->lenTautomer = len;
|
897
|
+
pINChI_Aux->nNumberOfTGroups = n;
|
898
|
+
} else {
|
899
|
+
pINChI->lenTautomer = 0;
|
900
|
+
pINChI_Aux->nNumberOfTGroups = 0;
|
901
|
+
if ( t_group_info && ((t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT) ||
|
902
|
+
t_group_info->nNumIsotopicEndpoints>1 &&
|
903
|
+
(t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE)))
|
904
|
+
) {
|
905
|
+
/* only protons (re)moved or added */
|
906
|
+
pINChI->lenTautomer = 1;
|
907
|
+
pINChI->nTautomer[0] = 0;
|
908
|
+
}
|
909
|
+
}
|
910
|
+
|
911
|
+
/* number of H (excluding tautomeric) */
|
912
|
+
if ( pCS->nNum_H ) {
|
913
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
914
|
+
pINChI->nNum_H[i] = pCS->nNum_H[i];
|
915
|
+
}
|
916
|
+
}
|
917
|
+
/* number of fixed H (tautomeric H in non-tautomeric representation) */
|
918
|
+
if ( pCS->nNum_H_fixed && !pINChI->lenTautomer ) {
|
919
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
920
|
+
pINChI->nNum_H_fixed[i] = pCS->nNum_H_fixed[i];
|
921
|
+
pINChI->nNum_H[i] += pCS->nNum_H_fixed[i];
|
922
|
+
}
|
923
|
+
}
|
924
|
+
|
925
|
+
/***********************************************************
|
926
|
+
* tautomeric group(s) numbering and symmetry;
|
927
|
+
* should not depend on switching to rel. stereo numbering
|
928
|
+
*/
|
929
|
+
if ( pINChI->lenTautomer && (n=pINChI_Aux->nNumberOfTGroups) ) {
|
930
|
+
pCanonOrdTaut = pCS->nLenCanonOrdStereoTaut > 0? pCS->nCanonOrdStereoTaut :
|
931
|
+
pCS->nLenCanonOrdTaut > 0? pCS->nCanonOrdTaut : NULL;
|
932
|
+
pConstitEquNumb = pINChI_Aux->nConstitEquTGroupNumbers;
|
933
|
+
pSymmRank = pCS->nSymmRankTaut;
|
934
|
+
if ( pCanonOrdTaut && pSymmRank && pConstitEquNumb ) {
|
935
|
+
for ( i = 0; i < n; i ++ ) {
|
936
|
+
pConstitEquNumb[i] = pSymmRank[pCanonOrdTaut[i]];
|
937
|
+
pSortOrd[i] = i;
|
938
|
+
}
|
939
|
+
pn_RankForSort = pConstitEquNumb;
|
940
|
+
qsort( pSortOrd, n, sizeof(pSortOrd[0]), CompRanksOrd );
|
941
|
+
for ( i = 0, nMinOrd = pSortOrd[0], j = 1; j <= n; j ++ ) {
|
942
|
+
if ( j == n || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]] ) {
|
943
|
+
nMinOrd ++; /* make is start from 1, not from zero */
|
944
|
+
if ( j - i > 1 ) {
|
945
|
+
/* found a sequence of more than one equivalent t-groups: i..j-1 */
|
946
|
+
while ( i < j ) {
|
947
|
+
pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
|
948
|
+
}
|
949
|
+
} else {
|
950
|
+
pConstitEquNumb[pSortOrd[i++]] = 0;
|
951
|
+
}
|
952
|
+
nMinOrd = pSortOrd[j]; /* at the end j == n */
|
953
|
+
}
|
954
|
+
}
|
955
|
+
}
|
956
|
+
}
|
957
|
+
|
958
|
+
/* Allocate and fill Hill formula */
|
959
|
+
if ( !(pINChI->szHillFormula = AllocateAndFillHillFormula( pINChI ) ) ) {
|
960
|
+
nErrorCode = 0;
|
961
|
+
ret = CT_OUT_OF_RAM; /* <BRKPT> */
|
962
|
+
pINChI->nErrorCode = pINChI_Aux->nErrorCode = CT_OUT_OF_RAM;
|
963
|
+
goto exit_function;
|
964
|
+
}
|
965
|
+
|
966
|
+
if ( nStereoUnmarkMode = UnmarkAllUndefinedUnknownStereo( pINChI->Stereo, nUserMode ) ) {
|
967
|
+
pINChI->nFlags |= (nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU)? INCHI_FLAG_SC_IGN_ALL_UU : 0;
|
968
|
+
pINChI->nFlags |= (nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU)? INCHI_FLAG_SB_IGN_ALL_UU : 0;
|
969
|
+
if ( (nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU) ||
|
970
|
+
(nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU) ) {
|
971
|
+
AddMOLfileError(pStrErrStruct, "Omitted undefined stereo");
|
972
|
+
}
|
973
|
+
}
|
974
|
+
|
975
|
+
/*************************/
|
976
|
+
/* mark ambiguous stereo */
|
977
|
+
/*************************/
|
978
|
+
MarkAmbiguousStereo( at, norm_at, 0 /* non-isotopic */, pCanonOrd,
|
979
|
+
pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb,
|
980
|
+
pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble );
|
981
|
+
|
982
|
+
|
983
|
+
/************************************************************************
|
984
|
+
*
|
985
|
+
* isotopic part
|
986
|
+
*/
|
987
|
+
/* abs or rel stereo may establish one of two canonical numberings */
|
988
|
+
if ( (pCS->nLenLinearCTIsotopicStereoCarb > 0 || pCS->nLenLinearCTIsotopicStereoDble > 0) &&
|
989
|
+
pCS->nLenCanonOrdIsotopicStereo > 0 &&
|
990
|
+
(pCS->LinearCTIsotopicStereoCarb && pCS->LinearCTIsotopicStereoCarbInv ||
|
991
|
+
pCS->LinearCTIsotopicStereoDble && pCS->LinearCTIsotopicStereoDbleInv) &&
|
992
|
+
pCS->nCanonOrdIsotopicStereo && pCS->nCanonOrdIsotopicStereoInv
|
993
|
+
) {
|
994
|
+
/* found isotopic stereo */
|
995
|
+
pCanonRank = pCanonRankAtoms;
|
996
|
+
pCanonOrd = pCS->nCanonOrdIsotopicStereo;
|
997
|
+
pCanonRankInv = pSortOrd;
|
998
|
+
pCanonOrdInv = pCS->nCanonOrdIsotopicStereoInv;
|
999
|
+
Stereo = pINChI->StereoIsotopic;
|
1000
|
+
for ( i = 0; i < num_at_tg; i ++ ) {
|
1001
|
+
pCanonRankInv[pCanonOrdInv[i]] =
|
1002
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
1003
|
+
}
|
1004
|
+
/********************************************************************/
|
1005
|
+
/* copy stereo bonds and stereo centers; compare Inv and Abs stereo */
|
1006
|
+
/********************************************************************/
|
1007
|
+
nErrorCode = CopyLinearCTStereoToINChIStereo( Stereo,
|
1008
|
+
pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb,
|
1009
|
+
pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble
|
1010
|
+
, pCanonOrd, pCanonRank, at, 1 /* isotopic */
|
1011
|
+
, pCS->LinearCTIsotopicStereoCarbInv
|
1012
|
+
, pCS->LinearCTIsotopicStereoDbleInv
|
1013
|
+
, pCanonOrdInv, pCanonRankInv );
|
1014
|
+
|
1015
|
+
if ( Stereo->t_parityInv && Stereo->nNumberInv ) {
|
1016
|
+
if ( nUserMode & REQ_MODE_RELATIVE_STEREO ) {
|
1017
|
+
pINChI->nFlags |= INCHI_FLAG_REL_STEREO;
|
1018
|
+
}
|
1019
|
+
if ( nUserMode & REQ_MODE_RACEMIC_STEREO ) {
|
1020
|
+
pINChI->nFlags |= INCHI_FLAG_RAC_STEREO;
|
1021
|
+
}
|
1022
|
+
if ( Stereo->nCompInv2Abs ) {
|
1023
|
+
if ( Stereo->nCompInv2Abs == -1 ) {
|
1024
|
+
/* switch pointers so that the stereo becomes the smallest (relative) */
|
1025
|
+
/* flag Stereo->nCompInv2Abs == -1 will keep track of this exchange */
|
1026
|
+
AT_NUMB *nNumberInv = Stereo->nNumberInv;
|
1027
|
+
S_CHAR *t_parityInv = Stereo->t_parityInv;
|
1028
|
+
Stereo->nNumberInv = Stereo->nNumber;
|
1029
|
+
Stereo->t_parityInv = Stereo->t_parity;
|
1030
|
+
Stereo->nNumber = nNumberInv;
|
1031
|
+
Stereo->t_parity = t_parityInv;
|
1032
|
+
switch_ptrs( &pCanonRank, &pCanonRankInv );
|
1033
|
+
switch_ptrs( &pCanonOrd, &pCanonOrdInv );
|
1034
|
+
bUseIsotopicNumberingInv = 1;
|
1035
|
+
}
|
1036
|
+
}
|
1037
|
+
}
|
1038
|
+
|
1039
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
1040
|
+
pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv[i] = at[pCanonOrdInv[i]].orig_at_number;
|
1041
|
+
pINChI_Aux->nIsotopicOrigAtNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
|
1042
|
+
}
|
1043
|
+
if ( bUseIsotopicNumberingInv ) {
|
1044
|
+
switch_ptrs( &pCanonRank, &pCanonRankInv );
|
1045
|
+
switch_ptrs( &pCanonOrd, &pCanonOrdInv );
|
1046
|
+
memcpy( pCanonRank, pCanonRankInv, num_at_tg * sizeof(pCanonRank[0]) );
|
1047
|
+
memcpy( pCanonOrd, pCanonOrdInv, num_at_tg * sizeof(pCanonOrd[0]) );
|
1048
|
+
}
|
1049
|
+
pCanonRankInv = NULL;
|
1050
|
+
pCanonOrdInv = NULL;
|
1051
|
+
pOrigNosInCanonOrd = NULL;
|
1052
|
+
|
1053
|
+
} else {
|
1054
|
+
/* no isotopic stereo */
|
1055
|
+
pCanonOrd = pCS->nLenCanonOrdIsotopicStereo > 0? pCS->nCanonOrdIsotopicStereo :
|
1056
|
+
pCS->nLenCanonOrdIsotopic > 0? pCS->nCanonOrdIsotopic : NULL;
|
1057
|
+
pCanonRank = pCanonRankAtoms;
|
1058
|
+
pOrigNosInCanonOrd = pINChI_Aux->nIsotopicOrigAtNosInCanonOrd;
|
1059
|
+
if ( pCanonOrd && pCanonRank ) {
|
1060
|
+
for ( i = 0; i < num_atoms; i ++ ) { /* Fix13 -- out of bounds */
|
1061
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
1062
|
+
pOrigNosInCanonOrd[i] = at[pCanonOrd[i]].orig_at_number;
|
1063
|
+
}
|
1064
|
+
for ( ; i < num_at_tg; i ++ ) { /* Fix13 -- out of bounds */
|
1065
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
1066
|
+
}
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
/*pCanonOrdIso = pCanonOrd;*/
|
1070
|
+
|
1071
|
+
pConstitEquNumb = pINChI_Aux->nConstitEquIsotopicNumbers;
|
1072
|
+
pSymmRank = pCS->nSymmRankIsotopic;
|
1073
|
+
if ( pCanonOrd && pCanonRank && pConstitEquNumb && pSymmRank ) {
|
1074
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
1075
|
+
pConstitEquNumb[i] = pSymmRank[pCanonOrd[i]];
|
1076
|
+
pSortOrd[i] = i;
|
1077
|
+
}
|
1078
|
+
for ( ; i < num_at_tg; i ++ ) {
|
1079
|
+
pSortOrd[i] = i;
|
1080
|
+
}
|
1081
|
+
pn_RankForSort = pConstitEquNumb;
|
1082
|
+
qsort( pSortOrd, num_atoms, sizeof(pSortOrd[0]), CompRanksOrd );
|
1083
|
+
for ( i = 0, nMinOrd = pSortOrd[0], j = 1; j <= num_atoms; j ++ ) {
|
1084
|
+
if ( j == num_atoms || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]] ) {
|
1085
|
+
nMinOrd ++;
|
1086
|
+
if ( j - i > 1 ) {
|
1087
|
+
/* found a sequence of equivalent atoms: i..j-1 */
|
1088
|
+
while ( i < j ) {
|
1089
|
+
pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
|
1090
|
+
}
|
1091
|
+
} else {
|
1092
|
+
pConstitEquNumb[pSortOrd[i++]] = 0; /* nMinOrd; */
|
1093
|
+
}
|
1094
|
+
nMinOrd = pSortOrd[j];
|
1095
|
+
}
|
1096
|
+
}
|
1097
|
+
} else {
|
1098
|
+
goto exit_function; /* no isotopic info available */
|
1099
|
+
}
|
1100
|
+
/* isotopic atoms */
|
1101
|
+
n = pINChI->nNumberOfIsotopicAtoms = pCS->nLenLinearCTIsotopic;
|
1102
|
+
for ( i = 0; i < n; i ++ ) {
|
1103
|
+
pINChI->IsotopicAtom[i].nAtomNumber = pCS->LinearCTIsotopic[i].at_num;
|
1104
|
+
pINChI->IsotopicAtom[i].nIsoDifference = pCS->LinearCTIsotopic[i].iso_atw_diff;
|
1105
|
+
pINChI->IsotopicAtom[i].nNum_H = pCS->LinearCTIsotopic[i].num_1H;
|
1106
|
+
pINChI->IsotopicAtom[i].nNum_D = pCS->LinearCTIsotopic[i].num_D;
|
1107
|
+
pINChI->IsotopicAtom[i].nNum_T = pCS->LinearCTIsotopic[i].num_T;
|
1108
|
+
}
|
1109
|
+
/* isotopic tautomeric groups */
|
1110
|
+
n = pINChI->nNumberOfIsotopicTGroups = pCS->nLenLinearCTIsotopicTautomer;
|
1111
|
+
for ( i = 0; i < n; i ++ ) {
|
1112
|
+
pINChI->IsotopicTGroup[i].nTGroupNumber = pCS->LinearCTIsotopicTautomer[i].tgroup_num;
|
1113
|
+
pINChI->IsotopicTGroup[i].nNum_H = pCS->LinearCTIsotopicTautomer[i].num[2];
|
1114
|
+
pINChI->IsotopicTGroup[i].nNum_D = pCS->LinearCTIsotopicTautomer[i].num[1];
|
1115
|
+
pINChI->IsotopicTGroup[i].nNum_T = pCS->LinearCTIsotopicTautomer[i].num[0];
|
1116
|
+
}
|
1117
|
+
/* atoms that may exchange isotopic H-atoms */
|
1118
|
+
if ( pCS->nExchgIsoH && pINChI->nPossibleLocationsOfIsotopicH ) {
|
1119
|
+
for ( i = 0, j = 1; i < num_atoms; i ++ ) {
|
1120
|
+
if ( pCS->nExchgIsoH[i] ) {
|
1121
|
+
pINChI->nPossibleLocationsOfIsotopicH[j++] = (AT_NUMB)(i+1); /* canonical number */
|
1122
|
+
}
|
1123
|
+
}
|
1124
|
+
pINChI->nPossibleLocationsOfIsotopicH[0] = (AT_NUMB)j; /* length including the 0th element */
|
1125
|
+
}
|
1126
|
+
|
1127
|
+
if ( nStereoUnmarkMode = UnmarkAllUndefinedUnknownStereo( pINChI->StereoIsotopic, nUserMode ) ) {
|
1128
|
+
pINChI->nFlags |= (nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU)? INCHI_FLAG_SC_IGN_ALL_ISO_UU : 0;
|
1129
|
+
pINChI->nFlags |= (nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU)? INCHI_FLAG_SC_IGN_ALL_ISO_UU : 0;
|
1130
|
+
if ( (nStereoUnmarkMode & REQ_MODE_SC_IGN_ALL_UU) ||
|
1131
|
+
(nStereoUnmarkMode & REQ_MODE_SB_IGN_ALL_UU) ) {
|
1132
|
+
AddMOLfileError(pStrErrStruct, "Omitted undefined stereo");
|
1133
|
+
}
|
1134
|
+
}
|
1135
|
+
/* mark ambiguous stereo */
|
1136
|
+
MarkAmbiguousStereo( at, norm_at, 1 /* isotopic */, pCanonOrd,
|
1137
|
+
pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb,
|
1138
|
+
pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble );
|
1139
|
+
|
1140
|
+
/***********************************************************
|
1141
|
+
* isotopic tautomeric group(s) numbering and symmetry;
|
1142
|
+
* should not depend on switching to rel. stereo numbering
|
1143
|
+
*/
|
1144
|
+
if ( pINChI->lenTautomer && pINChI_Aux->nConstitEquIsotopicTGroupNumbers && pCS->nSymmRankIsotopicTaut &&
|
1145
|
+
(pCS->nLenLinearCTIsotopic || pCS->nLenLinearCTIsotopicTautomer) &&
|
1146
|
+
t_group_info && t_group_info->num_t_groups > 0 ) {
|
1147
|
+
n = t_group_info->num_t_groups;
|
1148
|
+
pCanonOrdTaut = pCS->nLenCanonOrdIsotopicStereoTaut > 0?
|
1149
|
+
(n=pCS->nLenCanonOrdIsotopicStereoTaut, pCS->nCanonOrdIsotopicStereoTaut) :
|
1150
|
+
pCS->nLenCanonOrdIsotopicTaut > 0?
|
1151
|
+
(n=pCS->nLenCanonOrdIsotopicTaut,pCS->nCanonOrdIsotopicTaut) : (n=0,(AT_RANK*)NULL);
|
1152
|
+
pConstitEquNumb = pINChI_Aux->nConstitEquIsotopicTGroupNumbers;
|
1153
|
+
pSymmRank = pCS->nSymmRankIsotopicTaut;
|
1154
|
+
if ( pCanonOrdTaut && pSymmRank && pConstitEquNumb && n > 0 ) {
|
1155
|
+
for ( i = 0; i < n; i ++ ) {
|
1156
|
+
pConstitEquNumb[i] = pSymmRank[pCanonOrdTaut[i]];
|
1157
|
+
pSortOrd[i] = i;
|
1158
|
+
}
|
1159
|
+
pn_RankForSort = pConstitEquNumb;
|
1160
|
+
qsort( pSortOrd, n, sizeof(pSortOrd[0]), CompRanksOrd );
|
1161
|
+
for ( i = 0, nMinOrd = pSortOrd[0], j = 1; j <= n; j ++ ) {
|
1162
|
+
if ( j == n || pConstitEquNumb[pSortOrd[i]] != pConstitEquNumb[pSortOrd[j]] ) {
|
1163
|
+
nMinOrd ++;
|
1164
|
+
if ( j - i > 1 ) {
|
1165
|
+
/* found a sequence of equivalent t-groups: i..j-1 */
|
1166
|
+
while ( i < j ) {
|
1167
|
+
pConstitEquNumb[pSortOrd[i++]] = nMinOrd;
|
1168
|
+
}
|
1169
|
+
} else {
|
1170
|
+
pConstitEquNumb[pSortOrd[i++]] = 0; /* nMinOrd; */
|
1171
|
+
}
|
1172
|
+
nMinOrd = pSortOrd[j]; /* at the end j = n */
|
1173
|
+
}
|
1174
|
+
}
|
1175
|
+
}
|
1176
|
+
}
|
1177
|
+
|
1178
|
+
|
1179
|
+
exit_function:
|
1180
|
+
if ( pCanonRankAtoms )
|
1181
|
+
inchi_free( pCanonRankAtoms );
|
1182
|
+
if ( pSortOrd )
|
1183
|
+
inchi_free( pSortOrd );
|
1184
|
+
|
1185
|
+
pINChI->nErrorCode |= nErrorCode;
|
1186
|
+
pINChI_Aux->nErrorCode |= nErrorCode;
|
1187
|
+
|
1188
|
+
return ret;
|
1189
|
+
}
|