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/ichimake.c
ADDED
@@ -0,0 +1,3812 @@
|
|
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
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
18
|
+
#include "ichitime.h"
|
19
|
+
#endif
|
20
|
+
#include "inpdef.h"
|
21
|
+
#include "ichi.h"
|
22
|
+
#include "strutil.h"
|
23
|
+
#include "util.h"
|
24
|
+
#include "extr_ct.h"
|
25
|
+
#include "ichitaut.h"
|
26
|
+
#include "ichinorm.h"
|
27
|
+
#include "ichicant.h"
|
28
|
+
#include "ichicano.h"
|
29
|
+
#include "ichicomn.h"
|
30
|
+
|
31
|
+
#include "ichicomp.h"
|
32
|
+
#include "ichimain.h"
|
33
|
+
#include "ichimake.h"
|
34
|
+
#include "ichister.h"
|
35
|
+
|
36
|
+
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at );
|
37
|
+
int GetElementAndCount( const char **f, char *szEl, int *count );
|
38
|
+
int CompareHillFormulas( const char *f1, const char *f2 );
|
39
|
+
int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 );
|
40
|
+
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 );
|
41
|
+
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
|
42
|
+
AT_NUMB *nOrigAtNosInCanonOrd, int num_at );
|
43
|
+
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
|
44
|
+
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
|
45
|
+
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
|
46
|
+
AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
|
47
|
+
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode);
|
48
|
+
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
|
49
|
+
int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers);
|
50
|
+
|
51
|
+
int CheckCanonNumberingCorrectness(
|
52
|
+
int num_atoms, int num_at_tg,
|
53
|
+
sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
|
54
|
+
char *pStrErrStruct );
|
55
|
+
|
56
|
+
static int CompareDfsDescendants4CT( const void *a1, const void *a2 );
|
57
|
+
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo );
|
58
|
+
|
59
|
+
|
60
|
+
#if( TEST_RENUMB_ATOMS == 1 ) /* { */
|
61
|
+
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 );
|
62
|
+
#endif
|
63
|
+
|
64
|
+
/**********************************************************************************************/
|
65
|
+
int inp2spATOM( inp_ATOM *inp_at, int num_inp_at, sp_ATOM *at )
|
66
|
+
{
|
67
|
+
int i, j, val;
|
68
|
+
memset( at, 0, sizeof(at[0])*num_inp_at );
|
69
|
+
for ( i = 0; i < num_inp_at; i ++ ) {
|
70
|
+
strncpy( at[i].elname, inp_at[i].elname, sizeof(at[0].elname) );
|
71
|
+
at[i].el_number = (U_CHAR)get_periodic_table_number( at[i].elname );
|
72
|
+
val = at[i].valence = inp_at[i].valence;
|
73
|
+
for ( j = 0; j < val; j ++ ) {
|
74
|
+
at[i].neighbor[j] = inp_at[i].neighbor[j];
|
75
|
+
at[i].bond_type[j] = inp_at[i].bond_type[j];
|
76
|
+
}
|
77
|
+
at[i].chem_bonds_valence = inp_at[i].chem_bonds_valence;
|
78
|
+
at[i].orig_at_number = inp_at[i].orig_at_number;
|
79
|
+
at[i].orig_compt_at_numb= inp_at[i].orig_compt_at_numb;
|
80
|
+
at[i].endpoint = inp_at[i].endpoint;
|
81
|
+
at[i].iso_atw_diff = inp_at[i].iso_atw_diff;
|
82
|
+
at[i].num_H = inp_at[i].num_H;
|
83
|
+
at[i].cFlags = inp_at[i].cFlags;
|
84
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
85
|
+
at[i].num_iso_H[j] = inp_at[i].num_iso_H[j];
|
86
|
+
}
|
87
|
+
at[i].charge = inp_at[i].charge;
|
88
|
+
at[i].radical = inp_at[i].radical;
|
89
|
+
|
90
|
+
#if( FIND_RING_SYSTEMS == 1 )
|
91
|
+
at[i].nBlockSystem = inp_at[i].nBlockSystem;
|
92
|
+
at[i].bCutVertex = inp_at[i].bCutVertex;
|
93
|
+
at[i].nRingSystem = inp_at[i].nRingSystem;
|
94
|
+
at[i].nNumAtInRingSystem = inp_at[i].nNumAtInRingSystem;
|
95
|
+
#if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
|
96
|
+
at[i].nDistanceFromTerminal = inp_at[i].nDistanceFromTerminal;
|
97
|
+
#endif
|
98
|
+
#endif
|
99
|
+
|
100
|
+
/*
|
101
|
+
at[i].x = inp_at[i].x;
|
102
|
+
at[i].y = inp_at[i].y;
|
103
|
+
at[i].z = inp_at[i].z;
|
104
|
+
*/
|
105
|
+
}
|
106
|
+
return 0;
|
107
|
+
}
|
108
|
+
/**********************************************************************************************/
|
109
|
+
int GetElementAndCount( const char **f, char *szEl, int *count )
|
110
|
+
{
|
111
|
+
const char *p = *f;
|
112
|
+
char *q;
|
113
|
+
int i = 0;
|
114
|
+
if ( *p ) {
|
115
|
+
if ( isupper( UCINT *p ) ) {
|
116
|
+
szEl[i++] = *p++;
|
117
|
+
if ( *p && islower( UCINT *p ) ) {
|
118
|
+
szEl[i++] = *p++;
|
119
|
+
}
|
120
|
+
szEl[i] = '\0';
|
121
|
+
if ( 1 == i && szEl[0] == 'C' ) {
|
122
|
+
szEl[0] = 'A'; /* less than any element: */
|
123
|
+
/* carbon-containing compounds should be first */
|
124
|
+
}
|
125
|
+
if ( *p && isdigit( UCINT *p ) ) {
|
126
|
+
*count = strtol( p, &q, 10 );
|
127
|
+
p = q;
|
128
|
+
} else {
|
129
|
+
*count = 1;
|
130
|
+
}
|
131
|
+
*f = p; /* next element; */
|
132
|
+
return 1;
|
133
|
+
}
|
134
|
+
return -1; /* not a chemical formula */
|
135
|
+
}
|
136
|
+
strcpy( szEl, "Zz" ); /* zero termination 'element' is larger than any other element */
|
137
|
+
*count = 9999; /* zero termination 'element count' is larger than any other count */
|
138
|
+
return 0;
|
139
|
+
}
|
140
|
+
/**********************************************************************************************
|
141
|
+
|
142
|
+
E1 < E2 if strcmp( E1, E2) < 0 OR E2 is empty and E1 is not
|
143
|
+
n1 < n2 if value n1 > n2
|
144
|
+
|
145
|
+
Sorting order:
|
146
|
+
|
147
|
+
C10H22N
|
148
|
+
C10H22
|
149
|
+
C2
|
150
|
+
Ag2Cl2
|
151
|
+
Ag2Cl
|
152
|
+
Ag2F2
|
153
|
+
Ag2
|
154
|
+
AgCl
|
155
|
+
AgF
|
156
|
+
F6S
|
157
|
+
F2S
|
158
|
+
|
159
|
+
**********************************************************************************************/
|
160
|
+
int CompareHillFormulas( const char *f1, const char *f2 )
|
161
|
+
{
|
162
|
+
char szEl1[4], szEl2[4];
|
163
|
+
int count1, count2, ret1, ret2, ret;
|
164
|
+
|
165
|
+
do {
|
166
|
+
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
|
167
|
+
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
|
168
|
+
if ( 0 <= ret1 && 0 <= ret2 ) {
|
169
|
+
if ( ret = strcmp( szEl1, szEl2 ) ) {
|
170
|
+
return ret; /* lexicographic order, string termination > any character */
|
171
|
+
}
|
172
|
+
if ( ret = count2 - count1 ) {
|
173
|
+
return ret; /* inverse atom count order */
|
174
|
+
}
|
175
|
+
} else {
|
176
|
+
return 0; /* program error <BRKPT> */
|
177
|
+
}
|
178
|
+
|
179
|
+
} while ( 0 < ret1 && 0 < ret2 );
|
180
|
+
|
181
|
+
return 0;
|
182
|
+
}
|
183
|
+
/**********************************************************************************************/
|
184
|
+
int CompareHillFormulasNoH( const char *f1, const char *f2, int *num_H1, int *num_H2 )
|
185
|
+
{
|
186
|
+
char szEl1[4], szEl2[4];
|
187
|
+
int count1, count2, ret1, ret2, ret;
|
188
|
+
|
189
|
+
do {
|
190
|
+
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
|
191
|
+
if ( 0 < ret1 && szEl1[0] == 'H' && !szEl1[1] ) {
|
192
|
+
*num_H1 += count1;
|
193
|
+
ret1 = GetElementAndCount( &f1, szEl1, &count1 );
|
194
|
+
}
|
195
|
+
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
|
196
|
+
if ( 0 < ret2 && szEl2[0] == 'H' && !szEl2[1] ) {
|
197
|
+
*num_H2 += count2;
|
198
|
+
ret2 = GetElementAndCount( &f2, szEl2, &count2 );
|
199
|
+
}
|
200
|
+
if ( 0 <= ret1 && 0 <= ret2 ) {
|
201
|
+
if ( ret = strcmp( szEl1, szEl2 ) ) {
|
202
|
+
return ret; /* lexicographic order, string termination > any character */
|
203
|
+
}
|
204
|
+
if ( ret = count2 - count1 ) {
|
205
|
+
return ret; /* inverse atom count order */
|
206
|
+
}
|
207
|
+
} else {
|
208
|
+
return 0; /* program error <BRKPT> */
|
209
|
+
}
|
210
|
+
|
211
|
+
} while ( 0 < ret1 && 0 < ret2 );
|
212
|
+
|
213
|
+
return 0;
|
214
|
+
}
|
215
|
+
|
216
|
+
/**************************************************************/
|
217
|
+
int CompareTautNonIsoPartOfINChI( const INChI *i1, const INChI *i2 )
|
218
|
+
{
|
219
|
+
int len1, len2, ret, i;
|
220
|
+
|
221
|
+
len1 = i1->lenTautomer > 0 && i1->nTautomer[0]? i1->lenTautomer:0;
|
222
|
+
len2 = i2->lenTautomer > 0 && i2->nTautomer[0]? i2->lenTautomer:0;
|
223
|
+
if ( ret = len2 - len1 ) {
|
224
|
+
return ret;
|
225
|
+
}
|
226
|
+
for ( i = 0; i < len1; i ++ ) {
|
227
|
+
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
|
228
|
+
return ret;
|
229
|
+
}
|
230
|
+
return 0;
|
231
|
+
}
|
232
|
+
|
233
|
+
/**********************************************************************************************/
|
234
|
+
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
|
235
|
+
/**********************************************************************************************/
|
236
|
+
int CompINChITautVsNonTaut(const INCHI_SORT *p1, const INCHI_SORT *p2, int bCompareIsotopic)
|
237
|
+
{
|
238
|
+
int ret, num, i, num_H1, num_H2;
|
239
|
+
|
240
|
+
const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
|
241
|
+
const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
|
242
|
+
|
243
|
+
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
|
244
|
+
|
245
|
+
/* INChI_Stereo *Stereo1, *Stereo2; */
|
246
|
+
|
247
|
+
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
|
248
|
+
|
249
|
+
i1 = p1->pINChI[n1];
|
250
|
+
i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
|
251
|
+
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
|
252
|
+
|
253
|
+
|
254
|
+
/* non-deleted-non-empty < deleted < empty */
|
255
|
+
if ( i1 && !i2 )
|
256
|
+
return 0; /* non-empty is the smallest (first) */
|
257
|
+
if ( !i1 && i2 )
|
258
|
+
return 0;
|
259
|
+
if ( !i1 && !i2 )
|
260
|
+
return 0;
|
261
|
+
if ( i1->bDeleted )
|
262
|
+
return 1; /* deleted is the largest (last) among non-empty */
|
263
|
+
if ( i2->bDeleted )
|
264
|
+
return -1;
|
265
|
+
|
266
|
+
if ( i1->nNumberOfAtoms > 0 && !i2->nNumberOfAtoms )
|
267
|
+
return 0;
|
268
|
+
|
269
|
+
i2 = i2;
|
270
|
+
|
271
|
+
num_H1 = num_H2 = 0;
|
272
|
+
|
273
|
+
/* do not compare terminal H */
|
274
|
+
if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
|
275
|
+
return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
|
276
|
+
}
|
277
|
+
|
278
|
+
/*********************************************************
|
279
|
+
compare non-isotopic non-tautomeric part
|
280
|
+
*********************************************************/
|
281
|
+
|
282
|
+
/* compare number of atoms (excluding terminal H) */
|
283
|
+
if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
|
284
|
+
return ret; /* more atoms first */
|
285
|
+
|
286
|
+
/* compare elements (excluding terminal H) */
|
287
|
+
num = i1->nNumberOfAtoms;
|
288
|
+
for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
|
289
|
+
if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
|
290
|
+
return ret; /* greater periodic number first */
|
291
|
+
}
|
292
|
+
/**********************************************************
|
293
|
+
compare connection tables
|
294
|
+
***********************************************************/
|
295
|
+
if ( ret = i2->lenConnTable - i1->lenConnTable )
|
296
|
+
return ret; /* longer connection table first */
|
297
|
+
num = i2->lenConnTable;
|
298
|
+
for ( i = 0; i < num; i ++ ) {
|
299
|
+
if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
|
300
|
+
return ret; /* greater connection table first */
|
301
|
+
}
|
302
|
+
/*********************************************************
|
303
|
+
compare compare total number of H (inverse: H3 < H2 )
|
304
|
+
**********************************************************/
|
305
|
+
if ( ret = num_H2 - num_H1 )
|
306
|
+
return ret;
|
307
|
+
/*********************************************************
|
308
|
+
compare non-tautomeric num_H: N < NH3 < NH2 < NH
|
309
|
+
**********************************************************/
|
310
|
+
num = i1->nNumberOfAtoms;
|
311
|
+
for ( i = 0; i < num; i ++ ) {
|
312
|
+
if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
|
313
|
+
return !i2->nNum_H[i]? 1 : /* no H first */
|
314
|
+
!i1->nNum_H[i]? -1 :
|
315
|
+
(int)i2->nNum_H[i] - (int)i1->nNum_H[i];
|
316
|
+
}
|
317
|
+
}
|
318
|
+
/*********************************************************
|
319
|
+
compare non-isotopic tautomeric part
|
320
|
+
*********************************************************/
|
321
|
+
if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
|
322
|
+
return ret;
|
323
|
+
}
|
324
|
+
/*
|
325
|
+
if ( ret = i2->lenTautomer - i1->lenTautomer )
|
326
|
+
return ret;
|
327
|
+
num = inchi_min( i2->lenTautomer, i1->lenTautomer );
|
328
|
+
for ( i = 0; i < num; i ++ ) {
|
329
|
+
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
|
330
|
+
return ret;
|
331
|
+
}
|
332
|
+
*/
|
333
|
+
/*********************************************************
|
334
|
+
* *
|
335
|
+
* at this point both components are either tautomeric *
|
336
|
+
* or non-tautomeric *
|
337
|
+
* *
|
338
|
+
*********************************************************/
|
339
|
+
|
340
|
+
/*********************************************************
|
341
|
+
non-tautomeric "fixed H" specific
|
342
|
+
*********************************************************/
|
343
|
+
if ( /*TAUT_NON == bTaut &&*/ (i2 && i2->nNum_H_fixed ) ) {
|
344
|
+
/* first, compare non-tautomeric chem. formulas -- they may be different */
|
345
|
+
/* secondly, compare fixed-H distribution */
|
346
|
+
if ( i2->nNum_H_fixed ) {
|
347
|
+
num = i2->nNumberOfAtoms;
|
348
|
+
for ( i = 0; i < num; i ++ ) {
|
349
|
+
if ( i2->nNum_H_fixed[i] != 0 ) {
|
350
|
+
return 1;
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
/*********************************************************
|
356
|
+
compare non-isotopic stereo
|
357
|
+
*********************************************************/
|
358
|
+
ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
|
359
|
+
if ( ret ) {
|
360
|
+
return ret;
|
361
|
+
}
|
362
|
+
/*******************************************************
|
363
|
+
do not switch back to tautomeric i1, i2
|
364
|
+
*******************************************************/
|
365
|
+
/* -- how to switch back --
|
366
|
+
if ( i1t ) {
|
367
|
+
i1 = i1t;
|
368
|
+
i1t = NULL;
|
369
|
+
}
|
370
|
+
if ( i2t ) {
|
371
|
+
i2 = i2t;
|
372
|
+
i2t = NULL;
|
373
|
+
}
|
374
|
+
*/
|
375
|
+
/******************************************************
|
376
|
+
compare isotopic non-tautomeric part
|
377
|
+
******************************************************/
|
378
|
+
if ( bCompareIsotopic ) {
|
379
|
+
if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
|
380
|
+
return ret;
|
381
|
+
num = i1->nNumberOfIsotopicAtoms;
|
382
|
+
/* compare isotopic atoms */
|
383
|
+
for ( i = 0; i < num; i ++ ) {
|
384
|
+
if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
|
385
|
+
return ret;
|
386
|
+
if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
|
387
|
+
return ret;
|
388
|
+
}
|
389
|
+
/* compare isotopic H */
|
390
|
+
/* if tautomeric comparison mode then here are compared only non-tautomeric H */
|
391
|
+
for ( i = 0; i < num; i ++ ) {
|
392
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
|
393
|
+
return ret;
|
394
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
|
395
|
+
return ret;
|
396
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
|
397
|
+
return ret;
|
398
|
+
}
|
399
|
+
/*****************************************************
|
400
|
+
compare isotopic tautomeric part
|
401
|
+
*****************************************************/
|
402
|
+
if ( ret = i2->nNumberOfIsotopicTGroups || i1->nNumberOfIsotopicTGroups )
|
403
|
+
return ret;
|
404
|
+
/*
|
405
|
+
num = i1->nNumberOfIsotopicTGroups;
|
406
|
+
for ( i = 0; i < num; i ++ ) {
|
407
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
|
408
|
+
return ret;
|
409
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
|
410
|
+
return ret;
|
411
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
|
412
|
+
return ret;
|
413
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
|
414
|
+
return ret;
|
415
|
+
}
|
416
|
+
*/
|
417
|
+
/****************************************************
|
418
|
+
compare isotopic stereo
|
419
|
+
****************************************************/
|
420
|
+
ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
|
421
|
+
if ( ret ) {
|
422
|
+
return ret;
|
423
|
+
}
|
424
|
+
|
425
|
+
}
|
426
|
+
|
427
|
+
|
428
|
+
/**********************************************************
|
429
|
+
compare charges: non-charged first, then in order of
|
430
|
+
ascending charges (negative first)
|
431
|
+
***********************************************************/
|
432
|
+
if ( i2->nTotalCharge && i1->nTotalCharge ) {
|
433
|
+
/* both are charged; smaller charges first */
|
434
|
+
ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
|
435
|
+
return ret;
|
436
|
+
}
|
437
|
+
if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
|
438
|
+
/* only one is charged; uncharged first */
|
439
|
+
return ret;
|
440
|
+
}
|
441
|
+
/* stable sort */
|
442
|
+
/*ret = p1->ord_number - p2->ord_number;*/
|
443
|
+
|
444
|
+
return ret;
|
445
|
+
}
|
446
|
+
|
447
|
+
/*************************** stereo ***********************************************************/
|
448
|
+
typedef enum tagSp3StereoTypeTmp {
|
449
|
+
SP3_NONE = 0, /* no sp3 stereo: no /t, /m, /s segments */
|
450
|
+
/* /t is present: */
|
451
|
+
SP3_ONLY = 1, /* no /s or /m segment: inversion leaves the structure unchanged */
|
452
|
+
SP3_ABS = 2, /* abs stereo: both /m and /s are present */
|
453
|
+
SP3_REL = 4, /* rel stereo: /s is present, /m is not */
|
454
|
+
SP3_RAC = 8, /* racemic stereo: /s is presen, /m is nott */
|
455
|
+
SP3_TYPE = (SP3_ABS|SP3_REL|SP3_RAC), /* bitmap for checking the presence of /m */
|
456
|
+
SP3_ANY = (SP3_ABS|SP3_REL|SP3_RAC|SP3_ONLY) /* bitmap for checking the presence of /t */
|
457
|
+
} SP3_TYPE_TMP;
|
458
|
+
|
459
|
+
/**********************************************************************************************/
|
460
|
+
int GetSp3RelRacAbs( const INChI *pINChI, INChI_Stereo *Stereo )
|
461
|
+
{
|
462
|
+
int nRet = SP3_NONE;
|
463
|
+
if ( pINChI && !pINChI->bDeleted && Stereo && 0 < Stereo->nNumberOfStereoCenters ) {
|
464
|
+
if ( 0 != Stereo->nCompInv2Abs ) {
|
465
|
+
if ( pINChI->nFlags & INCHI_FLAG_REL_STEREO ) {
|
466
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
467
|
+
if ( 1 < Stereo->nNumberOfStereoCenters ) {
|
468
|
+
nRet = SP3_REL;
|
469
|
+
}
|
470
|
+
#else
|
471
|
+
nRet = SP3_REL;
|
472
|
+
#endif
|
473
|
+
} else
|
474
|
+
if ( pINChI->nFlags & INCHI_FLAG_RAC_STEREO ) {
|
475
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
476
|
+
if ( 1 < Stereo->nNumberOfStereoCenters ) {
|
477
|
+
nRet = SP3_REL;
|
478
|
+
}
|
479
|
+
#else
|
480
|
+
nRet = SP3_RAC;
|
481
|
+
#endif
|
482
|
+
} else {
|
483
|
+
nRet = SP3_ABS;
|
484
|
+
}
|
485
|
+
} else
|
486
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
487
|
+
if ( !(( pINChI->nFlags & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO) ) && 1 == Stereo->nNumberOfStereoCenters) )
|
488
|
+
#endif
|
489
|
+
{
|
490
|
+
nRet = SP3_ONLY; /* SP3_NONE if relative stereo and 1 stereocenter */
|
491
|
+
}
|
492
|
+
}
|
493
|
+
return nRet;
|
494
|
+
}
|
495
|
+
|
496
|
+
/* char sDifSegs[DIFL_LENGTH][DIFS_LENGTH]; */
|
497
|
+
|
498
|
+
/**********************************************************************************************/
|
499
|
+
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
|
500
|
+
/**********************************************************************************************/
|
501
|
+
int CompINChILayers(const INCHI_SORT *p1, const INCHI_SORT *p2, char sDifSegs[][DIFS_LENGTH] )
|
502
|
+
{
|
503
|
+
int ret = 0, num, i, num_H1, num_H2;
|
504
|
+
|
505
|
+
const INChI *i1 = NULL; /* Mobile-H layers in Mobile-H sorting order */
|
506
|
+
const INChI *i2 = NULL; /* Fixed-H layers in Fixed-H sorting order */
|
507
|
+
|
508
|
+
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
|
509
|
+
|
510
|
+
INChI_Stereo *Stereo1, *Stereo2;
|
511
|
+
INChI_Stereo *IsoStereo1, *IsoStereo2;
|
512
|
+
int bRelRac[DIFL_LENGTH];
|
513
|
+
char *psDifSegs;
|
514
|
+
|
515
|
+
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
|
516
|
+
|
517
|
+
i1 = p1->pINChI[n1];
|
518
|
+
i2 = (n1 == TAUT_YES && p2->pINChI[TAUT_NON] &&
|
519
|
+
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
|
520
|
+
|
521
|
+
num_H1 = num_H2 = 0;
|
522
|
+
memset( bRelRac, DIFV_BOTH_EMPTY, sizeof(bRelRac) );
|
523
|
+
/*=====================*/
|
524
|
+
/*==== /f ======*/
|
525
|
+
/*=====================*/
|
526
|
+
if ( i1 && !i1->bDeleted && i1->szHillFormula && i1->szHillFormula[0] ) {
|
527
|
+
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
|
528
|
+
if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
|
529
|
+
if ( !CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) &&
|
530
|
+
num_H1 == num_H2 ) {
|
531
|
+
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_EQL2PRECED;
|
532
|
+
} else {
|
533
|
+
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
|
534
|
+
}
|
535
|
+
} else {
|
536
|
+
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
537
|
+
}
|
538
|
+
} else {
|
539
|
+
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
|
540
|
+
if ( i2 && !i2->bDeleted && i2->szHillFormula && i2->szHillFormula[0] ) {
|
541
|
+
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
|
542
|
+
} else {
|
543
|
+
sDifSegs[DIFL_F][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
|
544
|
+
}
|
545
|
+
}
|
546
|
+
/*=====================*/
|
547
|
+
/*==== /c ======*/
|
548
|
+
/*=====================*/
|
549
|
+
if ( i1 && !i1->bDeleted && i1->lenConnTable > 1 ) {
|
550
|
+
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_NEQ2PRECED;
|
551
|
+
} else {
|
552
|
+
sDifSegs[DIFL_M][DIFS_f_FORMULA] |= DIFV_BOTH_EMPTY;
|
553
|
+
}
|
554
|
+
/*=====================*/
|
555
|
+
/*==== /h ======*/
|
556
|
+
/*=====================*/
|
557
|
+
/* M: H atoms */
|
558
|
+
if ( i1 && !i1->bDeleted ) {
|
559
|
+
num_H1 = (i1->lenTautomer > 0 && i1->nTautomer && i1->nTautomer[0])? 1 : 0; /* number of t-groups */
|
560
|
+
if ( !num_H1 && i1->nNum_H ) {
|
561
|
+
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) { /* immobile H */
|
562
|
+
if ( i1->nNum_H[i] ) {
|
563
|
+
num_H1 = 1;
|
564
|
+
break;
|
565
|
+
}
|
566
|
+
}
|
567
|
+
}
|
568
|
+
sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= num_H1? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
|
569
|
+
} else {
|
570
|
+
sDifSegs[DIFL_M][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
|
571
|
+
}
|
572
|
+
/* F: fixed mobile H */
|
573
|
+
if ( i2 && !i2->bDeleted && i2->nNum_H_fixed ) {
|
574
|
+
num_H2 = 0;
|
575
|
+
if ( i1 && !i1->bDeleted ) {
|
576
|
+
for ( i = 0; i < i1->nNumberOfAtoms; i ++ ) {
|
577
|
+
if ( i2->nNum_H_fixed[i] ) {
|
578
|
+
num_H2 = 1;
|
579
|
+
break;
|
580
|
+
}
|
581
|
+
}
|
582
|
+
}
|
583
|
+
sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= num_H2? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
|
584
|
+
} else {
|
585
|
+
sDifSegs[DIFL_F][DIFS_h_H_ATOMS] |= DIFV_BOTH_EMPTY;
|
586
|
+
}
|
587
|
+
/* MI: exchangable isotopic H: see OutputINChI1(), num_iso_H[] */
|
588
|
+
|
589
|
+
/*=====================*/
|
590
|
+
/*==== /q ======*/
|
591
|
+
/*=====================*/
|
592
|
+
psDifSegs = &sDifSegs[DIFL_F][DIFS_q_CHARGE];
|
593
|
+
if ( i1 && !i1->bDeleted ) {
|
594
|
+
if ( i1->nTotalCharge ) {
|
595
|
+
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
|
596
|
+
} else {
|
597
|
+
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
|
598
|
+
}
|
599
|
+
if ( i2 && !i2->bDeleted ) {
|
600
|
+
if ( i1->nTotalCharge ) {
|
601
|
+
if ( i1->nTotalCharge == i2->nTotalCharge ) {
|
602
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
603
|
+
} else
|
604
|
+
if ( i2->nTotalCharge ) {
|
605
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
606
|
+
} else {
|
607
|
+
*psDifSegs |= DIFV_IS_EMPTY;
|
608
|
+
}
|
609
|
+
} else {
|
610
|
+
if ( i2->nTotalCharge ) {
|
611
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
612
|
+
} else {
|
613
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
614
|
+
}
|
615
|
+
}
|
616
|
+
} else
|
617
|
+
if ( !i2 ) {
|
618
|
+
*psDifSegs |= i1->nTotalCharge? DIFV_EQL2PRECED : DIFV_BOTH_EMPTY;
|
619
|
+
} else {
|
620
|
+
/* i2 && i2->bDeleted */
|
621
|
+
*psDifSegs |= i1->nTotalCharge? DIFV_IS_EMPTY : DIFV_BOTH_EMPTY;
|
622
|
+
}
|
623
|
+
} else {
|
624
|
+
sDifSegs[DIFL_M][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
|
625
|
+
if ( i2 && !i2->bDeleted ) {
|
626
|
+
if ( i2->nTotalCharge ) {
|
627
|
+
sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_NEQ2PRECED;
|
628
|
+
} else {
|
629
|
+
sDifSegs[DIFL_F][DIFS_q_CHARGE] |= DIFV_BOTH_EMPTY;
|
630
|
+
}
|
631
|
+
}
|
632
|
+
}
|
633
|
+
/*************** stereo *****************/
|
634
|
+
if ( i1 && !i1->bDeleted ) {
|
635
|
+
Stereo1 = i1->Stereo;
|
636
|
+
IsoStereo1 = i1->StereoIsotopic;
|
637
|
+
} else {
|
638
|
+
Stereo1 = NULL;
|
639
|
+
IsoStereo1 = NULL;
|
640
|
+
}
|
641
|
+
if ( i2 && !i2->bDeleted ) {
|
642
|
+
Stereo2 = i2->Stereo;
|
643
|
+
IsoStereo2 = i2->StereoIsotopic;
|
644
|
+
} else {
|
645
|
+
Stereo2 = NULL;
|
646
|
+
IsoStereo2 = NULL;
|
647
|
+
}
|
648
|
+
/*=====================*/
|
649
|
+
/*==== /b ======*/
|
650
|
+
/*=====================*/
|
651
|
+
/* M double bond stereo */
|
652
|
+
psDifSegs = &sDifSegs[DIFL_M][DIFS_b_SBONDS];
|
653
|
+
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
|
654
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
655
|
+
} else {
|
656
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
657
|
+
}
|
658
|
+
/* F double bond stereo */
|
659
|
+
psDifSegs = &sDifSegs[DIFL_F][DIFS_b_SBONDS];
|
660
|
+
if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
|
661
|
+
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
|
662
|
+
if ( Eql_INChI_Stereo( Stereo1, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
|
663
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
664
|
+
} else {
|
665
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
666
|
+
}
|
667
|
+
} else {
|
668
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
669
|
+
}
|
670
|
+
} else {
|
671
|
+
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
|
672
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
673
|
+
} else {
|
674
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
675
|
+
}
|
676
|
+
}
|
677
|
+
/* MI double bond stereo */
|
678
|
+
psDifSegs = &sDifSegs[DIFL_MI][DIFS_b_SBONDS];
|
679
|
+
if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds ) {
|
680
|
+
if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP2, Stereo1, EQL_SP2, 0 ) ) {
|
681
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
682
|
+
} else {
|
683
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
684
|
+
}
|
685
|
+
} else {
|
686
|
+
if ( Stereo1 && Stereo1->nNumberOfStereoBonds ) {
|
687
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
688
|
+
} else {
|
689
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
690
|
+
}
|
691
|
+
}
|
692
|
+
/* FI double bond stereo */
|
693
|
+
psDifSegs = &sDifSegs[DIFL_FI][DIFS_b_SBONDS];
|
694
|
+
if ( IsoStereo2 && IsoStereo2->nNumberOfStereoBonds ) {
|
695
|
+
if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP2, Stereo2, EQL_SP2, 0 ) ) {
|
696
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
697
|
+
} else {
|
698
|
+
if ( !(Stereo1 && Stereo1->nNumberOfStereoBonds) &&
|
699
|
+
!(Stereo2 && Stereo2->nNumberOfStereoBonds) &&
|
700
|
+
Eql_INChI_Stereo( IsoStereo2, EQL_SP2, IsoStereo1, EQL_SP2, 0 ) ) {
|
701
|
+
*psDifSegs |= DIFV_FI_EQ_MI;
|
702
|
+
} else {
|
703
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
704
|
+
}
|
705
|
+
}
|
706
|
+
} else {
|
707
|
+
/* the solution table for FI stereo,
|
708
|
+
in case of FI stereo is empty
|
709
|
+
E = segment is empty, NE = not empty
|
710
|
+
+==============================+
|
711
|
+
| M | MI | F | result |
|
712
|
+
+=====+=====+=====+============+
|
713
|
+
| E | E | E | both empty |
|
714
|
+
+-----+-----+-----+------------+
|
715
|
+
| NE | E | E | both empty |
|
716
|
+
+-----+-----+-----+------------+
|
717
|
+
| E | NE | E | is empty |
|
718
|
+
+-----+-----+-----+------------+
|
719
|
+
| NE | NE | E | both empty |
|
720
|
+
+-----+-----+-----+------------+
|
721
|
+
| E | E | NE | is empty |
|
722
|
+
+-----+-----+-----+------------+
|
723
|
+
| NE | E | NE | is empty |
|
724
|
+
+-----+-----+-----+------------+
|
725
|
+
| E | NE | NE | is empty |
|
726
|
+
+-----+-----+-----+------------+
|
727
|
+
| NE | NE | ME | is empty |
|
728
|
+
+==============================+
|
729
|
+
*/
|
730
|
+
if ( Stereo2 && Stereo2->nNumberOfStereoBonds ) {
|
731
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
732
|
+
} else
|
733
|
+
if ( IsoStereo1 && IsoStereo1->nNumberOfStereoBonds &&
|
734
|
+
!(Stereo1 && Stereo1->nNumberOfStereoBonds)
|
735
|
+
) {
|
736
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
737
|
+
} else {
|
738
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
739
|
+
}
|
740
|
+
}
|
741
|
+
/*==================================*/
|
742
|
+
/*==== /t, /m, /s for M ======*/
|
743
|
+
/*==================================*/
|
744
|
+
/* M sp3 stereo */
|
745
|
+
bRelRac[DIFL_M ] = GetSp3RelRacAbs( i1, Stereo1 );
|
746
|
+
bRelRac[DIFL_MI] = GetSp3RelRacAbs( i1, IsoStereo1 );
|
747
|
+
bRelRac[DIFL_F ] = GetSp3RelRacAbs( i2, Stereo2 );
|
748
|
+
bRelRac[DIFL_FI] = GetSp3RelRacAbs( i2, IsoStereo2 );
|
749
|
+
if ( SP3_NONE != bRelRac[DIFL_M] ) {
|
750
|
+
sDifSegs[DIFL_M][DIFS_t_SATOMS] |= (bRelRac[DIFL_M] & SP3_ANY)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
|
751
|
+
sDifSegs[DIFL_M][DIFS_m_SP3INV] |= (bRelRac[DIFL_M] & SP3_ABS)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
|
752
|
+
sDifSegs[DIFL_M][DIFS_s_STYPE] |= (bRelRac[DIFL_M] & SP3_TYPE)? DIFV_NEQ2PRECED : DIFV_BOTH_EMPTY;
|
753
|
+
} else {
|
754
|
+
sDifSegs[DIFL_M][DIFS_t_SATOMS] |= DIFV_BOTH_EMPTY;
|
755
|
+
sDifSegs[DIFL_M][DIFS_m_SP3INV] |= DIFV_BOTH_EMPTY;
|
756
|
+
sDifSegs[DIFL_M][DIFS_s_STYPE] |= DIFV_BOTH_EMPTY;
|
757
|
+
}
|
758
|
+
/*=====================*/
|
759
|
+
/*==== /t ======*/
|
760
|
+
/*=====================*/
|
761
|
+
/* F sp3 stereo */
|
762
|
+
psDifSegs = &sDifSegs[DIFL_F][DIFS_t_SATOMS];
|
763
|
+
if ( SP3_ANY & bRelRac[DIFL_F] ) {
|
764
|
+
if ( Eql_INChI_Stereo( Stereo2, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
|
765
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
766
|
+
} else {
|
767
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
768
|
+
}
|
769
|
+
} else
|
770
|
+
if ( SP3_ANY & bRelRac[DIFL_M] ) {
|
771
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
772
|
+
} else {
|
773
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
774
|
+
}
|
775
|
+
/* MI sp3 stereo */
|
776
|
+
psDifSegs = &sDifSegs[DIFL_MI][DIFS_t_SATOMS];
|
777
|
+
if ( SP3_ANY & bRelRac[DIFL_MI] ) {
|
778
|
+
if ( Eql_INChI_Stereo( IsoStereo1, EQL_SP3, Stereo1, EQL_SP3, 0 ) ) {
|
779
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
780
|
+
} else {
|
781
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
782
|
+
}
|
783
|
+
} else
|
784
|
+
if ( SP3_ANY & bRelRac[DIFL_M] ) {
|
785
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
786
|
+
} else {
|
787
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
788
|
+
}
|
789
|
+
/* FI sp3 stereo */
|
790
|
+
psDifSegs = &sDifSegs[DIFL_FI][DIFS_t_SATOMS];
|
791
|
+
if ( SP3_ANY & bRelRac[DIFL_FI] ) {
|
792
|
+
if ( Eql_INChI_Stereo( IsoStereo2, EQL_SP3, Stereo2, EQL_SP3, 0 ) ) {
|
793
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
794
|
+
} else
|
795
|
+
if ( !(SP3_ANY & bRelRac[DIFL_M]) &&
|
796
|
+
!(SP3_ANY & bRelRac[DIFL_F]) &&
|
797
|
+
Eql_INChI_Stereo( IsoStereo2, EQL_SP3, IsoStereo1, EQL_SP3, 0 ) ) {
|
798
|
+
*psDifSegs |= DIFV_FI_EQ_MI;
|
799
|
+
} else {
|
800
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
801
|
+
}
|
802
|
+
} else /* similar to /b */
|
803
|
+
if ( (SP3_ANY & bRelRac[DIFL_F]) ) {
|
804
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
805
|
+
} else
|
806
|
+
if ( (SP3_ANY & bRelRac[DIFL_MI]) && !(SP3_ANY & bRelRac[DIFL_M]) ) {
|
807
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
808
|
+
} else {
|
809
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
810
|
+
}
|
811
|
+
/*=====================*/
|
812
|
+
/*==== /m ======*/
|
813
|
+
/*=====================*/
|
814
|
+
/* F sp3 abs stereo inversion */
|
815
|
+
psDifSegs = &sDifSegs[DIFL_F][DIFS_m_SP3INV];
|
816
|
+
if ( bRelRac[DIFL_F] & SP3_ABS ) {
|
817
|
+
/* the order of || operands below is critically important: || is not a commutative operation */
|
818
|
+
if ( !(bRelRac[DIFL_M] & SP3_ABS) || Stereo2->nCompInv2Abs != Stereo1->nCompInv2Abs ) {
|
819
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
820
|
+
} else {
|
821
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
822
|
+
}
|
823
|
+
} else
|
824
|
+
if ( bRelRac[DIFL_M] & SP3_ABS ) {
|
825
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
826
|
+
} else {
|
827
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
828
|
+
}
|
829
|
+
/* MI sp3 abs stereo inversion */
|
830
|
+
psDifSegs = &sDifSegs[DIFL_MI][DIFS_m_SP3INV];
|
831
|
+
if ( SP3_ABS & bRelRac[DIFL_MI] ) {
|
832
|
+
if ( (SP3_ABS & bRelRac[DIFL_M]) && IsoStereo1->nCompInv2Abs == Stereo1->nCompInv2Abs ) {
|
833
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
834
|
+
} else {
|
835
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
836
|
+
}
|
837
|
+
} else
|
838
|
+
if ( SP3_ABS & bRelRac[DIFL_M] ) {
|
839
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
840
|
+
} else {
|
841
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
842
|
+
}
|
843
|
+
/* FI sp3 abs stereo inversion */
|
844
|
+
psDifSegs = &sDifSegs[DIFL_FI][DIFS_m_SP3INV];
|
845
|
+
if ( SP3_ABS & bRelRac[DIFL_FI] ) {
|
846
|
+
if ( (SP3_ABS & bRelRac[DIFL_F]) && IsoStereo2->nCompInv2Abs == Stereo2->nCompInv2Abs ) {
|
847
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
848
|
+
} else
|
849
|
+
if ( !(SP3_ABS & bRelRac[DIFL_M]) &&
|
850
|
+
!(SP3_ABS & bRelRac[DIFL_F]) &&
|
851
|
+
(SP3_ABS & bRelRac[DIFL_MI]) && /* make sure IsoStereo1 != NULL */
|
852
|
+
IsoStereo2->nCompInv2Abs == IsoStereo1->nCompInv2Abs ) {
|
853
|
+
*psDifSegs |= DIFV_FI_EQ_MI;
|
854
|
+
} else {
|
855
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
856
|
+
}
|
857
|
+
} else /* similar to /b */
|
858
|
+
/* the order of || operands below is critically important: || is no a commutative operation */
|
859
|
+
if ( (SP3_ABS & bRelRac[DIFL_F]) ) {
|
860
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
861
|
+
} else
|
862
|
+
if ( (SP3_ABS & bRelRac[DIFL_MI]) && !(SP3_ABS & bRelRac[DIFL_M]) ) {
|
863
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
864
|
+
} else {
|
865
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
866
|
+
}
|
867
|
+
/*=====================*/
|
868
|
+
/*==== /s ======*/
|
869
|
+
/*=====================*/
|
870
|
+
/* F sp3 stereo type */
|
871
|
+
psDifSegs = &sDifSegs[DIFL_F][DIFS_s_STYPE];
|
872
|
+
if ( bRelRac[DIFL_F] & SP3_TYPE ) {
|
873
|
+
if ( (bRelRac[DIFL_F] & SP3_TYPE) == (bRelRac[DIFL_M] & SP3_TYPE) ) {
|
874
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
875
|
+
} else {
|
876
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
877
|
+
}
|
878
|
+
} else
|
879
|
+
if ( bRelRac[DIFL_M] & SP3_TYPE ) {
|
880
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
881
|
+
} else {
|
882
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
883
|
+
}
|
884
|
+
/* MI sp3 stereo type */
|
885
|
+
psDifSegs = &sDifSegs[DIFL_MI][DIFS_s_STYPE];
|
886
|
+
if ( SP3_TYPE & bRelRac[DIFL_MI] ) {
|
887
|
+
if ( (SP3_TYPE & bRelRac[DIFL_MI]) == (SP3_TYPE & bRelRac[DIFL_M]) ) {
|
888
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
889
|
+
} else {
|
890
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
891
|
+
}
|
892
|
+
} else
|
893
|
+
if ( SP3_TYPE & bRelRac[DIFL_M] ) {
|
894
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
895
|
+
} else {
|
896
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
897
|
+
}
|
898
|
+
/* FI sp3 stereo type */
|
899
|
+
psDifSegs = &sDifSegs[DIFL_FI][DIFS_s_STYPE];
|
900
|
+
if ( SP3_TYPE & bRelRac[DIFL_FI] ) {
|
901
|
+
if ( (SP3_TYPE & bRelRac[DIFL_FI]) == (SP3_TYPE & bRelRac[DIFL_F]) ) {
|
902
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
903
|
+
} else
|
904
|
+
if ( !(SP3_TYPE & bRelRac[DIFL_M]) &&
|
905
|
+
!(SP3_TYPE & bRelRac[DIFL_F]) &&
|
906
|
+
(SP3_TYPE & bRelRac[DIFL_MI]) ) {
|
907
|
+
*psDifSegs |= DIFV_FI_EQ_MI;
|
908
|
+
} else {
|
909
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
910
|
+
}
|
911
|
+
} else /* similar to /b */
|
912
|
+
/* the order of || operands below is critically important: || is not a commutative operation */
|
913
|
+
if ( (SP3_TYPE & bRelRac[DIFL_F]) ) {
|
914
|
+
*psDifSegs |= DIFV_EQL2PRECED; /* isotopic is missing because there is no isotopes */
|
915
|
+
} else
|
916
|
+
if ( (SP3_TYPE & bRelRac[DIFL_MI]) && !(SP3_TYPE & bRelRac[DIFL_M]) ) {
|
917
|
+
*psDifSegs |= i2? DIFV_IS_EMPTY : DIFV_EQL2PRECED;
|
918
|
+
} else {
|
919
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
920
|
+
}
|
921
|
+
/*=====================*/
|
922
|
+
/*==== /o ======*/
|
923
|
+
/*=====================*/
|
924
|
+
if ( p1 && p2 && p1->ord_number != p2->ord_number ) {
|
925
|
+
sDifSegs[DIFL_F][DIFS_o_TRANSP] |= DIFV_NEQ2PRECED;
|
926
|
+
}
|
927
|
+
/*=====================*/
|
928
|
+
/*==== /i ======*/
|
929
|
+
/*=====================*/
|
930
|
+
/* M isotopic atoms */
|
931
|
+
psDifSegs = &sDifSegs[DIFL_MI][DIFS_i_IATOMS];
|
932
|
+
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
|
933
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
934
|
+
} else {
|
935
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
936
|
+
}
|
937
|
+
/* F isotopic atoms */
|
938
|
+
psDifSegs = &sDifSegs[DIFL_FI][DIFS_i_IATOMS];
|
939
|
+
if ( i2 && !i2->bDeleted ) {
|
940
|
+
if ( i2->nNumberOfIsotopicAtoms || i2->nNumberOfIsotopicTGroups ) {
|
941
|
+
if ( !i1 || i1->bDeleted ||
|
942
|
+
i2->nNumberOfIsotopicAtoms != i1->nNumberOfIsotopicAtoms ||
|
943
|
+
i2->nNumberOfIsotopicTGroups != i1->nNumberOfIsotopicTGroups ) {
|
944
|
+
*psDifSegs |= DIFV_NEQ2PRECED;
|
945
|
+
} else {
|
946
|
+
int diff;
|
947
|
+
num = i1->nNumberOfIsotopicAtoms;
|
948
|
+
diff = 0;
|
949
|
+
for ( i = 0; i < num; i ++ ) {
|
950
|
+
/* compare isotopic atoms */
|
951
|
+
if ( diff = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
|
952
|
+
break;
|
953
|
+
if ( diff = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
|
954
|
+
break;
|
955
|
+
/* compare isotopic H */
|
956
|
+
if ( diff = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
|
957
|
+
break;
|
958
|
+
if ( diff = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
|
959
|
+
break;
|
960
|
+
if ( diff = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
|
961
|
+
break;
|
962
|
+
}
|
963
|
+
if ( !diff ) {
|
964
|
+
num = i1->nNumberOfIsotopicTGroups;
|
965
|
+
for ( i = 0; i < num; i ++ ) {
|
966
|
+
if ( diff = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
|
967
|
+
break;
|
968
|
+
if ( diff = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
|
969
|
+
break;
|
970
|
+
if ( diff = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
|
971
|
+
return diff;
|
972
|
+
if ( diff = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
|
973
|
+
break;
|
974
|
+
}
|
975
|
+
}
|
976
|
+
*psDifSegs |= diff? DIFV_NEQ2PRECED : DIFV_FI_EQ_MI;
|
977
|
+
|
978
|
+
}
|
979
|
+
} else
|
980
|
+
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
|
981
|
+
*psDifSegs |= DIFV_IS_EMPTY;
|
982
|
+
}
|
983
|
+
} else
|
984
|
+
if ( !i2 ) {
|
985
|
+
if ( i1 && !i1->bDeleted && (i1->nNumberOfIsotopicAtoms || i1->nNumberOfIsotopicTGroups) ) {
|
986
|
+
*psDifSegs |= DIFV_EQL2PRECED;
|
987
|
+
} else {
|
988
|
+
*psDifSegs |= DIFV_BOTH_EMPTY;
|
989
|
+
}
|
990
|
+
}
|
991
|
+
|
992
|
+
return ret;
|
993
|
+
}
|
994
|
+
/**********************************************************************************************/
|
995
|
+
int INChI_SegmentAction( char cDifSegs )
|
996
|
+
{
|
997
|
+
if ( !(cDifSegs & DIFV_OUTPUT_OMIT_F) ) {
|
998
|
+
return INCHI_SEGM_OMIT;
|
999
|
+
}
|
1000
|
+
if ( (cDifSegs & DIFV_OUTPUT_EMPTY_T) && !(cDifSegs & DIFV_OUTPUT_EMPTY_F) ) {
|
1001
|
+
return INCHI_SEGM_EMPTY;
|
1002
|
+
}
|
1003
|
+
if ( (cDifSegs & DIFV_OUTPUT_FILL_T) ) {
|
1004
|
+
return INCHI_SEGM_FILL;
|
1005
|
+
}
|
1006
|
+
return INCHI_SEGM_OMIT; /* the control flow shoul never reach this point */
|
1007
|
+
}
|
1008
|
+
/**********************************************************************************************/
|
1009
|
+
int MarkUnusedAndEmptyLayers( char sDifSegs[][DIFS_LENGTH] )
|
1010
|
+
{
|
1011
|
+
/****************************************************
|
1012
|
+
1. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
|
1013
|
+
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
|
1014
|
+
and there is NO succeeding non-empty layer then mark the 1st element
|
1015
|
+
of the layer DIFV_BOTH_EMPTY; this layerr will be omitted.
|
1016
|
+
|
1017
|
+
2. If all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
|
1018
|
+
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
|
1019
|
+
and there IS a succeeding non-empty layer then mark the 1st element
|
1020
|
+
of the layer DIFV_IS_EMPTY and all other elements DIFV_BOTH_EMPTY;
|
1021
|
+
only the first empty segment of this layerr will be output.
|
1022
|
+
|
1023
|
+
3. If NOT all elements of a layer are DIFV_IS_EMPTY and/or DIFV_BOTH_EMPTY
|
1024
|
+
and/or DIFV_EQL2PRECED and/or DIFV_FI_EQ_MI
|
1025
|
+
and the 1st element of the layer is DIFV_BOTH_EMPTY then mark it
|
1026
|
+
DIFV_IS_EMPTY; it will be output as empty (except M layer).
|
1027
|
+
*/
|
1028
|
+
|
1029
|
+
int i, nLayer, sBits, nFirstSegm;
|
1030
|
+
#define nFirstFmlSegm DIFS_f_FORMULA
|
1031
|
+
#define nFirstIsoSegm DIFS_i_IATOMS
|
1032
|
+
/* FI */
|
1033
|
+
nLayer = DIFL_FI;
|
1034
|
+
nFirstSegm = nFirstIsoSegm;
|
1035
|
+
sBits = 0;
|
1036
|
+
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
|
1037
|
+
sBits |= sDifSegs[nLayer][i];
|
1038
|
+
}
|
1039
|
+
if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
|
1040
|
+
/* Omit the FI layer */
|
1041
|
+
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
|
1042
|
+
} else
|
1043
|
+
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
|
1044
|
+
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
|
1045
|
+
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
/* MI */
|
1049
|
+
nLayer = DIFL_MI;
|
1050
|
+
nFirstSegm = nFirstIsoSegm;
|
1051
|
+
sBits = 0;
|
1052
|
+
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
|
1053
|
+
sBits |= sDifSegs[nLayer][i];
|
1054
|
+
}
|
1055
|
+
if ( !(sBits & DIFV_OUTPUT_OMIT_F) ) {
|
1056
|
+
/* Omit the MI layer */
|
1057
|
+
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
|
1058
|
+
} else
|
1059
|
+
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
|
1060
|
+
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
|
1061
|
+
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
/* F */
|
1065
|
+
nLayer = DIFL_F;
|
1066
|
+
nFirstSegm = nFirstFmlSegm;
|
1067
|
+
sBits = 0;
|
1068
|
+
for ( i = 0; i < DIFS_idf_LENGTH; i ++ ) {
|
1069
|
+
sBits |= sDifSegs[nLayer][i];
|
1070
|
+
}
|
1071
|
+
if ( !(sBits & DIFV_OUTPUT_OMIT_F) &&
|
1072
|
+
sDifSegs[DIFL_FI][nFirstIsoSegm] == DIFV_BOTH_EMPTY ) {
|
1073
|
+
/* Omit the F layer: no non-iotopic and no isotopic segments */
|
1074
|
+
memset( sDifSegs[nLayer], DIFV_BOTH_EMPTY, DIFS_idf_LENGTH);
|
1075
|
+
} else
|
1076
|
+
/* do not omit fixed-H layer */
|
1077
|
+
if ( sDifSegs[nLayer][nFirstSegm] == DIFV_BOTH_EMPTY ||
|
1078
|
+
!(sDifSegs[nLayer][nFirstSegm] & DIFV_OUTPUT_OMIT_F) ) {
|
1079
|
+
sDifSegs[nLayer][nFirstSegm] = DIFV_IS_EMPTY;
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
/* M -- leave as it is */
|
1083
|
+
return 0;
|
1084
|
+
#undef nFirstFmlSegm
|
1085
|
+
#undef nFirstIsoSegm
|
1086
|
+
}
|
1087
|
+
/*********************************************************************************************/
|
1088
|
+
int CompareInchiStereo( INChI_Stereo *Stereo1, INCHI_MODE nFlags1, INChI_Stereo *Stereo2, INCHI_MODE nFlags2 )
|
1089
|
+
{
|
1090
|
+
int i, num, ret;
|
1091
|
+
if ( Stereo2 && Stereo1 ) {
|
1092
|
+
/* compare stereogenic bonds */
|
1093
|
+
num = inchi_min( Stereo2->nNumberOfStereoBonds, Stereo1->nNumberOfStereoBonds );
|
1094
|
+
for ( i = 0; i < num; i ++ ) {
|
1095
|
+
if ( ret = (int)Stereo2->nBondAtom1[i] - (int)Stereo1->nBondAtom1[i] )
|
1096
|
+
return ret;
|
1097
|
+
if ( ret = (int)Stereo2->nBondAtom2[i] - (int)Stereo1->nBondAtom2[i] )
|
1098
|
+
return ret;
|
1099
|
+
if ( ret = (int)Stereo2->b_parity[i] - (int)Stereo1->b_parity[i] )
|
1100
|
+
return ret;
|
1101
|
+
}
|
1102
|
+
if ( ret = (int)Stereo2->nNumberOfStereoBonds - (int)Stereo1->nNumberOfStereoBonds )
|
1103
|
+
return ret;
|
1104
|
+
/* compare stereogenic atoms */
|
1105
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
1106
|
+
if ( ((nFlags1 | nFlags2) & (INCHI_FLAG_REL_STEREO | INCHI_FLAG_RAC_STEREO) ) &&
|
1107
|
+
1 == Stereo2->nNumberOfStereoCenters &&
|
1108
|
+
1 == Stereo1->nNumberOfStereoCenters ) {
|
1109
|
+
; /* do not compare single stereocenters in case of relative stereo */
|
1110
|
+
} else
|
1111
|
+
#endif
|
1112
|
+
{
|
1113
|
+
num = inchi_min( Stereo2->nNumberOfStereoCenters, Stereo1->nNumberOfStereoCenters );
|
1114
|
+
for ( i = 0; i < num; i ++ ) {
|
1115
|
+
if ( ret = (int)Stereo2->nNumber[i] - (int)Stereo1->nNumber[i] )
|
1116
|
+
return ret;
|
1117
|
+
if ( ret = (int)Stereo2->t_parity[i] - (int)Stereo1->t_parity[i] )
|
1118
|
+
return ret;
|
1119
|
+
}
|
1120
|
+
if ( ret = (int)Stereo2->nNumberOfStereoCenters - (int)Stereo1->nNumberOfStereoCenters )
|
1121
|
+
return ret;
|
1122
|
+
/* compare stereo-abs-is-inverted flags for non-relative, non-racemic */
|
1123
|
+
if ( !((nFlags1 | nFlags2) & (INCHI_FLAG_RAC_STEREO | INCHI_FLAG_REL_STEREO)) ) {
|
1124
|
+
if ( ret = (Stereo2->nCompInv2Abs < 0) - (Stereo1->nCompInv2Abs < 0) ) {
|
1125
|
+
return ret;
|
1126
|
+
}
|
1127
|
+
}
|
1128
|
+
}
|
1129
|
+
} else
|
1130
|
+
if ( Stereo2 && ( Stereo2->nNumberOfStereoBonds > 0 ||
|
1131
|
+
Stereo2->nNumberOfStereoCenters > 0
|
1132
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
1133
|
+
&& /* do not compare single stereocenters in case of relative stereo */
|
1134
|
+
!((nFlags2 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
|
1135
|
+
1 == Stereo2->nNumberOfStereoCenters
|
1136
|
+
)
|
1137
|
+
#endif
|
1138
|
+
) ) {
|
1139
|
+
return 1;
|
1140
|
+
}else
|
1141
|
+
if ( Stereo1 && ( Stereo1->nNumberOfStereoBonds > 0 ||
|
1142
|
+
Stereo1->nNumberOfStereoCenters > 0
|
1143
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
1144
|
+
&& /* do not compare single stereocenters in case of relative stereo */
|
1145
|
+
!((nFlags1 & (INCHI_FLAG_REL_STEREO|INCHI_FLAG_RAC_STEREO)) &&
|
1146
|
+
1 == Stereo1->nNumberOfStereoCenters
|
1147
|
+
)
|
1148
|
+
#endif
|
1149
|
+
) ) {
|
1150
|
+
return -1;
|
1151
|
+
}
|
1152
|
+
return 0;
|
1153
|
+
}
|
1154
|
+
/**********************************************************************************************/
|
1155
|
+
/* sorting in descending order: return -1 if *p1 > *p2, return +1 if *p1 < *p2 */
|
1156
|
+
/**********************************************************************************************/
|
1157
|
+
int CompINChI2(const INCHI_SORT *p1, const INCHI_SORT *p2, int bTaut, int bCompareIsotopic)
|
1158
|
+
{
|
1159
|
+
int ret, num, i, num_H1, num_H2;
|
1160
|
+
|
1161
|
+
const INChI *i1 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
|
1162
|
+
const INChI *i2 = NULL; /* tautomeric if exists, otherwise non-tautomeric */
|
1163
|
+
|
1164
|
+
int n1; /* TAUT_YES if tautomeric i1 exists, otherwise TAUT_NON */
|
1165
|
+
int n2; /* TAUT_YES if tautomeric i2 exists, otherwise TAUT_NON */
|
1166
|
+
|
1167
|
+
const INChI *i1n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
|
1168
|
+
const INChI *i2n = NULL; /* non-tautomeric if both tautomeric AND non-tautomeric exist */
|
1169
|
+
|
1170
|
+
/*const INChI *i1t = NULL;*/ /* temp for i1 if both tautomeric AND non-tautomeric exist */
|
1171
|
+
/*const INChI *i2t = NULL;*/ /* temp for i2 if both tautomeric AND non-tautomeric exist */
|
1172
|
+
|
1173
|
+
|
1174
|
+
/* INChI_Stereo *Stereo1, *Stereo2; */
|
1175
|
+
|
1176
|
+
n1 = ( p1->pINChI[TAUT_YES] && p1->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
|
1177
|
+
n2 = ( p2->pINChI[TAUT_YES] && p2->pINChI[TAUT_YES]->nNumberOfAtoms )? TAUT_YES : TAUT_NON;
|
1178
|
+
|
1179
|
+
i1 = p1->pINChI[n1];
|
1180
|
+
i1n = (n1 == TAUT_YES && p1->pINChI[TAUT_NON] &&
|
1181
|
+
p1->pINChI[TAUT_NON]->nNumberOfAtoms)? p1->pINChI[TAUT_NON] : (const INChI *)NULL;
|
1182
|
+
|
1183
|
+
i2 = p2->pINChI[n2];
|
1184
|
+
i2n = (n2 == TAUT_YES && p2->pINChI[TAUT_NON] &&
|
1185
|
+
p2->pINChI[TAUT_NON]->nNumberOfAtoms)? p2->pINChI[TAUT_NON] : (const INChI *)NULL;
|
1186
|
+
|
1187
|
+
/* non-deleted-non-empty < deleted < empty */
|
1188
|
+
if ( i1 && !i2 )
|
1189
|
+
return -1; /* non-empty is the smallest (first) */
|
1190
|
+
if ( !i1 && i2 )
|
1191
|
+
return 1;
|
1192
|
+
if ( !i1 && !i2 )
|
1193
|
+
return 0;
|
1194
|
+
if ( i1->bDeleted && !i2->bDeleted )
|
1195
|
+
return 1; /* deleted is the largest (last) among non-empty */
|
1196
|
+
if ( !i1->bDeleted && i2->bDeleted )
|
1197
|
+
return -1;
|
1198
|
+
|
1199
|
+
num_H1 = num_H2 = 0;
|
1200
|
+
|
1201
|
+
/* do not compare terminal H */
|
1202
|
+
if ( ret = CompareHillFormulasNoH( i1->szHillFormula, i2->szHillFormula, &num_H1, &num_H2 ) ) {
|
1203
|
+
return ret; /* lexicographic order except the shorter one is greater (last): CH2O < CH2; C3XX < C2XX */
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
/*********************************************************
|
1207
|
+
compare non-isotopic non-tautomeric part
|
1208
|
+
*********************************************************/
|
1209
|
+
|
1210
|
+
/* compare number of atoms (excluding terminal H) */
|
1211
|
+
if ( ret = i2->nNumberOfAtoms - i1->nNumberOfAtoms )
|
1212
|
+
return ret; /* more atoms first */
|
1213
|
+
|
1214
|
+
/* compare elements (excluding terminal H) */
|
1215
|
+
num = i1->nNumberOfAtoms;
|
1216
|
+
for ( i = 0; i < num; i ++ ) { /* should always be equal if Hill formulas are same */
|
1217
|
+
if ( ret = (int)i2->nAtom[i] - (int)i1->nAtom[i] )
|
1218
|
+
return ret; /* greater periodic number first */
|
1219
|
+
}
|
1220
|
+
/**********************************************************
|
1221
|
+
compare connection tables
|
1222
|
+
***********************************************************/
|
1223
|
+
if ( ret = i2->lenConnTable - i1->lenConnTable )
|
1224
|
+
return ret; /* longer connection table first */
|
1225
|
+
num = i2->lenConnTable;
|
1226
|
+
for ( i = 0; i < num; i ++ ) {
|
1227
|
+
if ( ret = (int)i2->nConnTable[i] - (int)i1->nConnTable[i] )
|
1228
|
+
return ret; /* greater connection table first */
|
1229
|
+
}
|
1230
|
+
/*********************************************************
|
1231
|
+
compare compare total number of H (inverse: H3 < H2 )
|
1232
|
+
**********************************************************/
|
1233
|
+
if ( ret = num_H2 - num_H1 )
|
1234
|
+
return ret;
|
1235
|
+
/*********************************************************
|
1236
|
+
compare non-tautomeric num_H: N < NH3 < NH2 < NH
|
1237
|
+
**********************************************************/
|
1238
|
+
num = i1->nNumberOfAtoms;
|
1239
|
+
for ( i = 0; i < num; i ++ ) {
|
1240
|
+
if ( i2->nNum_H[i] != i1->nNum_H[i] ) {
|
1241
|
+
return !i2->nNum_H[i]? 1 : /* no H first */
|
1242
|
+
!i1->nNum_H[i]? -1 :
|
1243
|
+
(int)i2->nNum_H[i] - (int)i1->nNum_H[i];
|
1244
|
+
}
|
1245
|
+
}
|
1246
|
+
/*********************************************************
|
1247
|
+
compare non-isotopic tautomeric part
|
1248
|
+
*********************************************************/
|
1249
|
+
if ( ret = CompareTautNonIsoPartOfINChI( i1, i2) ) {
|
1250
|
+
return ret;
|
1251
|
+
}
|
1252
|
+
/*
|
1253
|
+
if ( ret = i2->lenTautomer - i1->lenTautomer )
|
1254
|
+
return ret;
|
1255
|
+
num = inchi_min( i2->lenTautomer, i1->lenTautomer );
|
1256
|
+
for ( i = 0; i < num; i ++ ) {
|
1257
|
+
if ( ret = (int)i2->nTautomer[i] - (int)i1->nTautomer[i] )
|
1258
|
+
return ret;
|
1259
|
+
}
|
1260
|
+
*/
|
1261
|
+
/*********************************************************
|
1262
|
+
* *
|
1263
|
+
* at this point both components are either tautomeric *
|
1264
|
+
* or non-tautomeric *
|
1265
|
+
* *
|
1266
|
+
*********************************************************/
|
1267
|
+
|
1268
|
+
/*********************************************************
|
1269
|
+
non-tautomeric "fixed H" specific
|
1270
|
+
*********************************************************/
|
1271
|
+
if ( TAUT_NON == bTaut && (i1n && i1n->nNum_H_fixed || i2n && i2n->nNum_H_fixed) ) {
|
1272
|
+
/* first, compare non-tautomeric chem. formulas -- they may be different */
|
1273
|
+
const char *f1 = (i1n /*&& i1n->nNum_H_fixed*/)? i1n->szHillFormula : i1->szHillFormula;
|
1274
|
+
const char *f2 = (i2n /*&& i2n->nNum_H_fixed*/)? i2n->szHillFormula : i2->szHillFormula;
|
1275
|
+
if ( f1 && f2 &&(ret = CompareHillFormulas( f1, f2 ))) {
|
1276
|
+
return ret;
|
1277
|
+
}
|
1278
|
+
/* secondly, compare fixed-H distribution */
|
1279
|
+
if ( i1n && i1n->nNum_H_fixed && i2n && i2n->nNum_H_fixed ) {
|
1280
|
+
num = inchi_min( i1n->nNumberOfAtoms, i2n->nNumberOfAtoms);
|
1281
|
+
for ( i = 0; i < num; i ++ ) {
|
1282
|
+
if ( i2n->nNum_H_fixed[i] != i1n->nNum_H_fixed[i] ) {
|
1283
|
+
return !i2n->nNum_H_fixed[i]? 1 : /* no fixed H first */
|
1284
|
+
!i1n->nNum_H_fixed[i]? -1 :
|
1285
|
+
(int)i2n->nNum_H_fixed[i] - (int)i1n->nNum_H_fixed[i];
|
1286
|
+
}
|
1287
|
+
}
|
1288
|
+
if ( ret = (int)i2n->nNumberOfAtoms - (int)i1n->nNumberOfAtoms ) {
|
1289
|
+
return ret; /* should not happen <BRKPT> */
|
1290
|
+
}
|
1291
|
+
} else
|
1292
|
+
if ( i1n && i1n->nNum_H_fixed ) {
|
1293
|
+
num = i1n->nNumberOfAtoms;
|
1294
|
+
for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
|
1295
|
+
if ( i1n->nNum_H_fixed[i] ) {
|
1296
|
+
return -1; /* i1n->nNum_H_fixed[i] > 0? -1:1;*/
|
1297
|
+
}
|
1298
|
+
}
|
1299
|
+
/* p1 is tautomeric, p2 is not tautomeric; this must have been detected earlier */
|
1300
|
+
/*return -1;*/ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
|
1301
|
+
} else {
|
1302
|
+
num = i2n->nNumberOfAtoms;
|
1303
|
+
for ( i = 0; i < num; i ++ ) { /* added 2004-05-04 */
|
1304
|
+
if ( i2n->nNum_H_fixed[i] ) {
|
1305
|
+
return 1; /* i2n->nNum_H_fixed[i] > 0? 1:-1;*/
|
1306
|
+
}
|
1307
|
+
}
|
1308
|
+
/* p2 is tautomeric, p1 is not tautomeric; this must have been detected earlier */
|
1309
|
+
/*return 1; */ /* has fixed H first *//* <BRKPT> */ /* removed 2004-05-04 */
|
1310
|
+
}
|
1311
|
+
}
|
1312
|
+
|
1313
|
+
/*************************************************************************
|
1314
|
+
if requested non-tautomeric comparison then
|
1315
|
+
prepare to compare non-taut non-isotopic stereo, etc.
|
1316
|
+
*************************************************************************/
|
1317
|
+
if ( TAUT_NON == bTaut ) {
|
1318
|
+
if ( i1n ) {
|
1319
|
+
/*i1t = i1;*/
|
1320
|
+
i1 = i1n;
|
1321
|
+
}
|
1322
|
+
if ( i2n ) {
|
1323
|
+
/*i2t = i2;*/
|
1324
|
+
i2 = i2n;
|
1325
|
+
}
|
1326
|
+
}
|
1327
|
+
|
1328
|
+
/*********************************************************
|
1329
|
+
compare non-isotopic stereo
|
1330
|
+
*********************************************************/
|
1331
|
+
ret = CompareInchiStereo( i1->Stereo, i1->nFlags, i2->Stereo, i2->nFlags );
|
1332
|
+
if ( ret ) {
|
1333
|
+
return ret;
|
1334
|
+
}
|
1335
|
+
/*******************************************************
|
1336
|
+
do not switch back to tautomeric i1, i2
|
1337
|
+
*******************************************************/
|
1338
|
+
/* -- how to switch back --
|
1339
|
+
if ( i1t ) {
|
1340
|
+
i1 = i1t;
|
1341
|
+
i1t = NULL;
|
1342
|
+
}
|
1343
|
+
if ( i2t ) {
|
1344
|
+
i2 = i2t;
|
1345
|
+
i2t = NULL;
|
1346
|
+
}
|
1347
|
+
*/
|
1348
|
+
/******************************************************
|
1349
|
+
compare isotopic non-tautomeric part
|
1350
|
+
******************************************************/
|
1351
|
+
if ( bCompareIsotopic ) {
|
1352
|
+
if ( ret = i2->nNumberOfIsotopicAtoms - i1->nNumberOfIsotopicAtoms )
|
1353
|
+
return ret;
|
1354
|
+
num = i1->nNumberOfIsotopicAtoms;
|
1355
|
+
/* compare isotopic atoms */
|
1356
|
+
for ( i = 0; i < num; i ++ ) {
|
1357
|
+
if ( ret = (int)i2->IsotopicAtom[i].nAtomNumber - (int)i1->IsotopicAtom[i].nAtomNumber )
|
1358
|
+
return ret;
|
1359
|
+
if ( ret = (int)i2->IsotopicAtom[i].nIsoDifference - (int)i1->IsotopicAtom[i].nIsoDifference )
|
1360
|
+
return ret;
|
1361
|
+
}
|
1362
|
+
/* compare isotopic H */
|
1363
|
+
/* if tautomeric comparison mode then here are compared only non-tautomeric H */
|
1364
|
+
for ( i = 0; i < num; i ++ ) {
|
1365
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_T - (int)i1->IsotopicAtom[i].nNum_T )
|
1366
|
+
return ret;
|
1367
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_D - (int)i1->IsotopicAtom[i].nNum_D )
|
1368
|
+
return ret;
|
1369
|
+
if ( ret = (int)i2->IsotopicAtom[i].nNum_H - (int)i1->IsotopicAtom[i].nNum_H )
|
1370
|
+
return ret;
|
1371
|
+
}
|
1372
|
+
/*****************************************************
|
1373
|
+
compare isotopic tautomeric part
|
1374
|
+
*****************************************************/
|
1375
|
+
if ( ret = i2->nNumberOfIsotopicTGroups - i1->nNumberOfIsotopicTGroups )
|
1376
|
+
return ret;
|
1377
|
+
num = i1->nNumberOfIsotopicTGroups;
|
1378
|
+
for ( i = 0; i < num; i ++ ) {
|
1379
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nTGroupNumber - (int)i1->IsotopicTGroup[i].nTGroupNumber )
|
1380
|
+
return ret;
|
1381
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_T - (int)i1->IsotopicTGroup[i].nNum_T )
|
1382
|
+
return ret;
|
1383
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_D - (int)i1->IsotopicTGroup[i].nNum_D )
|
1384
|
+
return ret;
|
1385
|
+
if ( ret = (int)i2->IsotopicTGroup[i].nNum_H - (int)i1->IsotopicTGroup[i].nNum_H )
|
1386
|
+
return ret;
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
/****************************************************
|
1390
|
+
compare isotopic stereo
|
1391
|
+
****************************************************/
|
1392
|
+
ret = CompareInchiStereo( i1->StereoIsotopic, i1->nFlags, i2->StereoIsotopic, i2->nFlags );
|
1393
|
+
if ( ret ) {
|
1394
|
+
return ret;
|
1395
|
+
}
|
1396
|
+
}
|
1397
|
+
|
1398
|
+
/**********************************************************
|
1399
|
+
compare charges: non-charged first, then in order of
|
1400
|
+
ascending charges (negative first)
|
1401
|
+
***********************************************************/
|
1402
|
+
if ( i2->nTotalCharge && i1->nTotalCharge ) {
|
1403
|
+
/* both are charged; smaller charges first */
|
1404
|
+
ret = (int)i1->nTotalCharge - (int)i2->nTotalCharge;
|
1405
|
+
return ret;
|
1406
|
+
}
|
1407
|
+
if ( ret = (i1->nTotalCharge? 1:0) - (i2->nTotalCharge? 1:0) ) {
|
1408
|
+
/* only one is charged; uncharged first */
|
1409
|
+
return ret;
|
1410
|
+
}
|
1411
|
+
/* stable sort */
|
1412
|
+
/*ret = p1->ord_number - p2->ord_number;*/
|
1413
|
+
|
1414
|
+
return ret;
|
1415
|
+
}
|
1416
|
+
/***********************************************************************/
|
1417
|
+
int CompINChINonTaut2(const void *p1, const void *p2)
|
1418
|
+
{
|
1419
|
+
int ret;
|
1420
|
+
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
|
1421
|
+
#if( CANON_FIXH_TRANS == 1 )
|
1422
|
+
if ( !ret ) {
|
1423
|
+
/* to obtain canonical transposition 2004-05-10 */
|
1424
|
+
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
|
1425
|
+
}
|
1426
|
+
#endif
|
1427
|
+
if ( !ret ) {
|
1428
|
+
/* stable sort */
|
1429
|
+
ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
|
1430
|
+
}
|
1431
|
+
return ret;
|
1432
|
+
}
|
1433
|
+
/***********************************************************************/
|
1434
|
+
int CompINChITaut2(const void *p1, const void *p2)
|
1435
|
+
{
|
1436
|
+
int ret;
|
1437
|
+
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_YES, 1 );
|
1438
|
+
#if( CANON_FIXH_TRANS == 1 )
|
1439
|
+
if ( !ret ) {
|
1440
|
+
/* to obtain canonical transposition 2004-05-10 */
|
1441
|
+
ret = CompINChI2( (const INCHI_SORT *)p1, (const INCHI_SORT *)p2, TAUT_NON, 1 );
|
1442
|
+
}
|
1443
|
+
#endif
|
1444
|
+
if ( !ret ) {
|
1445
|
+
/* stable sort */
|
1446
|
+
ret = ((const INCHI_SORT *)p1)->ord_number - ((const INCHI_SORT *)p2)->ord_number;
|
1447
|
+
}
|
1448
|
+
return ret;
|
1449
|
+
}
|
1450
|
+
/**********************************************************************************************/
|
1451
|
+
/* strrev from K&R is not in ANSI-compatible C library */
|
1452
|
+
void mystrrev( char *p )
|
1453
|
+
{
|
1454
|
+
char c, *q = p;
|
1455
|
+
while( *q++ )
|
1456
|
+
;
|
1457
|
+
q -= 2; /* pointer to the last character */
|
1458
|
+
while ( p < q ) {
|
1459
|
+
c = *q; /* swap */
|
1460
|
+
*q-- = *p;
|
1461
|
+
*p++ = c;
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
/*****************************************************************************************/
|
1465
|
+
/* Find DFS order for CT(canon. numbers and Hs) output */
|
1466
|
+
/*****************************************************************************************/
|
1467
|
+
|
1468
|
+
static AT_NUMB *gDfs4CT_nDfsNumber;
|
1469
|
+
static AT_NUMB *gDfs4CT_nNumDescendants;
|
1470
|
+
static int gDfs4CT_nCurrentAtom;
|
1471
|
+
|
1472
|
+
/**********************************************************************************************/
|
1473
|
+
static int CompareDfsDescendants4CT( const void *a1, const void *a2 )
|
1474
|
+
{
|
1475
|
+
int neigh1 = (int)*(const AT_RANK*)a1;
|
1476
|
+
int neigh2 = (int)*(const AT_RANK*)a2;
|
1477
|
+
if ( neigh1 > MAX_ATOMS ) {
|
1478
|
+
if ( neigh2 > MAX_ATOMS ) {
|
1479
|
+
return 0;
|
1480
|
+
}
|
1481
|
+
return 1;
|
1482
|
+
} else
|
1483
|
+
if ( neigh2 > MAX_ATOMS ) {
|
1484
|
+
return -1;
|
1485
|
+
} else {
|
1486
|
+
AT_RANK nCurDfsNumber = gDfs4CT_nDfsNumber[gDfs4CT_nCurrentAtom];
|
1487
|
+
int nDesc1 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh1]?
|
1488
|
+
0 : (int)gDfs4CT_nNumDescendants[neigh1];
|
1489
|
+
int nDesc2 = nCurDfsNumber > gDfs4CT_nDfsNumber[neigh2]?
|
1490
|
+
0 : (int)gDfs4CT_nNumDescendants[neigh2];
|
1491
|
+
int ret;
|
1492
|
+
if ( ret = nDesc1 - nDesc2 ) {
|
1493
|
+
return ret;
|
1494
|
+
}
|
1495
|
+
return (int)neigh1 - (int)neigh2; /* canon. numbers difference */
|
1496
|
+
}
|
1497
|
+
}
|
1498
|
+
/**********************************************************************************************/
|
1499
|
+
/* sp_ATOM *at, AT_RANK *nRank, int num_atoms */
|
1500
|
+
AT_NUMB *GetDfsOrder4CT( AT_NUMB *LinearCT, int nLenCT, S_CHAR *nNum_H, int num_atoms, int nCtMode )
|
1501
|
+
{
|
1502
|
+
AT_NUMB *nStackAtom = NULL;
|
1503
|
+
int nTopStackAtom=-1;
|
1504
|
+
AT_NUMB *nNumDescendants = NULL; /* number of descendants incl. closures and the atom itself */
|
1505
|
+
AT_NUMB *nDfsNumber = NULL;
|
1506
|
+
S_CHAR *cNeighNumb = NULL;
|
1507
|
+
NEIGH_LIST *nl = NULL;
|
1508
|
+
AT_NUMB nDfs;
|
1509
|
+
int i, j, u, k, start, num_rings, nTotOutputStringLen;
|
1510
|
+
AT_NUMB *nOutputString = NULL, cDelim;
|
1511
|
+
int bCtPredecessors = (nCtMode & CT_MODE_PREDECESSORS);
|
1512
|
+
|
1513
|
+
/* int nNumStartChildren; */
|
1514
|
+
|
1515
|
+
|
1516
|
+
/* allocate arrays */
|
1517
|
+
nStackAtom = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
|
1518
|
+
nNumDescendants = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nNumDescendants[0]));
|
1519
|
+
nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
|
1520
|
+
cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
|
1521
|
+
nl = CreateNeighListFromLinearCT( LinearCT, nLenCT, num_atoms );
|
1522
|
+
/* check allocation */
|
1523
|
+
if ( !nStackAtom || !nNumDescendants || !nDfsNumber || !cNeighNumb || !nl ) {
|
1524
|
+
/* ret = CT_OUT_OF_RAM; */ /* program error */ /* <BRKPT> */
|
1525
|
+
goto exit_function;
|
1526
|
+
}
|
1527
|
+
if ( bCtPredecessors ) {
|
1528
|
+
start = 0;
|
1529
|
+
} else {
|
1530
|
+
/* find DFS start vertex (atom) */
|
1531
|
+
for ( i = 1, start = 0; i < num_atoms; i ++ ) {
|
1532
|
+
if ( nl[i][0] < nl[start][0] ) { /* index = nRank-1 */
|
1533
|
+
start = i;
|
1534
|
+
}
|
1535
|
+
}
|
1536
|
+
}
|
1537
|
+
/*
|
1538
|
+
vertex information:
|
1539
|
+
1. Number of (forward edges) + (back edges, first visit -- ring closures): nl[i][0]
|
1540
|
+
2. Number of vertices traversed from this vertex, including the vertex: nNumDescendants[i]
|
1541
|
+
3. Each edge information:
|
1542
|
+
a. forward edge (0) or back edge (1) indicator: nDfsNumber[i] > nDfsNumber[neigh]
|
1543
|
+
b. neighbor at another end of the edge neigh = nl[i][k+1], k < i
|
1544
|
+
|
1545
|
+
Total per edge: 2 + 2*(number of edges)
|
1546
|
+
*/
|
1547
|
+
|
1548
|
+
/* DFS initiation */
|
1549
|
+
u = start; /* start atom */
|
1550
|
+
nDfs = 0;
|
1551
|
+
nTopStackAtom =-1;
|
1552
|
+
memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
|
1553
|
+
memset( nNumDescendants, 0, num_atoms*sizeof(nNumDescendants[0]));
|
1554
|
+
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
|
1555
|
+
/* push the start atom on the stack */
|
1556
|
+
nDfsNumber[u] = ++nDfs;
|
1557
|
+
if ( bCtPredecessors ) {
|
1558
|
+
nNumDescendants[u] = 0; /* atom #1 has no predecessor */
|
1559
|
+
} else {
|
1560
|
+
nNumDescendants[u] = 1; /* count itself as a descendant */
|
1561
|
+
}
|
1562
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
1563
|
+
/* nNumStartChildren = 0; */
|
1564
|
+
num_rings = 0;
|
1565
|
+
|
1566
|
+
/* DFS */
|
1567
|
+
|
1568
|
+
do {
|
1569
|
+
/* advance */
|
1570
|
+
while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) ) {
|
1571
|
+
cNeighNumb[i] ++;
|
1572
|
+
u = (int)nl[i][j]; /* jth neighbor of the vertex i */
|
1573
|
+
if ( !nDfsNumber[u] ) {
|
1574
|
+
/* tree edge, 1st visit -- advance */
|
1575
|
+
/* put unexplored vertex u on the stack for further examination */
|
1576
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
1577
|
+
nDfsNumber[u] = ++nDfs;
|
1578
|
+
if ( bCtPredecessors ) {
|
1579
|
+
nNumDescendants[u] = i+1; /* predecessor's rank */
|
1580
|
+
} else {
|
1581
|
+
nNumDescendants[u] ++; /* count atom u as its descendant */
|
1582
|
+
}
|
1583
|
+
} else
|
1584
|
+
if ( nTopStackAtom && u != (int)nStackAtom[nTopStackAtom-1] &&
|
1585
|
+
/* back edge: u is not a predecessor of i */
|
1586
|
+
nDfsNumber[u] < nDfsNumber[i] ) {
|
1587
|
+
/* Back edge, 1st visit: u is an ancestor of i (ring closure) */
|
1588
|
+
if ( !bCtPredecessors ) {
|
1589
|
+
nNumDescendants[i] ++; /* count closures as descendants */
|
1590
|
+
}
|
1591
|
+
num_rings ++; /* count ring closures */
|
1592
|
+
} else {
|
1593
|
+
nl[i][j] = MAX_ATOMS+1; /* back edge, 2nd visit: mark as deleted */
|
1594
|
+
}
|
1595
|
+
}
|
1596
|
+
cNeighNumb[i] = 0; /* all neighbors of the ith atom have been
|
1597
|
+
traversed; resore the neighbor counter */
|
1598
|
+
/* back up */
|
1599
|
+
if ( !bCtPredecessors && nTopStackAtom /* that is, i != start */) {
|
1600
|
+
u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
|
1601
|
+
nNumDescendants[u] += nNumDescendants[i]; /* add descendants */
|
1602
|
+
}
|
1603
|
+
} while ( --nTopStackAtom >= 0 );
|
1604
|
+
|
1605
|
+
/* Sort the neighbors in ascending order so that:
|
1606
|
+
primary key = number of descendants in the DFS tree; closure neighbor is 0
|
1607
|
+
secondary key = canonical number (here vertex number = canonical number - 1)
|
1608
|
+
*/
|
1609
|
+
|
1610
|
+
/* set static globals for the sorting: */
|
1611
|
+
gDfs4CT_nDfsNumber = nDfsNumber;
|
1612
|
+
gDfs4CT_nNumDescendants = nNumDescendants;
|
1613
|
+
gDfs4CT_nCurrentAtom = -1;
|
1614
|
+
|
1615
|
+
/* sorting; deleted will be the last neighbors */
|
1616
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
1617
|
+
if ( nl[i][0] > 1 ) {
|
1618
|
+
gDfs4CT_nCurrentAtom = i;
|
1619
|
+
insertions_sort( &nl[i][1], nl[i][0], sizeof(nl[i][1]), CompareDfsDescendants4CT );
|
1620
|
+
}
|
1621
|
+
/* reduce number of neighbors to exclude deleted */
|
1622
|
+
for ( k = 0; k < nl[i][0] && nl[i][k+1] <= MAX_ATOMS; k ++ )
|
1623
|
+
;
|
1624
|
+
nl[i][0] = k;
|
1625
|
+
}
|
1626
|
+
|
1627
|
+
nTotOutputStringLen = 3*(num_atoms+num_rings+1); /* last 3 elements are a 'zero termination' */
|
1628
|
+
|
1629
|
+
if ( bCtPredecessors ) {
|
1630
|
+
if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
|
1631
|
+
cDelim = '-';
|
1632
|
+
for ( u = 0, k = -3 ; u < num_atoms; u ++ ) {
|
1633
|
+
k += 3;
|
1634
|
+
if ( k+6 > nTotOutputStringLen ) {
|
1635
|
+
goto exit_error; /* program error */
|
1636
|
+
}
|
1637
|
+
nOutputString[k] = nNumDescendants[u]? nNumDescendants[u] : MAX_ATOMS+1;
|
1638
|
+
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
|
1639
|
+
nOutputString[k+2] = k? ',' : '\0';
|
1640
|
+
for ( j = 1; j <= nl[u][0] && nDfsNumber[u] > nDfsNumber[i=nl[u][j]]; j ++ ) {
|
1641
|
+
/* closures */
|
1642
|
+
k += 3;
|
1643
|
+
if ( k+6 > nTotOutputStringLen ) {
|
1644
|
+
goto exit_error; /* program error */
|
1645
|
+
}
|
1646
|
+
nOutputString[k] = i+1; /* closure */
|
1647
|
+
nOutputString[k+1] = 0;
|
1648
|
+
nOutputString[k+2] = cDelim;
|
1649
|
+
}
|
1650
|
+
}
|
1651
|
+
}
|
1652
|
+
} else {
|
1653
|
+
if ( nNumDescendants ) { /* do not need anymore */
|
1654
|
+
inchi_free( nNumDescendants );
|
1655
|
+
nNumDescendants = NULL;
|
1656
|
+
}
|
1657
|
+
/*
|
1658
|
+
the output string contains:
|
1659
|
+
(num_atoms) atoms for the DFS (spanning) tree
|
1660
|
+
(num_atoms-1) delimiters for the DFS (spanning) tree
|
1661
|
+
1 character for each atom that has 1 terminal hydrogen atoms
|
1662
|
+
2 characters for each atom that has 2-9 terminal hydrogen atoms
|
1663
|
+
3 characters for each atom that has 10-99 terminal hydrogen atoms, etc.
|
1664
|
+
(num_rings) atoms for the ring closures
|
1665
|
+
(num_rings) delimiters for the ring closures
|
1666
|
+
*/
|
1667
|
+
|
1668
|
+
if ( nOutputString = (AT_RANK *)inchi_calloc( nTotOutputStringLen, sizeof(nOutputString[0]) ) ) {
|
1669
|
+
u = start; /* start atom */
|
1670
|
+
nTopStackAtom =-1;
|
1671
|
+
memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
|
1672
|
+
/* push the start atom on the stack */
|
1673
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
1674
|
+
/* output the starting atom */
|
1675
|
+
k = 0;
|
1676
|
+
nOutputString[k] = u+1;
|
1677
|
+
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
|
1678
|
+
nOutputString[k+2] = '\0';
|
1679
|
+
|
1680
|
+
do {
|
1681
|
+
/* advance */
|
1682
|
+
while ( (int)nl[i=nStackAtom[nTopStackAtom]][0] >= (j = (int)cNeighNumb[i]+1) ) {
|
1683
|
+
k += 3;
|
1684
|
+
if ( k+6 > nTotOutputStringLen ) {
|
1685
|
+
goto exit_error; /* program error */
|
1686
|
+
}
|
1687
|
+
cNeighNumb[i] ++;
|
1688
|
+
u = (int)nl[i][j]; /* neighbor */
|
1689
|
+
|
1690
|
+
/* output neighbor's canonical number */
|
1691
|
+
nOutputString[k] = u+1;
|
1692
|
+
|
1693
|
+
if ( nDfsNumber[u] > nDfsNumber[i] ) {
|
1694
|
+
/* tree edge, 1st visit -- advance */
|
1695
|
+
/* put 'unexplored' vertex u on the stack */
|
1696
|
+
nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
|
1697
|
+
|
1698
|
+
/* output neighbor's number of H */
|
1699
|
+
nOutputString[k+1] = nNum_H? 16+nNum_H[u]:0;
|
1700
|
+
} else {
|
1701
|
+
nOutputString[k+1] = 0;
|
1702
|
+
}
|
1703
|
+
/* output a delimiter preceding the neighbor */
|
1704
|
+
if ( 1 < nl[i][0] ) {
|
1705
|
+
if ( j == 1 ) {
|
1706
|
+
cDelim = '(';
|
1707
|
+
} else
|
1708
|
+
if ( j == nl[i][0] ) {
|
1709
|
+
cDelim = ')';
|
1710
|
+
} else {
|
1711
|
+
cDelim = ',';
|
1712
|
+
}
|
1713
|
+
} else {
|
1714
|
+
cDelim = '-';
|
1715
|
+
}
|
1716
|
+
nOutputString[k+2] = cDelim;
|
1717
|
+
}
|
1718
|
+
cNeighNumb[i] = 0;
|
1719
|
+
|
1720
|
+
/* back up: nothing else to do */
|
1721
|
+
} while ( --nTopStackAtom >= 0 );
|
1722
|
+
}
|
1723
|
+
}
|
1724
|
+
goto exit_function;
|
1725
|
+
|
1726
|
+
exit_error:
|
1727
|
+
if ( nOutputString ) {
|
1728
|
+
inchi_free( nOutputString );
|
1729
|
+
nOutputString = NULL;
|
1730
|
+
}
|
1731
|
+
|
1732
|
+
exit_function:
|
1733
|
+
if ( nStackAtom )
|
1734
|
+
inchi_free( nStackAtom );
|
1735
|
+
if ( nNumDescendants )
|
1736
|
+
inchi_free( nNumDescendants );
|
1737
|
+
if ( nDfsNumber )
|
1738
|
+
inchi_free( nDfsNumber );
|
1739
|
+
if ( cNeighNumb )
|
1740
|
+
inchi_free( cNeighNumb );
|
1741
|
+
if ( nl )
|
1742
|
+
FreeNeighList( nl );
|
1743
|
+
return nOutputString;
|
1744
|
+
}
|
1745
|
+
/**********************************************************************************************/
|
1746
|
+
int GetInpStructErrorType( INPUT_PARMS *ip, int err, char *pStrErrStruct, int num_inp_atoms )
|
1747
|
+
{
|
1748
|
+
if ( err && err == 9 )
|
1749
|
+
return _IS_ERROR; /* sdfile bypassed to $$$$ */
|
1750
|
+
if ( err && err < 30 )
|
1751
|
+
return _IS_FATAL;
|
1752
|
+
if ( num_inp_atoms <= 0 || err ) {
|
1753
|
+
if ( 98 == err && 0 == num_inp_atoms && ip->bAllowEmptyStructure )
|
1754
|
+
return _IS_WARNING;
|
1755
|
+
return _IS_ERROR;
|
1756
|
+
}
|
1757
|
+
if ( pStrErrStruct[0] )
|
1758
|
+
return _IS_WARNING;
|
1759
|
+
return _IS_OKAY;
|
1760
|
+
}
|
1761
|
+
/**********************************************************************************************/
|
1762
|
+
int ProcessStructError( INCHI_FILE *output_file, INCHI_FILE *log_file, /*int err,*/ char *pStrErrStruct, int nErrorType,
|
1763
|
+
int *bXmlStructStarted, int num_inp, INPUT_PARMS *ip, char *pStr, int nStrLen )
|
1764
|
+
{
|
1765
|
+
int b_ok;
|
1766
|
+
#ifdef INCHI_LIB
|
1767
|
+
int bPlainText = (ip->bINChIOutputOptions & INCHI_OUT_PLAIN_TEXT) &&
|
1768
|
+
(ip->bINChIOutputOptions & INCHI_OUT_WINCHI_WINDOW ) &&
|
1769
|
+
!(ip->bINChIOutputOptions & INCHI_OUT_XML);
|
1770
|
+
#else
|
1771
|
+
int bPlainText = 0;
|
1772
|
+
#endif
|
1773
|
+
if ( !bPlainText && *bXmlStructStarted <= 0 ) {
|
1774
|
+
return nErrorType;
|
1775
|
+
}
|
1776
|
+
/* Fatal error, Error, Warning */
|
1777
|
+
if ( nErrorType ) {
|
1778
|
+
if ( bPlainText ) {
|
1779
|
+
if ( !(b_ok=OutputINChIPlainError( output_file, pStr, nStrLen, pStrErrStruct, nErrorType ) ) ) {
|
1780
|
+
my_fprintf( log_file, "Cannot create message for error (structure #%d.%s%s%s%s) Terminating.\n",
|
1781
|
+
num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
|
1782
|
+
} else {
|
1783
|
+
inchi_print( output_file, "\n" ); /* add a blank line after the WINCHI Window message */
|
1784
|
+
}
|
1785
|
+
} else {
|
1786
|
+
if ( !(b_ok=OutputINChIXmlError( output_file, pStr, nStrLen, 2, /*err,*/ pStrErrStruct, nErrorType ) ) ) {
|
1787
|
+
my_fprintf( log_file, "Cannot create xml tag for error (structure #%d.%s%s%s%s) Terminating.\n",
|
1788
|
+
num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
|
1789
|
+
}
|
1790
|
+
if ( !b_ok || nErrorType == _IS_FATAL || nErrorType == _IS_ERROR ) {
|
1791
|
+
/* close current structure output */
|
1792
|
+
if ( !OutputINChIXmlStructEndTag( output_file, pStr, nStrLen, 1 ) ) {
|
1793
|
+
my_fprintf( log_file, "Cannot create end xml tag for structure #%d.%s%s%s%s Terminating.\n", num_inp, SDF_LBL_VAL(ip->pSdfLabel,ip->pSdfValue) );
|
1794
|
+
*bXmlStructStarted = -1;
|
1795
|
+
b_ok = 0;
|
1796
|
+
} else {
|
1797
|
+
*bXmlStructStarted = 0;
|
1798
|
+
}
|
1799
|
+
}
|
1800
|
+
}
|
1801
|
+
return b_ok? nErrorType : _IS_FATAL;
|
1802
|
+
}
|
1803
|
+
return nErrorType;
|
1804
|
+
|
1805
|
+
}
|
1806
|
+
|
1807
|
+
#if( TEST_RENUMB_ATOMS == 1 ) /* { */
|
1808
|
+
/***************************************************************************************/
|
1809
|
+
int CompareStereoINChI( INChI_Stereo *s1, INChI_Stereo *s2 )
|
1810
|
+
{
|
1811
|
+
if ( s1 == NULL && s2 == NULL )
|
1812
|
+
return 0;
|
1813
|
+
if ( (s1 == NULL) ^ (s2 == NULL) )
|
1814
|
+
return 20;
|
1815
|
+
|
1816
|
+
if ( s1->nNumberOfStereoCenters != s2->nNumberOfStereoCenters )
|
1817
|
+
return 21;
|
1818
|
+
if ( s1->nNumberOfStereoCenters > 0 ) {
|
1819
|
+
if ( memcmp( s1->nNumber, s2->nNumber, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
|
1820
|
+
return 22;
|
1821
|
+
if ( memcmp( s1->t_parity, s2->t_parity, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
|
1822
|
+
return 23;
|
1823
|
+
if ( s1->nNumberInv && s2->nNumberInv ) {
|
1824
|
+
if ( memcmp( s1->nNumberInv, s2->nNumberInv, s1->nNumberOfStereoCenters*sizeof(s1->nNumber[0]) ) )
|
1825
|
+
return 28;
|
1826
|
+
if ( memcmp( s1->t_parityInv, s2->t_parityInv, s1->nNumberOfStereoCenters*sizeof(s1->t_parity[0]) ) )
|
1827
|
+
return 29;
|
1828
|
+
if ( s1->nCompInv2Abs != s2->nCompInv2Abs ||
|
1829
|
+
s1->bTrivialInv != s2->bTrivialInv ) {
|
1830
|
+
return 30;
|
1831
|
+
}
|
1832
|
+
} else
|
1833
|
+
if ( s1->nNumberInv || s2->nNumberInv ) {
|
1834
|
+
return 31;
|
1835
|
+
}
|
1836
|
+
}
|
1837
|
+
if ( s1->nNumberOfStereoBonds != s2->nNumberOfStereoBonds )
|
1838
|
+
return 24;
|
1839
|
+
if ( s1->nNumberOfStereoBonds > 0 ) {
|
1840
|
+
if ( memcmp( s1->nBondAtom1, s2->nBondAtom1, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom1[0]) ) )
|
1841
|
+
return 25;
|
1842
|
+
if ( memcmp( s1->nBondAtom2, s2->nBondAtom2, s1->nNumberOfStereoBonds*sizeof(s1->nBondAtom2[0]) ) )
|
1843
|
+
return 26;
|
1844
|
+
if ( memcmp( s1->b_parity, s2->b_parity, s1->nNumberOfStereoBonds*sizeof(s1->b_parity[0]) ) )
|
1845
|
+
return 27;
|
1846
|
+
}
|
1847
|
+
return 0;
|
1848
|
+
}
|
1849
|
+
/***************************************************************************************/
|
1850
|
+
int CompareINChI( INChI *i1, INChI *i2, INChI_Aux *a1, INChI_Aux *a2 )
|
1851
|
+
{
|
1852
|
+
int ret;
|
1853
|
+
if ( i1 == NULL && i2 == NULL )
|
1854
|
+
return 0;
|
1855
|
+
if ( (i1 == NULL) ^ (i2 == NULL) )
|
1856
|
+
return 1;
|
1857
|
+
|
1858
|
+
if ( i1->nErrorCode == i2->nErrorCode ) {
|
1859
|
+
if ( i1->nErrorCode )
|
1860
|
+
return 0;
|
1861
|
+
} else {
|
1862
|
+
return 2;
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
if ( i1->nNumberOfAtoms != i2->nNumberOfAtoms )
|
1866
|
+
return 3;
|
1867
|
+
if ( i1->nNumberOfAtoms > 0 ) {
|
1868
|
+
if ( memcmp( i1->nAtom, i2->nAtom, i1->nNumberOfAtoms*sizeof(i1->nAtom[0]) ) )
|
1869
|
+
return 4;
|
1870
|
+
if ( memcmp( i1->nNum_H, i2->nNum_H, i1->nNumberOfAtoms*sizeof(i1->nNum_H[0]) ) )
|
1871
|
+
return 5;
|
1872
|
+
if ( i1->nNum_H_fixed && i2->nNum_H_fixed &&
|
1873
|
+
memcmp( i1->nNum_H_fixed, i2->nNum_H_fixed, i1->nNumberOfAtoms*sizeof(i1->nNum_H_fixed[0]) ) ) {
|
1874
|
+
return 6;
|
1875
|
+
}
|
1876
|
+
if ( strcmp( i1->szHillFormula, i2->szHillFormula ) )
|
1877
|
+
return 7;
|
1878
|
+
}
|
1879
|
+
|
1880
|
+
if ( i1->lenConnTable != i2->lenConnTable )
|
1881
|
+
return 8;
|
1882
|
+
if ( i1->lenConnTable > 0 && memcmp( i1->nConnTable, i2->nConnTable, i1->lenConnTable*sizeof(i1->nConnTable[0]) ) )
|
1883
|
+
return 9;
|
1884
|
+
|
1885
|
+
if ( i1->lenTautomer != i2->lenTautomer )
|
1886
|
+
return 10;
|
1887
|
+
if ( i1->lenTautomer > 0 && memcmp( i1->nTautomer, i2->nTautomer, i1->lenTautomer*sizeof(i1->nTautomer[0]) ) )
|
1888
|
+
return 11;
|
1889
|
+
|
1890
|
+
if ( i1->nNumberOfIsotopicAtoms != i2->nNumberOfIsotopicAtoms )
|
1891
|
+
return 12;
|
1892
|
+
if ( i1->nNumberOfIsotopicAtoms > 0 && memcmp( i1->IsotopicAtom, i2->IsotopicAtom, i1->nNumberOfIsotopicAtoms*sizeof(i1->IsotopicAtom[0]) ) )
|
1893
|
+
return 13;
|
1894
|
+
|
1895
|
+
if ( i1->nNumberOfIsotopicTGroups != i2->nNumberOfIsotopicTGroups )
|
1896
|
+
return 14;
|
1897
|
+
if ( i1->nNumberOfIsotopicTGroups > 0 && memcmp( i1->IsotopicTGroup, i2->IsotopicTGroup, i1->nNumberOfIsotopicTGroups*sizeof(i1->IsotopicTGroup[0]) ) )
|
1898
|
+
return 15;
|
1899
|
+
if ( a1->nNumRemovedProtons != a2->nNumRemovedProtons )
|
1900
|
+
return 16;
|
1901
|
+
if ( memcmp( a1->nNumRemovedIsotopicH, a2->nNumRemovedIsotopicH, sizeof(a1->nNumRemovedIsotopicH) ) )
|
1902
|
+
return 17;
|
1903
|
+
if ( i1->nPossibleLocationsOfIsotopicH && i2->nPossibleLocationsOfIsotopicH ) {
|
1904
|
+
if ( i1->nPossibleLocationsOfIsotopicH[0] != i2->nPossibleLocationsOfIsotopicH[0] ||
|
1905
|
+
memcmp(i1->nPossibleLocationsOfIsotopicH, i2->nPossibleLocationsOfIsotopicH,
|
1906
|
+
sizeof(i1->nPossibleLocationsOfIsotopicH[0])*i1->nPossibleLocationsOfIsotopicH[0]) )
|
1907
|
+
return 18;
|
1908
|
+
} else
|
1909
|
+
if ( !i1->nPossibleLocationsOfIsotopicH != !i2->nPossibleLocationsOfIsotopicH ) {
|
1910
|
+
return 19;
|
1911
|
+
}
|
1912
|
+
/* ret = 20..31 */
|
1913
|
+
if ( ret = CompareStereoINChI( i1->Stereo, i2->Stereo ) )
|
1914
|
+
return ret;
|
1915
|
+
/* ret = 40..51 */
|
1916
|
+
if ( ret = CompareStereoINChI( i1->StereoIsotopic, i2->StereoIsotopic ) )
|
1917
|
+
return ret+20;
|
1918
|
+
|
1919
|
+
return 0;
|
1920
|
+
}
|
1921
|
+
#endif /* } TEST_RENUMB_ATOMS == 1 */
|
1922
|
+
/***************************************************************************************/
|
1923
|
+
int Create_INChI( INChI **ppINChI, INChI_Aux **ppINChI_Aux, ORIG_ATOM_DATA *orig_inp_data,
|
1924
|
+
inp_ATOM *inp_at, INP_ATOM_DATA *out_norm_data[2],
|
1925
|
+
int num_inp_at, INCHI_MODE nUserMode,
|
1926
|
+
INCHI_MODE *pbTautFlags, INCHI_MODE *pbTautFlagsDone,
|
1927
|
+
struct tagInchiTime *ulMaxTime, char *pStrErrStruct)
|
1928
|
+
{
|
1929
|
+
/*
|
1930
|
+
#define NON_TAUT 0
|
1931
|
+
#define TAUT 1
|
1932
|
+
*/
|
1933
|
+
sp_ATOM *at[TAUT_NUM]; /* at[0]=>non-tautomeric, at[1]=>tautomeric */
|
1934
|
+
/* inp_ATOM *out_norm_taut_at, *out_norm_nontaut_at; */
|
1935
|
+
int i, n1, n2, num_atoms, num_at_tg, num_removed_H, num_removed_H_taut=0, ret=0, ret2=0;
|
1936
|
+
INCHI_MODE nMode=0;
|
1937
|
+
T_GROUP_INFO vt_group_info;
|
1938
|
+
T_GROUP_INFO vt_group_info_orig;
|
1939
|
+
T_GROUP_INFO * /*const*/ t_group_info = &vt_group_info;
|
1940
|
+
T_GROUP_INFO * /*const*/ t_group_info_orig = &vt_group_info_orig;
|
1941
|
+
|
1942
|
+
CANON_STAT CS, CS2;
|
1943
|
+
CANON_STAT *pCS = &CS;
|
1944
|
+
CANON_STAT *pCS2 = &CS2; /* save all allocations to avoid memory leaks in case Canon_INChI() removes the pointer */
|
1945
|
+
|
1946
|
+
ATOM_SIZES s[TAUT_NUM];
|
1947
|
+
|
1948
|
+
BCN Bcn;
|
1949
|
+
BCN *pBCN = &Bcn;
|
1950
|
+
|
1951
|
+
int bHasIsotopicAtoms = 0;
|
1952
|
+
int bMayHaveStereo = 0;
|
1953
|
+
int num_taut_at = 0;
|
1954
|
+
|
1955
|
+
inp_ATOM *out_at = NULL; /*, *norm_at_fixed_bonds[TAUT_NUM]; *//* = {out_norm_nontaut_at, out_norm_taut_at} ; */
|
1956
|
+
INChI *pINChI;
|
1957
|
+
INChI_Aux *pINChI_Aux;
|
1958
|
+
int bPointedEdgeStereo = (0 != (TG_FLAG_POINTED_EDGE_STEREO & *pbTautFlags));
|
1959
|
+
INCHI_MODE bTautFlags = (*pbTautFlags & (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) );
|
1960
|
+
INCHI_MODE bTautFlagsDone = (*pbTautFlagsDone /*& (~(INCHI_MODE)TG_FLAG_ALL_TAUTOMERIC) */);
|
1961
|
+
#if( bRELEASE_VERSION == 0 )
|
1962
|
+
int bExtract = 0; /* EXTR_HAS_ATOM_WITH_DEFINED_PARITY; */
|
1963
|
+
#endif
|
1964
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
1965
|
+
long ulNormTime=0;
|
1966
|
+
long ulCanonTime=0, ulCanonTime2=0;
|
1967
|
+
|
1968
|
+
inchiTime ulNormTimeStart;
|
1969
|
+
inchiTime ulCanonTimeStart;
|
1970
|
+
|
1971
|
+
InchiTimeGet( &ulNormTimeStart );
|
1972
|
+
#endif
|
1973
|
+
|
1974
|
+
memset( s, 0, sizeof(s) );
|
1975
|
+
if ( pBCN ) {
|
1976
|
+
memset( pBCN, 0, sizeof( pBCN[0] ) );
|
1977
|
+
}
|
1978
|
+
memset( t_group_info, 0, sizeof(*t_group_info) );
|
1979
|
+
memset( t_group_info_orig, 0, sizeof(*t_group_info_orig) );
|
1980
|
+
/*norm_at[TAUT_NON] = out_norm_data[TAUT_NON]->at; *//* output normalized non-tautomeric component */
|
1981
|
+
/*norm_at[TAUT_YES] = out_norm_data[TAUT_YES]->at; *//* output normalized tautomeric component */
|
1982
|
+
/*norm_at_fixed_bonds[TAUT_NON] = NULL;*/
|
1983
|
+
/*norm_at_fixed_bonds[TAUT_YES] = out_norm_data[TAUT_YES]->at_fixed_bonds;*/
|
1984
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
1985
|
+
if ( out_norm_data[i]->at ) {
|
1986
|
+
if ( !(at[i] = (sp_ATOM *)inchi_malloc( num_inp_at * sizeof(*at[0]) ) ) ) {
|
1987
|
+
ret = -1;
|
1988
|
+
}
|
1989
|
+
} else {
|
1990
|
+
at[i] = NULL;
|
1991
|
+
}
|
1992
|
+
}
|
1993
|
+
if ( !out_norm_data[TAUT_NON]->at && !out_norm_data[TAUT_YES]->at || !inp_at || ret ) {
|
1994
|
+
ret = -1;
|
1995
|
+
goto exit_function;
|
1996
|
+
}
|
1997
|
+
/* the first struct to process: tautomeric if exists else non-tautomeric */
|
1998
|
+
out_at = out_norm_data[TAUT_YES]->at? out_norm_data[TAUT_YES]->at : out_norm_data[TAUT_NON]->at;
|
1999
|
+
/* copy the input structure to be normalized to the buffer for the normalization data */
|
2000
|
+
memcpy( out_at, inp_at, num_inp_at*sizeof(out_at[0]) );
|
2001
|
+
|
2002
|
+
/* tautomeric groups setting */
|
2003
|
+
t_group_info->bIgnoreIsotopic = 0; /* include tautomeric group isotopic info in MarkTautomerGroups() */
|
2004
|
+
t_group_info->bTautFlags = *pbTautFlags;
|
2005
|
+
t_group_info->bTautFlagsDone = *pbTautFlagsDone;
|
2006
|
+
|
2007
|
+
/* Preprocess the structure; here THE NUMBER OF ATOMS MAY BE REDUCED */
|
2008
|
+
/* ??? Ambiguity: H-D may become HD or DH (that is, H+implicit D or D+implicit H) */
|
2009
|
+
num_at_tg =
|
2010
|
+
num_atoms = remove_terminal_HDT( num_inp_at, out_at );
|
2011
|
+
num_removed_H = num_inp_at - num_atoms;
|
2012
|
+
t_group_info->tni.nNumRemovedExplicitH = num_removed_H;
|
2013
|
+
add_DT_to_num_H( num_atoms, out_at );
|
2014
|
+
/*fix_odd_things( num_atoms, out_at );*/
|
2015
|
+
#if( FIND_RING_SYSTEMS == 1 )
|
2016
|
+
MarkRingSystemsInp( out_at, num_atoms );
|
2017
|
+
#endif
|
2018
|
+
/* duplicate the preprocessed structure so that all supplied out_norm_data[]->at buffers are filled */
|
2019
|
+
if ( out_at != out_norm_data[TAUT_YES]->at && out_norm_data[TAUT_YES]->at ) {
|
2020
|
+
memcpy( out_norm_data[TAUT_YES]->at, out_at, num_inp_at*sizeof(out_at[0]) );
|
2021
|
+
}
|
2022
|
+
if ( out_norm_data[TAUT_YES]->at_fixed_bonds && out_norm_data[TAUT_YES]->at ) {
|
2023
|
+
memcpy( out_norm_data[TAUT_YES]->at_fixed_bonds, out_at, num_inp_at*sizeof(out_at[0]) );
|
2024
|
+
}
|
2025
|
+
if ( out_at != out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_NON]->at ) {
|
2026
|
+
memcpy( out_norm_data[TAUT_NON]->at, out_at, num_inp_at*sizeof(out_at[0]) );
|
2027
|
+
}
|
2028
|
+
|
2029
|
+
/*******************************************************************************
|
2030
|
+
* ??? not true ??? duplicate inp_at and keep inp_at[] unchanged after terminal hydrogens removal
|
2031
|
+
* set stereo parities in taut_at[], non_taut_at[]
|
2032
|
+
* obtain max. lenghts of the name stereo parts
|
2033
|
+
* Ignore absence/presence of isotopic stereo for now
|
2034
|
+
* mark isotopic atoms
|
2035
|
+
*******************************************************************************/
|
2036
|
+
if ( out_norm_data[TAUT_YES]->at && at[TAUT_YES] ) {
|
2037
|
+
/* final normalization of possibly tautomeric structure */
|
2038
|
+
ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_YES]->at, out_norm_data[TAUT_YES]->at_fixed_bonds, num_atoms,
|
2039
|
+
t_group_info, NULL, NULL );
|
2040
|
+
if ( ret < 0 ) {
|
2041
|
+
goto exit_function;/* out of RAM or other normalization problem */
|
2042
|
+
}
|
2043
|
+
num_taut_at = ret; /* number of atoms without removed H? */
|
2044
|
+
num_removed_H_taut = t_group_info->tni.nNumRemovedExplicitH;
|
2045
|
+
out_norm_data[TAUT_YES]->num_at = num_atoms + num_removed_H_taut; /* protons might have been removed */
|
2046
|
+
out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;
|
2047
|
+
out_norm_data[TAUT_YES]->nNumRemovedProtons += t_group_info->tni.nNumRemovedProtons;
|
2048
|
+
for ( i = 0; i < NUM_H_ISOTOPES; i ++ ) {
|
2049
|
+
out_norm_data[TAUT_YES]->nNumRemovedProtonsIsotopic[i] += t_group_info->tni.nNumRemovedProtonsIsotopic[i] /*+ t_group_info->num_iso_H[i]*/;
|
2050
|
+
out_norm_data[TAUT_YES]->num_iso_H[i] += t_group_info->num_iso_H[i];
|
2051
|
+
}
|
2052
|
+
/* mark deleted isolated tautomeric H(+) */
|
2053
|
+
if ( num_taut_at == 1 && out_norm_data[TAUT_YES]->at[0].at_type == ATT_PROTON &&
|
2054
|
+
t_group_info && t_group_info->tni.nNumRemovedProtons == 1 ) {
|
2055
|
+
out_norm_data[TAUT_YES]->bDeleted = 1;
|
2056
|
+
FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
|
2057
|
+
} else
|
2058
|
+
if ( (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT) &&
|
2059
|
+
out_norm_data[TAUT_YES]->at_fixed_bonds) {
|
2060
|
+
out_norm_data[TAUT_YES]->bTautPreprocessed = 1;
|
2061
|
+
}
|
2062
|
+
/*
|
2063
|
+
if ( !(t_group_info->tni.bNormalizationFlags & (FLAG_NORM_CONSIDER_TAUT & ~FLAG_PROTON_SINGLE_REMOVED)) &&
|
2064
|
+
out_norm_data[TAUT_YES]->at_fixed_bonds) {
|
2065
|
+
FreeInpAtom( &out_norm_data[TAUT_YES]->at_fixed_bonds );
|
2066
|
+
}
|
2067
|
+
*/
|
2068
|
+
/*out_norm_data[TAUT_YES]->num_removed_H = num_removed_H_taut;*/
|
2069
|
+
out_norm_data[TAUT_YES]->bTautFlags = *pbTautFlags = t_group_info->bTautFlags;
|
2070
|
+
out_norm_data[TAUT_YES]->bTautFlagsDone = *pbTautFlagsDone = t_group_info->bTautFlagsDone;
|
2071
|
+
out_norm_data[TAUT_YES]->bNormalizationFlags = t_group_info->tni.bNormalizationFlags;
|
2072
|
+
/* create internal sp_ATOM at[] out of out_norm_data[]->at */
|
2073
|
+
inp2spATOM( out_norm_data[TAUT_YES]->at, num_inp_at, at[TAUT_YES] );
|
2074
|
+
/* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
|
2075
|
+
ret = set_stereo_parity( out_norm_data[TAUT_YES]->at, at[TAUT_YES], num_taut_at, num_removed_H_taut,
|
2076
|
+
&s[TAUT_YES].nMaxNumStereoAtoms, &s[TAUT_YES].nMaxNumStereoBonds, nUserMode,
|
2077
|
+
bPointedEdgeStereo );
|
2078
|
+
#if( bRELEASE_VERSION == 0 )
|
2079
|
+
if ( 0 < ret ) {
|
2080
|
+
bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
|
2081
|
+
}
|
2082
|
+
if ( t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT ) {
|
2083
|
+
bExtract |= EXTR_TAUT_TREATMENT_CHARGES;
|
2084
|
+
}
|
2085
|
+
#endif
|
2086
|
+
if ( RETURNED_ERROR( ret ) ) {
|
2087
|
+
goto exit_function; /* stereo bond error */
|
2088
|
+
}
|
2089
|
+
s[TAUT_YES].bMayHaveStereo = (s[TAUT_YES].nMaxNumStereoAtoms || s[TAUT_YES].nMaxNumStereoBonds);
|
2090
|
+
/*
|
2091
|
+
* mark isotopic atoms and atoms that have non-tautomeric
|
2092
|
+
* isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
|
2093
|
+
*/
|
2094
|
+
s[TAUT_YES].num_isotopic_atoms = set_atom_iso_sort_keys( num_taut_at, at[TAUT_YES], t_group_info,
|
2095
|
+
&s[TAUT_YES].bHasIsotopicTautGroups );
|
2096
|
+
/**************************************************************************
|
2097
|
+
* prepare tautomeric (if no tautomerism found then prepare non-tautomeric)
|
2098
|
+
* structure for canonicalizaton:
|
2099
|
+
**************************************************************************
|
2100
|
+
* remove t-groups that have no H,
|
2101
|
+
* remove charges from t-groups if requested
|
2102
|
+
* renumber t-groups and find final t_group_info->num_t_groups
|
2103
|
+
* add to t-groups lists of endpoints tgroup->nEndpointAtomNumber[]
|
2104
|
+
* calculate length of the t-group part of the connection table
|
2105
|
+
**************************************************************************/
|
2106
|
+
s[TAUT_YES].nLenLinearCTTautomer = CountTautomerGroups( at[TAUT_YES], num_taut_at, t_group_info );
|
2107
|
+
if ( RETURNED_ERROR(s[TAUT_YES].nLenLinearCTTautomer) ) { /* added error treatment 9-11-2003 */
|
2108
|
+
ret = s[TAUT_YES].nLenLinearCTTautomer;
|
2109
|
+
goto exit_function;
|
2110
|
+
/* error has happened; no breakpoint here
|
2111
|
+
s[TAUT_YES].nLenLinearCTTautomer = 0;
|
2112
|
+
*/
|
2113
|
+
} else
|
2114
|
+
if ( s[TAUT_YES].nLenLinearCTTautomer > 0 ) {
|
2115
|
+
num_at_tg = num_taut_at+t_group_info->num_t_groups;
|
2116
|
+
/* ??? -not true- create t_group_info_orig for multiple calls with atom renumbering */
|
2117
|
+
make_a_copy_of_t_group_info( t_group_info_orig, t_group_info );
|
2118
|
+
/* mark isotopic tautomer groups: calculate t_group->iWeight */
|
2119
|
+
s[TAUT_YES].nLenLinearCTIsotopicTautomer=set_tautomer_iso_sort_keys( t_group_info );
|
2120
|
+
if ( s[TAUT_YES].nLenLinearCTIsotopicTautomer < 0 ) {
|
2121
|
+
/* ??? -error cannot happen- error has happened; no breakpoint here */
|
2122
|
+
s[TAUT_YES].nLenLinearCTIsotopicTautomer = 0;
|
2123
|
+
}
|
2124
|
+
out_norm_data[TAUT_YES]->bTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
|
2125
|
+
}
|
2126
|
+
/* new variable: s[TAUT_YES].nLenCT introduced 7-22-2002 */
|
2127
|
+
GetCanonLengths( num_taut_at, at[TAUT_YES], &s[TAUT_YES], t_group_info );
|
2128
|
+
}
|
2129
|
+
if ( out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at && at[TAUT_NON] && !s[TAUT_YES].nLenLinearCTTautomer ) {
|
2130
|
+
/* the structure is non-tautomeric: use tautomeric treatment results only for it */
|
2131
|
+
inchi_free( at[TAUT_NON] );
|
2132
|
+
at[TAUT_NON] = NULL;
|
2133
|
+
} else
|
2134
|
+
if ( !out_norm_data[TAUT_NON]->at && out_norm_data[TAUT_YES]->at &&
|
2135
|
+
!at[TAUT_NON] && at[TAUT_YES] && !s[TAUT_YES].nLenLinearCTTautomer ) {
|
2136
|
+
/* requested tautomeric; found non-tautomeric; it is located in out_norm_data[TAUT_YES]->at */
|
2137
|
+
out_norm_data[TAUT_YES]->bTautomeric = 0;
|
2138
|
+
} else
|
2139
|
+
if ( out_norm_data[TAUT_NON]->at && at[TAUT_NON] ) {
|
2140
|
+
/* the structure needs non-tautomeric treatment: final normalization of non-tautomeric structure */
|
2141
|
+
ret = mark_alt_bonds_and_taut_groups ( out_norm_data[TAUT_NON]->at, NULL, num_atoms, NULL, &bTautFlags, &bTautFlagsDone );
|
2142
|
+
if ( ret < 0 ) {
|
2143
|
+
goto exit_function; /* out of RAM or other normalization problem */
|
2144
|
+
}
|
2145
|
+
out_norm_data[TAUT_NON]->num_at = num_atoms + num_removed_H;
|
2146
|
+
out_norm_data[TAUT_NON]->num_removed_H = num_removed_H;
|
2147
|
+
out_norm_data[TAUT_NON]->bTautFlags = *pbTautFlags;
|
2148
|
+
out_norm_data[TAUT_NON]->bTautFlagsDone = *pbTautFlagsDone;
|
2149
|
+
out_norm_data[TAUT_NON]->bNormalizationFlags = 0;
|
2150
|
+
/* create internal sp_ATOM at[] out of out_norm_data[]->at */
|
2151
|
+
inp2spATOM( out_norm_data[TAUT_NON]->at, num_inp_at, at[TAUT_NON] );
|
2152
|
+
/* set stereo parities to at[]; nUserMode: accept alt. stereo bonds, min ring size */
|
2153
|
+
ret = set_stereo_parity( out_norm_data[TAUT_NON]->at, at[TAUT_NON], num_atoms, num_removed_H,
|
2154
|
+
&s[TAUT_NON].nMaxNumStereoAtoms, &s[TAUT_NON].nMaxNumStereoBonds, nUserMode,
|
2155
|
+
bPointedEdgeStereo );
|
2156
|
+
#if( bRELEASE_VERSION == 0 )
|
2157
|
+
if ( 0 < ret ) {
|
2158
|
+
bExtract |= EXTR_HAS_ATOM_WITH_DEFINED_PARITY;
|
2159
|
+
}
|
2160
|
+
#endif
|
2161
|
+
if ( RETURNED_ERROR( ret ) ) {
|
2162
|
+
goto exit_function; /* stereo bond error */
|
2163
|
+
}
|
2164
|
+
s[TAUT_NON].bMayHaveStereo = (s[TAUT_NON].nMaxNumStereoAtoms || s[TAUT_NON].nMaxNumStereoBonds);
|
2165
|
+
/*
|
2166
|
+
* mark isotopic atoms and atoms that have non-tautomeric
|
2167
|
+
* isotopic terminal hydrogen atoms 1H, 2H(D), 3H(T)
|
2168
|
+
*/
|
2169
|
+
s[TAUT_NON].num_isotopic_atoms = set_atom_iso_sort_keys( num_atoms, at[TAUT_NON], NULL, NULL );
|
2170
|
+
GetCanonLengths( num_atoms, at[TAUT_NON], &s[TAUT_NON], NULL);
|
2171
|
+
out_norm_data[TAUT_NON]->bTautomeric = 0;
|
2172
|
+
}
|
2173
|
+
|
2174
|
+
/**********************************************************/
|
2175
|
+
/* common */
|
2176
|
+
bMayHaveStereo = s[TAUT_YES].bMayHaveStereo || s[TAUT_NON].bMayHaveStereo;
|
2177
|
+
bHasIsotopicAtoms = s[TAUT_NON].num_isotopic_atoms > 0 || s[TAUT_NON].bHasIsotopicTautGroups > 0 ||
|
2178
|
+
s[TAUT_YES].num_isotopic_atoms > 0 || s[TAUT_YES].bHasIsotopicTautGroups > 0 ||
|
2179
|
+
s[TAUT_YES].nLenIsotopicEndpoints > 1 && t_group_info &&
|
2180
|
+
(t_group_info->bTautFlagsDone & (TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE));
|
2181
|
+
|
2182
|
+
/* default mode */
|
2183
|
+
if ( !(nUserMode & REQ_MODE_DEFAULT) ) {
|
2184
|
+
/* default */
|
2185
|
+
nUserMode |= REQ_MODE_DEFAULT;
|
2186
|
+
}
|
2187
|
+
|
2188
|
+
/* adjust the mode to the reality */
|
2189
|
+
if ( ( nUserMode & REQ_MODE_ISO ) && !bHasIsotopicAtoms ) {
|
2190
|
+
nUserMode ^= REQ_MODE_ISO;
|
2191
|
+
nUserMode |= REQ_MODE_NON_ISO; /* at least one is needed */
|
2192
|
+
}
|
2193
|
+
if ( (nUserMode & REQ_MODE_STEREO) && ( nUserMode & REQ_MODE_ISO ) ) {
|
2194
|
+
nUserMode |= REQ_MODE_ISO_STEREO;
|
2195
|
+
}
|
2196
|
+
if ( (nUserMode & REQ_MODE_STEREO) && !( nUserMode & REQ_MODE_NON_ISO ) ) {
|
2197
|
+
nUserMode ^= REQ_MODE_STEREO;
|
2198
|
+
}
|
2199
|
+
if ( !bMayHaveStereo ) {
|
2200
|
+
if ( nUserMode & REQ_MODE_STEREO )
|
2201
|
+
nUserMode ^= REQ_MODE_STEREO;
|
2202
|
+
if ( nUserMode & REQ_MODE_ISO_STEREO )
|
2203
|
+
nUserMode ^= REQ_MODE_ISO_STEREO;
|
2204
|
+
}
|
2205
|
+
|
2206
|
+
if ( (nUserMode & REQ_MODE_BASIC) && (!out_norm_data[TAUT_NON]->at || !ppINChI[TAUT_NON] || !ppINChI_Aux[TAUT_NON] || !at[TAUT_NON]) ) {
|
2207
|
+
nUserMode ^= REQ_MODE_BASIC;
|
2208
|
+
}
|
2209
|
+
if ( (nUserMode & REQ_MODE_TAUT) && (!out_norm_data[TAUT_YES]->at || !ppINChI[TAUT_YES] || !ppINChI_Aux[TAUT_YES] || !at[TAUT_YES]) ) {
|
2210
|
+
nUserMode ^= REQ_MODE_TAUT;
|
2211
|
+
}
|
2212
|
+
|
2213
|
+
|
2214
|
+
switch ((int)nUserMode & (REQ_MODE_BASIC | REQ_MODE_TAUT)) {
|
2215
|
+
case REQ_MODE_BASIC:
|
2216
|
+
n1 = TAUT_NON;
|
2217
|
+
n2 = TAUT_NON;
|
2218
|
+
break;
|
2219
|
+
case REQ_MODE_TAUT:
|
2220
|
+
n1 = TAUT_YES;
|
2221
|
+
n2 = TAUT_YES;
|
2222
|
+
break;
|
2223
|
+
case (REQ_MODE_BASIC | REQ_MODE_TAUT):
|
2224
|
+
n1 = TAUT_NON;
|
2225
|
+
n2 = TAUT_YES;
|
2226
|
+
break;
|
2227
|
+
default:
|
2228
|
+
ret = -3;
|
2229
|
+
goto exit_function; /* program error: inconsistent nUserMode or missing taut/non-taut allocation */ /* <BRKPT> */
|
2230
|
+
}
|
2231
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
2232
|
+
ulNormTime = InchiTimeElapsed( &ulNormTimeStart);
|
2233
|
+
#endif
|
2234
|
+
/************************************************************
|
2235
|
+
* *
|
2236
|
+
* Obtain all non-stereo canonical numberings *
|
2237
|
+
* *
|
2238
|
+
************************************************************/
|
2239
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
2240
|
+
InchiTimeGet( &ulCanonTimeStart );
|
2241
|
+
#endif
|
2242
|
+
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
|
2243
|
+
/* added for special non-isotopic test mode 2004-10-04 */
|
2244
|
+
if ( t_group_info ) {
|
2245
|
+
t_group_info->bIgnoreIsotopic = 1;
|
2246
|
+
if ( t_group_info->nIsotopicEndpointAtomNumber ) {
|
2247
|
+
t_group_info->nIsotopicEndpointAtomNumber[0] = inchi_min(1, t_group_info->nIsotopicEndpointAtomNumber[0]);
|
2248
|
+
}
|
2249
|
+
memset( t_group_info->num_iso_H, 0, sizeof(t_group_info->num_iso_H) );
|
2250
|
+
memset ( t_group_info->tni.nNumRemovedProtonsIsotopic, 0, sizeof(t_group_info->tni.nNumRemovedProtonsIsotopic));
|
2251
|
+
t_group_info->bTautFlagsDone &= ~(TG_FLAG_FOUND_ISOTOPIC_H_DONE|TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE);
|
2252
|
+
}
|
2253
|
+
for ( i = 0; i < TAUT_NUM; i ++ ) {
|
2254
|
+
s[i].bHasIsotopicTautGroups = 0;
|
2255
|
+
s[i].bIgnoreIsotopic = 1;
|
2256
|
+
s[i].nLenIsotopic = 0;
|
2257
|
+
s[i].nLenIsotopicEndpoints = 0;
|
2258
|
+
s[i].nLenLinearCTIsotopicTautomer = 0;
|
2259
|
+
s[i].num_isotopic_atoms = 0;
|
2260
|
+
}
|
2261
|
+
bHasIsotopicAtoms = 0;
|
2262
|
+
}
|
2263
|
+
ret = GetBaseCanonRanking( num_atoms, num_at_tg, at, t_group_info, s, pBCN, ulMaxTime );
|
2264
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
2265
|
+
ulCanonTime = InchiTimeElapsed( &ulCanonTimeStart );
|
2266
|
+
#endif
|
2267
|
+
if ( ret < 0 ) {
|
2268
|
+
goto exit_function; /* program error */
|
2269
|
+
}
|
2270
|
+
#if( bRELEASE_VERSION == 0 && FIND_CANON_NE_EQUITABLE == 1 )
|
2271
|
+
/* Debug only: find whether canonical equivalence is different from equitable partition */
|
2272
|
+
if ( bCanonIsFinerThanEquitablePartition( num_atoms, at[n1], pBCN->ftcn[TAUT_NON].nSymmRankCt ) ) {
|
2273
|
+
bExtract |= EXTR_CANON_NE_EQUITABLE;
|
2274
|
+
}
|
2275
|
+
#endif
|
2276
|
+
/* added for special non-isotopic test mode 2004-10-04 */
|
2277
|
+
if ( !pBCN->ftcn[n1].PartitionCt.Rank ) {
|
2278
|
+
n1 = ALT_TAUT(n1);
|
2279
|
+
}
|
2280
|
+
if ( !pBCN->ftcn[n2].PartitionCt.Rank ) {
|
2281
|
+
n2 = ALT_TAUT(n2);
|
2282
|
+
}
|
2283
|
+
if ( n1 > n2 ) {
|
2284
|
+
ret = CT_TAUCOUNT_ERR;
|
2285
|
+
goto exit_function; /* program error */
|
2286
|
+
}
|
2287
|
+
|
2288
|
+
/************************************************************
|
2289
|
+
* *
|
2290
|
+
* Obtain stereo canonical numberings *
|
2291
|
+
* *
|
2292
|
+
************************************************************/
|
2293
|
+
|
2294
|
+
for ( i = n2; i >= n1 && !RETURNED_ERROR( ret ); i -- ) {
|
2295
|
+
|
2296
|
+
memset( pCS, 0, sizeof(*pCS) );
|
2297
|
+
|
2298
|
+
switch( i ) {
|
2299
|
+
case TAUT_NON: /* non-tautomeric */
|
2300
|
+
nMode = 0;
|
2301
|
+
nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
|
2302
|
+
nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO))? CANON_MODE_ISO:0;
|
2303
|
+
nMode |= (s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
|
2304
|
+
nMode |= (bHasIsotopicAtoms && s[TAUT_NON].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
|
2305
|
+
nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
|
2306
|
+
nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
|
2307
|
+
nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
|
2308
|
+
if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
|
2309
|
+
(nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
|
2310
|
+
nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
|
2311
|
+
nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
|
2312
|
+
nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
|
2313
|
+
nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
|
2314
|
+
}
|
2315
|
+
if ( ret= AllocateCS( pCS, num_atoms, num_atoms, s[TAUT_NON].nLenCT, s[TAUT_NON].nLenCTAtOnly,
|
2316
|
+
s[TAUT_NON].nLenLinearCTStereoDble, s[TAUT_NON].nMaxNumStereoBonds,
|
2317
|
+
s[TAUT_NON].nLenLinearCTStereoCarb, s[TAUT_NON].nMaxNumStereoAtoms,
|
2318
|
+
0, 0, s[TAUT_NON].nLenIsotopic, nMode, pBCN ) ) {
|
2319
|
+
goto exit_function;
|
2320
|
+
}
|
2321
|
+
*pCS2 = *pCS;
|
2322
|
+
break;
|
2323
|
+
case TAUT_YES: /* tautomeric */
|
2324
|
+
nMode = 0;
|
2325
|
+
nMode = (s[i].nLenLinearCTTautomer == 0)? CANON_MODE_CT:CANON_MODE_TAUT;
|
2326
|
+
nMode |= (bHasIsotopicAtoms && (nUserMode & REQ_MODE_ISO) )? CANON_MODE_ISO:0;
|
2327
|
+
nMode |= (s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_STEREO) )? CANON_MODE_STEREO:0;
|
2328
|
+
nMode |= (bHasIsotopicAtoms && s[TAUT_YES].bMayHaveStereo && (nUserMode & REQ_MODE_ISO_STEREO))? CANON_MODE_ISO_STEREO:0;
|
2329
|
+
nMode |= (nUserMode & REQ_MODE_NOEQ_STEREO )? CMODE_NOEQ_STEREO : 0;
|
2330
|
+
nMode |= (nUserMode & REQ_MODE_REDNDNT_STEREO)? CMODE_REDNDNT_STEREO : 0;
|
2331
|
+
nMode |= (nUserMode & REQ_MODE_NO_ALT_SBONDS )? CMODE_NO_ALT_SBONDS : 0;
|
2332
|
+
if ( (nMode & CANON_MODE_STEREO) == CANON_MODE_STEREO ||
|
2333
|
+
(nMode & CANON_MODE_ISO_STEREO) == CANON_MODE_ISO_STEREO ) {
|
2334
|
+
nMode |= (nUserMode & REQ_MODE_RELATIVE_STEREO)? CMODE_RELATIVE_STEREO: 0;
|
2335
|
+
nMode |= (nUserMode & REQ_MODE_RACEMIC_STEREO )? CMODE_RACEMIC_STEREO : 0;
|
2336
|
+
nMode |= (nUserMode & REQ_MODE_SC_IGN_ALL_UU )? CMODE_SC_IGN_ALL_UU : 0;
|
2337
|
+
nMode |= (nUserMode & REQ_MODE_SB_IGN_ALL_UU )? CMODE_SB_IGN_ALL_UU : 0;
|
2338
|
+
}
|
2339
|
+
if ( ret= AllocateCS( pCS, num_atoms, num_at_tg, s[TAUT_YES].nLenCT, s[TAUT_YES].nLenCTAtOnly,
|
2340
|
+
s[TAUT_YES].nLenLinearCTStereoDble, s[TAUT_YES].nMaxNumStereoBonds,
|
2341
|
+
s[TAUT_YES].nLenLinearCTStereoCarb, s[TAUT_YES].nMaxNumStereoAtoms,
|
2342
|
+
s[TAUT_YES].nLenLinearCTTautomer, s[TAUT_YES].nLenLinearCTIsotopicTautomer,
|
2343
|
+
s[TAUT_YES].nLenIsotopic, nMode, pBCN ) ) {
|
2344
|
+
goto exit_function;
|
2345
|
+
}
|
2346
|
+
*pCS2 = *pCS;
|
2347
|
+
break;
|
2348
|
+
}
|
2349
|
+
|
2350
|
+
|
2351
|
+
/* settings */
|
2352
|
+
pCS->lNumDecreasedCT = -1;
|
2353
|
+
pCS->bDoubleBondSquare = DOUBLE_BOND_NEIGH_LIST? 2:0; /* 2 => special mode */
|
2354
|
+
pCS->bIgnoreIsotopic = !((s[TAUT_NON].num_isotopic_atoms ||
|
2355
|
+
s[TAUT_YES].num_isotopic_atoms ||
|
2356
|
+
s[TAUT_YES].bHasIsotopicTautGroups) ||
|
2357
|
+
(nUserMode & REQ_MODE_NON_ISO) ||
|
2358
|
+
!(nUserMode & REQ_MODE_ISO));
|
2359
|
+
|
2360
|
+
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
|
2361
|
+
pCS->bIgnoreIsotopic = 1; /* 10-04-2004 */
|
2362
|
+
}
|
2363
|
+
|
2364
|
+
if ( i == TAUT_YES ) { /* tautomeric */
|
2365
|
+
pCS->t_group_info = t_group_info; /* ??? make a copy or reuse ??? */
|
2366
|
+
pCS->t_group_info->bIgnoreIsotopic = !(s[TAUT_YES].bHasIsotopicTautGroups ||
|
2367
|
+
(nUserMode & REQ_MODE_NON_ISO) ||
|
2368
|
+
!(nUserMode & REQ_MODE_ISO));
|
2369
|
+
if ( (nUserMode & REQ_MODE_NON_ISO) && !(nUserMode & REQ_MODE_ISO) ) {
|
2370
|
+
pCS->t_group_info->bIgnoreIsotopic = 1; /* 10-04-2004 */
|
2371
|
+
}
|
2372
|
+
}
|
2373
|
+
pCS->ulTimeOutTime = pBCN->ulTimeOutTime;
|
2374
|
+
/*=========== Obsolete Mode Bits (bit 0 is Least Significant Bit) ===========
|
2375
|
+
*
|
2376
|
+
* Mode Bits Description
|
2377
|
+
* '0' c 0 Only one connection table canonicalization
|
2378
|
+
* '1' C 1 Recalculate CT using fixed nSymmRank
|
2379
|
+
* '2' i 1|2 Isotopic canonicalization (internal)
|
2380
|
+
* '3' I 1|2|4 Isotopic canonicalization (output)
|
2381
|
+
* '4' s 1|8 Stereo canonicalization
|
2382
|
+
* '5' S 1|2|4|16 Stereo isotopic canonicalization
|
2383
|
+
* '6' A 1|2|4|8|16 Output All
|
2384
|
+
*/
|
2385
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
2386
|
+
InchiTimeGet( &ulCanonTimeStart );
|
2387
|
+
#endif
|
2388
|
+
/***************************************
|
2389
|
+
The last canonicalization step
|
2390
|
+
***************************************/
|
2391
|
+
if ( pBCN ) {
|
2392
|
+
/* USE_CANON2 == 1 */
|
2393
|
+
pCS->NeighList = NULL;
|
2394
|
+
pCS->pBCN = pBCN;
|
2395
|
+
ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
|
2396
|
+
} else {
|
2397
|
+
/* old way */
|
2398
|
+
pCS->NeighList = CreateNeighList( num_atoms, i?num_at_tg:num_atoms, at[i], pCS->bDoubleBondSquare, pCS->t_group_info );
|
2399
|
+
pCS->pBCN = NULL;
|
2400
|
+
ret = Canon_INChI( num_atoms, i?num_at_tg:num_atoms, at[i], pCS, nMode, i);
|
2401
|
+
}
|
2402
|
+
|
2403
|
+
pINChI = ppINChI[i];
|
2404
|
+
pINChI_Aux = ppINChI_Aux[i];
|
2405
|
+
if ( ret <= 0 ) {
|
2406
|
+
/***************************************/
|
2407
|
+
/* failure in Canon_INChI() */
|
2408
|
+
/***************************************/
|
2409
|
+
pINChI->nErrorCode = ret;
|
2410
|
+
pINChI_Aux->nErrorCode = ret;
|
2411
|
+
} else {
|
2412
|
+
/***************************************/
|
2413
|
+
/* success Canon_INChI() */
|
2414
|
+
/* save canonicalization results in */
|
2415
|
+
/* pINChI and pINChI_Aux */
|
2416
|
+
/***************************************/
|
2417
|
+
pINChI->nErrorCode = 0;
|
2418
|
+
pINChI_Aux->nErrorCode = 0;
|
2419
|
+
pINChI->bDeleted = pINChI_Aux->bDeleted = out_norm_data[i]->bDeleted;
|
2420
|
+
pINChI_Aux->nCanonFlags = pCS->nCanonFlags;
|
2421
|
+
pINChI_Aux->bTautFlags = out_norm_data[i]->bTautFlags;
|
2422
|
+
pINChI_Aux->bTautFlagsDone = out_norm_data[i]->bTautFlagsDone;
|
2423
|
+
pINChI_Aux->bNormalizationFlags = out_norm_data[i]->bNormalizationFlags;
|
2424
|
+
/* may return an error or a warning */
|
2425
|
+
ret = FillOutINChI( pINChI, pINChI_Aux,
|
2426
|
+
num_atoms, i?num_at_tg:num_atoms,
|
2427
|
+
i?num_removed_H_taut:num_removed_H, at[i], out_norm_data[i]->at, pCS, i, nUserMode, pStrErrStruct );
|
2428
|
+
if ( RETURNED_ERROR( ret ) ) {
|
2429
|
+
/* failure in FillOutINChI() */
|
2430
|
+
pINChI->nErrorCode = ret;
|
2431
|
+
pINChI_Aux->nErrorCode = ret;
|
2432
|
+
} else {
|
2433
|
+
/****************************/
|
2434
|
+
/* success in FillOutINChI() */
|
2435
|
+
/****************************/
|
2436
|
+
#if( bRELEASE_VERSION == 0 )
|
2437
|
+
if ( pINChI->Stereo &&
|
2438
|
+
(pINChI->Stereo->nCompInv2Abs && !pINChI->Stereo->bTrivialInv) ||
|
2439
|
+
pINChI->StereoIsotopic &&
|
2440
|
+
(pINChI->StereoIsotopic->nCompInv2Abs && !pINChI->StereoIsotopic->bTrivialInv) ) {
|
2441
|
+
bExtract |= EXTR_NON_TRIVIAL_STEREO;
|
2442
|
+
}
|
2443
|
+
#endif
|
2444
|
+
/* mark non-tautomeric representation as having another, tautomeric representation */
|
2445
|
+
if ( pINChI_Aux && s[TAUT_YES].nLenLinearCTTautomer ) {
|
2446
|
+
pINChI_Aux->bIsTautomeric = s[TAUT_YES].nLenLinearCTTautomer;
|
2447
|
+
}
|
2448
|
+
#if( bRELEASE_VERSION == 0 )
|
2449
|
+
pCS->bExtract |= bExtract;
|
2450
|
+
pINChI->bExtract |= pCS->bExtract;
|
2451
|
+
#endif
|
2452
|
+
ret2 = CheckCanonNumberingCorrectness(
|
2453
|
+
num_atoms, i?num_at_tg:num_atoms,
|
2454
|
+
at[i], pCS, i, pStrErrStruct );
|
2455
|
+
if ( ret2 ) {
|
2456
|
+
pINChI->nErrorCode = ret2;
|
2457
|
+
pINChI_Aux->nErrorCode = ret2;
|
2458
|
+
ret = ret2;
|
2459
|
+
}
|
2460
|
+
}
|
2461
|
+
}
|
2462
|
+
#if( TEST_RENUMB_ATOMS == 1 )
|
2463
|
+
ulCanonTime2 = InchiTimeElapsed( &ulCanonTimeStart );
|
2464
|
+
pINChI_Aux->ulCanonTime = ulCanonTime+ulCanonTime2;
|
2465
|
+
pINChI_Aux->ulNormTime = ulNormTime;
|
2466
|
+
#endif
|
2467
|
+
FreeNeighList( pCS->NeighList );
|
2468
|
+
DeAllocateCS( pCS2 );
|
2469
|
+
}
|
2470
|
+
if ( ret == 0 ) {
|
2471
|
+
ret = num_atoms;
|
2472
|
+
}
|
2473
|
+
/* treat the results later */
|
2474
|
+
|
2475
|
+
exit_function:
|
2476
|
+
DeAllocBCN( pBCN );
|
2477
|
+
if ( at[TAUT_YES] )
|
2478
|
+
inchi_free( at[TAUT_YES] );
|
2479
|
+
if ( at[TAUT_NON] )
|
2480
|
+
inchi_free( at[TAUT_NON] );
|
2481
|
+
free_t_group_info( t_group_info );
|
2482
|
+
free_t_group_info( t_group_info_orig );
|
2483
|
+
return ret;
|
2484
|
+
}
|
2485
|
+
#ifndef INCHI_ANSI_ONLY /* { */
|
2486
|
+
/***************************************************************************************/
|
2487
|
+
int GetAtomOrdNbrInCanonOrd( inp_ATOM *norm_at, AT_NUMB *nAtomOrdNbr,
|
2488
|
+
AT_NUMB *nOrigAtNosInCanonOrd, int num_at )
|
2489
|
+
{
|
2490
|
+
AT_NUMB *nCanonNbr, *nOrigAtNos, *nOrigAtNosOrd;
|
2491
|
+
int i, ret;
|
2492
|
+
|
2493
|
+
ret = 0;
|
2494
|
+
|
2495
|
+
nCanonNbr = (AT_NUMB *)inchi_calloc( num_at, sizeof(nCanonNbr[0]) );
|
2496
|
+
nOrigAtNos = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNos[0]) );
|
2497
|
+
nOrigAtNosOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nOrigAtNosOrd[0]) );
|
2498
|
+
|
2499
|
+
if ( !nCanonNbr || !nOrigAtNos || !nAtomOrdNbr || !nOrigAtNosOrd ) {
|
2500
|
+
ret = CT_OUT_OF_RAM; /* <BRKPT> */
|
2501
|
+
goto exit_function;
|
2502
|
+
}
|
2503
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2504
|
+
nCanonNbr[i] = nAtomOrdNbr[i] = nOrigAtNosOrd[i] = (AT_NUMB)i;
|
2505
|
+
nOrigAtNos[i] = norm_at[i].orig_at_number;
|
2506
|
+
}
|
2507
|
+
/* get nCanonNbr[]: canon. numbers-1 in order of increasing original atom numbers */
|
2508
|
+
pn_RankForSort = nOrigAtNosInCanonOrd;
|
2509
|
+
qsort( nCanonNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
|
2510
|
+
/* get nOrigAtNosOrd[]: norm_atom ord. numbers the same order of increasing original atom numbers */
|
2511
|
+
pn_RankForSort = nOrigAtNos;
|
2512
|
+
qsort( nOrigAtNosOrd, num_at, sizeof(nOrigAtNosOrd[0]), CompRank );
|
2513
|
+
/* check whether the 2 sets of origiginal atom numbers have identical elements */
|
2514
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2515
|
+
if ( nOrigAtNosInCanonOrd[nCanonNbr[i]] != nOrigAtNos[nOrigAtNosOrd[i]] ) {
|
2516
|
+
ret = CT_RANKING_ERR; /* <BRKPT> */
|
2517
|
+
goto exit_function;
|
2518
|
+
}
|
2519
|
+
}
|
2520
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2521
|
+
nAtomOrdNbr[(int)nCanonNbr[i]] = nOrigAtNosOrd[i];
|
2522
|
+
}
|
2523
|
+
|
2524
|
+
/*
|
2525
|
+
pn_RankForSort = nCanonNbr;
|
2526
|
+
qsort( nAtomOrdNbr, num_at, sizeof(nCanonNbr[0]), CompRank );
|
2527
|
+
*/
|
2528
|
+
|
2529
|
+
exit_function:
|
2530
|
+
if ( nCanonNbr )
|
2531
|
+
inchi_free( nCanonNbr );
|
2532
|
+
if ( nOrigAtNos )
|
2533
|
+
inchi_free( nOrigAtNos );
|
2534
|
+
if ( nOrigAtNosOrd )
|
2535
|
+
inchi_free( nOrigAtNosOrd );
|
2536
|
+
return ret;
|
2537
|
+
}
|
2538
|
+
/***************************************************************************************/
|
2539
|
+
int FillOutCanonInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int bIsotopic,
|
2540
|
+
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
|
2541
|
+
{
|
2542
|
+
int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
|
2543
|
+
int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
|
2544
|
+
int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len;
|
2545
|
+
int num_iso_H[NUM_H_ISOTOPES];
|
2546
|
+
char *str;
|
2547
|
+
AT_NUMB g, e;
|
2548
|
+
int num_at = pINChI->nNumberOfAtoms;
|
2549
|
+
int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
|
2550
|
+
AT_NUMB *nOrigAtNosInCanonOrd;
|
2551
|
+
INChI_Stereo *Stereo;
|
2552
|
+
AT_NUMB *nConstitEquNumbers;
|
2553
|
+
AT_NUMB *nConstitEquTGroupNumbers;
|
2554
|
+
S_CHAR *t_parity = NULL;
|
2555
|
+
AT_NUMB *nNumber = NULL;
|
2556
|
+
int bIncludeIsotopicH;
|
2557
|
+
|
2558
|
+
AT_NUMB *nNormAtNosInCanonOrd;
|
2559
|
+
int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
|
2560
|
+
int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
|
2561
|
+
int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
|
2562
|
+
int bRelRac= bRel || bRac;
|
2563
|
+
int bDoDisplaySp3 = 1;
|
2564
|
+
|
2565
|
+
inf_ATOM *inf_norm_at = inf_norm_at_data? inf_norm_at_data->at : NULL;
|
2566
|
+
|
2567
|
+
ret = 0;
|
2568
|
+
num_err = 0;
|
2569
|
+
|
2570
|
+
if ( !inf_norm_at )
|
2571
|
+
return ret;
|
2572
|
+
/* prepare removeable protons and H info */
|
2573
|
+
inf_norm_at_data->nNumRemovedProtons = pINChI_Aux->nNumRemovedProtons;
|
2574
|
+
MakeRemovedProtonsString( pINChI_Aux->nNumRemovedProtons, pINChI_Aux->nNumRemovedIsotopicH, NULL, bIsotopic,
|
2575
|
+
inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
|
2576
|
+
/* fill out info atom */
|
2577
|
+
if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
|
2578
|
+
pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
|
2579
|
+
bIsotopic = 0;
|
2580
|
+
|
2581
|
+
Stereo = bIsotopic? pINChI->StereoIsotopic :
|
2582
|
+
pINChI->Stereo;
|
2583
|
+
bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
|
2584
|
+
|
2585
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
2586
|
+
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
|
2587
|
+
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
|
2588
|
+
bDoDisplaySp3 = 0;
|
2589
|
+
if ( Stereo->nCompInv2Abs ) {
|
2590
|
+
inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
|
2591
|
+
}
|
2592
|
+
}
|
2593
|
+
#endif
|
2594
|
+
/* flag has stereo */
|
2595
|
+
if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
|
2596
|
+
inf_norm_at_data->StereoFlags |= INF_STEREO;
|
2597
|
+
}
|
2598
|
+
|
2599
|
+
/*
|
2600
|
+
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
|
2601
|
+
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
|
2602
|
+
bDoDisplaySp3 = 0;
|
2603
|
+
}
|
2604
|
+
*/
|
2605
|
+
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
|
2606
|
+
/* inversion changes stereo */
|
2607
|
+
if ( bRel ) {
|
2608
|
+
inf_norm_at_data->StereoFlags |= INF_STEREO_REL;
|
2609
|
+
} else
|
2610
|
+
if ( bRac ) {
|
2611
|
+
inf_norm_at_data->StereoFlags |= INF_STEREO_RAC;
|
2612
|
+
} else {
|
2613
|
+
inf_norm_at_data->StereoFlags |= INF_STEREO_ABS;
|
2614
|
+
}
|
2615
|
+
if ( bRelRac ) {
|
2616
|
+
inf_norm_at_data->StereoFlags |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
|
2617
|
+
}
|
2618
|
+
}
|
2619
|
+
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
|
2620
|
+
/* display Inv stereo which is Absolute Stereo */
|
2621
|
+
nNumber = Stereo->nNumberInv;
|
2622
|
+
t_parity = Stereo->t_parityInv;
|
2623
|
+
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
|
2624
|
+
pINChI_Aux->nOrigAtNosInCanonOrdInv;
|
2625
|
+
} else {
|
2626
|
+
/* display Inv stereo which is Absolute Stereo */
|
2627
|
+
if ( bDoDisplaySp3 ) {
|
2628
|
+
nNumber = Stereo->nNumber;
|
2629
|
+
t_parity = Stereo->t_parity;
|
2630
|
+
}
|
2631
|
+
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
|
2632
|
+
pINChI_Aux->nOrigAtNosInCanonOrd;
|
2633
|
+
}
|
2634
|
+
|
2635
|
+
nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
|
2636
|
+
pINChI_Aux->nConstitEquNumbers;
|
2637
|
+
nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
|
2638
|
+
pINChI_Aux->nConstitEquTGroupNumbers;
|
2639
|
+
memset( inf_norm_at, 0, init_num_at*sizeof(inf_norm_at[0]) );
|
2640
|
+
|
2641
|
+
/* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
|
2642
|
+
nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
|
2643
|
+
if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
|
2644
|
+
goto exit_function;
|
2645
|
+
}
|
2646
|
+
|
2647
|
+
/* atom canonical and equivalence numbers > 0 */
|
2648
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2649
|
+
j = (int)nNormAtNosInCanonOrd[i];
|
2650
|
+
if ( j < 0 || j >= num_at )
|
2651
|
+
continue;
|
2652
|
+
inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
|
2653
|
+
inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
|
2654
|
+
#ifdef DISPLAY_DEBUG_DATA
|
2655
|
+
inf_norm_at[j].nDebugData = 0;
|
2656
|
+
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
|
2657
|
+
inf_norm_at[j].nDebugData = norm_at[j].c_point;
|
2658
|
+
#endif
|
2659
|
+
#endif
|
2660
|
+
}
|
2661
|
+
/* tautomeric groups */
|
2662
|
+
if ( nNumberOfTGroups ) {
|
2663
|
+
/*
|
2664
|
+
: start from 1: bypass number of t-groups
|
2665
|
+
: j is a counter within the current t-group
|
2666
|
+
: g is a tautomeric group canonical number
|
2667
|
+
: e is a tautomeric group equivalence
|
2668
|
+
*/
|
2669
|
+
for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
|
2670
|
+
n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
|
2671
|
+
e = nConstitEquTGroupNumbers[(int)g - 1];
|
2672
|
+
/* bypass number of hydrogen atoms, negative charges, ... */
|
2673
|
+
for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
|
2674
|
+
/* scan canonical numbers of atoms within the atom t-group */
|
2675
|
+
k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
|
2676
|
+
inf_norm_at[k].nTautGroupCanonNbr = g;
|
2677
|
+
inf_norm_at[k].nTautGroupEquNbr = e;
|
2678
|
+
}
|
2679
|
+
}
|
2680
|
+
if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
|
2681
|
+
ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
|
2682
|
+
goto exit_function;
|
2683
|
+
}
|
2684
|
+
}
|
2685
|
+
/* atoms that may exchange isotopic H */
|
2686
|
+
if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
|
2687
|
+
for ( i = 1; i < n; i ++ ) {
|
2688
|
+
j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
|
2689
|
+
k = (int)nNormAtNosInCanonOrd[j - 1];
|
2690
|
+
if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
|
2691
|
+
inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
|
2692
|
+
}
|
2693
|
+
}
|
2694
|
+
}
|
2695
|
+
|
2696
|
+
#if( DISPLAY_RING_SYSTEMS == 1 )
|
2697
|
+
/* debug only */
|
2698
|
+
for ( j = 0; j < num_at; j ++ ) {
|
2699
|
+
inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
|
2700
|
+
inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
|
2701
|
+
#if( USE_DISTANCES_FOR_RANKING == 1 )
|
2702
|
+
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
|
2703
|
+
inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
|
2704
|
+
#else
|
2705
|
+
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
|
2706
|
+
inf_norm_at[j].nTautGroupEquNbr = 0;
|
2707
|
+
#endif
|
2708
|
+
}
|
2709
|
+
#endif
|
2710
|
+
|
2711
|
+
|
2712
|
+
|
2713
|
+
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
|
2714
|
+
len_str = sizeof(inf_norm_at[0].at_string);
|
2715
|
+
for ( i = 0; i < init_num_at; i ++ ) {
|
2716
|
+
str = inf_norm_at[i].at_string;
|
2717
|
+
len = 0;
|
2718
|
+
bIncludeIsotopicH = bIsotopic && !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT);
|
2719
|
+
/* isotopic mass */
|
2720
|
+
atw = 0;
|
2721
|
+
if ( norm_at[i].iso_atw_diff && bIsotopic ) {
|
2722
|
+
if ( norm_at[i].at_type == ATT_PROTON ) {
|
2723
|
+
; /* do not set isotopic mass of a tautomeric proton */
|
2724
|
+
} else
|
2725
|
+
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && norm_at[i].chem_bonds_valence == 1 &&
|
2726
|
+
!norm_at[i].charge && !norm_at[i].radical && !norm_at[i].num_H &&
|
2727
|
+
(inf_norm_at[j=(int)norm_at[i].neighbor[0]].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
|
2728
|
+
; /* do not set isotopic mass of an exchangeable proton */
|
2729
|
+
} else {
|
2730
|
+
atw = get_atw(norm_at[i].elname);
|
2731
|
+
atw += (norm_at[i].iso_atw_diff>0)? norm_at[i].iso_atw_diff-1:norm_at[i].iso_atw_diff;
|
2732
|
+
/*len += sprintf( str+len, "^%d", atw );*/
|
2733
|
+
}
|
2734
|
+
}
|
2735
|
+
/* element name */
|
2736
|
+
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
|
2737
|
+
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
|
2738
|
+
} else {
|
2739
|
+
if ( atw ) {
|
2740
|
+
len += sprintf( str+len, "^%d", atw );
|
2741
|
+
}
|
2742
|
+
len += sprintf( str+len, "%s", norm_at[i].elname );
|
2743
|
+
}
|
2744
|
+
/* hydrogens */
|
2745
|
+
/* find number of previuosly removed terminal hydrogen atoms because these terminal H will be displayed */
|
2746
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
2747
|
+
num_iso_H[j] = norm_at[i].num_iso_H[j];
|
2748
|
+
}
|
2749
|
+
/* n = number of implicit H to display */
|
2750
|
+
for ( j = num_at, n = (int)norm_at[i].num_H; j < init_num_at; j ++ ) {
|
2751
|
+
/* subtract number of removed terminal */
|
2752
|
+
/* H atoms from the total number of H atoms */
|
2753
|
+
if ( i == (int)norm_at[j].neighbor[0] ) {
|
2754
|
+
n -= 1; /* found explicit H => decrement number of implicit H */
|
2755
|
+
m = (int)norm_at[j].iso_atw_diff-1;
|
2756
|
+
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
|
2757
|
+
/* subtract number of removed terminal isotopic H */
|
2758
|
+
/* atoms from the total number of isotopic H atoms */
|
2759
|
+
num_iso_H[m] -= 1;
|
2760
|
+
}
|
2761
|
+
}
|
2762
|
+
}
|
2763
|
+
/* at this point n = number of implicit H to display,
|
2764
|
+
num_iso_H[] contains number of implicit isotopic H among n */
|
2765
|
+
if ( bIncludeIsotopicH ) {
|
2766
|
+
/* subtract number of isotopic H atoms from the total number of H atoms */
|
2767
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
2768
|
+
n -= num_iso_H[j];
|
2769
|
+
}
|
2770
|
+
}
|
2771
|
+
/* non-isotopic hydrogen atoms */
|
2772
|
+
if ( n > 1 ) {
|
2773
|
+
len += sprintf( str+len, "H%d", n );
|
2774
|
+
} else
|
2775
|
+
if ( n == 1 ) {
|
2776
|
+
len += sprintf( str+len, "H" );
|
2777
|
+
}
|
2778
|
+
/* isotopic hydrogen atoms */
|
2779
|
+
if ( bIncludeIsotopicH ) {
|
2780
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
2781
|
+
if ( num_iso_H[j] ) {
|
2782
|
+
if ( j == 0 || j != 1 && j != 2 ) {
|
2783
|
+
len += sprintf( str+len, "^%dH", j+1 );
|
2784
|
+
} else {
|
2785
|
+
len += sprintf( str+len, j == 1? "D" : "T" );
|
2786
|
+
}
|
2787
|
+
if ( num_iso_H[j] != 1 ) {
|
2788
|
+
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
|
2789
|
+
}
|
2790
|
+
}
|
2791
|
+
}
|
2792
|
+
}
|
2793
|
+
if ( norm_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
|
2794
|
+
char *q;
|
2795
|
+
if ( !str[2] ) {
|
2796
|
+
str[1] = '2'; /* quick fix: replace HH with H2 */
|
2797
|
+
} else
|
2798
|
+
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
|
2799
|
+
len = 1 + sprintf( str+1, "%d", n+1 );
|
2800
|
+
}
|
2801
|
+
}
|
2802
|
+
/*
|
2803
|
+
if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
|
2804
|
+
str[1] = '2';
|
2805
|
+
}
|
2806
|
+
*/
|
2807
|
+
/* charge */
|
2808
|
+
if ( abs(norm_at[i].charge) > 1 )
|
2809
|
+
len += sprintf( str+len, "%+d", norm_at[i].charge );
|
2810
|
+
else
|
2811
|
+
if ( abs(norm_at[i].charge) == 1 )
|
2812
|
+
len += sprintf( str+len, "%s", norm_at[i].charge>0? "+" : "-" );
|
2813
|
+
/* radical */
|
2814
|
+
if ( norm_at[i].radical )
|
2815
|
+
len += sprintf( str+len, "%s", norm_at[i].radical==RADICAL_SINGLET? ":" :
|
2816
|
+
norm_at[i].radical==RADICAL_DOUBLET? "." :
|
2817
|
+
norm_at[i].radical==RADICAL_TRIPLET? ".." : "?");
|
2818
|
+
}
|
2819
|
+
|
2820
|
+
/* stereogenic centers */
|
2821
|
+
if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
|
2822
|
+
for ( i = 0; i < num_stereo; i ++ ) {
|
2823
|
+
j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
|
2824
|
+
c = t_parity[i];
|
2825
|
+
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
|
2826
|
+
inf_norm_at[j].cStereoCenterParity = c;
|
2827
|
+
str=inf_norm_at[j].at_string;
|
2828
|
+
len = strlen(str);
|
2829
|
+
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
2830
|
+
str[len++] = '(';
|
2831
|
+
str[len++] = inf_norm_at[j].cStereoCenterParity;
|
2832
|
+
str[len++] = ')';
|
2833
|
+
str[len] = '\0';
|
2834
|
+
/* mark ambuguous stereo center */
|
2835
|
+
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
|
2836
|
+
len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
2837
|
+
memmove( str+1, str, len+1 );
|
2838
|
+
str[0] = '!'; /* output the atom in red color */
|
2839
|
+
}
|
2840
|
+
}
|
2841
|
+
}
|
2842
|
+
}
|
2843
|
+
|
2844
|
+
/* stereogenic bonds */
|
2845
|
+
/* (cumulenes with odd number of double bonds are stereocenters, */
|
2846
|
+
/* and atom parity should be set) */
|
2847
|
+
if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
|
2848
|
+
for ( i = 0; i < num_stereo; i ++ ) {
|
2849
|
+
int start_at, num_eql=0, bAmbiguousStereoBond = 0;
|
2850
|
+
j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
|
2851
|
+
k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
|
2852
|
+
start_at = j;
|
2853
|
+
c = Stereo->b_parity[i];
|
2854
|
+
|
2855
|
+
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
|
2856
|
+
|
2857
|
+
/* mark ambuguous stereo bond atom(s) */
|
2858
|
+
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
|
2859
|
+
(len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
|
2860
|
+
str[0] != '!' ) {
|
2861
|
+
memmove( str+1, str, len );
|
2862
|
+
str[0] = '!'; /* output the atom in red color */
|
2863
|
+
bAmbiguousStereoBond ++;
|
2864
|
+
}
|
2865
|
+
if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
|
2866
|
+
(len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
|
2867
|
+
str[0] != '!' ) {
|
2868
|
+
memmove( str+1, str, len );
|
2869
|
+
str[0] = '!'; /* output the atom in red color */
|
2870
|
+
bAmbiguousStereoBond ++;
|
2871
|
+
}
|
2872
|
+
|
2873
|
+
/* find the opposite atom k. */
|
2874
|
+
/* Note: since it may be a cumulene, find the shortest(best) path */
|
2875
|
+
/* to atom number k to avoid confusion in case of, for example, */
|
2876
|
+
/* 4-member aromatic rings. */
|
2877
|
+
best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
|
2878
|
+
for ( n = 0; n < norm_at[j].valence; n ++ ) {
|
2879
|
+
if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
|
2880
|
+
/* single bond cannot be stereogenic. */
|
2881
|
+
continue;
|
2882
|
+
}
|
2883
|
+
/* best_len = MAX_CUMULENE_LEN+1; */
|
2884
|
+
len = 0; /* number of bonds in cumulene - 1 */
|
2885
|
+
next_atom[len] = (int)norm_at[j].neighbor[n];
|
2886
|
+
next_neigh[len] = n;
|
2887
|
+
cur_atom = j;
|
2888
|
+
while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
|
2889
|
+
next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0] == cur_atom);
|
2890
|
+
next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]];
|
2891
|
+
cur_atom = next_atom[len];
|
2892
|
+
len ++;
|
2893
|
+
}
|
2894
|
+
if ( next_atom[len] == k ) {
|
2895
|
+
if ( len < best_len ) {
|
2896
|
+
memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
|
2897
|
+
memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
|
2898
|
+
best_len = len;
|
2899
|
+
num_eql = 0;
|
2900
|
+
if ( len == 0 ) {
|
2901
|
+
break; /* path length cannot be smaller than 1 */
|
2902
|
+
}
|
2903
|
+
} else
|
2904
|
+
if ( len == best_len ) {
|
2905
|
+
num_eql ++;
|
2906
|
+
}
|
2907
|
+
}
|
2908
|
+
}
|
2909
|
+
if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
|
2910
|
+
if ( num_eql ) {
|
2911
|
+
num_err ++; /* program error; no breakpoint here */
|
2912
|
+
}
|
2913
|
+
if ( best_len % 2 ) {
|
2914
|
+
/* even number of bonds: chiral atom, draw parity on the cenrtal atom */
|
2915
|
+
j = best_next_atom[best_len/2];
|
2916
|
+
inf_norm_at[j].cStereoCenterParity = c;
|
2917
|
+
str=inf_norm_at[j].at_string;
|
2918
|
+
len = strlen(str);
|
2919
|
+
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
2920
|
+
str[len++] = '(';
|
2921
|
+
str[len++] = inf_norm_at[j].cStereoCenterParity;
|
2922
|
+
str[len++] = ')';
|
2923
|
+
str[len] = '\0';
|
2924
|
+
}
|
2925
|
+
} else {
|
2926
|
+
/* odd number of bonds: draw parity on the central bond */
|
2927
|
+
if ( best_len == 0 ) {
|
2928
|
+
/* double bond */
|
2929
|
+
j = start_at;
|
2930
|
+
k = best_next_neigh[0];
|
2931
|
+
} else {
|
2932
|
+
/* cumulene */
|
2933
|
+
best_len = best_len/2-1;
|
2934
|
+
j = best_next_atom[best_len];
|
2935
|
+
k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
|
2936
|
+
}
|
2937
|
+
/* mark "forward" bond */
|
2938
|
+
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
|
2939
|
+
;
|
2940
|
+
if ( m < MAX_STEREO_BONDS ) {
|
2941
|
+
inf_norm_at[j].cStereoBondParity[m] = c;
|
2942
|
+
inf_norm_at[j].cStereoBondNumber[m] = k;
|
2943
|
+
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
|
2944
|
+
} else {
|
2945
|
+
num_err ++; /* program error; no breakpoint here */
|
2946
|
+
}
|
2947
|
+
/* mark "backward" bond */
|
2948
|
+
n = norm_at[j].neighbor[k];
|
2949
|
+
for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]; k ++ )
|
2950
|
+
;
|
2951
|
+
if ( k < norm_at[n].valence ) {
|
2952
|
+
j = n;
|
2953
|
+
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
|
2954
|
+
;
|
2955
|
+
if ( m < MAX_STEREO_BONDS ) {
|
2956
|
+
inf_norm_at[j].cStereoBondParity[m] = c;
|
2957
|
+
inf_norm_at[j].cStereoBondNumber[m] = k;
|
2958
|
+
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
|
2959
|
+
} else {
|
2960
|
+
num_err ++; /* program error; no breakpoint here */
|
2961
|
+
}
|
2962
|
+
} else {
|
2963
|
+
num_err ++; /* program error; no breakpoint here */
|
2964
|
+
}
|
2965
|
+
}
|
2966
|
+
} else {
|
2967
|
+
num_err ++; /* program error; no breakpoint here */
|
2968
|
+
}
|
2969
|
+
}
|
2970
|
+
}
|
2971
|
+
|
2972
|
+
for ( i = 0; i < init_num_at; i ++ ) {
|
2973
|
+
/* canonical numbers */
|
2974
|
+
if ( inf_norm_at[i].nCanonNbr ) {
|
2975
|
+
str = inf_norm_at[i].at_string;
|
2976
|
+
len = strlen(str);
|
2977
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
|
2978
|
+
if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
|
2979
|
+
if ( inf_norm_at[i].nCanonEquNbr ) {
|
2980
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
|
2981
|
+
} else
|
2982
|
+
if ( len + 1 < len_str ) {
|
2983
|
+
len += 1;
|
2984
|
+
strcat( str, "/" );
|
2985
|
+
}
|
2986
|
+
}
|
2987
|
+
/* tautomeric groups */
|
2988
|
+
if ( inf_norm_at[i].nTautGroupCanonNbr ) {
|
2989
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
|
2990
|
+
if ( inf_norm_at[i].nTautGroupEquNbr ) {
|
2991
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
|
2992
|
+
}
|
2993
|
+
}
|
2994
|
+
if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
|
2995
|
+
str[len++] = '/';
|
2996
|
+
str[len++] = '*';
|
2997
|
+
str[len] = '\0';
|
2998
|
+
}
|
2999
|
+
#ifdef DISPLAY_DEBUG_DATA
|
3000
|
+
if ( inf_norm_at[i].nDebugData ) {
|
3001
|
+
len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
|
3002
|
+
}
|
3003
|
+
#endif
|
3004
|
+
}
|
3005
|
+
}
|
3006
|
+
|
3007
|
+
|
3008
|
+
exit_function:
|
3009
|
+
|
3010
|
+
if ( nNormAtNosInCanonOrd )
|
3011
|
+
inchi_free( nNormAtNosInCanonOrd );
|
3012
|
+
|
3013
|
+
|
3014
|
+
return ret;
|
3015
|
+
}
|
3016
|
+
/***************************************************************************************/
|
3017
|
+
int FillOutOneCanonInfAtom(inp_ATOM *inp_norm_at, INF_ATOM_DATA *inf_norm_at_data,
|
3018
|
+
AT_NUMB *pStereoFlags, int init_num_at, int offset, int offset_H, int bIsotopic,
|
3019
|
+
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode)
|
3020
|
+
{
|
3021
|
+
int i, j, m, n, num_stereo, k, c, ret, len_str, len, atw, num_err;
|
3022
|
+
int next_atom[MAX_CUMULENE_LEN+1], best_next_atom[MAX_CUMULENE_LEN+1], cur_atom;
|
3023
|
+
int next_neigh[MAX_CUMULENE_LEN+1], best_next_neigh[MAX_CUMULENE_LEN+1], best_len, bIncludeIsotopicH;
|
3024
|
+
int num_iso_H[NUM_H_ISOTOPES];
|
3025
|
+
char *str;
|
3026
|
+
AT_NUMB g, e;
|
3027
|
+
int num_at = pINChI->nNumberOfAtoms;
|
3028
|
+
int num_H = init_num_at - num_at; /* number of removed H */
|
3029
|
+
int nNumberOfTGroups = (pINChI->lenTautomer && pINChI->nTautomer && pINChI->nTautomer[0])? (int)pINChI->nTautomer[0] : 0;
|
3030
|
+
AT_NUMB *nOrigAtNosInCanonOrd;
|
3031
|
+
INChI_Stereo *Stereo;
|
3032
|
+
AT_NUMB *nConstitEquNumbers;
|
3033
|
+
AT_NUMB *nConstitEquTGroupNumbers;
|
3034
|
+
S_CHAR *t_parity = NULL;
|
3035
|
+
AT_NUMB *nNumber = NULL;
|
3036
|
+
|
3037
|
+
AT_NUMB *nNormAtNosInCanonOrd;
|
3038
|
+
int (*MakeNumber)(char*, int, const char*, int) = bAbcNumbers? MakeAbcNumber:MakeDecNumber;
|
3039
|
+
int bRel= (0 != (nMode & ( REQ_MODE_RELATIVE_STEREO)));
|
3040
|
+
int bRac= (0 != (nMode & ( REQ_MODE_RACEMIC_STEREO)));
|
3041
|
+
int bRelRac= bRel || bRac;
|
3042
|
+
int bDoDisplaySp3 = 1;
|
3043
|
+
|
3044
|
+
inf_ATOM *inf_norm_at = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset : NULL;
|
3045
|
+
inp_ATOM *norm_at = inp_norm_at? inp_norm_at + offset : NULL;
|
3046
|
+
inf_ATOM *inf_norm_at_H = (inf_norm_at_data && inf_norm_at_data->at)? inf_norm_at_data->at+offset_H : NULL;
|
3047
|
+
inp_ATOM *norm_at_H = inp_norm_at? inp_norm_at + offset_H : NULL;
|
3048
|
+
|
3049
|
+
ret = 0;
|
3050
|
+
num_err = 0;
|
3051
|
+
|
3052
|
+
if ( !inf_norm_at )
|
3053
|
+
return ret;
|
3054
|
+
/* -- already added in FillOutCompositeCanonInfAtom() --
|
3055
|
+
if ( bIsotopic ) {
|
3056
|
+
for ( i = 0, j = 0; i < NUM_H_ISOTOPES; i ++ ) {
|
3057
|
+
if ( pINChI_Aux->nNumRemovedIsotopicH[i] ) {
|
3058
|
+
inf_norm_at_data->num_iso_H[i] += pINChI_Aux->nNumRemovedIsotopicH[i];
|
3059
|
+
inf_norm_at_data->num_removed_iso_H ++;
|
3060
|
+
}
|
3061
|
+
}
|
3062
|
+
}
|
3063
|
+
*/
|
3064
|
+
|
3065
|
+
if ( bIsotopic && !(pINChI->nNumberOfIsotopicAtoms || pINChI->nNumberOfIsotopicTGroups ||
|
3066
|
+
pINChI->nPossibleLocationsOfIsotopicH && pINChI->nPossibleLocationsOfIsotopicH[0]>1) )
|
3067
|
+
bIsotopic = 0;
|
3068
|
+
|
3069
|
+
Stereo = bIsotopic? pINChI->StereoIsotopic :
|
3070
|
+
pINChI->Stereo;
|
3071
|
+
bDoDisplaySp3 = (NULL != Stereo) && (Stereo->nNumberOfStereoCenters > 0);
|
3072
|
+
|
3073
|
+
#if( REL_RAC_STEREO_IGN_1_SC == 1 )
|
3074
|
+
if ( bDoDisplaySp3 && bRelRac && Stereo->nNumberOfStereoCenters < 2 &&
|
3075
|
+
(Stereo->nCompInv2Abs || ATOM_PARITY_ILL_DEF(Stereo->t_parity[0]) ) ) {
|
3076
|
+
bDoDisplaySp3 = 0;
|
3077
|
+
if ( Stereo->nCompInv2Abs ) {
|
3078
|
+
inf_norm_at_data->StereoFlags |= bRel? INF_STEREO_REL : bRac? INF_STEREO_RAC : 0;
|
3079
|
+
}
|
3080
|
+
}
|
3081
|
+
#endif
|
3082
|
+
/* flag has stereo */
|
3083
|
+
if ( (NULL != Stereo) && (bDoDisplaySp3 || Stereo->nNumberOfStereoBonds > 0) ) {
|
3084
|
+
(*pStereoFlags) |= INF_STEREO;
|
3085
|
+
}
|
3086
|
+
|
3087
|
+
/*
|
3088
|
+
if ( bDoDisplaySp3 && bRelRac && Stereo->nCompInv2Abs && Stereo->nNumberOfStereoCenters < 2 ) {
|
3089
|
+
bDoDisplaySp3 = 0;
|
3090
|
+
}
|
3091
|
+
*/
|
3092
|
+
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs ) {
|
3093
|
+
/* inversion changes stereo */
|
3094
|
+
if ( bRel ) {
|
3095
|
+
(*pStereoFlags) |= INF_STEREO_REL;
|
3096
|
+
} else
|
3097
|
+
if ( bRac ) {
|
3098
|
+
(*pStereoFlags) |= INF_STEREO_RAC;
|
3099
|
+
} else {
|
3100
|
+
(*pStereoFlags) |= INF_STEREO_ABS;
|
3101
|
+
}
|
3102
|
+
if ( bRelRac ) {
|
3103
|
+
(*pStereoFlags) |= (Stereo->nCompInv2Abs > 0)? INF_STEREO_NORM : INF_STEREO_INV;
|
3104
|
+
}
|
3105
|
+
}
|
3106
|
+
if ( bDoDisplaySp3 && Stereo->nCompInv2Abs < 0 && !bRelRac ) {
|
3107
|
+
/* display Inv stereo which is Absolute Stereo */
|
3108
|
+
nNumber = Stereo->nNumberInv;
|
3109
|
+
t_parity = Stereo->t_parityInv;
|
3110
|
+
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrdInv :
|
3111
|
+
pINChI_Aux->nOrigAtNosInCanonOrdInv;
|
3112
|
+
} else {
|
3113
|
+
/* display Output stereo which is Absolute Stereo */
|
3114
|
+
if ( bDoDisplaySp3 ) {
|
3115
|
+
nNumber = Stereo->nNumber;
|
3116
|
+
t_parity = Stereo->t_parity;
|
3117
|
+
}
|
3118
|
+
nOrigAtNosInCanonOrd = bIsotopic? pINChI_Aux->nIsotopicOrigAtNosInCanonOrd :
|
3119
|
+
pINChI_Aux->nOrigAtNosInCanonOrd;
|
3120
|
+
}
|
3121
|
+
|
3122
|
+
nConstitEquNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicNumbers :
|
3123
|
+
pINChI_Aux->nConstitEquNumbers;
|
3124
|
+
nConstitEquTGroupNumbers = bIsotopic? pINChI_Aux->nConstitEquIsotopicTGroupNumbers :
|
3125
|
+
pINChI_Aux->nConstitEquTGroupNumbers;
|
3126
|
+
memset( inf_norm_at, 0, num_at*sizeof(inf_norm_at[0]) );
|
3127
|
+
if ( num_H > 0 ) {
|
3128
|
+
memset( inf_norm_at_H, 0, num_H*sizeof(inf_norm_at[0]) );
|
3129
|
+
}
|
3130
|
+
|
3131
|
+
/* obtain norm_at[] atom numbers (from zero) in order of canonical numbers */
|
3132
|
+
nNormAtNosInCanonOrd = (AT_NUMB *)inchi_calloc( num_at, sizeof(nNormAtNosInCanonOrd[0]) );
|
3133
|
+
if ( ret = GetAtomOrdNbrInCanonOrd( norm_at, nNormAtNosInCanonOrd, nOrigAtNosInCanonOrd, num_at ) ) {
|
3134
|
+
goto exit_function;
|
3135
|
+
}
|
3136
|
+
|
3137
|
+
/* atom canonical and equivalence numbers > 0 */
|
3138
|
+
for ( i = 0; i < num_at; i ++ ) {
|
3139
|
+
j = (int)nNormAtNosInCanonOrd[i];
|
3140
|
+
if ( j < 0 || j >= num_at )
|
3141
|
+
continue;
|
3142
|
+
inf_norm_at[j].nCanonNbr = (AT_NUMB)(i+1);
|
3143
|
+
inf_norm_at[j].nCanonEquNbr = nConstitEquNumbers[i];
|
3144
|
+
#ifdef DISPLAY_DEBUG_DATA
|
3145
|
+
inf_norm_at[j].nDebugData = 0;
|
3146
|
+
#if( DISPLAY_DEBUG_DATA == DISPLAY_DEBUG_DATA_C_POINT )
|
3147
|
+
inf_norm_at[j].nDebugData = norm_at[j].c_point;
|
3148
|
+
#endif
|
3149
|
+
#endif
|
3150
|
+
}
|
3151
|
+
/* tautomeric groups */
|
3152
|
+
if ( nNumberOfTGroups ) {
|
3153
|
+
/*
|
3154
|
+
: start from 1: bypass number of t-groups
|
3155
|
+
: j is a counter within the current t-group
|
3156
|
+
: g is a tautomeric group canonical number
|
3157
|
+
: e is a tautomeric group equivalence
|
3158
|
+
*/
|
3159
|
+
for ( g = 1, i = 1; g <= nNumberOfTGroups; g ++ ) {
|
3160
|
+
n = (int)pINChI->nTautomer[i] - INCHI_T_NUM_MOVABLE; /* number of atoms in t-group */
|
3161
|
+
e = nConstitEquTGroupNumbers[(int)g - 1];
|
3162
|
+
/* bypass number of hydrogen atoms, negative charges, ... */
|
3163
|
+
for ( i += INCHI_T_NUM_MOVABLE+1, j = 0; j < n && i < pINChI->lenTautomer; j ++, i ++ ) {
|
3164
|
+
/* scan canonical numbers of atoms within the atom t-group */
|
3165
|
+
k = (int)nNormAtNosInCanonOrd[(int)pINChI->nTautomer[i]-1];
|
3166
|
+
inf_norm_at[k].nTautGroupCanonNbr = g;
|
3167
|
+
inf_norm_at[k].nTautGroupEquNbr = e;
|
3168
|
+
}
|
3169
|
+
}
|
3170
|
+
if ( i != pINChI->lenTautomer || g != nNumberOfTGroups+1 ) {
|
3171
|
+
ret = CT_TAUCOUNT_ERR; /* <BRKPT> */
|
3172
|
+
goto exit_function;
|
3173
|
+
}
|
3174
|
+
}
|
3175
|
+
/* atoms that may exchange isotopic H */
|
3176
|
+
if ( bIsotopic && pINChI->nPossibleLocationsOfIsotopicH && (n = (int)pINChI->nPossibleLocationsOfIsotopicH[0]) ) {
|
3177
|
+
for ( i = 1; i < n; i ++ ) {
|
3178
|
+
j = (int)pINChI->nPossibleLocationsOfIsotopicH[i];
|
3179
|
+
k = (int)nNormAtNosInCanonOrd[j - 1];
|
3180
|
+
if ( !inf_norm_at[k].nTautGroupCanonNbr ) {
|
3181
|
+
inf_norm_at[k].cFlags |= AT_FLAG_ISO_H_POINT;
|
3182
|
+
}
|
3183
|
+
}
|
3184
|
+
}
|
3185
|
+
#if( DISPLAY_RING_SYSTEMS == 1 )
|
3186
|
+
/* debug only */
|
3187
|
+
for ( j = 0; j < num_at; j ++ ) {
|
3188
|
+
inf_norm_at[j].nCanonNbr = norm_at[j].nBlockSystem;
|
3189
|
+
inf_norm_at[j].nCanonEquNbr = norm_at[j].nRingSystem;
|
3190
|
+
#if( USE_DISTANCES_FOR_RANKING == 1 )
|
3191
|
+
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].nDistanceFromTerminal;
|
3192
|
+
inf_norm_at[j].nTautGroupEquNbr = norm_at[j].bCutVertex;
|
3193
|
+
#else
|
3194
|
+
inf_norm_at[j].nTautGroupCanonNbr = norm_at[j].bCutVertex;
|
3195
|
+
inf_norm_at[j].nTautGroupEquNbr = 0;
|
3196
|
+
#endif
|
3197
|
+
}
|
3198
|
+
#endif
|
3199
|
+
|
3200
|
+
|
3201
|
+
|
3202
|
+
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
|
3203
|
+
len_str = sizeof(inf_norm_at[0].at_string);
|
3204
|
+
for ( i = 0; i < init_num_at; i ++ ) {
|
3205
|
+
inf_ATOM *cur_inf_norm_at = (i < num_at)? inf_norm_at+i : inf_norm_at_H+i-num_at;
|
3206
|
+
inp_ATOM *cur_norm_at = (i < num_at)? norm_at +i : norm_at_H +i-num_at;
|
3207
|
+
str = cur_inf_norm_at->at_string;
|
3208
|
+
len = 0;
|
3209
|
+
bIncludeIsotopicH = bIsotopic && (i >= num_at || !inf_norm_at[i].nTautGroupCanonNbr && !(inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT));
|
3210
|
+
/* isotopic mass */
|
3211
|
+
atw = 0;
|
3212
|
+
if ( cur_norm_at->iso_atw_diff && bIsotopic ) {
|
3213
|
+
if ( cur_norm_at->at_type == ATT_PROTON ) {
|
3214
|
+
; /* do not set isotopic mass of a tautomeric proton */
|
3215
|
+
} else
|
3216
|
+
if ( num_at <= i && cur_norm_at->el_number == PERIODIC_NUMBER_H && cur_norm_at->chem_bonds_valence == 1 &&
|
3217
|
+
!cur_norm_at->charge && !cur_norm_at->radical && !cur_norm_at->num_H &&
|
3218
|
+
0 <= (j=(int)cur_norm_at->neighbor[0]-offset) && j < num_at &&
|
3219
|
+
(inf_norm_at[j].nTautGroupCanonNbr || (inf_norm_at[j].cFlags & AT_FLAG_ISO_H_POINT) ) ) {
|
3220
|
+
; /* do not set isotopic mass of an exchangeable proton */
|
3221
|
+
} else {
|
3222
|
+
atw = get_atw(cur_norm_at->elname);
|
3223
|
+
atw += (cur_norm_at->iso_atw_diff>0)? cur_norm_at->iso_atw_diff-1:cur_norm_at->iso_atw_diff;
|
3224
|
+
/*len += sprintf( str+len, "^%d", atw );*/
|
3225
|
+
}
|
3226
|
+
}
|
3227
|
+
/* element name */
|
3228
|
+
if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
|
3229
|
+
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
|
3230
|
+
} else {
|
3231
|
+
if ( atw ) {
|
3232
|
+
len += sprintf( str+len, "^%d", atw );
|
3233
|
+
}
|
3234
|
+
len += sprintf( str+len, "%s", cur_norm_at->elname );
|
3235
|
+
}
|
3236
|
+
/* hydrogens */
|
3237
|
+
/* find number of previuosly removed terminal hydrogen atoms */
|
3238
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3239
|
+
num_iso_H[j] = cur_norm_at->num_iso_H[j];
|
3240
|
+
}
|
3241
|
+
for ( j = 0, n = (int)cur_norm_at->num_H; j < num_H; j ++ ) {
|
3242
|
+
/* subtract number of removed terminal */
|
3243
|
+
/* H atoms from the total number of H atoms */
|
3244
|
+
if ( i == (int)norm_at_H[j].neighbor[0]-offset ) {
|
3245
|
+
n -= 1;
|
3246
|
+
m = (int)norm_at_H[j].iso_atw_diff-1;
|
3247
|
+
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
|
3248
|
+
/* subtract number of removed terminal isotopic */
|
3249
|
+
/* H atoms from the total number of isotopic H atoms */
|
3250
|
+
num_iso_H[m] -= 1;
|
3251
|
+
}
|
3252
|
+
}
|
3253
|
+
}
|
3254
|
+
if ( bIncludeIsotopicH ) {
|
3255
|
+
/* subtract number of isotopic H atoms from the total number of H atoms */
|
3256
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3257
|
+
n -= num_iso_H[j];
|
3258
|
+
}
|
3259
|
+
}
|
3260
|
+
/* non-isotopic hydrogen atoms */
|
3261
|
+
if ( n > 1 ) {
|
3262
|
+
len += sprintf( str+len, "H%d", n );
|
3263
|
+
} else
|
3264
|
+
if ( n == 1 ) {
|
3265
|
+
len += sprintf( str+len, "H" );
|
3266
|
+
}
|
3267
|
+
/* isotopic hydrogen atoms */
|
3268
|
+
if ( bIncludeIsotopicH ) {
|
3269
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3270
|
+
if ( num_iso_H[j] ) {
|
3271
|
+
if ( j == 0 || j != 1 && j != 2 ) {
|
3272
|
+
len += sprintf( str+len, "^%dH", j+1 );
|
3273
|
+
} else {
|
3274
|
+
len += sprintf( str+len, j == 1? "D" : "T" );
|
3275
|
+
}
|
3276
|
+
if ( num_iso_H[j] != 1 ) {
|
3277
|
+
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
|
3278
|
+
}
|
3279
|
+
}
|
3280
|
+
}
|
3281
|
+
}
|
3282
|
+
if ( cur_norm_at->el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
|
3283
|
+
char *q;
|
3284
|
+
if ( !str[2] ) {
|
3285
|
+
str[1] = '2'; /* quick fix: replace HH with H2 */
|
3286
|
+
} else
|
3287
|
+
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
|
3288
|
+
len = 1 + sprintf( str+1, "%d", n+1 );
|
3289
|
+
}
|
3290
|
+
}
|
3291
|
+
/* charge */
|
3292
|
+
if ( abs(cur_norm_at->charge) > 1 )
|
3293
|
+
len += sprintf( str+len, "%+d", cur_norm_at->charge );
|
3294
|
+
else
|
3295
|
+
if ( abs(cur_norm_at->charge) == 1 )
|
3296
|
+
len += sprintf( str+len, "%s", cur_norm_at->charge>0? "+" : "-" );
|
3297
|
+
/* radical */
|
3298
|
+
if ( cur_norm_at->radical )
|
3299
|
+
len += sprintf( str+len, "%s", cur_norm_at->radical==RADICAL_SINGLET? ":" :
|
3300
|
+
cur_norm_at->radical==RADICAL_DOUBLET? "." :
|
3301
|
+
cur_norm_at->radical==RADICAL_TRIPLET? ".." : "?");
|
3302
|
+
}
|
3303
|
+
|
3304
|
+
/* stereogenic centers */
|
3305
|
+
if ( bDoDisplaySp3 && Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoCenters) ) {
|
3306
|
+
for ( i = 0; i < num_stereo; i ++ ) {
|
3307
|
+
j = (int)nNormAtNosInCanonOrd[(int)nNumber[i]-1];
|
3308
|
+
c = t_parity[i];
|
3309
|
+
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
|
3310
|
+
inf_norm_at[j].cStereoCenterParity = c;
|
3311
|
+
str=inf_norm_at[j].at_string;
|
3312
|
+
len = strlen(str);
|
3313
|
+
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
3314
|
+
str[len++] = '(';
|
3315
|
+
str[len++] = inf_norm_at[j].cStereoCenterParity;
|
3316
|
+
str[len++] = ')';
|
3317
|
+
str[len] = '\0';
|
3318
|
+
/* mark ambuguous stereo center */
|
3319
|
+
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' || c=='?') && str[0] != '!' &&
|
3320
|
+
len+1 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
3321
|
+
memmove( str+1, str, len+1 );
|
3322
|
+
str[0] = '!'; /* output the atom in red color */
|
3323
|
+
}
|
3324
|
+
}
|
3325
|
+
}
|
3326
|
+
}
|
3327
|
+
|
3328
|
+
/* stereogenic bonds */
|
3329
|
+
/* (cumulenes with odd number of double bonds are stereocenters, */
|
3330
|
+
/* and atom parity should be set) */
|
3331
|
+
if ( Stereo && 0 < (num_stereo = Stereo->nNumberOfStereoBonds) ) {
|
3332
|
+
for ( i = 0; i < num_stereo; i ++ ) {
|
3333
|
+
int start_at, num_eql=0, bAmbiguousStereoBond = 0;
|
3334
|
+
j = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom1[i]-1];
|
3335
|
+
k = (int)nNormAtNosInCanonOrd[(int)Stereo->nBondAtom2[i]-1];
|
3336
|
+
start_at = j;
|
3337
|
+
c = Stereo->b_parity[i];
|
3338
|
+
|
3339
|
+
c = c==1? '-' : c==2? '+' : c==3? 'u' : c== 4? '?' : '*';
|
3340
|
+
|
3341
|
+
/* mark ambuguous stereo bond atom(s) */
|
3342
|
+
if ( norm_at[j].bAmbiguousStereo && (c=='+' || c=='-' ) &&
|
3343
|
+
(len=strlen(str=inf_norm_at[j].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
|
3344
|
+
str[0] != '!' ) {
|
3345
|
+
memmove( str+1, str, len );
|
3346
|
+
str[0] = '!'; /* output the atom in red color */
|
3347
|
+
bAmbiguousStereoBond ++;
|
3348
|
+
}
|
3349
|
+
if ( norm_at[k].bAmbiguousStereo && (c=='+' || c=='-') &&
|
3350
|
+
(len=strlen(str=inf_norm_at[k].at_string)+1) < (int)sizeof(inf_norm_at[0].at_string) &&
|
3351
|
+
str[0] != '!' ) {
|
3352
|
+
memmove( str+1, str, len );
|
3353
|
+
str[0] = '!'; /* output the atom in red color */
|
3354
|
+
bAmbiguousStereoBond ++;
|
3355
|
+
}
|
3356
|
+
|
3357
|
+
/* find the opposite atom k. */
|
3358
|
+
/* Note: since it may be a cumulene, find the shortest(best) path */
|
3359
|
+
/* to atom number k to avoid confusion in case of, for example, */
|
3360
|
+
/* 4-member aromatic rings. */
|
3361
|
+
best_len = MAX_CUMULENE_LEN+1; /* moved here from inside the cycle 1-8-2003 */
|
3362
|
+
for ( n = 0; n < norm_at[j].valence; n ++ ) {
|
3363
|
+
if ( norm_at[j].bond_type[n] == BOND_SINGLE ) {
|
3364
|
+
/* single bond cannot be stereogenic. */
|
3365
|
+
continue;
|
3366
|
+
}
|
3367
|
+
/* best_len = MAX_CUMULENE_LEN+1; */
|
3368
|
+
len = 0; /* number of bonds in cumulene - 1 */
|
3369
|
+
next_atom[len] = (int)norm_at[j].neighbor[n]-offset;
|
3370
|
+
next_neigh[len] = n;
|
3371
|
+
cur_atom = j;
|
3372
|
+
while ( next_atom[len] != k && len < MAX_CUMULENE_LEN && 2 == norm_at[next_atom[len]].valence ) {
|
3373
|
+
next_neigh[len+1] = ((int)norm_at[next_atom[len]].neighbor[0]-offset == cur_atom);
|
3374
|
+
next_atom[len+1] = (int)norm_at[next_atom[len]].neighbor[next_neigh[len+1]]-offset;
|
3375
|
+
cur_atom = next_atom[len];
|
3376
|
+
len ++;
|
3377
|
+
}
|
3378
|
+
if ( next_atom[len] == k ) {
|
3379
|
+
if ( len < best_len ) {
|
3380
|
+
memcpy( best_next_neigh, next_neigh, sizeof(best_next_neigh) );
|
3381
|
+
memcpy( best_next_atom, next_atom, sizeof(best_next_atom) );
|
3382
|
+
best_len = len;
|
3383
|
+
num_eql = 0;
|
3384
|
+
if ( len == 0 ) {
|
3385
|
+
break; /* path length cannot be smaller than 1 */
|
3386
|
+
}
|
3387
|
+
} else
|
3388
|
+
if ( len == best_len ) {
|
3389
|
+
num_eql ++;
|
3390
|
+
}
|
3391
|
+
}
|
3392
|
+
}
|
3393
|
+
if ( best_len <= MAX_CUMULENE_LEN && best_next_atom[best_len] == k ) {
|
3394
|
+
if ( num_eql ) {
|
3395
|
+
num_err ++; /* program error; no breakpoint here */
|
3396
|
+
}
|
3397
|
+
if ( best_len % 2 ) {
|
3398
|
+
/* even number of bonds: chiral atom, draw parity on the cenrtal atom */
|
3399
|
+
j = best_next_atom[best_len/2];
|
3400
|
+
inf_norm_at[j].cStereoCenterParity = c;
|
3401
|
+
str=inf_norm_at[j].at_string;
|
3402
|
+
len = strlen(str);
|
3403
|
+
if ( len + 3 < (int)sizeof(inf_norm_at[0].at_string) ) {
|
3404
|
+
str[len++] = '(';
|
3405
|
+
str[len++] = inf_norm_at[j].cStereoCenterParity;
|
3406
|
+
str[len++] = ')';
|
3407
|
+
str[len] = '\0';
|
3408
|
+
}
|
3409
|
+
} else {
|
3410
|
+
/* odd number of bonds: draw parity on the central bond */
|
3411
|
+
if ( best_len == 0 ) {
|
3412
|
+
/* double bond */
|
3413
|
+
j = start_at;
|
3414
|
+
k = best_next_neigh[0];
|
3415
|
+
} else {
|
3416
|
+
/* cumulene */
|
3417
|
+
best_len = best_len/2-1;
|
3418
|
+
j = best_next_atom[best_len];
|
3419
|
+
k = best_next_neigh[best_len+1]; /* added +1 to display cumulene parity on the middle bond (6-24-2002) */
|
3420
|
+
}
|
3421
|
+
/* mark "forward" bond */
|
3422
|
+
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
|
3423
|
+
;
|
3424
|
+
if ( m < MAX_STEREO_BONDS ) {
|
3425
|
+
inf_norm_at[j].cStereoBondParity[m] = c;
|
3426
|
+
inf_norm_at[j].cStereoBondNumber[m] = k;
|
3427
|
+
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
|
3428
|
+
} else {
|
3429
|
+
num_err ++; /* program error; no breakpoint here */
|
3430
|
+
}
|
3431
|
+
/* mark "backward" bond */
|
3432
|
+
n = norm_at[j].neighbor[k]-offset;
|
3433
|
+
for ( k = 0; k < norm_at[n].valence && j != (int)norm_at[n].neighbor[k]-offset; k ++ )
|
3434
|
+
;
|
3435
|
+
if ( k < norm_at[n].valence ) {
|
3436
|
+
j = n;
|
3437
|
+
for ( m = 0; m < MAX_STEREO_BONDS && inf_norm_at[j].cStereoBondParity[m]; m ++ )
|
3438
|
+
;
|
3439
|
+
if ( m < MAX_STEREO_BONDS ) {
|
3440
|
+
inf_norm_at[j].cStereoBondParity[m] = c;
|
3441
|
+
inf_norm_at[j].cStereoBondNumber[m] = k;
|
3442
|
+
inf_norm_at[j].cStereoBondWarning[m] = bAmbiguousStereoBond;
|
3443
|
+
} else {
|
3444
|
+
num_err ++; /* program error; no breakpoint here */
|
3445
|
+
}
|
3446
|
+
} else {
|
3447
|
+
num_err ++; /* program error; no breakpoint here */
|
3448
|
+
}
|
3449
|
+
}
|
3450
|
+
} else {
|
3451
|
+
num_err ++; /* program error; no breakpoint here */
|
3452
|
+
}
|
3453
|
+
}
|
3454
|
+
}
|
3455
|
+
|
3456
|
+
for ( i = 0; i < num_at; i ++ ) {
|
3457
|
+
/* canonical numbers */
|
3458
|
+
if ( inf_norm_at[i].nCanonNbr ) {
|
3459
|
+
str = inf_norm_at[i].at_string;
|
3460
|
+
len = strlen(str);
|
3461
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonNbr );
|
3462
|
+
if ( inf_norm_at[i].nCanonEquNbr || inf_norm_at[i].nTautGroupCanonNbr || (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) ) {
|
3463
|
+
if ( inf_norm_at[i].nCanonEquNbr ) {
|
3464
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nCanonEquNbr );
|
3465
|
+
} else
|
3466
|
+
if ( len + 1 < len_str ) {
|
3467
|
+
len += 1;
|
3468
|
+
strcat( str, "/" );
|
3469
|
+
}
|
3470
|
+
}
|
3471
|
+
/* tautomeric groups */
|
3472
|
+
if ( inf_norm_at[i].nTautGroupCanonNbr ) {
|
3473
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupCanonNbr );
|
3474
|
+
if ( inf_norm_at[i].nTautGroupEquNbr ) {
|
3475
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_norm_at[i].nTautGroupEquNbr );
|
3476
|
+
}
|
3477
|
+
}
|
3478
|
+
if ( (inf_norm_at[i].cFlags & AT_FLAG_ISO_H_POINT) && len+2 <= len_str ) {
|
3479
|
+
str[len++] = '/';
|
3480
|
+
str[len++] = '*';
|
3481
|
+
str[len] = '\0';
|
3482
|
+
}
|
3483
|
+
#ifdef DISPLAY_DEBUG_DATA
|
3484
|
+
if ( inf_norm_at[i].nDebugData ) {
|
3485
|
+
len += (*MakeNumber)( str+len, len_str-len, "`", (int)inf_norm_at[i].nDebugData );
|
3486
|
+
}
|
3487
|
+
#endif
|
3488
|
+
}
|
3489
|
+
}
|
3490
|
+
|
3491
|
+
|
3492
|
+
exit_function:
|
3493
|
+
|
3494
|
+
if ( nNormAtNosInCanonOrd )
|
3495
|
+
inchi_free( nNormAtNosInCanonOrd );
|
3496
|
+
|
3497
|
+
return ret;
|
3498
|
+
}
|
3499
|
+
|
3500
|
+
/***************************************************************************************/
|
3501
|
+
int FillOutInputInfAtom(inp_ATOM *inp_at, INF_ATOM_DATA *inf_at_data, int init_num_at, int num_removed_H,
|
3502
|
+
int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic, int bAbcNumbers)
|
3503
|
+
{
|
3504
|
+
int i, j, m, n, ret, len_str, len, atw;
|
3505
|
+
int num_iso_H[NUM_H_ISOTOPES];
|
3506
|
+
char *str;
|
3507
|
+
int num_at = init_num_at - num_removed_H;
|
3508
|
+
int (*MakeNumber)(char*, int, const char*, int) = MakeDecNumber;
|
3509
|
+
|
3510
|
+
inf_ATOM *inf_at = inf_at_data? inf_at_data->at : NULL;
|
3511
|
+
|
3512
|
+
|
3513
|
+
ret = 0;
|
3514
|
+
|
3515
|
+
|
3516
|
+
if ( !inf_at )
|
3517
|
+
return ret;
|
3518
|
+
|
3519
|
+
memset( inf_at, 0, init_num_at*sizeof(inf_at[0]) );
|
3520
|
+
|
3521
|
+
inf_at_data->nNumRemovedProtons = nNumRemovedProtons;
|
3522
|
+
MakeRemovedProtonsString( nNumRemovedProtons, nNumRemovedProtonsIsotopic, NULL, bIsotopic, inf_at_data->szRemovedProtons, NULL );
|
3523
|
+
/*
|
3524
|
+
if ( inf_at_data->nNumRemovedProtons ) {
|
3525
|
+
sprintf ( inf_at_data->szRemovedProtons, "Proton balance: %c %d H+",
|
3526
|
+
inf_at_data->nNumRemovedProtons>=0? '+':'-',
|
3527
|
+
abs(inf_at_data->nNumRemovedProtons) );
|
3528
|
+
} else {
|
3529
|
+
inf_at_data->szRemovedProtons[0] = '\0';
|
3530
|
+
|
3531
|
+
}
|
3532
|
+
*/
|
3533
|
+
/* atom canonical and equivalence numbers > 0 */
|
3534
|
+
for ( i = 0; i < num_at; i ++ ) {
|
3535
|
+
#if( DISPLAY_ORIG_AT_NUMBERS == 1 )
|
3536
|
+
inf_at[i].nCanonNbr = inp_at[i].orig_at_number;
|
3537
|
+
#else
|
3538
|
+
inf_at[i].nCanonNbr = (AT_NUMB)(i+1);
|
3539
|
+
#endif
|
3540
|
+
}
|
3541
|
+
/* Write isotopic mass, chemical element symbols and hydrogens, charge, radical, canon. numbers */
|
3542
|
+
len_str = sizeof(inf_at[0].at_string);
|
3543
|
+
for ( i = 0; i < init_num_at; i ++ ) {
|
3544
|
+
str = inf_at[i].at_string;
|
3545
|
+
len = 0;
|
3546
|
+
/* isotopic mass */
|
3547
|
+
atw = 0;
|
3548
|
+
if ( inp_at[i].iso_atw_diff && bIsotopic ) {
|
3549
|
+
atw = get_atw(inp_at[i].elname);
|
3550
|
+
atw += (inp_at[i].iso_atw_diff>0)? inp_at[i].iso_atw_diff-1:inp_at[i].iso_atw_diff;
|
3551
|
+
/*len += sprintf( str+len, "^%d", atw );*/
|
3552
|
+
}
|
3553
|
+
/* element name */
|
3554
|
+
if ( inp_at[i].el_number == PERIODIC_NUMBER_H && 2 <= atw && atw <= 3 ) {
|
3555
|
+
len += sprintf( str+len, "%s", atw==2? "D" : "T" );
|
3556
|
+
} else {
|
3557
|
+
if ( atw ) {
|
3558
|
+
len += sprintf( str+len, "^%d", atw );
|
3559
|
+
}
|
3560
|
+
len += sprintf( str+len, "%s", inp_at[i].elname );
|
3561
|
+
}
|
3562
|
+
/* hydrogens */
|
3563
|
+
/* find number of previuosly removed terminal hydrogen atoms */
|
3564
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3565
|
+
num_iso_H[j] = inp_at[i].num_iso_H[j];
|
3566
|
+
}
|
3567
|
+
for ( j = num_at, n = (int)inp_at[i].num_H; j < init_num_at; j ++ ) {
|
3568
|
+
/* subtract number of removed terminal */
|
3569
|
+
/* H atoms from the total number of H atoms */
|
3570
|
+
if ( i == (int)inp_at[j].neighbor[0] ) {
|
3571
|
+
n -= 1;
|
3572
|
+
m = (int)inp_at[j].iso_atw_diff-1;
|
3573
|
+
if ( 0 <= m && m < NUM_H_ISOTOPES ) {
|
3574
|
+
/* subtract number of removed terminal isotopic */
|
3575
|
+
/* H atoms from the total number of isotopic H atoms */
|
3576
|
+
num_iso_H[m] -= 1;
|
3577
|
+
}
|
3578
|
+
}
|
3579
|
+
}
|
3580
|
+
if ( bIsotopic ) {
|
3581
|
+
/* subtract number of isotopic H atoms from the total number of H atoms */
|
3582
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3583
|
+
n -= num_iso_H[j];
|
3584
|
+
}
|
3585
|
+
}
|
3586
|
+
/* non-isotopic hydrogen atoms */
|
3587
|
+
if ( n > 1 ) {
|
3588
|
+
len += sprintf( str+len, "H%d", n );
|
3589
|
+
} else
|
3590
|
+
if ( n == 1 ) {
|
3591
|
+
len += sprintf( str+len, "H" ); /* fixed 12-21-2002: removed 3rd argument */
|
3592
|
+
}
|
3593
|
+
if ( bIsotopic ) {
|
3594
|
+
/* isotopic hydrogen atoms */
|
3595
|
+
for ( j = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
3596
|
+
if ( num_iso_H[j] ) {
|
3597
|
+
if ( j == 0 || j != 1 && j != 2 ) {
|
3598
|
+
len += sprintf( str+len, "^%dH", j+1 );
|
3599
|
+
} else {
|
3600
|
+
len += sprintf( str+len, j == 1? "D" : "T" );
|
3601
|
+
}
|
3602
|
+
if ( num_iso_H[j] != 1 ) {
|
3603
|
+
len += sprintf( str+len, "%d", (int)num_iso_H[j] );
|
3604
|
+
}
|
3605
|
+
}
|
3606
|
+
}
|
3607
|
+
}
|
3608
|
+
if ( inp_at[i].el_number == PERIODIC_NUMBER_H && str[0] == str[1] ) {
|
3609
|
+
char *q;
|
3610
|
+
if ( !str[2] ) {
|
3611
|
+
str[1] = '2'; /* quick fix: replace HH with H2 */
|
3612
|
+
} else
|
3613
|
+
if ( isdigit( UCINT str[2] ) && (n = strtol( str+2, &q, 10 )) && !q[0] ) {
|
3614
|
+
len = 1 + sprintf( str+1, "%d", n+1 );
|
3615
|
+
}
|
3616
|
+
}
|
3617
|
+
/*
|
3618
|
+
if ( str[0] == 'H' && str[1] == 'H' && !str[2] ) {
|
3619
|
+
str[1] = '2';
|
3620
|
+
}
|
3621
|
+
*/
|
3622
|
+
/* charge */
|
3623
|
+
if ( abs(inp_at[i].charge) > 1 )
|
3624
|
+
len += sprintf( str+len, "%+d", inp_at[i].charge );
|
3625
|
+
else
|
3626
|
+
if ( abs(inp_at[i].charge) == 1 )
|
3627
|
+
len += sprintf( str+len, "%s", inp_at[i].charge>0? "+" : "-" );
|
3628
|
+
/* radical */
|
3629
|
+
if ( inp_at[i].radical )
|
3630
|
+
len += sprintf( str+len, "%s", inp_at[i].radical==RADICAL_SINGLET? ":" :
|
3631
|
+
inp_at[i].radical==RADICAL_DOUBLET? "." :
|
3632
|
+
inp_at[i].radical==RADICAL_TRIPLET? ".." : "?");
|
3633
|
+
}
|
3634
|
+
|
3635
|
+
for ( i = 0; i < init_num_at; i ++ ) {
|
3636
|
+
/* canonical numbers */
|
3637
|
+
if ( inf_at[i].nCanonNbr ) {
|
3638
|
+
str = inf_at[i].at_string;
|
3639
|
+
len = strlen(str);
|
3640
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonNbr );
|
3641
|
+
if ( inf_at[i].nCanonEquNbr || inf_at[i].nTautGroupCanonNbr ) {
|
3642
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nCanonEquNbr );
|
3643
|
+
}
|
3644
|
+
/* tautomeric groups */
|
3645
|
+
if ( inf_at[i].nTautGroupCanonNbr ) {
|
3646
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupCanonNbr );
|
3647
|
+
if ( inf_at[i].nTautGroupEquNbr ) {
|
3648
|
+
len += (*MakeNumber)( str+len, len_str-len, "/", (int)inf_at[i].nTautGroupEquNbr );
|
3649
|
+
}
|
3650
|
+
}
|
3651
|
+
}
|
3652
|
+
}
|
3653
|
+
ret = init_num_at;
|
3654
|
+
|
3655
|
+
return ret;
|
3656
|
+
}
|
3657
|
+
/**********************************************************************************************/
|
3658
|
+
int FillOutInfAtom(inp_ATOM *norm_at, INF_ATOM_DATA *inf_norm_at_data, int init_num_at, int num_removed_H,
|
3659
|
+
int nNumRemovedProtons, NUM_H *nNumRemovedProtonsIsotopic, int bIsotopic,
|
3660
|
+
INChI *pINChI, INChI_Aux *pINChI_Aux, int bAbcNumbers, INCHI_MODE nMode )
|
3661
|
+
{
|
3662
|
+
if ( norm_at && inf_norm_at_data && inf_norm_at_data->at ) {
|
3663
|
+
if ( pINChI && pINChI_Aux ) {
|
3664
|
+
return FillOutCanonInfAtom( norm_at, inf_norm_at_data, init_num_at, bIsotopic, pINChI,
|
3665
|
+
pINChI_Aux, bAbcNumbers, nMode);
|
3666
|
+
} else {
|
3667
|
+
return FillOutInputInfAtom( norm_at, inf_norm_at_data, init_num_at, num_removed_H,
|
3668
|
+
nNumRemovedProtons, nNumRemovedProtonsIsotopic, bIsotopic, bAbcNumbers);
|
3669
|
+
}
|
3670
|
+
}
|
3671
|
+
return 0;
|
3672
|
+
}
|
3673
|
+
/***************************************************************************************/
|
3674
|
+
int FillOutCompositeCanonInfAtom(COMP_ATOM_DATA *composite_norm_data, INF_ATOM_DATA *inf_norm_at_data,
|
3675
|
+
int bIsotopic, int bTautomeric,
|
3676
|
+
PINChI2 *pINChI2, PINChI_Aux2 *pINChI_Aux2, int bAbcNumbers, INCHI_MODE nMode)
|
3677
|
+
{
|
3678
|
+
int i, num_components, j, k, ret;
|
3679
|
+
inp_ATOM *inp_norm_at;
|
3680
|
+
INChI *pINChI;
|
3681
|
+
INChI_Aux *pINChI_Aux;
|
3682
|
+
int num_inp_at, num_at, num_H, offset, offset_H, next_offset, next_offset_H;
|
3683
|
+
|
3684
|
+
if ( composite_norm_data && inf_norm_at_data && (bTautomeric == TAUT_INI || pINChI2 && pINChI_Aux2) ) {
|
3685
|
+
composite_norm_data += bTautomeric;
|
3686
|
+
inp_norm_at = composite_norm_data->at;
|
3687
|
+
num_components = composite_norm_data->num_components;
|
3688
|
+
offset = 0;
|
3689
|
+
offset_H = composite_norm_data->num_at - composite_norm_data->num_removed_H;
|
3690
|
+
if ( bTautomeric == TAUT_INI ) {
|
3691
|
+
ret = FillOutInputInfAtom( composite_norm_data->at, inf_norm_at_data, composite_norm_data->num_at,
|
3692
|
+
composite_norm_data->num_removed_H,
|
3693
|
+
composite_norm_data->nNumRemovedProtons,
|
3694
|
+
composite_norm_data->nNumRemovedProtonsIsotopic,
|
3695
|
+
bIsotopic, bAbcNumbers);
|
3696
|
+
return ret;
|
3697
|
+
} else {
|
3698
|
+
for ( i = 0; i < num_components; i ++ ) {
|
3699
|
+
j = inchi_min(bTautomeric, TAUT_YES);
|
3700
|
+
/* count isotopic H on removed atoms -- isolated H(+) cations */
|
3701
|
+
inf_norm_at_data->nNumRemovedProtons += pINChI_Aux2[i][j]->nNumRemovedProtons;
|
3702
|
+
if ( bIsotopic && bTautomeric == TAUT_YES ) {
|
3703
|
+
for ( k = 0; k < NUM_H_ISOTOPES; k ++ ) {
|
3704
|
+
if ( pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k] ) {
|
3705
|
+
inf_norm_at_data->num_iso_H[k] += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
|
3706
|
+
inf_norm_at_data->num_removed_iso_H += pINChI_Aux2[i][j]->nNumRemovedIsotopicH[k];
|
3707
|
+
}
|
3708
|
+
}
|
3709
|
+
}
|
3710
|
+
/* ignore deleted components */
|
3711
|
+
if ( pINChI2[i][j] && pINChI2[i][j]->bDeleted ) {
|
3712
|
+
continue;
|
3713
|
+
}
|
3714
|
+
if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
|
3715
|
+
j = ALT_TAUT(j);
|
3716
|
+
if ( !pINChI2[i][j] || !pINChI2[i][j]->nNumberOfAtoms ) {
|
3717
|
+
continue; /* error ??? */
|
3718
|
+
}
|
3719
|
+
}
|
3720
|
+
pINChI = pINChI2[i][j];
|
3721
|
+
pINChI_Aux = pINChI_Aux2[i][j];
|
3722
|
+
next_offset = composite_norm_data->nOffsetAtAndH[2*i];
|
3723
|
+
next_offset_H = composite_norm_data->nOffsetAtAndH[2*i+1];
|
3724
|
+
num_at = next_offset - offset;
|
3725
|
+
if ( num_at <= 0 )
|
3726
|
+
continue;
|
3727
|
+
num_H = next_offset_H - offset_H;
|
3728
|
+
num_inp_at = num_at + num_H;
|
3729
|
+
if ( num_at != pINChI->nNumberOfAtoms || num_at != pINChI_Aux->nNumberOfAtoms ) {
|
3730
|
+
return 0; /* error */
|
3731
|
+
}
|
3732
|
+
ret = FillOutOneCanonInfAtom(inp_norm_at, inf_norm_at_data,
|
3733
|
+
inf_norm_at_data->pStereoFlags+i+1, num_inp_at,
|
3734
|
+
offset, offset_H, bIsotopic, pINChI, pINChI_Aux, bAbcNumbers, nMode);
|
3735
|
+
if ( ret )
|
3736
|
+
return 0; /* error */
|
3737
|
+
|
3738
|
+
inf_norm_at_data->StereoFlags |= inf_norm_at_data->pStereoFlags[i+1];
|
3739
|
+
offset = next_offset;
|
3740
|
+
offset_H = next_offset_H;
|
3741
|
+
}
|
3742
|
+
}
|
3743
|
+
MakeRemovedProtonsString( inf_norm_at_data->nNumRemovedProtons, inf_norm_at_data->num_iso_H, NULL, bIsotopic,
|
3744
|
+
inf_norm_at_data->szRemovedProtons, &inf_norm_at_data->num_removed_iso_H );
|
3745
|
+
}
|
3746
|
+
return 1;
|
3747
|
+
}
|
3748
|
+
#endif /* } ifndef INCHI_ANSI_ONLY */
|
3749
|
+
/**********************************************************************************************/
|
3750
|
+
int CheckCanonNumberingCorrectness(int num_atoms, int num_at_tg,
|
3751
|
+
sp_ATOM *at, CANON_STAT *pCS, int bTautomeric,
|
3752
|
+
char *pStrErrStruct )
|
3753
|
+
{
|
3754
|
+
int i, ret=0;
|
3755
|
+
AT_NUMB *pCanonOrd=NULL;
|
3756
|
+
int nErrorCode = 0;
|
3757
|
+
AT_NUMB *pCanonRank; /* canonical ranks of the atoms or tautomeric groups */
|
3758
|
+
AT_NUMB *pCanonRankAtoms=NULL;
|
3759
|
+
|
3760
|
+
static int count=0; /* for debug only */
|
3761
|
+
count ++;
|
3762
|
+
|
3763
|
+
pCanonRankAtoms = (AT_NUMB *)inchi_calloc( num_at_tg+1, sizeof(pCanonRankAtoms[0]) );
|
3764
|
+
|
3765
|
+
/**********************************************************************************************
|
3766
|
+
*
|
3767
|
+
* non-isotopic part
|
3768
|
+
*/
|
3769
|
+
pCanonOrd = pCS->nLenCanonOrdStereo > 0? pCS->nCanonOrdStereo :
|
3770
|
+
pCS->nLenCanonOrd > 0? pCS->nCanonOrd : NULL;
|
3771
|
+
pCanonRank = pCanonRankAtoms;
|
3772
|
+
if ( pCanonOrd && pCanonRank ) {
|
3773
|
+
for ( i = 0; i < num_at_tg; i ++ ) {
|
3774
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
3775
|
+
}
|
3776
|
+
ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
|
3777
|
+
if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
|
3778
|
+
nErrorCode |= WARN_FAILED_STEREO;
|
3779
|
+
}
|
3780
|
+
|
3781
|
+
} else {
|
3782
|
+
nErrorCode |= ERR_NO_CANON_RESULTS;
|
3783
|
+
goto exit_function;
|
3784
|
+
}
|
3785
|
+
/**********************************************************************************************
|
3786
|
+
*
|
3787
|
+
* isotopic part
|
3788
|
+
*/
|
3789
|
+
pCanonOrd = pCS->nLenCanonOrdIsotopicStereo > 0? pCS->nCanonOrdIsotopicStereo :
|
3790
|
+
pCS->nLenCanonOrdIsotopic > 0? pCS->nCanonOrdIsotopic : NULL;
|
3791
|
+
pCanonRank = pCanonRankAtoms;
|
3792
|
+
|
3793
|
+
if ( pCanonOrd && pCanonRank ) {
|
3794
|
+
for ( i = 0; i < num_at_tg; i ++ ) {
|
3795
|
+
pCanonRank[pCanonOrd[i]] = (AT_NUMB)(i+1);
|
3796
|
+
}
|
3797
|
+
ret = UpdateFullLinearCT( num_atoms, num_at_tg, at, pCanonRank, pCanonOrd, pCS, 0 );
|
3798
|
+
if ( ret /*|| memcmp(pCS->LinearCT, pCS->LinearCT2, sizeof(AT_RANK) * pCS->nLenLinearCT )*/ ) {
|
3799
|
+
nErrorCode |= (pCS->nLenCanonOrdIsotopicStereo? WARN_FAILED_ISOTOPIC_STEREO : WARN_FAILED_ISOTOPIC);
|
3800
|
+
}
|
3801
|
+
|
3802
|
+
}
|
3803
|
+
|
3804
|
+
exit_function:
|
3805
|
+
if ( pCanonRankAtoms )
|
3806
|
+
inchi_free( pCanonRankAtoms );
|
3807
|
+
|
3808
|
+
if ( nErrorCode ) {
|
3809
|
+
return CT_CANON_ERR;
|
3810
|
+
}
|
3811
|
+
return 0;
|
3812
|
+
}
|