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
@@ -0,0 +1,3014 @@
|
|
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
|
+
/* this file is used only in case of #define CREATE_0D_PARITIES */
|
11
|
+
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <stdlib.h>
|
14
|
+
#include <math.h>
|
15
|
+
#include <string.h>
|
16
|
+
#include <ctype.h>
|
17
|
+
|
18
|
+
#include "e_mode.h"
|
19
|
+
#include "inchi_api.h"
|
20
|
+
#include "e_inchi_atom.h"
|
21
|
+
#include "e_ichisize.h"
|
22
|
+
#include "e_comdef.h"
|
23
|
+
#include "e_ichicomp.h"
|
24
|
+
#include "e_util.h"
|
25
|
+
#include "e_0dstereo.h"
|
26
|
+
|
27
|
+
#define ALWAYS_SET_STEREO_PARITY 0
|
28
|
+
|
29
|
+
#define SB_PARITY_FLAG 0x38 /* disconnected structure has undef. parity */
|
30
|
+
#define SB_PARITY_SHFT 3
|
31
|
+
#define SB_PARITY_MASK 0x07
|
32
|
+
#define SB_PARITY_1(X) (X & SB_PARITY_MASK) /* refers to connected structure */
|
33
|
+
#define SB_PARITY_2(X) (((X) >> SB_PARITY_SHFT) & SB_PARITY_MASK) /* refers to connected structure */
|
34
|
+
|
35
|
+
#define inchi_NUMH(AT,CUR_AT) (AT[CUR_AT].num_iso_H[0]+AT[CUR_AT].num_iso_H[1]+AT[CUR_AT].num_iso_H[2]+AT[CUR_AT].num_iso_H[3])
|
36
|
+
#define inchi_NUMH2(AT,CUR_AT) ((AT[CUR_AT].num_iso_H[0]>0?AT[CUR_AT].num_iso_H[0]:0) +AT[CUR_AT].num_iso_H[1]+AT[CUR_AT].num_iso_H[2]+AT[CUR_AT].num_iso_H[3])
|
37
|
+
#define IS_METAL(a) (a == AtType_Metal || a == AtType_Sn4 || a == AtType_Sn3 || a == AtType_Sn2)
|
38
|
+
|
39
|
+
typedef struct tagStereo0D {
|
40
|
+
inchi_Stereo0D *stereo0D; /* array of num_stereo0D 0D stereo elements or NULL */
|
41
|
+
int num_stereo0D; /* number of 0D stereo elements */
|
42
|
+
int max_num_Stereo0D; /* allocated length of stereo0D */
|
43
|
+
int delta_num_stereo0D;/* allocation increments */
|
44
|
+
S_CHAR *cAtType;
|
45
|
+
} Stereo0D;
|
46
|
+
|
47
|
+
typedef enum tagAtType {
|
48
|
+
/* possible stereocenter */
|
49
|
+
AtType_C4 = 1, /* >C< */
|
50
|
+
AtType_Si4 = 2, /* >Si< */
|
51
|
+
AtType_Ge4 = 3, /* >Ge< */
|
52
|
+
AtType_Sn4 = 4, /* >Sn< */
|
53
|
+
AtType_B4m = 5, /* B(-) */
|
54
|
+
AtType_S4 = 6, /* =S< */
|
55
|
+
AtType_S6 = 7, /* >S<, 2 double bonds */
|
56
|
+
AtType_S3p = 8, /* -S(+)< */
|
57
|
+
AtType_S5p = 9, /* >S(+)<, 1 double bond */
|
58
|
+
AtType_Se4 =10, /* =Se< */
|
59
|
+
AtType_Se6 =11, /* >Se<, 2 double bonds */
|
60
|
+
AtType_Se3p =12, /* -Se(+)< */
|
61
|
+
AtType_Se5p =13, /* >Se(+)<, 1 double bond */
|
62
|
+
AtType_N5 =14, /* >N<, 1 double bond */
|
63
|
+
AtType_N4p =15, /* >N(+)< */
|
64
|
+
AtType_N3r =16, /* -N<| (N in a 3-member ring) */
|
65
|
+
AtType_P4p =17, /* >N(+)< */
|
66
|
+
AtType_P5 =18, /* >P<, 1 double bond */
|
67
|
+
AtType_As4p =19, /* >As(+)< */
|
68
|
+
AtType_As5 =20, /* >As<, 1 double bond */
|
69
|
+
/* possible stereobond */
|
70
|
+
AtType_C3 =21, /* =C<, =C/ */
|
71
|
+
AtType_Si3 =22,
|
72
|
+
AtType_Ge3 =23,
|
73
|
+
AtType_Sn3 =24,
|
74
|
+
AtType_N3p =25, /* =N(+)< */
|
75
|
+
AtType_N3 =26, /* =N/ */
|
76
|
+
/* middle allene/cumulene */
|
77
|
+
AtType_C2 =27, /* =C= */
|
78
|
+
AtType_Si2 =28, /* =Si= */
|
79
|
+
AtType_Ge2 =29, /* =Ge= */
|
80
|
+
AtType_Sn2 =30, /* =Ge= */
|
81
|
+
/* may become stereobond after charge or radical shift */
|
82
|
+
AtType_Nns =31,
|
83
|
+
/* metal */
|
84
|
+
AtType_Metal =32,
|
85
|
+
/* terminal H */
|
86
|
+
AtType_TermH =33,
|
87
|
+
AtType_TermD =34,
|
88
|
+
AtType_TermT =35
|
89
|
+
} AT_TYPE;
|
90
|
+
|
91
|
+
typedef enum tagElType {
|
92
|
+
ElType_C = 1,
|
93
|
+
ElType_Si = 2,
|
94
|
+
ElType_Ge = 3,
|
95
|
+
ElType_Sn = 4,
|
96
|
+
ElType_B = 5,
|
97
|
+
ElType_S = 6,
|
98
|
+
ElType_Se = 7,
|
99
|
+
ElType_N = 8,
|
100
|
+
ElType_P = 9,
|
101
|
+
ElType_As =10,
|
102
|
+
ElType_H =11,
|
103
|
+
ElType_D =12,
|
104
|
+
ElType_T =13
|
105
|
+
|
106
|
+
} EL_TYPE;
|
107
|
+
|
108
|
+
inchi_Stereo0D *e_GetNewStereo( Stereo0D *pStereo );
|
109
|
+
|
110
|
+
|
111
|
+
static int ee_extract_ChargeRadical( char *elname, int *pnRadical, int *pnCharge );
|
112
|
+
static int ee_extract_H_atoms( char *elname, S_CHAR num_iso_H[] );
|
113
|
+
static int e_GetElType( inchi_Atom *at, int cur_atom );
|
114
|
+
static int e_bCanInpAtomBeAStereoCenter( int cur_at, S_CHAR *cAtType );
|
115
|
+
static int e_nNumNonMetalNeigh( inchi_Atom *atom, int cur_at, Stereo0D *pStereo, int *i_ord_LastMetal );
|
116
|
+
|
117
|
+
void e_swap ( char *a, char *b, size_t width );
|
118
|
+
int e_insertions_sort( void *base, size_t num, size_t width, int ( *compare )(const void *e1, const void *e2 ) );
|
119
|
+
int e_bCanAtomHaveAStereoBond( inchi_Atom *at, int cur_at, S_CHAR *cAtType );
|
120
|
+
int e_bCanAtomBeMiddleAllene( int cur_at, S_CHAR *cAtType );
|
121
|
+
int e_bCanAtomBeTerminalAllene( int cur_at, S_CHAR *cAtType );
|
122
|
+
|
123
|
+
/**********************************************************************************/
|
124
|
+
#define AMBIGUOUS_STEREO 1
|
125
|
+
#define AMBIGUOUS_STEREO_ERROR 32
|
126
|
+
|
127
|
+
|
128
|
+
#define AB_MAX_WELL_DEFINED_PARITY inchi_max(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* 1, 2 => well defined parities, uncluding 'unknown' */
|
129
|
+
#define AB_MIN_WELL_DEFINED_PARITY inchi_min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) */
|
130
|
+
|
131
|
+
#define AMBIGUOUS_STEREO 1
|
132
|
+
|
133
|
+
#define MIN_DOT_PROD 50 /* min value of at->stereo_bond_z_prod[i] to define parity */
|
134
|
+
|
135
|
+
#define ATOM_PARITY_WELL_DEF(X) (AB_MIN_WELL_DEFINED_PARITY <= (X) && (X) <= AB_MAX_WELL_DEFINED_PARITY)
|
136
|
+
/**********************************************************************************/
|
137
|
+
|
138
|
+
#define CT_ERR_FIRST (-30000)
|
139
|
+
#define CT_OUT_OF_RAM (CT_ERR_FIRST- 2) /*(-30002) */
|
140
|
+
#define CT_ISO_H_ERR (CT_ERR_FIRST- 9) /*(-30009) */
|
141
|
+
#define CT_CALC_STEREO_ERR (CT_ERR_FIRST-15) /*(-30015) */
|
142
|
+
#define CT_UNKNOWN_ERR (CT_ERR_FIRST-18) /*(-30018) */
|
143
|
+
|
144
|
+
#define CT_ERR_MIN CT_UNKNOWN_ERR
|
145
|
+
#define CT_ERR_MAX CT_ERR_FIRST
|
146
|
+
|
147
|
+
#define RETURNED_ERROR(nVal) (CT_ERR_MIN<=(nVal) && (nVal)<=CT_ERR_MAX)
|
148
|
+
/**********************************************************************************/
|
149
|
+
#define MAX_CUMULENE_LEN 2 /* max number of bonds in a cumulene chain - 1 */
|
150
|
+
/**********************************************************************************/
|
151
|
+
int ee_extract_ChargeRadical( char *elname, int *pnRadical, int *pnCharge )
|
152
|
+
{
|
153
|
+
char *q, *r, *p;
|
154
|
+
int nCharge=0, nRad = 0, charge_len = 0, k, nVal, nSign, nLastSign=1, len;
|
155
|
+
|
156
|
+
p = elname;
|
157
|
+
|
158
|
+
/* extract radicals & charges */
|
159
|
+
while ( q = strpbrk( p, "+-^" ) ) {
|
160
|
+
switch ( *q ) {
|
161
|
+
case '+':
|
162
|
+
case '-':
|
163
|
+
for ( k = 0, nVal=0; (nSign = ('+' == q[k])) || (nSign = -('-' == q[k])); k++ ) {
|
164
|
+
nVal += (nLastSign = nSign);
|
165
|
+
charge_len ++;
|
166
|
+
}
|
167
|
+
if ( nSign = (int)strtol( q+k, &r, 10 ) ) { /* fixed 12-5-2001 */
|
168
|
+
nVal += nLastSign * (nSign-1);
|
169
|
+
}
|
170
|
+
charge_len = r - q;
|
171
|
+
nCharge += nVal;
|
172
|
+
break;
|
173
|
+
/* case '.': */ /* singlet '.' may be confused with '.' in formulas like CaO.H2O */
|
174
|
+
case '^':
|
175
|
+
nRad = 1; /* doublet here is 1. See below */
|
176
|
+
charge_len = 1;
|
177
|
+
for ( k = 1; q[0] == q[k]; k++ ) {
|
178
|
+
nRad ++;
|
179
|
+
charge_len ++;
|
180
|
+
}
|
181
|
+
break;
|
182
|
+
}
|
183
|
+
memmove( q, q+charge_len, strlen(q+charge_len)+1 );
|
184
|
+
}
|
185
|
+
len = strlen(p);
|
186
|
+
/* radical */
|
187
|
+
if ( (q = strrchr( p, ':' )) && !q[1]) {
|
188
|
+
nRad = RADICAL_SINGLET;
|
189
|
+
q[0] = '\0';
|
190
|
+
len --;
|
191
|
+
} else {
|
192
|
+
while( (q = strrchr( p, '.' )) && !q[1] ) {
|
193
|
+
nRad ++;
|
194
|
+
q[0] = '\0';
|
195
|
+
len --;
|
196
|
+
}
|
197
|
+
|
198
|
+
nRad = nRad == 1? RADICAL_DOUBLET :
|
199
|
+
nRad == 2? RADICAL_TRIPLET : 0;
|
200
|
+
}
|
201
|
+
*pnRadical = nRad;
|
202
|
+
*pnCharge = nCharge;
|
203
|
+
return ( nRad || nCharge );
|
204
|
+
|
205
|
+
}
|
206
|
+
/***********************************************************************/
|
207
|
+
int ee_extract_H_atoms( char *elname, S_CHAR num_iso_H[] )
|
208
|
+
{
|
209
|
+
int i, len, c, k, val, bExtracted = 0;
|
210
|
+
char *q;
|
211
|
+
i = 0;
|
212
|
+
len = (int)strlen(elname);
|
213
|
+
c = UCINT elname[0];
|
214
|
+
while ( i < len ) {
|
215
|
+
switch ( c ) {
|
216
|
+
case 'H':
|
217
|
+
k = 0;
|
218
|
+
break;
|
219
|
+
case 'D':
|
220
|
+
k = 2;
|
221
|
+
break;
|
222
|
+
case 'T':
|
223
|
+
k = 3;
|
224
|
+
break;
|
225
|
+
default:
|
226
|
+
k = -1;
|
227
|
+
break;
|
228
|
+
}
|
229
|
+
q = elname+i+1; /* pointer to the next to elname[i] character */
|
230
|
+
c = UCINT q[0];
|
231
|
+
if ( k >= 0 && !islower( c ) ) {
|
232
|
+
/* found a hydrogen */
|
233
|
+
bExtracted ++;
|
234
|
+
if ( isdigit( c ) ) {
|
235
|
+
val = (int)strtol( q, &q, 10 );
|
236
|
+
/* q = pointer to the next to number of hydrogen atom(s) character */
|
237
|
+
} else {
|
238
|
+
val = 1;
|
239
|
+
}
|
240
|
+
num_iso_H[k] += val;
|
241
|
+
/* remove the hydrogen atom from the string */
|
242
|
+
len -= (q-elname)-i;
|
243
|
+
memmove( elname+i, q, len + 1 );
|
244
|
+
/* c = UCINT elname[i]; */
|
245
|
+
} else {
|
246
|
+
i ++;
|
247
|
+
}
|
248
|
+
c = UCINT elname[i]; /* moved here 11-04-2002 */
|
249
|
+
}
|
250
|
+
return bExtracted;
|
251
|
+
}
|
252
|
+
/************************************************/
|
253
|
+
#define MAX_BOND_TYPE 4
|
254
|
+
int e_GetElType( inchi_Atom *at, int cur_atom )
|
255
|
+
{
|
256
|
+
char szEl[ATOM_EL_LEN];
|
257
|
+
int nRadical, nCharge, bChargeOrRad, bH, bAddH = 0, nElType=0, bond_valence, valence, num_H=0;
|
258
|
+
S_CHAR num_iso_H[NUM_H_ISOTOPES+1];
|
259
|
+
S_CHAR num_bonds[MAX_BOND_TYPE];
|
260
|
+
int i;
|
261
|
+
int nRadicalValence = 0;
|
262
|
+
|
263
|
+
if ( sizeof(at->num_iso_H) != sizeof(num_iso_H) ||
|
264
|
+
sizeof(at->num_iso_H[0]) != sizeof(num_iso_H[0]) ) {
|
265
|
+
/* program error */
|
266
|
+
return -1;
|
267
|
+
}
|
268
|
+
strcpy( szEl, at[cur_atom].elname);
|
269
|
+
memset( num_iso_H, 0, sizeof(num_iso_H) );
|
270
|
+
bChargeOrRad = ee_extract_ChargeRadical( szEl, &nRadical, &nCharge );
|
271
|
+
bH = ee_extract_H_atoms( szEl, num_iso_H );
|
272
|
+
if ( !bChargeOrRad ) {
|
273
|
+
nRadical = at[cur_atom].radical;
|
274
|
+
nCharge = at[cur_atom].charge;
|
275
|
+
}
|
276
|
+
if ( !bH ) {
|
277
|
+
memcpy( num_iso_H, at[cur_atom].num_iso_H, sizeof(num_iso_H) );
|
278
|
+
if ( bAddH = (num_iso_H[0] < 0 ) ) {
|
279
|
+
num_iso_H[0] = 0;
|
280
|
+
}
|
281
|
+
}
|
282
|
+
num_H = num_iso_H[0]+num_iso_H[1]+num_iso_H[2]+num_iso_H[3];
|
283
|
+
|
284
|
+
if (nRadical==INCHI_RADICAL_DOUBLET) {
|
285
|
+
nRadicalValence = 1;
|
286
|
+
} else
|
287
|
+
if ( nRadical==INCHI_RADICAL_TRIPLET || nRadical==INCHI_RADICAL_SINGLET ){
|
288
|
+
nRadicalValence = 2;
|
289
|
+
}
|
290
|
+
|
291
|
+
/* element type */
|
292
|
+
if ( !strcmp( szEl, "C" ) ) {
|
293
|
+
nElType = ElType_C;
|
294
|
+
} else
|
295
|
+
if ( !strcmp( szEl, "Si" ) ) {
|
296
|
+
nElType = ElType_Si;
|
297
|
+
} else
|
298
|
+
if ( !strcmp( szEl, "Ge" ) ) {
|
299
|
+
nElType = ElType_Ge;
|
300
|
+
} else
|
301
|
+
if ( !strcmp( szEl, "Sn" ) ) {
|
302
|
+
nElType = ElType_Sn;
|
303
|
+
} else
|
304
|
+
if ( !strcmp( szEl, "B" ) ) {
|
305
|
+
nElType = ElType_B;
|
306
|
+
} else
|
307
|
+
if ( !strcmp( szEl, "S" ) ) {
|
308
|
+
nElType = ElType_S;
|
309
|
+
} else
|
310
|
+
if ( !strcmp( szEl, "Se" ) ) {
|
311
|
+
nElType = ElType_Se;
|
312
|
+
} else
|
313
|
+
if ( !strcmp( szEl, "N" ) ) {
|
314
|
+
nElType = ElType_N;
|
315
|
+
} else
|
316
|
+
if ( !strcmp( szEl, "P" ) ) {
|
317
|
+
nElType = ElType_P;
|
318
|
+
} else
|
319
|
+
if ( !strcmp( szEl, "As" ) ) {
|
320
|
+
nElType = ElType_As;
|
321
|
+
} else
|
322
|
+
if ( !szEl[0] ) {
|
323
|
+
if ( 1 == num_H && (num_iso_H[0] == 1 || num_iso_H[1] == 1) ) {
|
324
|
+
nElType = ElType_H;
|
325
|
+
} else
|
326
|
+
if ( 1 == num_H && num_iso_H[2] == 1 ) {
|
327
|
+
nElType = ElType_D;
|
328
|
+
} else
|
329
|
+
if ( 1 == num_H && num_iso_H[3] == 1 ) {
|
330
|
+
nElType = ElType_T;
|
331
|
+
} else {
|
332
|
+
return -1;
|
333
|
+
}
|
334
|
+
} else {
|
335
|
+
if ( e_is_element_a_metal( szEl ) ) {
|
336
|
+
return AtType_Metal;
|
337
|
+
}
|
338
|
+
return -1; /* no stereo */
|
339
|
+
}
|
340
|
+
|
341
|
+
/* atom type */
|
342
|
+
memset( num_bonds, 0, sizeof(num_bonds) );
|
343
|
+
bond_valence = 0;
|
344
|
+
valence = at[cur_atom].num_bonds;
|
345
|
+
for ( i = 0; i < valence; i ++ ) {
|
346
|
+
if ( 0 < at[cur_atom].bond_type[i] && at[cur_atom].bond_type[i] <= MAX_BOND_TYPE ) {
|
347
|
+
num_bonds[at[cur_atom].bond_type[i]-1] ++;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
bond_valence = num_bonds[0] + 2*num_bonds[1] + 3*num_bonds[2];
|
351
|
+
if ( num_bonds[3] ) {
|
352
|
+
if ( num_bonds[3] == 2 ) {
|
353
|
+
bond_valence += 3; /* -C= */
|
354
|
+
} else
|
355
|
+
if ( num_bonds[3] == 3 ) {
|
356
|
+
bond_valence += 4; /* >C= */
|
357
|
+
} else {
|
358
|
+
return -1;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
switch( nElType ) {
|
363
|
+
|
364
|
+
case ElType_C:
|
365
|
+
case ElType_Si:
|
366
|
+
case ElType_Ge:
|
367
|
+
case ElType_Sn:
|
368
|
+
|
369
|
+
if ( bAddH && bond_valence + num_H + (abs(nCharge)==1) + nRadicalValence == 4 ) {
|
370
|
+
bAddH = 0; /* no H will be added */
|
371
|
+
}
|
372
|
+
|
373
|
+
if ( bond_valence == valence && (valence==4 || valence == 3 && (bAddH || num_H==1)) && !nRadical ) {
|
374
|
+
switch( nElType ) {
|
375
|
+
case ElType_C:
|
376
|
+
return AtType_C4;
|
377
|
+
case ElType_Si:
|
378
|
+
return AtType_Si4;
|
379
|
+
case ElType_Ge:
|
380
|
+
return AtType_Ge4;
|
381
|
+
case ElType_Sn:
|
382
|
+
return AtType_Sn4;
|
383
|
+
}
|
384
|
+
} else
|
385
|
+
if ( bond_valence == valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nRadical == INCHI_RADICAL_DOUBLET ) {
|
386
|
+
switch( nElType ) {
|
387
|
+
case ElType_C:
|
388
|
+
return AtType_C3;
|
389
|
+
case ElType_Si:
|
390
|
+
return -1;
|
391
|
+
case ElType_Ge:
|
392
|
+
return -1;
|
393
|
+
case ElType_Sn:
|
394
|
+
return AtType_Metal;
|
395
|
+
}
|
396
|
+
} else
|
397
|
+
if ( bond_valence == 4 && valence == 2 && !num_H && !nRadical ) {
|
398
|
+
/* two double bonds or single & triple */
|
399
|
+
switch( nElType ) {
|
400
|
+
case ElType_C:
|
401
|
+
return AtType_C2;
|
402
|
+
case ElType_Si:
|
403
|
+
return AtType_Si2;
|
404
|
+
case ElType_Ge:
|
405
|
+
return AtType_Ge2;
|
406
|
+
case ElType_Sn:
|
407
|
+
return AtType_Sn2;
|
408
|
+
}
|
409
|
+
} else
|
410
|
+
if ( bond_valence == 3 && valence == 2 && !num_H && nRadical == INCHI_RADICAL_DOUBLET ) {
|
411
|
+
/* two double bonds or single & triple */
|
412
|
+
switch( nElType ) {
|
413
|
+
case ElType_C:
|
414
|
+
return AtType_C2;
|
415
|
+
case ElType_Si:
|
416
|
+
return -1;
|
417
|
+
case ElType_Ge:
|
418
|
+
return -1;
|
419
|
+
case ElType_Sn:
|
420
|
+
return AtType_Metal;
|
421
|
+
}
|
422
|
+
} else
|
423
|
+
if ( bond_valence > valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && !nRadical ) {
|
424
|
+
/* "bond_valence > valence" instead of "bond_valence == valence+1" to accommodate
|
425
|
+
* erroneouse acceptance by 1.12Beta of stereo bond case when C has valence > 5 */
|
426
|
+
switch( nElType ) {
|
427
|
+
case ElType_C:
|
428
|
+
return AtType_C3;
|
429
|
+
case ElType_Si:
|
430
|
+
return AtType_Si3;
|
431
|
+
case ElType_Ge:
|
432
|
+
return AtType_Ge3;
|
433
|
+
case ElType_Sn:
|
434
|
+
return AtType_Sn3;
|
435
|
+
}
|
436
|
+
} else
|
437
|
+
if ( bond_valence == valence+1 && bond_valence > 3 ) {
|
438
|
+
/* trying to accommodate hypervalence in coord compounds before disconnection */
|
439
|
+
switch( nElType ) {
|
440
|
+
case ElType_C:
|
441
|
+
return AtType_C3;
|
442
|
+
case ElType_Si:
|
443
|
+
return -1;
|
444
|
+
case ElType_Ge:
|
445
|
+
return -1;
|
446
|
+
case ElType_Sn:
|
447
|
+
return AtType_Metal;
|
448
|
+
}
|
449
|
+
} else
|
450
|
+
if ( bond_valence == valence && bond_valence >= 2 && abs(nCharge) == 1 && 3 == (valence + (bAddH || num_H==1)) ) {
|
451
|
+
/* trying to accommodate C(-)-N(+) bond that may become double after ion pair removal. added 2004-01-31 */
|
452
|
+
switch( nElType ) {
|
453
|
+
case ElType_C:
|
454
|
+
return AtType_C3;
|
455
|
+
case ElType_Si:
|
456
|
+
return AtType_Si3;
|
457
|
+
case ElType_Ge:
|
458
|
+
return -1;
|
459
|
+
case ElType_Sn:
|
460
|
+
return AtType_Metal;
|
461
|
+
}
|
462
|
+
}
|
463
|
+
return (nElType == ElType_Sn)? AtType_Metal : -1;
|
464
|
+
|
465
|
+
case ElType_B:
|
466
|
+
if ( bond_valence == valence && (valence==4 || valence==3 && (bAddH || num_H==1)) && nCharge == -1 && !nRadical ) {
|
467
|
+
return AtType_B4m;
|
468
|
+
}
|
469
|
+
return -1;
|
470
|
+
|
471
|
+
case ElType_S:
|
472
|
+
case ElType_Se:
|
473
|
+
if ( (valence == 3 && bond_valence == 3) && (nCharge == 1 || nRadical == INCHI_RADICAL_DOUBLET) ) {
|
474
|
+
switch( nElType ) {
|
475
|
+
case ElType_S:
|
476
|
+
return AtType_S3p;
|
477
|
+
case ElType_Se:
|
478
|
+
return AtType_Se3p;
|
479
|
+
}
|
480
|
+
} else
|
481
|
+
if ( (valence == 3 && bond_valence == 4) && nCharge == 0 && !nRadical ) {
|
482
|
+
switch( nElType ) {
|
483
|
+
case ElType_S:
|
484
|
+
return AtType_S4;
|
485
|
+
case ElType_Se:
|
486
|
+
return AtType_Se4;
|
487
|
+
}
|
488
|
+
} else
|
489
|
+
if ( (valence == 4 && bond_valence == 5) && (nCharge == 1 || nRadical == INCHI_RADICAL_DOUBLET) ) {
|
490
|
+
switch( nElType ) {
|
491
|
+
case ElType_S:
|
492
|
+
return AtType_S5p;
|
493
|
+
case ElType_Se:
|
494
|
+
return AtType_Se5p;
|
495
|
+
}
|
496
|
+
} else
|
497
|
+
if ( (valence == 4 && bond_valence == 6) && nCharge == 0 && !nRadical ) {
|
498
|
+
switch( nElType ) {
|
499
|
+
case ElType_S:
|
500
|
+
return AtType_S6;
|
501
|
+
case ElType_Se:
|
502
|
+
return AtType_S6;
|
503
|
+
}
|
504
|
+
} else {
|
505
|
+
return -1;
|
506
|
+
}
|
507
|
+
case ElType_N:
|
508
|
+
case ElType_P:
|
509
|
+
case ElType_As:
|
510
|
+
if ( bAddH && bond_valence + num_H - (abs(nCharge)==1? nCharge:0) + nRadicalValence == 3 ) {
|
511
|
+
bAddH = 0; /* no H will be added */
|
512
|
+
} else
|
513
|
+
if ( bAddH && bond_valence + num_H == 5 ) {
|
514
|
+
bAddH = 0; /* no H will be added */
|
515
|
+
}
|
516
|
+
if ( bond_valence == valence && (valence==4 || valence==3 && (bAddH || num_H==1)) && nCharge == 1 && !nRadical ) {
|
517
|
+
switch( nElType ) {
|
518
|
+
case ElType_N:
|
519
|
+
return AtType_N4p;
|
520
|
+
case ElType_P:
|
521
|
+
return AtType_P4p;
|
522
|
+
case ElType_As:
|
523
|
+
return AtType_As4p;
|
524
|
+
}
|
525
|
+
} else
|
526
|
+
if ( bond_valence == valence+1 && (valence==4 /*|| valence == 3*/) && nCharge == 0 ) {
|
527
|
+
switch( nElType ) {
|
528
|
+
case ElType_N:
|
529
|
+
return AtType_N5;
|
530
|
+
case ElType_P:
|
531
|
+
return AtType_P5;
|
532
|
+
case ElType_As:
|
533
|
+
return AtType_As5;
|
534
|
+
}
|
535
|
+
} else
|
536
|
+
if ( bond_valence == valence && valence==3 && nCharge == 0 && !nRadical ) {
|
537
|
+
switch( nElType ) {
|
538
|
+
case ElType_N:
|
539
|
+
{
|
540
|
+
AT_NUM neigh1, neigh2;
|
541
|
+
int j1, j2, bIn3MembRing = 0;
|
542
|
+
for ( j1 = 0; j1 < valence && !bIn3MembRing; j1 ++ ) {
|
543
|
+
neigh1 = at[cur_atom].neighbor[j1];
|
544
|
+
for ( j2 = j1+1; j2 < valence && !bIn3MembRing; j2 ++ ) {
|
545
|
+
neigh2 = at[cur_atom].neighbor[j2];
|
546
|
+
if ( e_is_in_the_slist( at[neigh1].neighbor, neigh2, at[neigh1].num_bonds ) ) {
|
547
|
+
bIn3MembRing ++;
|
548
|
+
}
|
549
|
+
}
|
550
|
+
}
|
551
|
+
return bIn3MembRing? AtType_N3r : AtType_Nns /* -1*/;
|
552
|
+
}
|
553
|
+
case ElType_P:
|
554
|
+
case ElType_As:
|
555
|
+
return -1;
|
556
|
+
}
|
557
|
+
} else
|
558
|
+
if ( bond_valence == valence+1 && valence==2 && nCharge == 0 && !nRadical ) {
|
559
|
+
switch( nElType ) {
|
560
|
+
case ElType_N:
|
561
|
+
return AtType_N3;
|
562
|
+
case ElType_P:
|
563
|
+
case ElType_As:
|
564
|
+
return -1;
|
565
|
+
}
|
566
|
+
} else
|
567
|
+
if ( bond_valence == valence+1 && valence==3 && nCharge == 0 && !nRadical ) {
|
568
|
+
/* reproduce 1.12Beta bug: =N< is accepted in stereogenic bonds */
|
569
|
+
switch( nElType ) {
|
570
|
+
case ElType_N:
|
571
|
+
return AtType_N3;
|
572
|
+
case ElType_P:
|
573
|
+
case ElType_As:
|
574
|
+
return -1;
|
575
|
+
}
|
576
|
+
} else
|
577
|
+
if ( bond_valence == valence && valence==2 && nCharge == 0 && nRadical == INCHI_RADICAL_DOUBLET ) {
|
578
|
+
switch( nElType ) {
|
579
|
+
case ElType_N:
|
580
|
+
return AtType_N3;
|
581
|
+
case ElType_P:
|
582
|
+
case ElType_As:
|
583
|
+
return -1;
|
584
|
+
}
|
585
|
+
} else
|
586
|
+
if ( bond_valence == valence+1 && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nCharge == 1 ) {
|
587
|
+
switch( nElType ) {
|
588
|
+
case ElType_N:
|
589
|
+
return AtType_N3p;
|
590
|
+
case ElType_P:
|
591
|
+
case ElType_As:
|
592
|
+
return -1;
|
593
|
+
}
|
594
|
+
} else
|
595
|
+
if ( bond_valence == valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nCharge == 1 && nRadical == INCHI_RADICAL_DOUBLET ) {
|
596
|
+
switch( nElType ) {
|
597
|
+
case ElType_N:
|
598
|
+
return AtType_N3p;
|
599
|
+
case ElType_P:
|
600
|
+
case ElType_As:
|
601
|
+
return -1;
|
602
|
+
}
|
603
|
+
} else
|
604
|
+
if ( bond_valence == valence && valence == 2 && (bAddH || num_H==1) && nCharge == 0 ||
|
605
|
+
bond_valence == valence && valence == 2 && nCharge == -1 ) {
|
606
|
+
switch( nElType ) {
|
607
|
+
case ElType_N:
|
608
|
+
return AtType_Nns;
|
609
|
+
case ElType_P:
|
610
|
+
case ElType_As:
|
611
|
+
return -1;
|
612
|
+
}
|
613
|
+
} else
|
614
|
+
if ( (bond_valence == valence+2 || bond_valence + nRadicalValence == valence+2) && valence==3 ) {
|
615
|
+
switch( nElType ) {
|
616
|
+
case ElType_N:
|
617
|
+
return AtType_Nns; /* -N<< may be in a stereogenic bond in case of double bond metal disconnection */
|
618
|
+
case ElType_P:
|
619
|
+
case ElType_As:
|
620
|
+
return -1;
|
621
|
+
}
|
622
|
+
}
|
623
|
+
return -1;
|
624
|
+
|
625
|
+
case ElType_H:
|
626
|
+
if ( valence == 1 )
|
627
|
+
return AtType_TermH;
|
628
|
+
break;
|
629
|
+
case ElType_D:
|
630
|
+
if ( valence == 1 )
|
631
|
+
return AtType_TermD;
|
632
|
+
break;
|
633
|
+
case ElType_T:
|
634
|
+
if ( valence == 1 )
|
635
|
+
return AtType_TermT;
|
636
|
+
break;
|
637
|
+
|
638
|
+
}
|
639
|
+
|
640
|
+
return -1;
|
641
|
+
}
|
642
|
+
|
643
|
+
|
644
|
+
/**********************************************************************************/
|
645
|
+
void e_swap ( char *a, char *b, size_t width )
|
646
|
+
{
|
647
|
+
char tmp;
|
648
|
+
if ( a != b )
|
649
|
+
while ( width-- ) {
|
650
|
+
tmp = *a;
|
651
|
+
*a++ = *b;
|
652
|
+
*b++ = tmp;
|
653
|
+
}
|
654
|
+
}
|
655
|
+
/**********************************************************************************/
|
656
|
+
/* Sort by insertions */
|
657
|
+
int e_insertions_sort( void *base, size_t num, size_t width, int ( *compare )(const void *e1, const void *e2 ) )
|
658
|
+
{
|
659
|
+
char *i, *j, *pk;
|
660
|
+
int num_trans = 0;
|
661
|
+
size_t k;
|
662
|
+
for( k=1, pk = (char*)base; k < num; k++, pk += width ) {
|
663
|
+
for( i = pk, j = pk + width; j > (char*)base && (*compare)(i,j) > 0; j=i, i -= width ) {
|
664
|
+
e_swap( i, j, width );
|
665
|
+
num_trans ++;
|
666
|
+
}
|
667
|
+
}
|
668
|
+
return num_trans;
|
669
|
+
}
|
670
|
+
|
671
|
+
|
672
|
+
#define ZTYPE_DOWN (-1) /* should be equal to -ZTYPE_UP */
|
673
|
+
#define ZTYPE_NONE 0
|
674
|
+
#define ZTYPE_UP 1 /* should be equal to -ZTYPE_DOWN */
|
675
|
+
#define ZTYPE_3D 3
|
676
|
+
#define ZTYPE_EITHER 9999
|
677
|
+
|
678
|
+
/* criteria for ill-defined */
|
679
|
+
#define MIN_ANGLE 0.10 /* 5.73 degrees */
|
680
|
+
#define MIN_SINE 0.03 /* min edge/plane angle in case the tetrahedra has significantly different edge length */
|
681
|
+
#define MIN_ANGLE_DBOND 0.087156 /* 5 degrees = max angle considered as too small for unambiguous double bond stereo */
|
682
|
+
#define MIN_SINE_OUTSIDE 0.06 /* min edge/plane angle to determine whether the central atom is outside of the tetrahedra */
|
683
|
+
#define MIN_SINE_SQUARE 0.125 /* min edge/plane angle in case the tetrahedra is somewhat close to a parallelogram */
|
684
|
+
#define MIN_SINE_EDGE 0.167 /* min sine/(min.edge) ratio to avoid undefined in case of long edges */
|
685
|
+
#define MIN_LEN_STRAIGHT 1.900 /* min length of two normalized to 1 bonds in a straight line */
|
686
|
+
#define MAX_SINE 0.70710678118654752440084436210485 /* 1/sqrt(2)=sin(pi/4) */
|
687
|
+
#define MIN_BOND_LEN 0.000001
|
688
|
+
#define ZERO_LENGTH MIN_BOND_LEN
|
689
|
+
#define ZERO_FLOAT 1.0e-12
|
690
|
+
#define BOND_PARITY_UNDEFINED 64
|
691
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
692
|
+
#define MPY_SINE 1.00 /* was 3.0 */
|
693
|
+
#define MAX_EDGE_RATIO 2.50 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
|
694
|
+
#else
|
695
|
+
#define MPY_SINE 3.00
|
696
|
+
#define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
|
697
|
+
#endif
|
698
|
+
/* local prototypes */
|
699
|
+
static double e_get_z_coord( inchi_Atom* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
|
700
|
+
static double e_len3( const double c[] );
|
701
|
+
static double e_len2( const double c[] );
|
702
|
+
static double* e_diff3( const double a[], const double b[], double result[] );
|
703
|
+
static double* e_add3( const double a[], const double b[], double result[] );
|
704
|
+
static double* e_mult3( const double a[], double b, double result[] );
|
705
|
+
static double* e_copy3( const double a[], double result[] );
|
706
|
+
static double* e_change_sign3( const double a[], double result[] );
|
707
|
+
static double e_dot_prod3( const double a[], const double b[] );
|
708
|
+
static int e_dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
|
709
|
+
static double* e_cross_prod3( const double a[], const double b[], double result[] );
|
710
|
+
static double e_triple_prod( double a[], double b[], double c[], double *sine_value );
|
711
|
+
static double e_triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
|
712
|
+
static int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
|
713
|
+
static int e_triple_prod_char( inchi_Atom *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
|
714
|
+
int at_2, int i_next_at_2, S_CHAR *z_dir2 );
|
715
|
+
|
716
|
+
static int e_CompDble( const void *a1, const void *a2 );
|
717
|
+
static int e_Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor );
|
718
|
+
static double e_triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
|
719
|
+
static int e_are_4at_in_one_plane( double at_coord[][3], double min_sine);
|
720
|
+
static int e_half_stereo_bond_parity( inchi_Atom *at, int cur_at, S_CHAR *z_dir, int *bOnlyNonMetal, int bPointedEdgeStereo, Stereo0D *pStereo );
|
721
|
+
static int e_set_stereo_bonds_parity( Stereo0D *pStereo, inchi_Atom *at, int at_1, int bPointedEdgeStereo );
|
722
|
+
static int e_set_stereo_atom_parity( Stereo0D *pStereo, inchi_Atom *at, int cur_at, int bPointedEdgeStereo );
|
723
|
+
static int e_FixSb0DParities( inchi_Atom *at, Stereo0D *pStereo, int chain_length, AT_NUM at_middle,
|
724
|
+
int at_1, int i_next_at_1, S_CHAR z_dir1[], S_CHAR z_dir1NM[], int bOnlyNM1, int bAnomaly1NM, int parity1, int parity1NM,
|
725
|
+
int at_2, int i_next_at_2, S_CHAR z_dir2[], S_CHAR z_dir2NM[], int bOnlyNM2, int bAnomaly2NM, int parity2, int parity2NM );
|
726
|
+
|
727
|
+
|
728
|
+
/******************************************************************/
|
729
|
+
|
730
|
+
|
731
|
+
static double *pDoubleForSort;
|
732
|
+
|
733
|
+
/**********************************************************************************/
|
734
|
+
double e_get_z_coord( inchi_Atom* at, int cur_atom, int neigh_no, int *nType, int bPointedEdgeStereo )
|
735
|
+
{
|
736
|
+
int stereo_value = at[cur_atom].bond_stereo[neigh_no];
|
737
|
+
int stereo_type = abs( stereo_value );
|
738
|
+
int neigh = (int)at[cur_atom].neighbor[neigh_no];
|
739
|
+
double z = at[neigh].z - at[cur_atom].z;
|
740
|
+
int bFlat;
|
741
|
+
|
742
|
+
if ( bFlat = (fabs(z) < ZERO_LENGTH) ) {
|
743
|
+
int i;
|
744
|
+
for ( i = 0; i < at[cur_atom].num_bonds; i ++ ) {
|
745
|
+
if ( fabs(at[cur_atom].z - at[(int)at[cur_atom].neighbor[i]].z) > ZERO_LENGTH ) {
|
746
|
+
bFlat = 0;
|
747
|
+
break;
|
748
|
+
}
|
749
|
+
}
|
750
|
+
}
|
751
|
+
|
752
|
+
if ( bFlat ) {
|
753
|
+
if ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) {
|
754
|
+
/* bPointedEdgeStereo > 0: define stereo from pointed end of the stereo bond only */
|
755
|
+
/* bPointedEdgeStereo < 0: define stereo from wide end of the stereo bond only (case of removed H) */
|
756
|
+
switch( stereo_type ) {
|
757
|
+
/* 1=Up (solid triangle), 6=Down (Dashed triangle), 4=Either (zigzag triangle) */
|
758
|
+
case 0: /* No stereo */
|
759
|
+
*nType = ZTYPE_NONE;
|
760
|
+
break;
|
761
|
+
case INCHI_BOND_STEREO_SINGLE_1UP: /* 1= Up */
|
762
|
+
*nType = ZTYPE_UP;
|
763
|
+
break;
|
764
|
+
case INCHI_BOND_STEREO_SINGLE_1EITHER: /* 4 = Either */
|
765
|
+
*nType = ZTYPE_EITHER;
|
766
|
+
break;
|
767
|
+
case INCHI_BOND_STEREO_SINGLE_1DOWN: /* 6 = Down */
|
768
|
+
*nType = ZTYPE_DOWN;
|
769
|
+
break;
|
770
|
+
default:
|
771
|
+
*nType = ZTYPE_NONE; /* ignore unexpected values */
|
772
|
+
}
|
773
|
+
if ( stereo_value < 0 && (*nType == ZTYPE_DOWN || *nType == ZTYPE_UP) )
|
774
|
+
*nType = -*nType;
|
775
|
+
} else {
|
776
|
+
*nType = ZTYPE_NONE; /* no stereo */
|
777
|
+
}
|
778
|
+
} else
|
779
|
+
if ( stereo_type == INCHI_BOND_STEREO_SINGLE_1EITHER &&
|
780
|
+
( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) ) {
|
781
|
+
*nType = ZTYPE_EITHER;
|
782
|
+
} else {
|
783
|
+
*nType = ZTYPE_3D;
|
784
|
+
}
|
785
|
+
return z;
|
786
|
+
}
|
787
|
+
/******************************************************************/
|
788
|
+
double e_len3( const double c[] )
|
789
|
+
{
|
790
|
+
return sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] );
|
791
|
+
}
|
792
|
+
/******************************************************************/
|
793
|
+
double e_len2( const double c[] )
|
794
|
+
{
|
795
|
+
return sqrt( c[0]*c[0] + c[1]*c[1] );
|
796
|
+
}
|
797
|
+
/******************************************************************/
|
798
|
+
double* e_diff3( const double a[], const double b[], double result[] )
|
799
|
+
{
|
800
|
+
|
801
|
+
result[0] = a[0] - b[0];
|
802
|
+
result[1] = a[1] - b[1];
|
803
|
+
result[2] = a[2] - b[2];
|
804
|
+
|
805
|
+
return result;
|
806
|
+
}
|
807
|
+
/******************************************************************/
|
808
|
+
double* e_add3( const double a[], const double b[], double result[] )
|
809
|
+
{
|
810
|
+
result[0] = a[0] + b[0];
|
811
|
+
result[1] = a[1] + b[1];
|
812
|
+
result[2] = a[2] + b[2];
|
813
|
+
|
814
|
+
return result;
|
815
|
+
}
|
816
|
+
/******************************************************************/
|
817
|
+
double* e_mult3( const double a[], double b, double result[] )
|
818
|
+
{
|
819
|
+
result[0] = a[0] * b;
|
820
|
+
result[1] = a[1] * b;
|
821
|
+
result[2] = a[2] * b;
|
822
|
+
|
823
|
+
return result;
|
824
|
+
}
|
825
|
+
/*************************************************************/
|
826
|
+
double* e_copy3( const double a[], double result[] )
|
827
|
+
{
|
828
|
+
result[0] = a[0];
|
829
|
+
result[1] = a[1];
|
830
|
+
result[2] = a[2];
|
831
|
+
|
832
|
+
return result;
|
833
|
+
}
|
834
|
+
/*************************************************************/
|
835
|
+
double* e_change_sign3( const double a[], double result[] )
|
836
|
+
{
|
837
|
+
result[0] = -a[0];
|
838
|
+
result[1] = -a[1];
|
839
|
+
result[2] = -a[2];
|
840
|
+
|
841
|
+
return result;
|
842
|
+
}
|
843
|
+
/*************************************************************/
|
844
|
+
double e_dot_prod3( const double a[], const double b[] )
|
845
|
+
{
|
846
|
+
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
|
847
|
+
}
|
848
|
+
/*************************************************************/
|
849
|
+
int e_dot_prodchar3( const S_CHAR a[], const S_CHAR b[] )
|
850
|
+
{
|
851
|
+
int prod = ((int)a[0]*(int)b[0] + (int)a[1]*(int)b[1] + (int)a[2]*(int)b[2])/100;
|
852
|
+
if ( prod > 100 )
|
853
|
+
prod = 100;
|
854
|
+
else
|
855
|
+
if ( prod < -100 )
|
856
|
+
prod = -100;
|
857
|
+
return prod;
|
858
|
+
}
|
859
|
+
/*************************************************************/
|
860
|
+
double* e_cross_prod3( const double a[], const double b[], double result[] )
|
861
|
+
{
|
862
|
+
double tmp[3];
|
863
|
+
|
864
|
+
tmp[0] = (a[1]*b[2]-a[2]*b[1]);
|
865
|
+
tmp[1] = -(a[0]*b[2]-a[2]*b[0]);
|
866
|
+
tmp[2] = (a[0]*b[1]-a[1]*b[0]);
|
867
|
+
|
868
|
+
result[0] = tmp[0];
|
869
|
+
result[1] = tmp[1];
|
870
|
+
result[2] = tmp[2];
|
871
|
+
|
872
|
+
return result;
|
873
|
+
}
|
874
|
+
/*************************************************************/
|
875
|
+
double e_triple_prod( double a[], double b[], double c[], double *sine_value )
|
876
|
+
{
|
877
|
+
double ab[3], dot_prod_ab_c, abs_c, abs_ab;
|
878
|
+
e_cross_prod3( a, b, ab );
|
879
|
+
/* ab[0] = (a[1]*b[2]-a[2]*b[1]); */
|
880
|
+
/* ab[1] = -(a[0]*b[2]-a[2]*b[0]); */
|
881
|
+
/* ab[2] = (a[0]*b[1]-a[1]*b[0]); */
|
882
|
+
dot_prod_ab_c = e_dot_prod3( ab, c );
|
883
|
+
/* dot_prod_ab_c = ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2]; */
|
884
|
+
if ( sine_value ) {
|
885
|
+
abs_c = e_len3( c );
|
886
|
+
/* abs_c = sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ); */
|
887
|
+
abs_ab = e_len3( ab );
|
888
|
+
/* abs_ab = sqrt( ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2] ); */
|
889
|
+
|
890
|
+
if ( abs_c > 1.e-7 /* otherwise c has zero length */ && abs_ab > 1.e-7 /* otherwise a is parallel to b*/ ) {
|
891
|
+
*sine_value = MPY_SINE * dot_prod_ab_c / ( abs_c * abs_ab);
|
892
|
+
/* *sine_value = dot_prod_ab_c / ( abs_c * abs_ab); */
|
893
|
+
} else {
|
894
|
+
*sine_value = 0.0;
|
895
|
+
}
|
896
|
+
}
|
897
|
+
return dot_prod_ab_c;
|
898
|
+
}
|
899
|
+
/*************************************************************/
|
900
|
+
int e_CompDble( const void *a1, const void *a2 )
|
901
|
+
{
|
902
|
+
double diff = pDoubleForSort[*(const int*)a1] - pDoubleForSort[*(const int*)a2];
|
903
|
+
if ( diff > 0.0 )
|
904
|
+
return 1;
|
905
|
+
if ( diff < 0.0 )
|
906
|
+
return -1;
|
907
|
+
return 0;
|
908
|
+
}
|
909
|
+
/*************************************************************/
|
910
|
+
#define T2D_OKAY 1
|
911
|
+
#define T2D_WARN 2
|
912
|
+
#define T2D_UNDF 4
|
913
|
+
int e_Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
|
914
|
+
{
|
915
|
+
const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
|
916
|
+
const double two_pi = 2.0*one_pi;
|
917
|
+
const double dAngleAndPiMaxDiff = 2.0*atan2(1.0, sqrt(7.0)); /* min sine between 2 InPlane bonds */
|
918
|
+
int nBondType[MAX_NUM_STEREO_ATOM_NEIGH], nBondOrder[MAX_NUM_STEREO_ATOM_NEIGH];
|
919
|
+
double dBondDirection[MAX_NUM_STEREO_ATOM_NEIGH], dAngle, dAlpha, dLimit, dBisector;
|
920
|
+
int nNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH - (bAddExplicitNeighbor != 0);
|
921
|
+
int i, num_Up, num_Dn, bPrev_Up, cur_len_Up, cur_first_Up, len_Up, first_Up;
|
922
|
+
int ret;
|
923
|
+
|
924
|
+
ret = 0;
|
925
|
+
for ( i = 0, num_Up = num_Dn = 0; i < nNumNeigh; i ++ ) {
|
926
|
+
dAngle = atan2( at_coord[i][1], at_coord[i][0] ); /* range from -pi to +pi */
|
927
|
+
if ( dAngle < 0.0 ) {
|
928
|
+
dAngle += two_pi;
|
929
|
+
}
|
930
|
+
dBondDirection[i] = dAngle;
|
931
|
+
nBondType[i] = (at_coord[i][2] > 0.0)? 1 : (at_coord[i][2] < 0.0)? -1 : 0; /* z-coord sign */
|
932
|
+
if ( nBondType[i] > 0 ) {
|
933
|
+
num_Up ++;
|
934
|
+
} else
|
935
|
+
if ( nBondType[i] < 0 ) {
|
936
|
+
num_Dn ++;
|
937
|
+
}
|
938
|
+
nBondOrder[i] = i;
|
939
|
+
}
|
940
|
+
if ( num_Up < num_Dn ) {
|
941
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
942
|
+
nBondType[i] = -nBondType[i];
|
943
|
+
}
|
944
|
+
e_swap( (char*)&num_Dn, (char*)&num_Up, sizeof(num_Dn) );
|
945
|
+
}
|
946
|
+
if ( !num_Up ) {
|
947
|
+
return T2D_UNDF;
|
948
|
+
}
|
949
|
+
/* sort according to the bond orientations */
|
950
|
+
pDoubleForSort = dBondDirection;
|
951
|
+
e_insertions_sort( nBondOrder, nNumNeigh, sizeof(nBondOrder[0]), e_CompDble );
|
952
|
+
|
953
|
+
/* find the longest contiguous sequence of Up bonds */
|
954
|
+
if ( num_Up == nNumNeigh ) {
|
955
|
+
/* all bonds are Up */
|
956
|
+
len_Up = cur_len_Up = nNumNeigh; /* added cur_len_Up initialization 1/8/2002 */
|
957
|
+
first_Up = 0;
|
958
|
+
} else {
|
959
|
+
/* at least one bond is not Up */
|
960
|
+
cur_len_Up = len_Up = bPrev_Up = 0;
|
961
|
+
/* prev. cycle header version ---
|
962
|
+
for ( i = 0; 1; i ++ ) {
|
963
|
+
if ( i >= nNumNeigh && !bPrev_Up ) {
|
964
|
+
break;
|
965
|
+
}
|
966
|
+
----------} */
|
967
|
+
/* look at all bonds and continue (circle therough the beginning) as long as the current bond is Up */
|
968
|
+
for ( i = 0; i < nNumNeigh || bPrev_Up; i ++ ) {
|
969
|
+
if ( nBondType[nBondOrder[i % nNumNeigh]] > 0 ) {
|
970
|
+
if ( bPrev_Up ) {
|
971
|
+
cur_len_Up ++; /* uncrement number of Up bonds in current contiguous sequence of them */
|
972
|
+
} else {
|
973
|
+
bPrev_Up = 1; /* start new contiguous sequence of Up bonds */
|
974
|
+
cur_len_Up = 1;
|
975
|
+
cur_first_Up = i % nNumNeigh;
|
976
|
+
}
|
977
|
+
} else
|
978
|
+
if ( bPrev_Up ) { /* end of contiguous sequence of Up bonds */
|
979
|
+
if ( cur_len_Up > len_Up ) {
|
980
|
+
first_Up = cur_first_Up; /* store the sequence because it is longer than the ptrvious one */
|
981
|
+
len_Up = cur_len_Up;
|
982
|
+
}
|
983
|
+
bPrev_Up = 0;
|
984
|
+
}
|
985
|
+
}
|
986
|
+
}
|
987
|
+
/* Turn all the bonds around the center so that */
|
988
|
+
/* the 1st Up bond has zero radian direction */
|
989
|
+
dAlpha = dBondDirection[nBondOrder[first_Up]];
|
990
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
991
|
+
if ( i == nBondOrder[first_Up] ) {
|
992
|
+
dBondDirection[i] = 0.0;
|
993
|
+
} else {
|
994
|
+
dAngle = dBondDirection[i] - dAlpha;
|
995
|
+
if ( dAngle < 0.0 ) {
|
996
|
+
dAngle += two_pi;
|
997
|
+
}
|
998
|
+
dBondDirection[i] = dAngle;
|
999
|
+
}
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
/********************************************************
|
1003
|
+
* Process particular cases
|
1004
|
+
********************************************************/
|
1005
|
+
|
1006
|
+
switch( nNumNeigh ) {
|
1007
|
+
|
1008
|
+
/************************ 3 bonds ***********************
|
1009
|
+
*/
|
1010
|
+
case 3:
|
1011
|
+
switch( num_Up ) {
|
1012
|
+
/* -------------------------- 0 Up ------------ */
|
1013
|
+
case 0:
|
1014
|
+
return T2D_UNDF;
|
1015
|
+
/* -------------------------- 1 Up ------------ */
|
1016
|
+
case 1:
|
1017
|
+
if ( num_Dn ) {
|
1018
|
+
#ifdef _DEBUG
|
1019
|
+
if ( num_Dn != 1 ) /* debug only */
|
1020
|
+
return -1;
|
1021
|
+
#endif
|
1022
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1023
|
+
} else {
|
1024
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
|
1025
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
1026
|
+
if ( dAngle < 0.0 ) {
|
1027
|
+
dAngle += two_pi;
|
1028
|
+
}
|
1029
|
+
if ( dAngle - one_pi < -MIN_ANGLE || dAngle - one_pi > MIN_ANGLE ) {
|
1030
|
+
ret = T2D_OKAY;
|
1031
|
+
} else {
|
1032
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1033
|
+
}
|
1034
|
+
}
|
1035
|
+
break;
|
1036
|
+
/* -------------------------- 2 Up ------------ */
|
1037
|
+
case 2:
|
1038
|
+
if ( num_Dn ) {
|
1039
|
+
dAlpha = dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]] -
|
1040
|
+
dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]];
|
1041
|
+
if ( dAlpha < 0.0 ) {
|
1042
|
+
dAlpha += two_pi;
|
1043
|
+
}
|
1044
|
+
if ( dAlpha > one_pi - MIN_ANGLE ) {
|
1045
|
+
ret = T2D_OKAY;
|
1046
|
+
} else
|
1047
|
+
if ( dAlpha < two_pi / 3.0 - MIN_ANGLE ) {
|
1048
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1049
|
+
} else {
|
1050
|
+
/* angle between 2 Up bonds is between 120 and 180 degrees */
|
1051
|
+
/* direction of the (Alpha angle bisector) + 180 degrees */
|
1052
|
+
dBisector = (dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]] +
|
1053
|
+
dBondDirection[nBondOrder[(first_Up + 1 ) % nNumNeigh]] ) / 2.0 - one_pi;
|
1054
|
+
if ( dBisector < 0.0 ) {
|
1055
|
+
dBisector += two_pi;
|
1056
|
+
}
|
1057
|
+
if ( dAlpha < two_pi / 3.0 + MIN_ANGLE ) {
|
1058
|
+
/* dAlpha is inside ( 2pi/3 - eps, 2pi/3 + eps ) interval */
|
1059
|
+
dLimit = MIN_ANGLE * 3.0 / 2.0;
|
1060
|
+
} else {
|
1061
|
+
dLimit = dAlpha * 3.0 / 2.0 - one_pi;
|
1062
|
+
}
|
1063
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2 ) % nNumNeigh]];
|
1064
|
+
if ( dBisector - dAngle < -dLimit ||
|
1065
|
+
dBisector - dAngle > dLimit ) {
|
1066
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1067
|
+
} else {
|
1068
|
+
ret = T2D_OKAY;
|
1069
|
+
}
|
1070
|
+
}
|
1071
|
+
} else {
|
1072
|
+
ret = T2D_OKAY;
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
break;
|
1076
|
+
/* -------------------------- 3 Up ------------ */
|
1077
|
+
case 3:
|
1078
|
+
ret = T2D_OKAY;
|
1079
|
+
break;
|
1080
|
+
/* -------------------------- other Up -------- */
|
1081
|
+
default:
|
1082
|
+
return -1;
|
1083
|
+
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
break;
|
1087
|
+
|
1088
|
+
/************************************** 4 bonds **************************
|
1089
|
+
*/
|
1090
|
+
case 4:
|
1091
|
+
switch( num_Up ) {
|
1092
|
+
/* -------------------------- 0 Up ------------ */
|
1093
|
+
case 0:
|
1094
|
+
return T2D_UNDF;
|
1095
|
+
/* -------------------------- 1 Up ------------ */
|
1096
|
+
case 1:
|
1097
|
+
if ( num_Dn ) {
|
1098
|
+
if ( nBondType[nBondOrder[(first_Up + 2) % nNumNeigh]] < 0 ) {
|
1099
|
+
/*
|
1100
|
+
* Up, In Plane, Dn, In Plane. Undefined if angle between
|
1101
|
+
* two In Plane bonds is wuthin pi +/- 2*arcsine(1/sqrt(8)) interval
|
1102
|
+
* That is, 138.5 to 221.4 degrees; for certainty the interval is
|
1103
|
+
* increased by 5.7 degrees at each end to
|
1104
|
+
* 134.8 to 227.1 degrees
|
1105
|
+
*/
|
1106
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
|
1107
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
1108
|
+
if ( dAngle < 0.0 ) {
|
1109
|
+
dAngle += two_pi;
|
1110
|
+
}
|
1111
|
+
if ( fabs( dAngle - one_pi ) < dAngleAndPiMaxDiff + MIN_ANGLE ) {
|
1112
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1113
|
+
} else {
|
1114
|
+
ret = T2D_OKAY;
|
1115
|
+
}
|
1116
|
+
} else {
|
1117
|
+
ret = T2D_OKAY;
|
1118
|
+
}
|
1119
|
+
#ifdef _DEBUG
|
1120
|
+
if ( num_Dn != 1 ) /* debug only */
|
1121
|
+
return -1;
|
1122
|
+
#endif
|
1123
|
+
} else {
|
1124
|
+
ret = T2D_OKAY;
|
1125
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
|
1126
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
1127
|
+
if ( dAngle < 0.0 ) {
|
1128
|
+
dAngle += two_pi;
|
1129
|
+
}
|
1130
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
1131
|
+
ret |= T2D_WARN;
|
1132
|
+
}
|
1133
|
+
}
|
1134
|
+
break;
|
1135
|
+
/* -------------------------- 2 Up ------------ */
|
1136
|
+
case 2:
|
1137
|
+
if ( cur_len_Up == 1 ) {
|
1138
|
+
ret = T2D_OKAY;
|
1139
|
+
} else {
|
1140
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1141
|
+
}
|
1142
|
+
break;
|
1143
|
+
/* -------------------------- 3 Up ------------ */
|
1144
|
+
case 3:
|
1145
|
+
ret = T2D_OKAY;
|
1146
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
|
1147
|
+
dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
|
1148
|
+
if ( dAngle < 0.0 ) {
|
1149
|
+
dAngle += two_pi;
|
1150
|
+
}
|
1151
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
1152
|
+
ret |= T2D_WARN;
|
1153
|
+
}
|
1154
|
+
break;
|
1155
|
+
/* -------------------------- 4 Up ------------ */
|
1156
|
+
case 4:
|
1157
|
+
ret = (T2D_UNDF | T2D_WARN);
|
1158
|
+
break;
|
1159
|
+
/* -------------------------- other Up -------- */
|
1160
|
+
default:
|
1161
|
+
return -1; /* program error */
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
if ( ret == T2D_OKAY ) {
|
1165
|
+
/* check whether all bonds are inside a less than 180 degrees sector */
|
1166
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
1167
|
+
dAngle = dBondDirection[nBondOrder[(i + nNumNeigh - 1) % nNumNeigh]] -
|
1168
|
+
dBondDirection[nBondOrder[ i % nNumNeigh]];
|
1169
|
+
if ( dAngle < 0.0 ) {
|
1170
|
+
dAngle += two_pi;
|
1171
|
+
}
|
1172
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
1173
|
+
ret |= T2D_WARN;
|
1174
|
+
break;
|
1175
|
+
}
|
1176
|
+
}
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
break;
|
1180
|
+
/*************************** other nuber of bonds ******************/
|
1181
|
+
default:
|
1182
|
+
return -1; /* error */
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
return ret;
|
1186
|
+
|
1187
|
+
}
|
1188
|
+
/*************************************************************/
|
1189
|
+
double e_triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous)
|
1190
|
+
{
|
1191
|
+
double min_sine_value=9999.0, sine_value, min_edge_len, max_edge_len, min_edge_len_NoExplNeigh, max_edge_len_NoExplNeigh;
|
1192
|
+
double s0, s1, s2, s3, e01, e02, e03, e12, e13, e23, tmp[3], e[3][3];
|
1193
|
+
double prod, ret, central_prod[4];
|
1194
|
+
int bLongEdges;
|
1195
|
+
|
1196
|
+
if ( !min_sine ) {
|
1197
|
+
return e_triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
|
1198
|
+
}
|
1199
|
+
|
1200
|
+
ret = e_triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
|
1201
|
+
sine_value = MPY_SINE * fabs( sine_value );
|
1202
|
+
|
1203
|
+
e_diff3( at_coord[1], at_coord[0], e[2] );
|
1204
|
+
e_diff3( at_coord[0], at_coord[2], e[1] );
|
1205
|
+
e_diff3( at_coord[2], at_coord[1], e[0] );
|
1206
|
+
|
1207
|
+
/* lengths of the 6 edges of the tetrahedra */
|
1208
|
+
e03 = e_len3( at_coord[0] ); /* 1 */
|
1209
|
+
e13 = e_len3( at_coord[1] );
|
1210
|
+
e23 = e_len3( at_coord[2] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
1211
|
+
e02 = e_len3( e[1] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
1212
|
+
e12 = e_len3( e[0] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
1213
|
+
e01 = e_len3( e[2] );
|
1214
|
+
|
1215
|
+
/* min & max edge length */
|
1216
|
+
max_edge_len =
|
1217
|
+
min_edge_len = e03;
|
1218
|
+
|
1219
|
+
if ( min_edge_len > e13 )
|
1220
|
+
min_edge_len = e13;
|
1221
|
+
if ( min_edge_len > e01 )
|
1222
|
+
min_edge_len = e01;
|
1223
|
+
min_edge_len_NoExplNeigh = min_edge_len;
|
1224
|
+
|
1225
|
+
if ( min_edge_len > e23 )
|
1226
|
+
min_edge_len = e23;
|
1227
|
+
if ( min_edge_len > e02 )
|
1228
|
+
min_edge_len = e02;
|
1229
|
+
if ( min_edge_len > e12 )
|
1230
|
+
min_edge_len = e12;
|
1231
|
+
|
1232
|
+
if ( max_edge_len < e13 )
|
1233
|
+
max_edge_len = e13;
|
1234
|
+
if ( max_edge_len < e01 )
|
1235
|
+
max_edge_len = e01;
|
1236
|
+
max_edge_len_NoExplNeigh = max_edge_len;
|
1237
|
+
|
1238
|
+
if ( max_edge_len < e23 )
|
1239
|
+
max_edge_len = e23;
|
1240
|
+
if ( max_edge_len < e02 )
|
1241
|
+
max_edge_len = e02;
|
1242
|
+
if ( max_edge_len < e12 )
|
1243
|
+
max_edge_len = e12;
|
1244
|
+
|
1245
|
+
if ( !bAddedExplicitNeighbor ) {
|
1246
|
+
min_edge_len_NoExplNeigh = min_edge_len;
|
1247
|
+
max_edge_len_NoExplNeigh = max_edge_len;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
bLongEdges = bAddedExplicitNeighbor?
|
1251
|
+
( max_edge_len_NoExplNeigh < MAX_EDGE_RATIO * min_edge_len_NoExplNeigh ) :
|
1252
|
+
( max_edge_len < MAX_EDGE_RATIO * min_edge_len );
|
1253
|
+
|
1254
|
+
if ( sine_value > MIN_SINE && ( min_sine || bAmbiguous ) ) {
|
1255
|
+
if ( min_sine ) {
|
1256
|
+
prod = fabs( ret );
|
1257
|
+
/* tetrahedra height = volume(prod) / area of a plane(cross_prod) */
|
1258
|
+
/* (instead of a tetrahedra calculate parallelogram/parallelepiped area/volume) */
|
1259
|
+
|
1260
|
+
/* 4 heights from each of the 4 vertices to the opposite plane */
|
1261
|
+
s0 = prod / e_len3( e_cross_prod3( at_coord[1], at_coord[2], tmp ) );
|
1262
|
+
s1 = prod / e_len3( e_cross_prod3( at_coord[0], at_coord[2], tmp ) );
|
1263
|
+
s2 = prod / e_len3( e_cross_prod3( at_coord[0], at_coord[1], tmp ) );
|
1264
|
+
s3 = prod / e_len3( e_cross_prod3( e[0], e[1], tmp ) );
|
1265
|
+
/* abs. value of a sine of an angle between each tetrahedra edge and plane */
|
1266
|
+
/* sine = height / edge length */
|
1267
|
+
if ( (sine_value = s0/e01) < min_sine_value )
|
1268
|
+
min_sine_value = sine_value;
|
1269
|
+
if ( (sine_value = s0/e02) < min_sine_value )
|
1270
|
+
min_sine_value = sine_value;
|
1271
|
+
if ( (sine_value = s0/e03) < min_sine_value )
|
1272
|
+
min_sine_value = sine_value;
|
1273
|
+
|
1274
|
+
if ( (sine_value = s1/e01) < min_sine_value )
|
1275
|
+
min_sine_value = sine_value;
|
1276
|
+
if ( (sine_value = s1/e12) < min_sine_value )
|
1277
|
+
min_sine_value = sine_value;
|
1278
|
+
if ( (sine_value = s1/e13) < min_sine_value )
|
1279
|
+
min_sine_value = sine_value;
|
1280
|
+
|
1281
|
+
if ( (sine_value = s2/e02) < min_sine_value )
|
1282
|
+
min_sine_value = sine_value;
|
1283
|
+
if ( (sine_value = s2/e12) < min_sine_value )
|
1284
|
+
min_sine_value = sine_value;
|
1285
|
+
if ( (sine_value = s2/e23) < min_sine_value )
|
1286
|
+
min_sine_value = sine_value;
|
1287
|
+
|
1288
|
+
if ( (sine_value = s3/e03) < min_sine_value )
|
1289
|
+
min_sine_value = sine_value;
|
1290
|
+
if ( (sine_value = s3/e13) < min_sine_value )
|
1291
|
+
min_sine_value = sine_value;
|
1292
|
+
if ( (sine_value = s3/e23) < min_sine_value )
|
1293
|
+
min_sine_value = sine_value;
|
1294
|
+
/* actually use triple sine */
|
1295
|
+
*min_sine = sine_value = MPY_SINE * min_sine_value;
|
1296
|
+
}
|
1297
|
+
|
1298
|
+
if ( bAmbiguous && sine_value >= MIN_SINE ) {
|
1299
|
+
/* check whether the central atom is outside the tetrahedra (0,0,0), at_coord[0,1,2] */
|
1300
|
+
/* compare the tetrahedra volume and the volume of a tetrahedra having central_at_coord[] vertex */
|
1301
|
+
int i;
|
1302
|
+
e_diff3( central_at_coord, at_coord[0], tmp );
|
1303
|
+
central_prod[0] = e_triple_prod( at_coord[0], at_coord[1], central_at_coord, NULL );
|
1304
|
+
central_prod[1] = e_triple_prod( at_coord[1], at_coord[2], central_at_coord, NULL );
|
1305
|
+
central_prod[2] = e_triple_prod( at_coord[2], at_coord[0], central_at_coord, NULL );
|
1306
|
+
central_prod[3] = e_triple_prod( e[2], e[1], tmp, NULL );
|
1307
|
+
for ( i = 0; i <= 3; i ++ ) {
|
1308
|
+
if ( central_prod[i] / ret < -MIN_SINE_OUTSIDE ) {
|
1309
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
1310
|
+
break;
|
1311
|
+
}
|
1312
|
+
}
|
1313
|
+
}
|
1314
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
1315
|
+
|
1316
|
+
if ( bLongEdges && !bAddedExplicitNeighbor && max_edge_len >= MIN_LEN_STRAIGHT ) {
|
1317
|
+
/* possible planar tetragon */
|
1318
|
+
if ( sine_value < MIN_SINE_SQUARE ) {
|
1319
|
+
*min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
|
1320
|
+
if ( bAmbiguous && !*bAmbiguous ) {
|
1321
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
1322
|
+
}
|
1323
|
+
}
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
if ( bLongEdges && sine_value < MIN_SINE_SQUARE && sine_value < MIN_SINE_EDGE * min_edge_len_NoExplNeigh ) {
|
1327
|
+
*min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
|
1328
|
+
if ( bAmbiguous && !*bAmbiguous ) {
|
1329
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
1330
|
+
}
|
1331
|
+
}
|
1332
|
+
#endif
|
1333
|
+
|
1334
|
+
} else
|
1335
|
+
if ( min_sine ) {
|
1336
|
+
*min_sine = sine_value;
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
return ret;
|
1340
|
+
}
|
1341
|
+
/*************************************************************/
|
1342
|
+
double e_triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine)
|
1343
|
+
{
|
1344
|
+
double min_sine_value=9999.0, sine_value;
|
1345
|
+
double prod=0.0;
|
1346
|
+
|
1347
|
+
if ( !min_sine ) {
|
1348
|
+
return e_triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
|
1349
|
+
}
|
1350
|
+
|
1351
|
+
prod = e_triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
|
1352
|
+
sine_value = fabs( sine_value );
|
1353
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
1354
|
+
|
1355
|
+
prod = e_triple_prod( at_coord[1], at_coord[2], at_coord[0], &sine_value );
|
1356
|
+
sine_value = fabs( sine_value );
|
1357
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
1358
|
+
|
1359
|
+
prod = e_triple_prod( at_coord[2], at_coord[0], at_coord[1], &sine_value );
|
1360
|
+
sine_value = fabs( sine_value );
|
1361
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
1362
|
+
|
1363
|
+
*min_sine = min_sine_value;
|
1364
|
+
|
1365
|
+
return prod;
|
1366
|
+
}
|
1367
|
+
/*************************************************************/
|
1368
|
+
/* Find if point (0,0,0)a and 3 atoms are in one plane */
|
1369
|
+
int are_3_vect_in_one_plane( double at_coord[][3], double min_sine)
|
1370
|
+
{
|
1371
|
+
double actual_min_sine;
|
1372
|
+
double prod;
|
1373
|
+
prod = e_triple_prod_and_min_abs_sine( at_coord, &actual_min_sine);
|
1374
|
+
return actual_min_sine <= min_sine;
|
1375
|
+
}
|
1376
|
+
/*************************************************************/
|
1377
|
+
/* Find if 4 atoms are in one plane */
|
1378
|
+
int e_are_4at_in_one_plane( double at_coord[][3], double min_sine)
|
1379
|
+
{
|
1380
|
+
double actual_min_sine, min_actual_min_sine;
|
1381
|
+
double coord[3][3], prod;
|
1382
|
+
int i, k, j;
|
1383
|
+
for ( k = 0; k < 4; k ++ ) { /* cycle added 4004-08-15 */
|
1384
|
+
for ( i = j = 0; i < 4; i ++ ) {
|
1385
|
+
if ( i != k ) {
|
1386
|
+
e_diff3( at_coord[i], at_coord[k], coord[j] );
|
1387
|
+
j ++;
|
1388
|
+
}
|
1389
|
+
}
|
1390
|
+
prod = e_triple_prod_and_min_abs_sine( coord, &actual_min_sine);
|
1391
|
+
if ( !k || actual_min_sine < min_actual_min_sine ) {
|
1392
|
+
min_actual_min_sine = actual_min_sine;
|
1393
|
+
}
|
1394
|
+
}
|
1395
|
+
return min_actual_min_sine <= min_sine;
|
1396
|
+
}
|
1397
|
+
/*************************************************************/
|
1398
|
+
int e_triple_prod_char( inchi_Atom *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
|
1399
|
+
int at_2, int i_next_at_2, S_CHAR *z_dir2 )
|
1400
|
+
{
|
1401
|
+
inchi_Atom *at1, *at2;
|
1402
|
+
double pnt[3][3], len;
|
1403
|
+
int i;
|
1404
|
+
int ret = 0;
|
1405
|
+
|
1406
|
+
at1 = at + at_1;
|
1407
|
+
at2 = at + at[at_1].neighbor[i_next_at_1];
|
1408
|
+
|
1409
|
+
pnt[0][0] = at2->x - at1->x;
|
1410
|
+
pnt[0][1] = at2->y - at1->y;
|
1411
|
+
pnt[0][2] = at2->z - at1->z;
|
1412
|
+
|
1413
|
+
at2 = at + at_2;
|
1414
|
+
at1 = at + at[at_2].neighbor[i_next_at_2];
|
1415
|
+
|
1416
|
+
pnt[1][0] = at2->x - at1->x;
|
1417
|
+
pnt[1][1] = at2->y - at1->y;
|
1418
|
+
pnt[1][2] = at2->z - at1->z;
|
1419
|
+
/*
|
1420
|
+
* resultant pnt vector directions:
|
1421
|
+
*
|
1422
|
+
* pnt[0] pnt[1]
|
1423
|
+
*
|
1424
|
+
* [at_1]---->[...] [...]---->[at_2]
|
1425
|
+
*
|
1426
|
+
*
|
1427
|
+
* e_add3 below: (pnt[0] + pnt[1]) -> pnt[1]
|
1428
|
+
*/
|
1429
|
+
e_add3( pnt[0], pnt[1], pnt[1] );
|
1430
|
+
|
1431
|
+
|
1432
|
+
|
1433
|
+
for ( i = 0; i < 3; i ++ ) {
|
1434
|
+
pnt[0][i] = (double)z_dir1[i];
|
1435
|
+
pnt[2][i] = (double)z_dir2[i];
|
1436
|
+
}
|
1437
|
+
for ( i = 0; i < 3; i ++ ) {
|
1438
|
+
len = e_len3( pnt[i] );
|
1439
|
+
if ( len < MIN_BOND_LEN ) {
|
1440
|
+
goto exit_function; /* too short bond */
|
1441
|
+
}
|
1442
|
+
e_mult3( pnt[i], 1.0/len, pnt[i] );
|
1443
|
+
}
|
1444
|
+
len = 100.0*e_triple_prod(pnt[0], pnt[1], pnt[2], NULL );
|
1445
|
+
/*
|
1446
|
+
* ^ pnt[0]
|
1447
|
+
* | The orientation on this diagram
|
1448
|
+
* | produces len = -100
|
1449
|
+
* [at_1]------>[at_2]
|
1450
|
+
* pnt[1] /
|
1451
|
+
* /
|
1452
|
+
* / pnt[2] (up from the plane)
|
1453
|
+
* v
|
1454
|
+
*
|
1455
|
+
* Note: len is invariant upon at_1 <--> at_2 transposition because
|
1456
|
+
* triple product changes sign upon pnt[0]<-->pnt[2] transposition and
|
1457
|
+
* triple product changes sign upon pnt[1]--> -pnt[1] change of direction:
|
1458
|
+
*
|
1459
|
+
* e_triple_prod(pnt[0], pnt[1], pnt[2], NULL ) =
|
1460
|
+
* e_triple_prod(pnt[2], -pnt[1], pnt[0], NULL )
|
1461
|
+
*
|
1462
|
+
*/
|
1463
|
+
|
1464
|
+
ret = len >= 0.0? (int)floor(len+0.5) : -(int)floor(0.5-len);
|
1465
|
+
|
1466
|
+
exit_function:
|
1467
|
+
|
1468
|
+
return ret;
|
1469
|
+
}
|
1470
|
+
|
1471
|
+
#ifdef NEVER
|
1472
|
+
/********************************************************************************************/
|
1473
|
+
int bCanInpAtomBeAStereoCenter( inchi_Atom *at, int cur_at )
|
1474
|
+
{
|
1475
|
+
|
1476
|
+
/*************************************************************************************
|
1477
|
+
* current version
|
1478
|
+
*************************************************************************************
|
1479
|
+
* Use #define to split the stereocenter description table into parts
|
1480
|
+
* to make it easier to read
|
1481
|
+
*
|
1482
|
+
* --------- 4 single bonds stereocenters -------
|
1483
|
+
*
|
1484
|
+
* | | | | | |
|
1485
|
+
* -C- -Si- -Ge- -Sn- >As[+] >B[-]
|
1486
|
+
* | | | | | |
|
1487
|
+
*/
|
1488
|
+
#define SZELEM1 "C\000","Si", "Ge", "Sn", "As", "B\000",
|
1489
|
+
#define CCHARGE1 0, 0, 0, 0, 1, -1,
|
1490
|
+
#define CNUMBONDSANDH1 4, 4, 4, 4, 4, 4,
|
1491
|
+
#define CCHEMVALENCEH1 4, 4, 4, 4, 4, 4,
|
1492
|
+
#define CHAS3MEMBRING1 0, 0, 0, 0, 0, 0,
|
1493
|
+
#define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
|
1494
|
+
/*
|
1495
|
+
* --------------- S, Se stereocenters ----------
|
1496
|
+
*
|
1497
|
+
* | | || | | ||
|
1498
|
+
* -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
|
1499
|
+
* | | | | | | | |
|
1500
|
+
*/
|
1501
|
+
#define SZELEM2 "S\000","S\000","S\000","S\000","Se", "Se", "Se", "Se",
|
1502
|
+
#define CCHARGE2 0, 0, 1, 1, 0, 0, 1, 1,
|
1503
|
+
#define CNUMBONDSANDH2 3, 4, 3, 4, 3, 4, 3, 4,
|
1504
|
+
#define CCHEMVALENCEH2 4, 6, 3, 5, 4, 6, 3, 5,
|
1505
|
+
#define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
|
1506
|
+
#define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
|
1507
|
+
/*
|
1508
|
+
* ------------------ N, P stereocenters --------
|
1509
|
+
*
|
1510
|
+
* X---Y
|
1511
|
+
* | | \ / | |
|
1512
|
+
* =N- >N[+] N >P[+] =P-
|
1513
|
+
* | | | | |
|
1514
|
+
*/
|
1515
|
+
#define SZELEM3 "N\000","N\000","N\000","P\000","P\000",
|
1516
|
+
#define CCHARGE3 0, 1, 0, 1, 0,
|
1517
|
+
#define CNUMBONDSANDH3 4, 4, 3, 4, 4,
|
1518
|
+
#define CCHEMVALENCEH3 5, 4, 3, 4, 5,
|
1519
|
+
#define CHAS3MEMBRING3 0, 0, 1, 0, 0,
|
1520
|
+
#define CREQUIRDNEIGH3 3, 3, 1, 3, 3,
|
1521
|
+
|
1522
|
+
|
1523
|
+
|
1524
|
+
static char szElem[][3]={ SZELEM1 SZELEM2 SZELEM3 };
|
1525
|
+
static S_CHAR cCharge[]={ CCHARGE1 CCHARGE2 CCHARGE3 };
|
1526
|
+
static S_CHAR cNumBondsAndH[]={ CNUMBONDSANDH1 CNUMBONDSANDH2 CNUMBONDSANDH3 };
|
1527
|
+
static S_CHAR cChemValenceH[]={ CCHEMVALENCEH1 CCHEMVALENCEH2 CCHEMVALENCEH3 };
|
1528
|
+
static S_CHAR cHas3MembRing[]={ CHAS3MEMBRING1 CHAS3MEMBRING2 CHAS3MEMBRING3 };
|
1529
|
+
static S_CHAR cRequirdNeigh[]={ CREQUIRDNEIGH1 CREQUIRDNEIGH2 CREQUIRDNEIGH3 };
|
1530
|
+
|
1531
|
+
static int n = sizeof(szElem)/sizeof(szElem[0]);
|
1532
|
+
/* reqired neighbor types (bitmap):
|
1533
|
+
0 => check bonds only
|
1534
|
+
1 => no terminal hydrogen atom neighbors
|
1535
|
+
2 => no terminal -X and -XH together (don't care the bond type, charge, radical)
|
1536
|
+
(X = tautomeric endpoint atom)
|
1537
|
+
Note: whenever cChemValenceH[] > cNumBondsAndH[]
|
1538
|
+
the tautomeric and/or alternating bonds
|
1539
|
+
are permitted
|
1540
|
+
|
1541
|
+
*/
|
1542
|
+
int i, ret = 0;
|
1543
|
+
for ( i = 0; i < n; i++ ) {
|
1544
|
+
if ( !strcmp( at[cur_at].elname, szElem[i]) &&
|
1545
|
+
at[cur_at].charge == cCharge[i] &&
|
1546
|
+
(!at[cur_at].radical || at[cur_at].radical == 1) &&
|
1547
|
+
at[cur_at].num_bonds + inchi_NUMH(at,cur_at) == cNumBondsAndH[i] &&
|
1548
|
+
at[cur_at].chem_bonds_valence+inchi_NUMH(at,cur_at) == cChemValenceH[i] &&
|
1549
|
+
(cHas3MembRing[i]? is_atom_in_3memb_ring( at, cur_at ) : 1) &&
|
1550
|
+
e_bInpAtomHasRequirdNeigh ( at, cur_at, cRequirdNeigh[i], cChemValenceH[i]-cNumBondsAndH[i]) ) {
|
1551
|
+
ret = cNumBondsAndH[i];
|
1552
|
+
break;
|
1553
|
+
}
|
1554
|
+
}
|
1555
|
+
return ret;
|
1556
|
+
}
|
1557
|
+
|
1558
|
+
#endif /* NEVER */
|
1559
|
+
/********************************************************************************************/
|
1560
|
+
int e_bCanInpAtomBeAStereoCenter( int cur_at, S_CHAR *cAtType )
|
1561
|
+
{
|
1562
|
+
switch ( cAtType[cur_at] ) {
|
1563
|
+
case AtType_C4 :
|
1564
|
+
case AtType_Si4 :
|
1565
|
+
case AtType_Ge4 :
|
1566
|
+
case AtType_Sn4 :
|
1567
|
+
case AtType_B4m :
|
1568
|
+
case AtType_S6 :
|
1569
|
+
case AtType_S5p :
|
1570
|
+
case AtType_Se6 :
|
1571
|
+
case AtType_Se5p:
|
1572
|
+
case AtType_N5 :
|
1573
|
+
case AtType_N4p :
|
1574
|
+
case AtType_P4p :
|
1575
|
+
case AtType_P5 :
|
1576
|
+
case AtType_As4p:
|
1577
|
+
case AtType_As5 :
|
1578
|
+
return 4;
|
1579
|
+
|
1580
|
+
case AtType_S3p :
|
1581
|
+
case AtType_Se3p:
|
1582
|
+
case AtType_S4 :
|
1583
|
+
case AtType_Se4 :
|
1584
|
+
case AtType_N3r :
|
1585
|
+
return 3;
|
1586
|
+
}
|
1587
|
+
return 0;
|
1588
|
+
}
|
1589
|
+
/****************************************************************/
|
1590
|
+
/* used for atoms adjacent to stereogenic bonds only */
|
1591
|
+
int e_bCanAtomHaveAStereoBond( inchi_Atom *at, int cur_at, S_CHAR *cAtType )
|
1592
|
+
{
|
1593
|
+
int i, neigh, nNumFound;
|
1594
|
+
char *p;
|
1595
|
+
static char sNeigh[] = "O;S;Se;Te;";
|
1596
|
+
switch ( cAtType[cur_at] ) {
|
1597
|
+
case AtType_C3 :
|
1598
|
+
case AtType_Si3:
|
1599
|
+
case AtType_Ge3:
|
1600
|
+
case AtType_Sn3:
|
1601
|
+
case AtType_N3p:
|
1602
|
+
case AtType_N3 :
|
1603
|
+
return 3;
|
1604
|
+
case AtType_Nns:
|
1605
|
+
/*
|
1606
|
+
|
|
1607
|
+
found =N=
|
1608
|
+
|
1609
|
+
if it has one neighbor =O or =S or =Se or =Te then return 3, otherwise return 1
|
1610
|
+
|
1611
|
+
*/
|
1612
|
+
nNumFound = 0;
|
1613
|
+
for ( i = 0; i < at[cur_at].num_bonds; i ++ ) {
|
1614
|
+
if ( at[cur_at].bond_type[i] == INCHI_BOND_TYPE_DOUBLE ) {
|
1615
|
+
neigh = (int)at[cur_at].neighbor[i];
|
1616
|
+
if ( (p = strstr(sNeigh, at[neigh].elname)) &&
|
1617
|
+
';' == p[strlen(at[neigh].elname)] ) {
|
1618
|
+
nNumFound ++;
|
1619
|
+
}
|
1620
|
+
}
|
1621
|
+
}
|
1622
|
+
return nNumFound==1? 3 : 1;
|
1623
|
+
}
|
1624
|
+
return 0;
|
1625
|
+
}
|
1626
|
+
/****************************************************************/
|
1627
|
+
int e_bCanAtomBeMiddleAllene( int cur_at, S_CHAR *cAtType )
|
1628
|
+
{
|
1629
|
+
switch ( cAtType[cur_at] ) {
|
1630
|
+
case AtType_C2 :
|
1631
|
+
case AtType_Si2:
|
1632
|
+
case AtType_Ge2:
|
1633
|
+
case AtType_Sn2:
|
1634
|
+
return 2;
|
1635
|
+
}
|
1636
|
+
return 0;
|
1637
|
+
}
|
1638
|
+
/****************************************************************/
|
1639
|
+
int e_bCanAtomBeTerminalAllene( int cur_at, S_CHAR *cAtType )
|
1640
|
+
{
|
1641
|
+
switch ( cAtType[cur_at] ) {
|
1642
|
+
case AtType_C3 :
|
1643
|
+
case AtType_Si3:
|
1644
|
+
case AtType_Ge3:
|
1645
|
+
case AtType_Sn3:
|
1646
|
+
return 3;
|
1647
|
+
}
|
1648
|
+
return 0;
|
1649
|
+
}
|
1650
|
+
/*******************************************************************************************/
|
1651
|
+
int e_FixSb0DParities( inchi_Atom *at, Stereo0D *pStereo, int chain_length, AT_NUM at_middle,
|
1652
|
+
int at_1, int i_next_at_1, S_CHAR z_dir1[], S_CHAR z_dir1NM[], int bOnlyNM1, int bAnomaly1NM, int parity1, int parity1NM,
|
1653
|
+
int at_2, int i_next_at_2, S_CHAR z_dir2[], S_CHAR z_dir2NM[], int bOnlyNM2, int bAnomaly2NM, int parity2, int parity2NM )
|
1654
|
+
{
|
1655
|
+
int i_neigh_at_1, i_neigh_at_2, i, j1, j2;
|
1656
|
+
int j_neigh_at_1, j_neigh_at_2, j_next_at_1, j_next_at_2; /* positions after metal removal */
|
1657
|
+
inchi_Stereo0D *stereo0D = NULL;
|
1658
|
+
int dot_prod_z = 0, dot_prod_zNM = 0, parity, parityNM;
|
1659
|
+
|
1660
|
+
if ( (!parity1 || !parity2) && (!parity1NM || !parity2NM) )
|
1661
|
+
return 0;
|
1662
|
+
|
1663
|
+
if ( ATOM_PARITY_WELL_DEF( parity1 ) && ATOM_PARITY_WELL_DEF( parity2 ) ) {
|
1664
|
+
/* find how the whole bond parity depend on geometry */
|
1665
|
+
/* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
|
1666
|
+
/* can be done only for a well-defined geometry */
|
1667
|
+
/********************************************************************
|
1668
|
+
* Case of bOnlyNonMetal: stereobond end atoms have valence > 3
|
1669
|
+
* therefore they will not be recognized until metals have
|
1670
|
+
* been disconnected. Until then the assigned parities will
|
1671
|
+
* not change: ReconcileCmlIncidentBondParities() in the dll
|
1672
|
+
* ignores hypervanlence atoms marked as belonging to a stereobond.
|
1673
|
+
* Explicit H are removed only after metal diconnection.
|
1674
|
+
*
|
1675
|
+
* However, there is a possibility that the normalization
|
1676
|
+
* removes an explicit H thus reducing the valence to acceptable
|
1677
|
+
* value for the bond to be treated as stereogenic.
|
1678
|
+
* In this case a wrong INChI stereolayer for the reconnected
|
1679
|
+
* structure will be produced.
|
1680
|
+
*
|
1681
|
+
* After the metal disconnection ReconcileAllCmlBondParities()
|
1682
|
+
* will be called to reconcile newly appearing stereobonds
|
1683
|
+
********************************************************************/
|
1684
|
+
|
1685
|
+
dot_prod_z = (chain_length%2)?
|
1686
|
+
e_triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
|
1687
|
+
e_dot_prodchar3(z_dir1, z_dir2);
|
1688
|
+
|
1689
|
+
if ( abs(dot_prod_z) < MIN_DOT_PROD ) {
|
1690
|
+
/* The geometry is not well-defined */
|
1691
|
+
parity1 = parity2 = INCHI_PARITY_UNDEFINED;
|
1692
|
+
dot_prod_z = 0;
|
1693
|
+
}
|
1694
|
+
|
1695
|
+
}
|
1696
|
+
if ( ATOM_PARITY_WELL_DEF( parity1NM ) && ATOM_PARITY_WELL_DEF( parity2NM ) ) {
|
1697
|
+
/* find how the whole bond parity depend on geometry */
|
1698
|
+
/* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
|
1699
|
+
/* can be done only for a well-defined geometry */
|
1700
|
+
/********************************************************************
|
1701
|
+
* Case of bOnlyNonMetal: stereobond end atoms have valence > 3
|
1702
|
+
* therefore they will not be recognized until metals have
|
1703
|
+
* been disconnected. Until then the assigned parities will
|
1704
|
+
* not change: ReconcileCmlIncidentBondParities() in the dll
|
1705
|
+
* ignores hypervanlence atoms marked as belonging to a stereobond.
|
1706
|
+
* Explicit H are removed only after metal diconnection.
|
1707
|
+
*
|
1708
|
+
* However, there is a possibility that the normalization
|
1709
|
+
* removes an explicit H thus reducing the valence to acceptable
|
1710
|
+
* value for the bond to be treated as stereogenic.
|
1711
|
+
* In this case a wrong INChI stereolayer for the reconnected
|
1712
|
+
* structure will be produced.
|
1713
|
+
*
|
1714
|
+
* After the metal disconnection ReconcileAllCmlBondParities()
|
1715
|
+
* will be called to reconcile newly appearing stereobonds
|
1716
|
+
********************************************************************/
|
1717
|
+
|
1718
|
+
dot_prod_zNM = (chain_length%2)?
|
1719
|
+
e_triple_prod_char( at, at_1, i_next_at_1, z_dir1NM, at_2, i_next_at_2, z_dir2NM ) :
|
1720
|
+
e_dot_prodchar3(z_dir1NM, z_dir2NM);
|
1721
|
+
|
1722
|
+
if ( abs(dot_prod_zNM) < MIN_DOT_PROD ) {
|
1723
|
+
/* The geometry is not well-defined */
|
1724
|
+
parity1NM = parity2NM = INCHI_PARITY_UNDEFINED;
|
1725
|
+
dot_prod_zNM = 0;
|
1726
|
+
}
|
1727
|
+
|
1728
|
+
}
|
1729
|
+
|
1730
|
+
i_neigh_at_1 = i_neigh_at_2 = -1;
|
1731
|
+
j_neigh_at_1 = j_neigh_at_2 = j_next_at_1 = j_next_at_2 = -1;
|
1732
|
+
|
1733
|
+
/************************************************************************
|
1734
|
+
*
|
1735
|
+
* The possibly stereogenic bond is defined by atoms at_1, at_2 and
|
1736
|
+
* positions in their adjacency lists i_next_at_1, i_next_at_2.
|
1737
|
+
*
|
1738
|
+
* We need one more neighbor of at_1 and at_2 to establist cis or trans.
|
1739
|
+
* The current API allows only same neighbors for both connected and
|
1740
|
+
* metal-disconnected (or non-metal, NM) structures. Therefore if an
|
1741
|
+
* atom has both metal and non-metal neighbors, select the non-metal one.
|
1742
|
+
*
|
1743
|
+
* In case of bOnlyNM we have to use ordering numbers of the bonds
|
1744
|
+
* counted as if all metals have been disconnected.
|
1745
|
+
*
|
1746
|
+
* In all other cases we use real ordering numbers of the bonds
|
1747
|
+
* to calculate the parities.
|
1748
|
+
*
|
1749
|
+
* The input parities meaning:
|
1750
|
+
* ===========================
|
1751
|
+
* EVEN=2: the atoms in the adjacency list are arranged clockwise as
|
1752
|
+
* seen from the arrowhead of the z_dir vector
|
1753
|
+
*
|
1754
|
+
* The output parities meaning:
|
1755
|
+
* ============================
|
1756
|
+
* EVEN=2: trans geometry. For more details see the API description.
|
1757
|
+
*
|
1758
|
+
**************************************************************************/
|
1759
|
+
|
1760
|
+
if ( bOnlyNM1 || ATOM_PARITY_WELL_DEF( parity1NM ) ) {
|
1761
|
+
/* disconnected metal case */
|
1762
|
+
for ( i = j1 = 0; i < at[at_1].num_bonds; i ++ ) {
|
1763
|
+
if ( IS_METAL(pStereo->cAtType[at[at_1].neighbor[i]]) ) {
|
1764
|
+
continue;
|
1765
|
+
}
|
1766
|
+
if ( i == i_next_at_1 ) {
|
1767
|
+
j_next_at_1 = j1; /* position of the stereo bond in adjacency list
|
1768
|
+
when metals are disconnected */
|
1769
|
+
} else
|
1770
|
+
if ( i_neigh_at_1 < 0 ) {
|
1771
|
+
i_neigh_at_1 = i; /* position of the first non-metal neighbor (metal is connected) */
|
1772
|
+
j_neigh_at_1 = j1; /* position of the first non-metal neighbor (metal is disconnected) */
|
1773
|
+
}
|
1774
|
+
j1 ++;
|
1775
|
+
}
|
1776
|
+
} else {
|
1777
|
+
/* no metal case */
|
1778
|
+
j_neigh_at_1 = i_neigh_at_1 = (i_next_at_1==0);
|
1779
|
+
j_next_at_1 = i_next_at_1;
|
1780
|
+
j1 = at[at_1].num_bonds;
|
1781
|
+
}
|
1782
|
+
|
1783
|
+
if ( bOnlyNM2 || ATOM_PARITY_WELL_DEF( parity2NM ) ) {
|
1784
|
+
for ( i = j2 = 0; i < at[at_2].num_bonds; i ++ ) {
|
1785
|
+
if ( IS_METAL(pStereo->cAtType[at[at_2].neighbor[i]]) ) {
|
1786
|
+
continue;
|
1787
|
+
}
|
1788
|
+
if ( i == i_next_at_2 ) {
|
1789
|
+
j_next_at_2 = j2;
|
1790
|
+
} else
|
1791
|
+
if ( i_neigh_at_2 < 0 ) {
|
1792
|
+
i_neigh_at_2 = i;
|
1793
|
+
j_neigh_at_2 = j2;
|
1794
|
+
}
|
1795
|
+
j2 ++;
|
1796
|
+
}
|
1797
|
+
} else {
|
1798
|
+
j_neigh_at_2 = i_neigh_at_2 = (i_next_at_2==0);
|
1799
|
+
j_next_at_2 = i_next_at_2;
|
1800
|
+
j2 = at[at_2].num_bonds;
|
1801
|
+
}
|
1802
|
+
|
1803
|
+
if ( i_neigh_at_1 < 0 || i_neigh_at_2 < 0 ||
|
1804
|
+
j_neigh_at_1 < 0 || j_neigh_at_2 < 0 ||
|
1805
|
+
j_next_at_1 < 0 || j_next_at_2 < 0 ) {
|
1806
|
+
return 0; /* debugging */
|
1807
|
+
}
|
1808
|
+
if ( parity1 || parity1NM ) {
|
1809
|
+
/* create a new stereo descriptor */
|
1810
|
+
stereo0D = e_GetNewStereo( pStereo );
|
1811
|
+
if ( !stereo0D ) {
|
1812
|
+
return -1; /* error */
|
1813
|
+
}
|
1814
|
+
/* choose the smallest (earliest in the adjacency list) neighbor of at_1 */
|
1815
|
+
stereo0D->neighbor[0] = at[at_1].neighbor[i_neigh_at_1];
|
1816
|
+
/* stereibond atoms */
|
1817
|
+
stereo0D->neighbor[1] = at_1;
|
1818
|
+
stereo0D->neighbor[2] = at_2;
|
1819
|
+
/* choose the smallest neighbor of at_2 */
|
1820
|
+
stereo0D->neighbor[3] = at[at_2].neighbor[i_neigh_at_2];
|
1821
|
+
stereo0D->central_atom = at_middle;
|
1822
|
+
stereo0D->type = (chain_length % 2)? INCHI_StereoType_Allene : INCHI_StereoType_DoubleBond;
|
1823
|
+
|
1824
|
+
if ( dot_prod_z || dot_prod_zNM ) {
|
1825
|
+
|
1826
|
+
int i_parity1 = i_neigh_at_1 + i_next_at_1 + (i_neigh_at_1 > i_next_at_1);
|
1827
|
+
int j_parity1 = j_neigh_at_1 + j_next_at_1 + (j_neigh_at_1 > j_next_at_1);
|
1828
|
+
int i_parity2 = i_neigh_at_2 + i_next_at_2 + (i_neigh_at_2 > i_next_at_2);
|
1829
|
+
int j_parity2 = j_neigh_at_2 + j_next_at_2 + (j_neigh_at_2 > j_next_at_2);
|
1830
|
+
|
1831
|
+
/* regular (connected) parity; parity1 and parity2 are well-defined only together */
|
1832
|
+
if ( ATOM_PARITY_WELL_DEF( parity1 ) ) {
|
1833
|
+
parity = 2 - ( parity1 + parity2 + (dot_prod_z < 0) +
|
1834
|
+
((bOnlyNM1)? j_parity1 : i_parity1) +
|
1835
|
+
((bOnlyNM2)? j_parity2 : i_parity2) ) % 2;
|
1836
|
+
} else {
|
1837
|
+
parity = parity1;
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
|
1841
|
+
/* disconnected parity; parity1NM and parity2NM are well-defined only together */
|
1842
|
+
if ( ATOM_PARITY_WELL_DEF( parity1NM ) ) {
|
1843
|
+
parityNM = 2 - ( parity1NM + parity2NM + (dot_prod_zNM < 0) +
|
1844
|
+
((bOnlyNM1||bAnomaly1NM)? j_parity1 : i_parity1) +
|
1845
|
+
((bOnlyNM2||bAnomaly2NM)? j_parity2 : i_parity2) ) % 2;
|
1846
|
+
} else {
|
1847
|
+
parityNM = parity1NM;
|
1848
|
+
}
|
1849
|
+
} else {
|
1850
|
+
parity = parity1;
|
1851
|
+
parityNM = parity1NM;
|
1852
|
+
}
|
1853
|
+
stereo0D->parity = parity;
|
1854
|
+
if ( parityNM != parity || bAnomaly1NM || bAnomaly2NM ) {
|
1855
|
+
stereo0D->parity |= (parityNM << SB_PARITY_SHFT);
|
1856
|
+
}
|
1857
|
+
|
1858
|
+
return stereo0D->parity;
|
1859
|
+
}
|
1860
|
+
return 0;
|
1861
|
+
}
|
1862
|
+
/**************************************************************************/
|
1863
|
+
int e_nNumNonMetalNeigh( inchi_Atom *atom, int cur_at, Stereo0D *pStereo, int *i_ord_LastMetal )
|
1864
|
+
{
|
1865
|
+
int j, nNumNonMetal;
|
1866
|
+
inchi_Atom *at = atom + cur_at;
|
1867
|
+
int val = at->num_bonds;
|
1868
|
+
int atype;
|
1869
|
+
|
1870
|
+
*i_ord_LastMetal = -1;
|
1871
|
+
nNumNonMetal = 0;
|
1872
|
+
|
1873
|
+
atype = pStereo->cAtType[cur_at];
|
1874
|
+
|
1875
|
+
if ( IS_METAL(atype) )
|
1876
|
+
return 0;
|
1877
|
+
for ( j = 0; j < val; j ++ ) {
|
1878
|
+
atype = pStereo->cAtType[(int)at->neighbor[j]];
|
1879
|
+
if ( IS_METAL(atype) )
|
1880
|
+
*i_ord_LastMetal = j;
|
1881
|
+
else
|
1882
|
+
nNumNonMetal ++;
|
1883
|
+
}
|
1884
|
+
return nNumNonMetal;
|
1885
|
+
}
|
1886
|
+
/*======================================================================================================
|
1887
|
+
|
1888
|
+
e_half_stereo_bond_parity() General Description:
|
1889
|
+
|
1890
|
+
A) find projections of 3 bonds on a reasonable plane defined
|
1891
|
+
by a vector z_dir perpendicular to the plane
|
1892
|
+
B) calculate parity (parity=2[EVEN]: neighbors are clockwise as seen from the arrowhead of z_dir[] vector)
|
1893
|
+
|
1894
|
+
e_half_stereo_bond_parity() Detailed Description:
|
1895
|
+
|
1896
|
+
1) Find at_coord[] = vectors from the central atoms to its neighbors
|
1897
|
+
2) If only 2 neighbors are present, then create a reasonable 3rd neighbor
|
1898
|
+
(an implicit H or a fictitious atom in case of =NX) coordinates
|
1899
|
+
3) Normalize at_coord[] to unit length
|
1900
|
+
4) Find unit vector pnt[2] perpendicular to the plane containing
|
1901
|
+
at_coord[] arrow ends.
|
1902
|
+
Even though it is not necessary, make z-coordinate of pnt[2] positive.
|
1903
|
+
** pnt[2] has the new z-axis direction **
|
1904
|
+
5) Let pnt[0] = perpendicular to pnt[2] component of at_coord[0];
|
1905
|
+
Normalize pnt[0] to unit length.
|
1906
|
+
** pnt[0] has the new x-axis direction **
|
1907
|
+
6) Let pnt[1] = pnt[2] x pnt[0] (cross-product);
|
1908
|
+
** pnt[1] has the new y-axis direction **
|
1909
|
+
7) Find at_coord[] in the new xyz-basis and normalize their xy-projections
|
1910
|
+
to a unit length
|
1911
|
+
8) In the new xy-plane find (counterclockwise) angles:
|
1912
|
+
tmp1 = (from at_coord[0] to at_coord[1])
|
1913
|
+
tmp2 = (from at_coord[0] to at_coord[2])
|
1914
|
+
9) Calculate the parity: if tmp1 < tmp2 then 1 (odd) else 2 (even)
|
1915
|
+
(even: looking from the arrow end of the new z-axis, 0, 1, and 2 neighbors
|
1916
|
+
are in clockwise order)
|
1917
|
+
10) Calculate z_dir = 100*pnt[2].
|
1918
|
+
|
1919
|
+
Note1. If z_dir vectors of atoms located at the opposite ends of a double bond have approximately
|
1920
|
+
opposite directions (that is, their dot-product is negative) then the parity of the
|
1921
|
+
stereogenic bond calculated from half-bond-parities should be inverted
|
1922
|
+
|
1923
|
+
Note2. In case of a tetrahedral cumulene a triple product (z_dir1, (1->2), z_dir2) is used instead
|
1924
|
+
of the dot-product. (1->2) is a vector from the atom#1 to the atom #2. This triple product
|
1925
|
+
is invariant with respect to the atom numbering because it does not change upon (1,2)
|
1926
|
+
permutation.
|
1927
|
+
|
1928
|
+
Stereo ambiguity in case of 2 neighbors:
|
1929
|
+
----------------------------------------
|
1930
|
+
Undefined: single-double bond angle > pi - arcsin(0.03) = 178.28164199834454285275613218975 degrees
|
1931
|
+
Ambiguous: single-double bond angle > 175 degrees = pi - 0.087156 Rad
|
1932
|
+
|
1933
|
+
Return values
|
1934
|
+
(cases: I=only in case of isotopic H atoms the neighbors are different,
|
1935
|
+
N=in case of non-isotopic H atoms the neighbors are different)
|
1936
|
+
|
1937
|
+
-4 = INCHI_PARITY_UNDEFINED => atom is adjacent to a stereogenic bond, but the geometry is undefined, I
|
1938
|
+
-3 = INCHI_PARITY_UNKNOWN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, I
|
1939
|
+
-2 =-INCHI_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, I
|
1940
|
+
-1 =-INCHI_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, I
|
1941
|
+
0 = INCHI_PARITY_NONE => the atom is not adjacent to a stereogenic bond
|
1942
|
+
1 = INCHI_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, N&I
|
1943
|
+
2 = INCHI_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, N&I
|
1944
|
+
3 = INCHI_PARITY_UNKNOWN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, N&I
|
1945
|
+
4 = INCHI_PARITY_UNDEFINED => atom is adjacent to a stereogenic bond, but the geometry is undefined, N&I
|
1946
|
+
|
1947
|
+
|
1948
|
+
=====================================================================================================*/
|
1949
|
+
|
1950
|
+
int e_half_stereo_bond_parity( inchi_Atom *at, int cur_at, S_CHAR *z_dir, int *bOnlyNonMetal,
|
1951
|
+
int bPointedEdgeStereo, Stereo0D *pStereo )
|
1952
|
+
{
|
1953
|
+
double at_coord[MAX_NUM_STEREO_BOND_NEIGH][3], c, s, tmp[3], tmp1, tmp2, min_tmp, max_tmp, z;
|
1954
|
+
double temp[3], pnt[3][3];
|
1955
|
+
int j, k, p0, p1, p2, next, num_z, nType, num_either_single, num_either_double;
|
1956
|
+
int nNumExplictAttachments;
|
1957
|
+
int bond_parity = INCHI_PARITY_UNDEFINED;
|
1958
|
+
int num_H=0, num_eH=0, num_nH=0 /* = num_iso_H[0] */;
|
1959
|
+
const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
|
1960
|
+
const double two_pi = 2.0*one_pi;
|
1961
|
+
AT_NUM nSbNeighOrigAtNumb[MAX_NUM_STEREO_BOND_NEIGH];
|
1962
|
+
int bAmbiguousStereo = 0;
|
1963
|
+
S_CHAR num_iso_eH[NUM_H_ISOTOPES+1]; /* count explicit H */
|
1964
|
+
|
1965
|
+
if ( z_dir && !z_dir[0] && !z_dir[1] && !z_dir[2] ) {
|
1966
|
+
z_dir[2]=100;
|
1967
|
+
}
|
1968
|
+
/* *bOnlyNonMetal = 0; */
|
1969
|
+
if ( at[cur_at].num_bonds > MAX_NUM_STEREO_BOND_NEIGH || *bOnlyNonMetal ) {
|
1970
|
+
int i_ord_LastMetal;
|
1971
|
+
int nNumNonMetal = e_nNumNonMetalNeigh( at, cur_at, pStereo, &i_ord_LastMetal );
|
1972
|
+
if ( nNumNonMetal <= MAX_NUM_STEREO_BOND_NEIGH ) {
|
1973
|
+
*bOnlyNonMetal = 1;
|
1974
|
+
if ( 1 == nNumNonMetal ) {
|
1975
|
+
return bond_parity; /* INCHI_PARITY_UNDEFINED */
|
1976
|
+
}
|
1977
|
+
if ( 0 == nNumNonMetal ) {
|
1978
|
+
return INCHI_PARITY_NONE;
|
1979
|
+
}
|
1980
|
+
} else {
|
1981
|
+
return INCHI_PARITY_NONE;
|
1982
|
+
}
|
1983
|
+
}
|
1984
|
+
memset(num_iso_eH, 0, sizeof(num_iso_eH));
|
1985
|
+
for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
|
1986
|
+
next = at[cur_at].neighbor[j];
|
1987
|
+
switch( pStereo->cAtType[next] ) {
|
1988
|
+
case AtType_TermH:
|
1989
|
+
if ( 0 <= at[next].isotopic_mass && at[next].isotopic_mass <= NUM_H_ISOTOPES ) {
|
1990
|
+
num_iso_eH[at[next].isotopic_mass] ++;
|
1991
|
+
} else {
|
1992
|
+
num_iso_eH[0] ++;
|
1993
|
+
}
|
1994
|
+
num_eH ++;
|
1995
|
+
break;
|
1996
|
+
case AtType_TermD:
|
1997
|
+
num_iso_eH[2] ++;
|
1998
|
+
num_eH ++;
|
1999
|
+
break;
|
2000
|
+
case AtType_TermT:
|
2001
|
+
num_iso_eH[3] ++;
|
2002
|
+
num_eH ++;
|
2003
|
+
break;
|
2004
|
+
}
|
2005
|
+
}
|
2006
|
+
|
2007
|
+
|
2008
|
+
num_H = inchi_NUMH2(at,cur_at) + num_eH;
|
2009
|
+
if ( num_H > NUM_H_ISOTOPES )
|
2010
|
+
return 0; /* at least 2 H atoms are isotopically identical */
|
2011
|
+
|
2012
|
+
for ( j = 0, num_nH = num_H; j < NUM_H_ISOTOPES; j ++ ) {
|
2013
|
+
if ( (k = (int)at[cur_at].num_iso_H[j+1]+(int)num_iso_eH[j+1]) > 1 ) {
|
2014
|
+
return INCHI_PARITY_NONE; /* two or more identical isotopic H atoms */
|
2015
|
+
}
|
2016
|
+
num_nH -= k;
|
2017
|
+
}
|
2018
|
+
/* at this point num_nH = number of non-isotopic H atoms */
|
2019
|
+
if ( num_nH > 1 )
|
2020
|
+
return INCHI_PARITY_NONE; /* two or more identical non-isotopic H atoms */
|
2021
|
+
if ( num_nH < 0 )
|
2022
|
+
return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
|
2023
|
+
|
2024
|
+
/********************************************************************
|
2025
|
+
* Note. At this point all (implicit and explicit) isotopic
|
2026
|
+
* terminal H neighbors are either different or not present.
|
2027
|
+
********************************************************************/
|
2028
|
+
|
2029
|
+
/* store neighbors coordinates */
|
2030
|
+
num_z = num_either_single = num_either_double = 0;
|
2031
|
+
nNumExplictAttachments = 0;
|
2032
|
+
for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
|
2033
|
+
next = at[cur_at].neighbor[j];
|
2034
|
+
if ( *bOnlyNonMetal && IS_METAL(pStereo->cAtType[next]) )
|
2035
|
+
continue;
|
2036
|
+
at_coord[nNumExplictAttachments][0] = at[next].x - at[cur_at].x;
|
2037
|
+
at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
|
2038
|
+
nSbNeighOrigAtNumb[nNumExplictAttachments] = next;
|
2039
|
+
|
2040
|
+
z = e_get_z_coord( at, cur_at, j /*neighbor #*/, &nType, bPointedEdgeStereo );
|
2041
|
+
switch ( nType ) {
|
2042
|
+
case ZTYPE_EITHER:
|
2043
|
+
num_either_single ++; /* bond in "Either" direction. */
|
2044
|
+
break;
|
2045
|
+
case ZTYPE_UP:
|
2046
|
+
case ZTYPE_DOWN:
|
2047
|
+
z = e_len2( at_coord[nNumExplictAttachments] );
|
2048
|
+
/*
|
2049
|
+
z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
|
2050
|
+
+ at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
|
2051
|
+
*/
|
2052
|
+
if ( nType == ZTYPE_DOWN )
|
2053
|
+
z = -z;
|
2054
|
+
/* no break; here */
|
2055
|
+
case ZTYPE_3D:
|
2056
|
+
num_z ++;
|
2057
|
+
}
|
2058
|
+
at_coord[nNumExplictAttachments][2] = z;
|
2059
|
+
nNumExplictAttachments ++;
|
2060
|
+
}
|
2061
|
+
|
2062
|
+
if ( num_either_single ) {
|
2063
|
+
bond_parity = INCHI_PARITY_UNKNOWN; /* single bond is 'unknown' */
|
2064
|
+
goto exit_function;
|
2065
|
+
}
|
2066
|
+
|
2067
|
+
/* nNumExplictAttachments is a total number of attachments */
|
2068
|
+
if ( nNumExplictAttachments == 2 ) {
|
2069
|
+
/* create coordinates of the implicit hydrogen (or a fictitious atom in case of ==N-X ), */
|
2070
|
+
/* coord[2][], attached to the cur_at. */
|
2071
|
+
for ( j = 0; j < 3; j ++ ) {
|
2072
|
+
at_coord[2][j] = - ( at_coord[0][j] + at_coord[1][j] );
|
2073
|
+
}
|
2074
|
+
nSbNeighOrigAtNumb[nNumExplictAttachments] = -1; /* implicit H or lone pair */
|
2075
|
+
}
|
2076
|
+
for ( j = 0; j < 3; j ++ ) {
|
2077
|
+
tmp[j] = e_len3( at_coord[j] );
|
2078
|
+
}
|
2079
|
+
min_tmp = inchi_min( tmp[0], inchi_min(tmp[1], tmp[2]) );
|
2080
|
+
max_tmp = inchi_max( tmp[0], inchi_max(tmp[1], tmp[2]) );
|
2081
|
+
if ( min_tmp < MIN_BOND_LEN || min_tmp < MIN_SINE*max_tmp ) {
|
2082
|
+
/* all bonds or some of bonds are too short */
|
2083
|
+
goto exit_function;
|
2084
|
+
}
|
2085
|
+
/* normalize lengths to 1 */
|
2086
|
+
for ( j = 0; j < 3; j ++ ) {
|
2087
|
+
e_mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
|
2088
|
+
}
|
2089
|
+
|
2090
|
+
/* find projections of at_coord vector differences on the plane containing their arrowhead ends */
|
2091
|
+
for ( j = 0; j < 3; j ++ ) {
|
2092
|
+
/* pnt[0..2] = {0-1, 1-2, 2-0} */
|
2093
|
+
tmp[j] = e_len3(e_diff3( at_coord[j], at_coord[(j+1)%3], pnt[j] ));
|
2094
|
+
if ( tmp[j] < MIN_SINE ) {
|
2095
|
+
goto exit_function; /* angle #i-cur_at-#j is too small */
|
2096
|
+
}
|
2097
|
+
e_mult3( pnt[j], 1.0/tmp[j], pnt[j] ); /* 2003-10-06 */
|
2098
|
+
}
|
2099
|
+
/* find pnt[p2], a vector perpendicular to the plane, and its length tmp[p2] */
|
2100
|
+
/* replace previous pnt[p2], tmp[p2] with new values; the old values do not have any additional */
|
2101
|
+
/* information because pnt[p0]+pnt[p1]+pnt[p2]=0 */
|
2102
|
+
/* 10-6-2003: a cross-product of one pair pnt[j], pnt[(j+1)%3] can be very small. Find the larges one */
|
2103
|
+
tmp1 = e_len3( e_cross_prod3( pnt[0], pnt[1], temp ) );
|
2104
|
+
for (j = 1, k = 0; j < 3; j ++ ) {
|
2105
|
+
tmp2 = e_len3( e_cross_prod3( pnt[j], pnt[(j+1)%3], temp ) );
|
2106
|
+
if ( tmp2 > tmp1 ) {
|
2107
|
+
tmp1 = tmp2;
|
2108
|
+
k = j;
|
2109
|
+
}
|
2110
|
+
}
|
2111
|
+
/* previously p0=0, p1=1, p2=2 */
|
2112
|
+
p0 = k;
|
2113
|
+
p1 = (k+1)%3;
|
2114
|
+
p2 = (k+2)%3;
|
2115
|
+
tmp[p2] = e_len3( e_cross_prod3( pnt[p0], pnt[p1], pnt[p2] ) );
|
2116
|
+
if ( tmp[p2] < MIN_SINE*tmp[p0]*tmp[p1] ) {
|
2117
|
+
goto exit_function; /* pnt[p0] is almost colinear to pnt[p1] */
|
2118
|
+
}
|
2119
|
+
/* new basis: pnt[p0], pnt[p1], pnt[p2]; set z-coord sign and make abs(pnt[p2]) = 1 */
|
2120
|
+
e_mult3( pnt[p2], (pnt[p2][2]>0.0? 1.0:-1.0)/tmp[p2], pnt[p2] ); /* unit vector in the new z-axis direction */
|
2121
|
+
|
2122
|
+
min_tmp = e_dot_prod3( at_coord[0], pnt[p2] ); /* non-planarity measure (sine): hight of at_coord[] pyramid */
|
2123
|
+
e_mult3( pnt[p2], min_tmp, pnt[p0] ); /* vector height of the pyramid, ideally 0 */
|
2124
|
+
/* find new pnt[p0] = projection of at_coord[p0] on plane orthogonal to pnt[p2] */
|
2125
|
+
tmp[p0] = e_len3(e_diff3( at_coord[0], pnt[p0], pnt[p0] ));
|
2126
|
+
e_mult3( pnt[p0], 1.0/tmp[p0], pnt[p0] ); /* new x axis basis vector */
|
2127
|
+
e_cross_prod3( pnt[p2], pnt[p0], pnt[p1] ); /* new y axis basis vector */
|
2128
|
+
/* find at_coord in the new basis of {pnt[p0], pnt[p1], pnt[p2]} */
|
2129
|
+
for ( j = 0; j < 3; j ++ ) {
|
2130
|
+
e_copy3( at_coord[j], temp );
|
2131
|
+
for ( k = 0; k < 3; k ++ ) {
|
2132
|
+
at_coord[j][k] = e_dot_prod3( temp, pnt[(k+p0)%3] );
|
2133
|
+
}
|
2134
|
+
/* new xy plane projection length */
|
2135
|
+
tmp[j] = sqrt(at_coord[j][0]*at_coord[j][0] + at_coord[j][1]*at_coord[j][1]);
|
2136
|
+
/* make new xy plane projection length = 1 */
|
2137
|
+
e_mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
|
2138
|
+
}
|
2139
|
+
|
2140
|
+
s = fabs( at_coord[1][0]*at_coord[2][1] - at_coord[1][1]*at_coord[2][0] ); /* 1-2 sine */
|
2141
|
+
c = at_coord[1][0]*at_coord[2][0] + at_coord[1][1]*at_coord[2][1]; /* 1-2 cosine */
|
2142
|
+
if ( s < MIN_SINE && c > 0.5 ) {
|
2143
|
+
goto exit_function; /* bonds to neigh. 1 and 2 have almost same direction; relative angles are undefined */
|
2144
|
+
}
|
2145
|
+
c = at_coord[0][0]; /* cosine of the angle between new Ox axis and a bond to the neighbor 0. Should be 1 */
|
2146
|
+
s = at_coord[0][1]; /* sine. Should be 0 */
|
2147
|
+
/* turn vectors so that vector #1 (at_coord[0]) becomes {1, 0} */
|
2148
|
+
for ( j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j ++ ) {
|
2149
|
+
tmp1 = c*at_coord[j][0] + s*at_coord[j][1];
|
2150
|
+
tmp2 = -s*at_coord[j][0] + c*at_coord[j][1];
|
2151
|
+
at_coord[j][0] = tmp1;
|
2152
|
+
at_coord[j][1] = tmp2;
|
2153
|
+
}
|
2154
|
+
/* counterclockwise angles from the direction to neigh 0 to to directions to neighbors 1 and 2: */
|
2155
|
+
tmp1 = atan2( at_coord[1][1], at_coord[1][0] ); /* range -pi and +pi */
|
2156
|
+
tmp2 = atan2( at_coord[2][1], at_coord[2][0] );
|
2157
|
+
if ( tmp1 < 0.0 )
|
2158
|
+
tmp1 += two_pi; /* range 0 to 2*pi */
|
2159
|
+
if ( tmp2 < 0.0 )
|
2160
|
+
tmp2 += two_pi;
|
2161
|
+
/*-----------------------------------
|
2162
|
+
Example
|
2163
|
+
1 \ case tmp1 < tmp2
|
2164
|
+
\ parity is odd
|
2165
|
+
\ (counterclockwise)
|
2166
|
+
A------- 0
|
2167
|
+
/
|
2168
|
+
/
|
2169
|
+
2 /
|
2170
|
+
|
2171
|
+
------------------------------------*/
|
2172
|
+
bond_parity = 2 - ( tmp1 < tmp2 );
|
2173
|
+
for ( j = 0; j < 3; j ++ ) {
|
2174
|
+
z_dir[j] = (S_CHAR)(pnt[p2][j]>= 0.0? floor(0.5 + 100.0 * pnt[p2][j]) :
|
2175
|
+
-floor(0.5 - 100.0 * pnt[p2][j])); /* abs(z_dir) = 100 */
|
2176
|
+
}
|
2177
|
+
/* check for ambiguity */
|
2178
|
+
if ( nNumExplictAttachments > 2 ) {
|
2179
|
+
min_tmp = inchi_min( tmp1, tmp2 );
|
2180
|
+
max_tmp = inchi_max( tmp1, tmp2 );
|
2181
|
+
if ( min_tmp > one_pi-MIN_SINE || max_tmp < one_pi+MIN_SINE || max_tmp-min_tmp > one_pi - MIN_SINE ) {
|
2182
|
+
bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
2183
|
+
} else /* 3D ambiguity 8-28-2002 */
|
2184
|
+
if ( fabs(at_coord[0][2]) > MAX_SINE ) { /* all fabs(at_coord[j][2] (j=0..2) must be equal */
|
2185
|
+
bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
2186
|
+
}
|
2187
|
+
} else
|
2188
|
+
if ( nNumExplictAttachments == 2 ) { /* 10-6-2003: added */
|
2189
|
+
min_tmp = fabs(tmp1 - one_pi);
|
2190
|
+
if ( min_tmp < MIN_SINE ) {
|
2191
|
+
bond_parity = INCHI_PARITY_UNDEFINED; /* consider as undefined 10-6-2003 */
|
2192
|
+
} else
|
2193
|
+
if ( min_tmp < MIN_ANGLE_DBOND ) {
|
2194
|
+
bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
2195
|
+
}
|
2196
|
+
}
|
2197
|
+
|
2198
|
+
/* for 3 neighbors moving implicit H to the index=0 from index=2 position */
|
2199
|
+
/* can be done in 2 transpositions and does not change atom's parity */
|
2200
|
+
|
2201
|
+
exit_function:
|
2202
|
+
return bond_parity;
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
#define MAX_ALLENE_LEN 20
|
2206
|
+
/*************************************************************/
|
2207
|
+
int e_set_stereo_bonds_parity( Stereo0D *pStereo, inchi_Atom *at, int at_1, int bPointedEdgeStereo )
|
2208
|
+
{
|
2209
|
+
int j, k, next_at_1, i_next_at_1, i_next_at_2, at_2, next_at_2, num_stereo_bonds, bFound, bAllene;
|
2210
|
+
int bond_type, num_2s_1, num_alt_1, bNxtStereobond, bCurStereobond, bNxtCumulene;
|
2211
|
+
int num_stored_stereo_bonds, num_stored_isotopic_stereo_bonds;
|
2212
|
+
int chain_length, num_chains, cur_chain_length;
|
2213
|
+
int all_at_2[MAX_NUM_STEREO_BONDS];
|
2214
|
+
int all_pos_1[MAX_NUM_STEREO_BONDS], all_pos_2[MAX_NUM_STEREO_BONDS];
|
2215
|
+
S_CHAR all_unkn[MAX_NUM_STEREO_BONDS], all_chain_len[MAX_NUM_STEREO_BONDS];
|
2216
|
+
int all_middle_at[MAX_NUM_STEREO_BONDS];
|
2217
|
+
AT_NUM chain_atoms[MAX_ALLENE_LEN], at_middle;
|
2218
|
+
int nUnknown;
|
2219
|
+
int bOnlyNM1, bOnlyNM2;
|
2220
|
+
|
2221
|
+
bCurStereobond = e_bCanAtomHaveAStereoBond( at, at_1, pStereo->cAtType );
|
2222
|
+
if ( !bCurStereobond )
|
2223
|
+
return 0;
|
2224
|
+
|
2225
|
+
/* count bonds and find the second atom on the stereo bond */
|
2226
|
+
num_2s_1 = num_alt_1 = 0;
|
2227
|
+
chain_length = 0;
|
2228
|
+
num_chains = 0;
|
2229
|
+
for ( i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].num_bonds; i_next_at_1 ++ ) {
|
2230
|
+
|
2231
|
+
at_2 = next_at_1 = at[at_1].neighbor[i_next_at_1];
|
2232
|
+
bond_type = at[at_1].bond_type[i_next_at_1];
|
2233
|
+
nUnknown = (at[at_1].bond_stereo[i_next_at_1] == INCHI_PARITY_UNKNOWN);
|
2234
|
+
next_at_2 = at_1;
|
2235
|
+
|
2236
|
+
bNxtStereobond = e_bCanAtomHaveAStereoBond( at, at_2, pStereo->cAtType );
|
2237
|
+
bNxtCumulene = 0;
|
2238
|
+
cur_chain_length = 0;
|
2239
|
+
|
2240
|
+
if ( bNxtStereobond + bCurStereobond > 3 ) {
|
2241
|
+
/* this includes single (ring) bonds in -NH-CH=N(+)< that may be deprotonated to -N=C-N< */
|
2242
|
+
if ( bond_type == INCHI_BOND_TYPE_TRIPLE ) {
|
2243
|
+
continue;
|
2244
|
+
}
|
2245
|
+
/* possibly stereogenic bond */
|
2246
|
+
} else {
|
2247
|
+
bNxtCumulene =
|
2248
|
+
e_bCanAtomBeMiddleAllene(at_2, pStereo->cAtType ) &&
|
2249
|
+
e_bCanAtomBeTerminalAllene( at_1, pStereo->cAtType );
|
2250
|
+
if ( !bNxtCumulene ) {
|
2251
|
+
continue;
|
2252
|
+
}
|
2253
|
+
if ( bond_type != INCHI_BOND_TYPE_DOUBLE ) {
|
2254
|
+
continue;
|
2255
|
+
}
|
2256
|
+
/* possibly allene or cumulenr */
|
2257
|
+
chain_atoms[cur_chain_length] = at_1;
|
2258
|
+
chain_atoms[cur_chain_length+1] = at_2;
|
2259
|
+
|
2260
|
+
/*
|
2261
|
+
* Example of cumulene
|
2262
|
+
* chain length = 2: >X=C=C=Y<
|
2263
|
+
* | | | |
|
2264
|
+
* 1st cumulene atom= at_1 | | at_2 =last cumlene chain atom
|
2265
|
+
* next to at_1= next_at_1 next_at_2 =previous to at_2
|
2266
|
+
*
|
2267
|
+
* chain length odd: stereocenter on the middle atom ( 1=> allene )
|
2268
|
+
* chain length even: "long stereogenic bond"
|
2269
|
+
*/
|
2270
|
+
while ( cur_chain_length < MAX_ALLENE_LEN-3 &&
|
2271
|
+
(bAllene =
|
2272
|
+
e_bCanAtomBeMiddleAllene( at_2, pStereo->cAtType ))) {
|
2273
|
+
k = ((int)at[at_2].neighbor[0]==next_at_2); /* opposite neighbor position */
|
2274
|
+
next_at_2 = at_2;
|
2275
|
+
nUnknown += (at[at_2].bond_stereo[k] == INCHI_BOND_STEREO_DOUBLE_EITHER);
|
2276
|
+
at_2 = (int)at[at_2].neighbor[k];
|
2277
|
+
cur_chain_length ++; /* count =C= atoms */
|
2278
|
+
chain_atoms[cur_chain_length+1] = at_2;
|
2279
|
+
}
|
2280
|
+
if ( cur_chain_length ) {
|
2281
|
+
if ( bAllene /* at the end of the chain atom Y is =Y=, not =Y< or =Y- */ ||
|
2282
|
+
!e_bCanAtomBeTerminalAllene( at_2, pStereo->cAtType)) {
|
2283
|
+
cur_chain_length = 0;
|
2284
|
+
continue; /* ignore: does not fit cumulene description; go to check next at_1 neighbor */
|
2285
|
+
}
|
2286
|
+
}
|
2287
|
+
if ( !cur_chain_length &&
|
2288
|
+
!e_bCanAtomHaveAStereoBond( at, at_2, pStereo->cAtType ) ) {
|
2289
|
+
continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
|
2290
|
+
}
|
2291
|
+
}
|
2292
|
+
|
2293
|
+
/* check atom at the opposite end of possibly stereogenic bond */
|
2294
|
+
|
2295
|
+
bFound = ( at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
|
2296
|
+
|
2297
|
+
if ( bFound ) {
|
2298
|
+
i_next_at_2 = -1; /* unassigned mark */
|
2299
|
+
for ( j = 0; j < at[at_2].num_bonds; j ++ ) {
|
2300
|
+
if ( (int)at[at_2].neighbor[j] == next_at_2 ) {
|
2301
|
+
i_next_at_2 = j; /* assigned */
|
2302
|
+
break;
|
2303
|
+
}
|
2304
|
+
}
|
2305
|
+
if ( i_next_at_2 < 0 ) {
|
2306
|
+
continue;
|
2307
|
+
}
|
2308
|
+
/* store the results */
|
2309
|
+
all_pos_1[num_stereo_bonds] = i_next_at_1; /* neighbor to at_1 position */
|
2310
|
+
all_pos_2[num_stereo_bonds] = i_next_at_2; /* neighbor to at_2 position */
|
2311
|
+
all_at_2[num_stereo_bonds] = at_2; /* at_2 */
|
2312
|
+
all_unkn[num_stereo_bonds] = nUnknown; /* stereogenic bond has Unknown configuration */
|
2313
|
+
/* allene/cumulene stuff */
|
2314
|
+
all_chain_len[num_stereo_bonds] = cur_chain_length;
|
2315
|
+
all_middle_at[num_stereo_bonds] = (cur_chain_length%2)? chain_atoms[(cur_chain_length+1)/2] : -1;
|
2316
|
+
num_stereo_bonds ++;
|
2317
|
+
}
|
2318
|
+
}
|
2319
|
+
if ( !num_stereo_bonds || num_stereo_bonds > 3 /*|| num_chains > 1*/ ) {
|
2320
|
+
return 0; /* At the end, we cannot be more than 1 cumulene chain. */
|
2321
|
+
}
|
2322
|
+
|
2323
|
+
/* ================== calculate parities ====================== */
|
2324
|
+
/* find possibly stereo bonds and save them */
|
2325
|
+
num_stored_isotopic_stereo_bonds = 0;
|
2326
|
+
num_stored_stereo_bonds = 0;
|
2327
|
+
for ( k = 0; k < num_stereo_bonds; k ++ ) {
|
2328
|
+
/* NM stands for non-metal */
|
2329
|
+
int parity_at_1, parity_at_2, parity_at_1NM=0, parity_at_2NM=0, bOnlyNM;
|
2330
|
+
S_CHAR z_dir1[3], z_dir2[3], z_dir1NM[3], z_dir2NM[3]; /* 3D vectors for half stereo bond parity direction */
|
2331
|
+
int i_ord_LastMetal1, i_ord_LastMetal2, bAnomaly1NM, bAnomaly2NM;
|
2332
|
+
|
2333
|
+
at_2 = all_at_2[k];
|
2334
|
+
i_next_at_1 = all_pos_1[k];
|
2335
|
+
i_next_at_2 = all_pos_2[k];
|
2336
|
+
nUnknown = all_unkn[k];
|
2337
|
+
at_middle = all_middle_at[k];
|
2338
|
+
cur_chain_length = all_chain_len[k];
|
2339
|
+
memset(z_dir1, 0, sizeof(z_dir1));
|
2340
|
+
memset(z_dir2, 0, sizeof(z_dir2));
|
2341
|
+
memset(z_dir1NM, 0, sizeof(z_dir1NM));
|
2342
|
+
memset(z_dir2NM, 0, sizeof(z_dir2NM));
|
2343
|
+
bOnlyNM1 = bOnlyNM2 = 0;
|
2344
|
+
bAnomaly1NM = bAnomaly2NM = 0;
|
2345
|
+
i_ord_LastMetal1 = i_ord_LastMetal2 = -1;
|
2346
|
+
|
2347
|
+
if ( nUnknown ) {
|
2348
|
+
parity_at_1 = parity_at_2 = parity_at_1NM = parity_at_2NM = INCHI_PARITY_UNKNOWN;
|
2349
|
+
} else {
|
2350
|
+
/***********************************************************************
|
2351
|
+
*
|
2352
|
+
* Obtain each atom parity from the geometry
|
2353
|
+
*
|
2354
|
+
* Warning: case when dot-product
|
2355
|
+
* (z_dir1,z_dir1NM) < 0 or (z_dir2,z_dir2NM) < 0
|
2356
|
+
* is not treated proprly.
|
2357
|
+
* This case may happen especially when z_dir?[3] << 100
|
2358
|
+
*
|
2359
|
+
***********************************************************************/
|
2360
|
+
|
2361
|
+
parity_at_1 = e_half_stereo_bond_parity( at, at_1, z_dir1, &bOnlyNM1, bPointedEdgeStereo, pStereo );
|
2362
|
+
parity_at_2 = e_half_stereo_bond_parity( at, at_2, z_dir2, &bOnlyNM2, bPointedEdgeStereo, pStereo );
|
2363
|
+
|
2364
|
+
if ( RETURNED_ERROR(parity_at_1) || RETURNED_ERROR(parity_at_2) ) {
|
2365
|
+
return CT_CALC_STEREO_ERR;
|
2366
|
+
}
|
2367
|
+
parity_at_1 = abs(parity_at_1);
|
2368
|
+
parity_at_2 = abs(parity_at_2);
|
2369
|
+
/* bond parities for the disconnected structure */
|
2370
|
+
if ( bOnlyNM1 ) {
|
2371
|
+
parity_at_1NM = parity_at_1;
|
2372
|
+
memcpy( z_dir1NM, z_dir1, sizeof(z_dir1NM) );
|
2373
|
+
parity_at_1 = INCHI_PARITY_NONE;
|
2374
|
+
} else
|
2375
|
+
if ( at[at_1].num_bonds == e_nNumNonMetalNeigh( at, at_1, pStereo, &i_ord_LastMetal1 ) ) {
|
2376
|
+
parity_at_1NM = parity_at_1; /* no metal bond present */
|
2377
|
+
memcpy( z_dir1NM, z_dir1, sizeof(z_dir1NM) );
|
2378
|
+
} else {
|
2379
|
+
bOnlyNM = 1; /* at_1 has a metal neighbor; in adjacency list
|
2380
|
+
it is located in (zero-based) position i_ord_LastMetal1 */
|
2381
|
+
parity_at_1NM = e_half_stereo_bond_parity( at, at_1, z_dir1NM, &bOnlyNM,
|
2382
|
+
bPointedEdgeStereo, pStereo );
|
2383
|
+
if ( RETURNED_ERROR(parity_at_1NM) ) {
|
2384
|
+
return CT_CALC_STEREO_ERR;
|
2385
|
+
}
|
2386
|
+
parity_at_1NM = abs(parity_at_1NM);
|
2387
|
+
/*
|
2388
|
+
if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && !ATOM_PARITY_WELL_DEF(parity_at_1) ) {
|
2389
|
+
memcpy( z_dir1, z_dir1NM, sizeof(z_dir1) );
|
2390
|
+
}
|
2391
|
+
*/
|
2392
|
+
if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && ATOM_PARITY_WELL_DEF(parity_at_1) &&
|
2393
|
+
0 <= i_ord_LastMetal1 ) {
|
2394
|
+
if ( 1 == i_ord_LastMetal1 % 2 && parity_at_1NM == parity_at_1 ||
|
2395
|
+
0 == i_ord_LastMetal1 % 2 && parity_at_1NM != parity_at_1 ) {
|
2396
|
+
/* abnormal geometry: all bonds in a sector < 180 degrees */
|
2397
|
+
/*parity_at_1NM = 3 - parity_at_1;*/
|
2398
|
+
bAnomaly1NM = 1;
|
2399
|
+
} else {
|
2400
|
+
parity_at_1 = parity_at_1NM;
|
2401
|
+
bOnlyNM1 = 1;
|
2402
|
+
}
|
2403
|
+
} else
|
2404
|
+
if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && !ATOM_PARITY_WELL_DEF(parity_at_1) &&
|
2405
|
+
0 <= i_ord_LastMetal1 ) {
|
2406
|
+
bAnomaly1NM = 1; /* 2005-02-01 force atom parity from non-metal neighbors */
|
2407
|
+
}
|
2408
|
+
|
2409
|
+
}
|
2410
|
+
|
2411
|
+
if ( bOnlyNM2 ) {
|
2412
|
+
parity_at_2NM = parity_at_2;
|
2413
|
+
memcpy( z_dir2NM, z_dir2, sizeof(z_dir2NM) );
|
2414
|
+
parity_at_2 = INCHI_PARITY_NONE;
|
2415
|
+
} else
|
2416
|
+
if ( at[at_2].num_bonds == e_nNumNonMetalNeigh( at, at_2, pStereo, &i_ord_LastMetal2 ) ) {
|
2417
|
+
memcpy( z_dir2NM, z_dir2, sizeof(z_dir2NM) );
|
2418
|
+
parity_at_2NM = parity_at_2; /* no metal bond present */
|
2419
|
+
} else {
|
2420
|
+
bOnlyNM = 1;
|
2421
|
+
parity_at_2NM = e_half_stereo_bond_parity( at, at_2, z_dir2NM, &bOnlyNM,
|
2422
|
+
bPointedEdgeStereo, pStereo );
|
2423
|
+
if ( RETURNED_ERROR(parity_at_2NM) ) {
|
2424
|
+
return CT_CALC_STEREO_ERR;
|
2425
|
+
}
|
2426
|
+
parity_at_2NM = abs(parity_at_2NM);
|
2427
|
+
if ( ATOM_PARITY_WELL_DEF(parity_at_2NM) && ATOM_PARITY_WELL_DEF(parity_at_2) &&
|
2428
|
+
0 <= i_ord_LastMetal2 ) {
|
2429
|
+
if ( 1 == i_ord_LastMetal2 % 2 && parity_at_2NM == parity_at_2 ||
|
2430
|
+
0 == i_ord_LastMetal2 % 2 && parity_at_2NM != parity_at_2 ) {
|
2431
|
+
/* abnormal geometry: all bonds in a sector < 180 degrees */
|
2432
|
+
/*parity_at_2NM = 3 - parity_at_2;*/
|
2433
|
+
bAnomaly2NM = 1;
|
2434
|
+
} else {
|
2435
|
+
parity_at_2 = parity_at_2NM;
|
2436
|
+
bOnlyNM2 = 1;
|
2437
|
+
}
|
2438
|
+
} else
|
2439
|
+
if ( ATOM_PARITY_WELL_DEF(parity_at_2NM) && !ATOM_PARITY_WELL_DEF(parity_at_2) &&
|
2440
|
+
0 <= i_ord_LastMetal2 ) {
|
2441
|
+
bAnomaly2NM = 1; /* 2005-02-01 force atom parity from non-metal neighbors */
|
2442
|
+
}
|
2443
|
+
}
|
2444
|
+
/* make both atoms have non-metal neighbors only */
|
2445
|
+
if ( (bOnlyNM1 || bAnomaly1NM) && ATOM_PARITY_WELL_DEF(parity_at_1NM) &&
|
2446
|
+
!(bOnlyNM2 || bAnomaly2NM) && ATOM_PARITY_WELL_DEF(parity_at_2NM) &&
|
2447
|
+
0 <= i_ord_LastMetal2 ) {
|
2448
|
+
|
2449
|
+
bAnomaly2NM = 1;
|
2450
|
+
parity_at_2NM = 2 - (parity_at_2NM + i_ord_LastMetal2) % 2;
|
2451
|
+
} else
|
2452
|
+
if ( !(bOnlyNM1 || bAnomaly1NM) && ATOM_PARITY_WELL_DEF(parity_at_1NM) &&
|
2453
|
+
(bOnlyNM2 || bAnomaly2NM) && ATOM_PARITY_WELL_DEF(parity_at_2NM) &&
|
2454
|
+
0 <= i_ord_LastMetal1 ) {
|
2455
|
+
|
2456
|
+
bAnomaly1NM = 1;
|
2457
|
+
parity_at_1NM = 2 - (parity_at_1NM + i_ord_LastMetal1) % 2;
|
2458
|
+
}
|
2459
|
+
|
2460
|
+
/* consistency */
|
2461
|
+
if ( parity_at_1 == INCHI_PARITY_NONE || parity_at_2 == INCHI_PARITY_NONE ) {
|
2462
|
+
parity_at_1 = parity_at_2 = INCHI_PARITY_NONE; /* =zero */
|
2463
|
+
} else {
|
2464
|
+
switch( !ATOM_PARITY_WELL_DEF( parity_at_1 ) + 2*!ATOM_PARITY_WELL_DEF( parity_at_2 ) ) {
|
2465
|
+
case 1:
|
2466
|
+
parity_at_2 = parity_at_1; /* set both to not-well-def */
|
2467
|
+
break;
|
2468
|
+
case 2:
|
2469
|
+
parity_at_1 = parity_at_2; /* set both to not-well-def */
|
2470
|
+
break;
|
2471
|
+
case 3:
|
2472
|
+
parity_at_1 = parity_at_2 = inchi_min(parity_at_1, parity_at_2);
|
2473
|
+
break;
|
2474
|
+
}
|
2475
|
+
}
|
2476
|
+
|
2477
|
+
if ( parity_at_1NM == INCHI_PARITY_NONE || parity_at_2NM == INCHI_PARITY_NONE ) {
|
2478
|
+
parity_at_1NM = parity_at_2NM = INCHI_PARITY_NONE; /* =zero */
|
2479
|
+
} else {
|
2480
|
+
switch( !ATOM_PARITY_WELL_DEF( parity_at_1NM ) + 2*!ATOM_PARITY_WELL_DEF( parity_at_2NM ) ) {
|
2481
|
+
case 1:
|
2482
|
+
parity_at_2NM = parity_at_1NM; /* set both to not-well-def */
|
2483
|
+
break;
|
2484
|
+
case 2:
|
2485
|
+
parity_at_1NM = parity_at_2NM; /* set both to not-well-def */
|
2486
|
+
break;
|
2487
|
+
case 3:
|
2488
|
+
parity_at_1NM = parity_at_2NM = inchi_min(parity_at_1NM, parity_at_2NM);
|
2489
|
+
break;
|
2490
|
+
}
|
2491
|
+
}
|
2492
|
+
if ( parity_at_1 != INCHI_PARITY_NONE && parity_at_1NM == INCHI_PARITY_NONE ) {
|
2493
|
+
parity_at_1NM = parity_at_2NM = INCHI_PARITY_UNDEFINED;
|
2494
|
+
} else
|
2495
|
+
if ( parity_at_1 == INCHI_PARITY_NONE && parity_at_1NM != INCHI_PARITY_NONE ) {
|
2496
|
+
parity_at_1 = parity_at_2 = INCHI_PARITY_UNDEFINED;
|
2497
|
+
}
|
2498
|
+
|
2499
|
+
|
2500
|
+
|
2501
|
+
if ( (parity_at_1 == INCHI_PARITY_UNDEFINED || parity_at_1 == INCHI_PARITY_NONE) &&
|
2502
|
+
(parity_at_1NM == INCHI_PARITY_UNDEFINED || parity_at_1NM == INCHI_PARITY_NONE) ) {
|
2503
|
+
continue;
|
2504
|
+
}
|
2505
|
+
}
|
2506
|
+
parity_at_1 = e_FixSb0DParities( at, pStereo, cur_chain_length, at_middle,
|
2507
|
+
at_1, i_next_at_1, z_dir1, z_dir1NM, bOnlyNM1, bAnomaly1NM, parity_at_1, parity_at_1NM,
|
2508
|
+
at_2, i_next_at_2, z_dir2, z_dir2NM, bOnlyNM2, bAnomaly2NM, parity_at_2, parity_at_2NM);
|
2509
|
+
num_stored_stereo_bonds += (parity_at_1 != 0);
|
2510
|
+
|
2511
|
+
}
|
2512
|
+
return num_stored_stereo_bonds;
|
2513
|
+
}
|
2514
|
+
|
2515
|
+
|
2516
|
+
/***************************************************************
|
2517
|
+
* Get stereo atom parity for the current order of attachments
|
2518
|
+
* The result in at[cur_at].parity is valid for previously removed
|
2519
|
+
* explicit hydrogen atoms, including isotopic ones, that are located in at_removed_H[]
|
2520
|
+
* The return value is a calculated parity.
|
2521
|
+
*/
|
2522
|
+
#define ADD_EXPLICIT_HYDROGEN_NEIGH 1
|
2523
|
+
#define ADD_EXPLICIT_LONE_PAIR_NEIGH 2
|
2524
|
+
int e_set_stereo_atom_parity( Stereo0D *pStereo, inchi_Atom *at, int cur_at, int bPointedEdgeStereo )
|
2525
|
+
{
|
2526
|
+
int j, k, next_at, num_z, j1, nType, num_eH, num_iH, tot_num_iso_H, nMustHaveNumNeigh, bAmbiguousStereo;
|
2527
|
+
double z, sum_xyz[3], min_sine, triple_product;
|
2528
|
+
double at_coord[MAX_NUM_STEREO_ATOM_NEIGH][3];
|
2529
|
+
double bond_len_xy[4], rmax, rmin;
|
2530
|
+
double at_coord_center[3];
|
2531
|
+
int parity, out_parity, out_stereo_atom_parity, bAmbiguous = 0, bAddExplicitNeighbor = 0;
|
2532
|
+
int b2D = 0, n2DTetrahedralAmbiguity = 0;
|
2533
|
+
AT_NUM nSbNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
|
2534
|
+
S_CHAR num_iso_eH[NUM_H_ISOTOPES+1]; /* count explicit H */
|
2535
|
+
|
2536
|
+
out_parity = out_stereo_atom_parity = INCHI_PARITY_NONE;
|
2537
|
+
parity = INCHI_PARITY_NONE;
|
2538
|
+
bAmbiguousStereo = 0;
|
2539
|
+
memset(num_iso_eH, 0, sizeof(num_iso_eH));
|
2540
|
+
num_eH = 0; /* number of explicit H -- will be found later */
|
2541
|
+
num_iH = inchi_NUMH2(at,cur_at); /* implicit H */
|
2542
|
+
|
2543
|
+
if ( !(nMustHaveNumNeigh = e_bCanInpAtomBeAStereoCenter( cur_at, pStereo->cAtType ) ) ||
|
2544
|
+
num_iH > NUM_H_ISOTOPES
|
2545
|
+
) {
|
2546
|
+
goto exit_function;
|
2547
|
+
}
|
2548
|
+
/* find explicit terminal H */
|
2549
|
+
memset(num_iso_eH, 0, sizeof(num_iso_eH));
|
2550
|
+
for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
|
2551
|
+
next_at = at[cur_at].neighbor[j];
|
2552
|
+
switch(pStereo->cAtType[next_at] ) {
|
2553
|
+
case AtType_TermH:
|
2554
|
+
if ( 0 <= at[next_at].isotopic_mass && at[next_at].isotopic_mass <= NUM_H_ISOTOPES ) {
|
2555
|
+
num_iso_eH[at[next_at].isotopic_mass] ++;
|
2556
|
+
} else {
|
2557
|
+
num_iso_eH[0] ++;
|
2558
|
+
}
|
2559
|
+
num_eH ++;
|
2560
|
+
break;
|
2561
|
+
case AtType_TermD:
|
2562
|
+
num_iso_eH[2] ++;
|
2563
|
+
num_eH ++;
|
2564
|
+
break;
|
2565
|
+
case AtType_TermT:
|
2566
|
+
num_iso_eH[3] ++;
|
2567
|
+
num_eH ++;
|
2568
|
+
break;
|
2569
|
+
}
|
2570
|
+
}
|
2571
|
+
|
2572
|
+
/* numbers of isotopic H atoms */
|
2573
|
+
for ( j = 0, tot_num_iso_H = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
2574
|
+
if ( at[cur_at].num_iso_H[j+1] + num_iso_eH[j+1] > 1 ) {
|
2575
|
+
goto exit_function; /* two or more identical hydrogen isotopic neighbors */
|
2576
|
+
}
|
2577
|
+
tot_num_iso_H += at[cur_at].num_iso_H[j+1] + num_iso_eH[j+1];
|
2578
|
+
}
|
2579
|
+
|
2580
|
+
/* number of non-isotopic H atoms */
|
2581
|
+
if ( inchi_NUMH2(at,cur_at) + num_eH - tot_num_iso_H > 1 ) {
|
2582
|
+
goto exit_function; /* two or more identical hydrogen non-isotopic neighbors */
|
2583
|
+
}
|
2584
|
+
|
2585
|
+
/* coordinates initialization */
|
2586
|
+
num_z = 0;
|
2587
|
+
sum_xyz[0] = sum_xyz[1] = sum_xyz[2] = 0.0;
|
2588
|
+
|
2589
|
+
at_coord_center[0] =
|
2590
|
+
at_coord_center[1] =
|
2591
|
+
at_coord_center[2] = 0.0;
|
2592
|
+
|
2593
|
+
/* fill out stereo center neighbors coordinates */
|
2594
|
+
/* and obtain the parity from the geometry */
|
2595
|
+
|
2596
|
+
/* add all coordinates of other neighboring atoms */
|
2597
|
+
for ( j = j1 = 0; j < at[cur_at].num_bonds; j ++, j1 ++ ) {
|
2598
|
+
next_at = at[cur_at].neighbor[j];
|
2599
|
+
z = e_get_z_coord( at, cur_at, j, &nType, bPointedEdgeStereo );
|
2600
|
+
switch ( nType ) {
|
2601
|
+
case ZTYPE_EITHER:
|
2602
|
+
parity = INCHI_PARITY_UNKNOWN; /* unknown parity: bond in "Either" direction. */
|
2603
|
+
goto exit_function;
|
2604
|
+
case ZTYPE_UP:
|
2605
|
+
case ZTYPE_DOWN:
|
2606
|
+
b2D ++;
|
2607
|
+
case ZTYPE_3D:
|
2608
|
+
num_z ++;
|
2609
|
+
}
|
2610
|
+
|
2611
|
+
nSbNeighOrigAtNumb[j1] = next_at+1;
|
2612
|
+
at_coord[j1][0] = at[next_at].x-at[cur_at].x;
|
2613
|
+
at_coord[j1][1] = at[next_at].y-at[cur_at].y;
|
2614
|
+
bond_len_xy[j1] = e_len2(at_coord[j1]);
|
2615
|
+
at_coord[j1][2] = (nType==ZTYPE_3D? z :
|
2616
|
+
nType==ZTYPE_UP? bond_len_xy[j1] :
|
2617
|
+
nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
|
2618
|
+
}
|
2619
|
+
/* j1 is the number of explicit neighbors (that is, all neighbors except implicit H) */
|
2620
|
+
|
2621
|
+
b2D = (b2D == num_z && num_z); /* 1 => two-dimensional */
|
2622
|
+
|
2623
|
+
if ( MAX_NUM_STEREO_ATOM_NEIGH != at[cur_at].num_bonds+num_iH &&
|
2624
|
+
MAX_NUM_STEREO_ATOM_NEIGH-1 != at[cur_at].num_bonds+num_iH ) {
|
2625
|
+
/* not enough geometry data to find the central atom parity */
|
2626
|
+
goto exit_function;
|
2627
|
+
}
|
2628
|
+
/* make all vector lengths equal to 1; exit if too short. 9-10-2002 */
|
2629
|
+
for ( j = 0; j < j1; j ++ ) {
|
2630
|
+
z = e_len3( at_coord[j] );
|
2631
|
+
if ( z < MIN_BOND_LEN ) {
|
2632
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2633
|
+
goto exit_function;
|
2634
|
+
}
|
2635
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
2636
|
+
else {
|
2637
|
+
e_mult3( at_coord[j], 1.0/z, at_coord[j] );
|
2638
|
+
}
|
2639
|
+
#endif
|
2640
|
+
rmax = j? inchi_max( rmax, z) : z;
|
2641
|
+
rmin = j? inchi_min( rmin, z) : z;
|
2642
|
+
}
|
2643
|
+
if ( rmin / rmax < MIN_SINE ) {
|
2644
|
+
/* bond ratio is too small */
|
2645
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2646
|
+
goto exit_function;
|
2647
|
+
}
|
2648
|
+
for ( j = 0; j < j1; j ++ ) {
|
2649
|
+
e_add3( sum_xyz, at_coord[j], sum_xyz );
|
2650
|
+
}
|
2651
|
+
|
2652
|
+
|
2653
|
+
|
2654
|
+
/* here j1 is a number of neighbors including explicit terminal isotopic H */
|
2655
|
+
/* num_iso_eH[0] = number of explicit non-isotopic hydrogen atom neighbors */
|
2656
|
+
j = j1;
|
2657
|
+
/* Add Explicit Neighbor */
|
2658
|
+
if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2659
|
+
/* add an explicit neighbor if possible */
|
2660
|
+
if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2661
|
+
bAddExplicitNeighbor = ADD_EXPLICIT_LONE_PAIR_NEIGH;
|
2662
|
+
} else
|
2663
|
+
if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH ) {
|
2664
|
+
/* check whether an explicit non-isotopic hydrogen can be added */
|
2665
|
+
/* to an atom that is a stereogenic atom */
|
2666
|
+
bAddExplicitNeighbor = ADD_EXPLICIT_HYDROGEN_NEIGH;
|
2667
|
+
}
|
2668
|
+
}
|
2669
|
+
|
2670
|
+
if ( bAddExplicitNeighbor ) {
|
2671
|
+
/***********************************************************
|
2672
|
+
* May happen only if (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1)
|
2673
|
+
* 3 neighbors only, no H-neighbors. Create and add coordinates of an implicit H
|
2674
|
+
* or a fake 4th neighbor, that is, a lone pair
|
2675
|
+
*/
|
2676
|
+
if ( parity == INCHI_PARITY_UNKNOWN ) {
|
2677
|
+
goto exit_function; /* the user insists the parity is unknown and the isotopic */
|
2678
|
+
/* composition of the neighbors does not contradict */
|
2679
|
+
} else
|
2680
|
+
if ( num_z == 0 || are_3_vect_in_one_plane(at_coord, MIN_SINE) ) {
|
2681
|
+
/* "hydrogen down" rule is needed to resolve an ambiguity */
|
2682
|
+
if ( num_z > 0 ) {
|
2683
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
2684
|
+
}
|
2685
|
+
#if( APPLY_IMPLICIT_H_DOWN_RULE == 1 ) /* { */
|
2686
|
+
/* Although H should be at the top of the list, add it to the bottom. */
|
2687
|
+
/* This will be taken care of later by inverting parity 1<->2 */
|
2688
|
+
at_coord[j][0] = 0.0;
|
2689
|
+
at_coord[j][1] = 0.0;
|
2690
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
2691
|
+
at_coord[j][2] = -1.0;
|
2692
|
+
#else
|
2693
|
+
at_coord[j][2] = -(bond_len_xy[0]+bond_len_xy[1]+bond_len_xy[2])/3.0;
|
2694
|
+
#endif
|
2695
|
+
#else /* } APPLY_IMPLICIT_H_DOWN_RULE { */
|
2696
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
2697
|
+
parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
2698
|
+
#else
|
2699
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2700
|
+
#endif
|
2701
|
+
goto exit_function;
|
2702
|
+
#endif /* } APPLY_IMPLICIT_H_DOWN_RULE */
|
2703
|
+
} else {
|
2704
|
+
/* we have enough information to find implicit hydrogen coordinates */
|
2705
|
+
e_copy3( sum_xyz, at_coord[j] );
|
2706
|
+
e_change_sign3( at_coord[j], at_coord[j] );
|
2707
|
+
z = e_len3( at_coord[j] );
|
2708
|
+
rmax = inchi_max( rmax, z );
|
2709
|
+
rmin = inchi_min( rmin, z );
|
2710
|
+
if ( z < MIN_BOND_LEN || rmin/rmax < MIN_SINE ) {
|
2711
|
+
/* the new 4th bond is too short */
|
2712
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2713
|
+
goto exit_function;
|
2714
|
+
}
|
2715
|
+
#if( STEREO_CENTER_BOND4_NORM == 1 )
|
2716
|
+
else {
|
2717
|
+
e_mult3( at_coord[j], 1.0/z, at_coord[j] );
|
2718
|
+
}
|
2719
|
+
#endif
|
2720
|
+
}
|
2721
|
+
} else
|
2722
|
+
if ( j1 != MAX_NUM_STEREO_ATOM_NEIGH ) {
|
2723
|
+
if ( parity == INCHI_PARITY_UNKNOWN ) {
|
2724
|
+
parity = -INCHI_PARITY_UNDEFINED; /* isotopic composition of H-neighbors contradicts 'unknown' */
|
2725
|
+
}
|
2726
|
+
goto exit_function;
|
2727
|
+
} else /* j1 == MAX_NUM_STEREO_ATOM_NEIGH */
|
2728
|
+
if ( num_z == 0 || e_are_4at_in_one_plane(at_coord, MIN_SINE) ) {
|
2729
|
+
/* all four neighours in xy plane: undefined geometry. */
|
2730
|
+
if ( num_z > 0 ) {
|
2731
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
2732
|
+
}
|
2733
|
+
if ( parity != INCHI_PARITY_UNKNOWN ) {
|
2734
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
2735
|
+
parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
2736
|
+
#else
|
2737
|
+
/* all 4 bonds are in one plain */
|
2738
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2739
|
+
#endif
|
2740
|
+
}
|
2741
|
+
goto exit_function;
|
2742
|
+
}
|
2743
|
+
/***********************************************************
|
2744
|
+
* At this point we have 4 neighboring atoms.
|
2745
|
+
* check for tetrahedral ambiguity in 2D case
|
2746
|
+
*/
|
2747
|
+
if ( b2D ) {
|
2748
|
+
if ( 0 < (n2DTetrahedralAmbiguity = e_Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor )) ) {
|
2749
|
+
if ( T2D_WARN & n2DTetrahedralAmbiguity ) {
|
2750
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
2751
|
+
}
|
2752
|
+
if ( T2D_UNDF & n2DTetrahedralAmbiguity ) {
|
2753
|
+
if ( parity != INCHI_PARITY_UNKNOWN ) {
|
2754
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
2755
|
+
parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
2756
|
+
#else
|
2757
|
+
parity = INCHI_PARITY_UNDEFINED; /* no parity */
|
2758
|
+
#endif
|
2759
|
+
}
|
2760
|
+
goto exit_function;
|
2761
|
+
}
|
2762
|
+
} else
|
2763
|
+
if ( n2DTetrahedralAmbiguity < 0 ) {
|
2764
|
+
bAmbiguous |= AMBIGUOUS_STEREO_ERROR; /* error */
|
2765
|
+
parity = INCHI_PARITY_UNDEFINED;
|
2766
|
+
goto exit_function;
|
2767
|
+
}
|
2768
|
+
}
|
2769
|
+
|
2770
|
+
/************************************************************/
|
2771
|
+
/* Move coordinates origin to the neighbor #0 */
|
2772
|
+
for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
|
2773
|
+
e_diff3(at_coord[j], at_coord[0], at_coord[j]);
|
2774
|
+
}
|
2775
|
+
e_diff3(at_coord_center, at_coord[0], at_coord_center);
|
2776
|
+
|
2777
|
+
/********************************************************
|
2778
|
+
* find the central (cur_at) atom's parity
|
2779
|
+
* (orientation of atoms #1-3 when looking from #0)
|
2780
|
+
********************************************************/
|
2781
|
+
triple_product = e_triple_prod_and_min_abs_sine2(&at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous);
|
2782
|
+
if ( fabs(triple_product) > ZERO_FLOAT && (min_sine > MIN_SINE || fabs(min_sine) > ZERO_FLOAT && (n2DTetrahedralAmbiguity & T2D_OKAY ) ) ) {
|
2783
|
+
/* Even => sorted in correct order, Odd=>transposed */
|
2784
|
+
parity = triple_product > 0.0? INCHI_PARITY_EVEN : INCHI_PARITY_ODD;
|
2785
|
+
|
2786
|
+
/* for 4 attached atoms, moving the implicit H from index=3 to index=0 */
|
2787
|
+
/* can be done in odd number (3) transpositions: (23)(12)(01), which inverts the parity */
|
2788
|
+
if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2789
|
+
parity = 3 - parity;
|
2790
|
+
}
|
2791
|
+
} else {
|
2792
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
2793
|
+
parity = AT_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
2794
|
+
#else
|
2795
|
+
if ( num_z > 0 ) {
|
2796
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
2797
|
+
}
|
2798
|
+
parity = INCHI_PARITY_UNDEFINED; /* no parity: 4 bonds are in one plane. */
|
2799
|
+
#endif
|
2800
|
+
}
|
2801
|
+
exit_function:
|
2802
|
+
|
2803
|
+
if ( parity ) {
|
2804
|
+
bAmbiguousStereo |= bAmbiguous;
|
2805
|
+
}
|
2806
|
+
/* isotopic parity => parity */
|
2807
|
+
if ( parity < 0 )
|
2808
|
+
parity = -parity;
|
2809
|
+
|
2810
|
+
if ( 0 < parity && parity < INCHI_PARITY_UNDEFINED ) {
|
2811
|
+
inchi_Stereo0D *stereo0D;
|
2812
|
+
if ( stereo0D = e_GetNewStereo( pStereo ) ) {
|
2813
|
+
stereo0D->central_atom = cur_at;
|
2814
|
+
stereo0D->parity = parity;
|
2815
|
+
stereo0D->type = INCHI_StereoType_Tetrahedral;
|
2816
|
+
k = 0;
|
2817
|
+
if ( at[cur_at].num_bonds == 3 ) {
|
2818
|
+
stereo0D->neighbor[k++] = cur_at;
|
2819
|
+
}
|
2820
|
+
for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
|
2821
|
+
stereo0D->neighbor[k++] = at[cur_at].neighbor[j];
|
2822
|
+
}
|
2823
|
+
}
|
2824
|
+
}
|
2825
|
+
return parity;
|
2826
|
+
|
2827
|
+
}
|
2828
|
+
#undef ADD_EXPLICIT_HYDROGEN_NEIGH
|
2829
|
+
#undef ADD_EXPLICIT_LONE_PAIR_NEIGH
|
2830
|
+
|
2831
|
+
/*************************************************************/
|
2832
|
+
inchi_Stereo0D *e_GetNewStereo( Stereo0D *pStereo )
|
2833
|
+
{
|
2834
|
+
#define DEFAULT_0D_STEREO_DELTA 64
|
2835
|
+
int delta = pStereo->delta_num_stereo0D > 0? pStereo->delta_num_stereo0D : DEFAULT_0D_STEREO_DELTA;
|
2836
|
+
if ( pStereo->num_stereo0D >= pStereo->max_num_Stereo0D ) {
|
2837
|
+
/*inchi_Stereo0D *pNew = (inchi_Stereo0D *)e_inchi_calloc( pStereo->max_num_Stereo0D + delta, sizeof(pNew[0]) );*/
|
2838
|
+
inchi_Stereo0D *pNew = e_CreateInchi_Stereo0D( pStereo->max_num_Stereo0D + delta );
|
2839
|
+
if ( pNew ) {
|
2840
|
+
if ( pStereo->num_stereo0D > 0 ) {
|
2841
|
+
memcpy( pNew, pStereo->stereo0D, pStereo->num_stereo0D * sizeof(pNew[0]) );
|
2842
|
+
}
|
2843
|
+
/*e_inchi_free(pStereo->stereo0D);*/
|
2844
|
+
e_FreeInchi_Stereo0D( &pStereo->stereo0D );
|
2845
|
+
pStereo->stereo0D = pNew;
|
2846
|
+
pStereo->max_num_Stereo0D += delta;
|
2847
|
+
}
|
2848
|
+
}
|
2849
|
+
return pStereo->stereo0D + pStereo->num_stereo0D ++;
|
2850
|
+
#undef DEFAULT_0D_STEREO_DELTA
|
2851
|
+
}
|
2852
|
+
|
2853
|
+
/*************************************************************/
|
2854
|
+
int set_0D_stereo_parities( inchi_Input *pInp, int bPointedEdgeStereo )
|
2855
|
+
{
|
2856
|
+
int num_3D_stereo_atoms=0, num_stereo_bonds=0;
|
2857
|
+
|
2858
|
+
int i, is_stereo, num_stereo;
|
2859
|
+
inchi_Atom* at = pInp->atom;
|
2860
|
+
int num_at = pInp->num_atoms;
|
2861
|
+
Stereo0D stereo;
|
2862
|
+
Stereo0D *pStereo = &stereo;
|
2863
|
+
|
2864
|
+
/**********************************************************
|
2865
|
+
*
|
2866
|
+
* Note: this parity reflects only relative positions of
|
2867
|
+
* the atoms-neighbors and their ordering in the
|
2868
|
+
* lists of neighbors.
|
2869
|
+
*
|
2870
|
+
* To obtain the actual parity, the parity of a number
|
2871
|
+
* of neighbors transpositions (to obtain a sorted
|
2872
|
+
* list of numbers assigned to the atoms) should be
|
2873
|
+
* added.
|
2874
|
+
*
|
2875
|
+
**********************************************************/
|
2876
|
+
|
2877
|
+
/*********************************************************************************
|
2878
|
+
|
2879
|
+
An example of parity=1 for stereogenic center, tetrahedral asymmetric atom
|
2880
|
+
|
2881
|
+
|
2882
|
+
|
2883
|
+
(1)
|
2884
|
+
|
|
2885
|
+
|
|
2886
|
+
[C] |
|
2887
|
+
|
|
2888
|
+
(2)------(0)
|
2889
|
+
/
|
2890
|
+
/
|
2891
|
+
/
|
2892
|
+
/
|
2893
|
+
(3)
|
2894
|
+
|
2895
|
+
|
2896
|
+
Notation: (n) is a tetrahedral atom neighbor; n is an index of a neighbor in
|
2897
|
+
the central_at->neighbor[] array : neighbor atom number is central_at->neighbor[n].
|
2898
|
+
|
2899
|
+
(0)-(1), (0)-(2), (0)-(3) are lines connecting atom [C] neighbors to neighbor (0)
|
2900
|
+
(0), (1) and (2) are in the plane
|
2901
|
+
(0)-(3) is directed from the plain to the viewer
|
2902
|
+
[C] is somewhere between (0), (1), (2), (3)
|
2903
|
+
Since (1)-(2)-(3) are in a clockwise order when looking from (0), parity is 2, or even;
|
2904
|
+
otherwise parity would be 1, or odd.
|
2905
|
+
|
2906
|
+
**********************************************************************************
|
2907
|
+
|
2908
|
+
Examples of a stereogenic bond.
|
2909
|
+
|
2910
|
+
Notation: [atom number], (index of a neighbor):
|
2911
|
+
[1] and [2] are atoms connected by the stereogenic bond
|
2912
|
+
numbers in () are indexes of neighbors of [1] or [2].
|
2913
|
+
(12 x 16)z = z-component of [1]-[2] and [1]-[6] cross-product
|
2914
|
+
|
2915
|
+
atom [1] atom [2]
|
2916
|
+
[8] [4] prod01 = (12 x 16)z < 0 prod01 = (21 x 24)z < 0
|
2917
|
+
\ / prod02 = (12 x 18)z > 0 prod02 = (21 x 25)z > 0
|
2918
|
+
(2) (1) 0 transpositions because 0 transpositions because
|
2919
|
+
\ / double bond is in 0 posit. double bond is in 0 position
|
2920
|
+
[1]==(0)(0)==[2] 0 = (prod01 > prod02) 0 = (prod01 > prod02)
|
2921
|
+
/ \
|
2922
|
+
(1) (2) result: parity = 2, even result: parity=2, even
|
2923
|
+
/ \
|
2924
|
+
[6] [5]
|
2925
|
+
|
2926
|
+
|
2927
|
+
|
2928
|
+
atom [1] atom [2]
|
2929
|
+
[8] [5] prod01 = (12 x 18)z > 0 prod01 = (21 x 24)z > 0
|
2930
|
+
\ / prod02 = (12 x 16)z < 0 prod02 = (21 x 25)z < 0
|
2931
|
+
(0) (2) 2 transpositions to move 1 transposition to move
|
2932
|
+
\ / at [2] from 2 to 0 pos. at [1] from 1 to 0 position
|
2933
|
+
[1]==(2)(1)==[2] 1 = (prod01 > prod02) 1 = (prod01 > prod02)
|
2934
|
+
/ \
|
2935
|
+
(1) (0) result: parity = (1+2) result: parity=(1+1)
|
2936
|
+
/ \ 2-(1+2)%2 = 1, odd 2-(1+1)%2 = 2, even
|
2937
|
+
[6] [4]
|
2938
|
+
|
2939
|
+
|
2940
|
+
***********************************************************************************
|
2941
|
+
Note: atoms' numbers [1], [2], [4],... are not used to calculate parity at this
|
2942
|
+
point. They will be used for each numbering in the canonicalization.
|
2943
|
+
Note: parity=3 for a stereo atom means entered undefined bond direction
|
2944
|
+
parity=4 for an atom means parity cannot be determined from the given geometry
|
2945
|
+
***********************************************************************************/
|
2946
|
+
|
2947
|
+
if ( !at ) {
|
2948
|
+
return -1;
|
2949
|
+
}
|
2950
|
+
|
2951
|
+
/* clear stereo descriptors */
|
2952
|
+
memset( pStereo, 0, sizeof(*pStereo) );
|
2953
|
+
pStereo->delta_num_stereo0D = num_at;
|
2954
|
+
pStereo->cAtType = (S_CHAR *)e_inchi_calloc( num_at, sizeof(pStereo->cAtType[0]) );
|
2955
|
+
if (!pStereo->cAtType ) {
|
2956
|
+
return -1;
|
2957
|
+
}
|
2958
|
+
/* atom stereo types */
|
2959
|
+
for ( i = 0; i < num_at; i ++ ) {
|
2960
|
+
pStereo->cAtType[i] = e_GetElType( at, i );
|
2961
|
+
}
|
2962
|
+
|
2963
|
+
|
2964
|
+
|
2965
|
+
/* calculate stereo descriptors */
|
2966
|
+
/* main cycle: set stereo parities */
|
2967
|
+
for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
|
2968
|
+
|
2969
|
+
if ( is_stereo = e_set_stereo_atom_parity( pStereo, at, i, bPointedEdgeStereo ) ) {
|
2970
|
+
num_3D_stereo_atoms += ATOM_PARITY_WELL_DEF( is_stereo );
|
2971
|
+
num_stereo += ATOM_PARITY_WELL_DEF( is_stereo );
|
2972
|
+
} else {
|
2973
|
+
is_stereo = e_set_stereo_bonds_parity( pStereo, at, i, bPointedEdgeStereo );
|
2974
|
+
if ( RETURNED_ERROR( is_stereo ) ) {
|
2975
|
+
num_3D_stereo_atoms = is_stereo;
|
2976
|
+
is_stereo = 0;
|
2977
|
+
break;
|
2978
|
+
} else {
|
2979
|
+
num_stereo_bonds += is_stereo;
|
2980
|
+
num_stereo += is_stereo;
|
2981
|
+
}
|
2982
|
+
}
|
2983
|
+
}
|
2984
|
+
/*
|
2985
|
+
if ( (nMode & REQ_MODE_SC_IGN_ALL_UU )
|
2986
|
+
REQ_MODE_SC_IGN_ALL_UU
|
2987
|
+
REQ_MODE_SB_IGN_ALL_UU
|
2988
|
+
*/
|
2989
|
+
if ( pStereo->cAtType ) {
|
2990
|
+
e_inchi_free( pStereo->cAtType );
|
2991
|
+
}
|
2992
|
+
if ( pInp->stereo0D ) {
|
2993
|
+
}
|
2994
|
+
|
2995
|
+
pInp->stereo0D = pStereo->stereo0D;
|
2996
|
+
pInp->num_stereo0D = pStereo->num_stereo0D;
|
2997
|
+
|
2998
|
+
return RETURNED_ERROR( num_3D_stereo_atoms )? num_3D_stereo_atoms : num_stereo;
|
2999
|
+
}
|
3000
|
+
/*****************************************************************/
|
3001
|
+
int Clear3D2Dstereo(inchi_Input *pInp)
|
3002
|
+
{
|
3003
|
+
int i;
|
3004
|
+
if ( !pInp->atom || !pInp->num_atoms )
|
3005
|
+
return 0;
|
3006
|
+
for ( i = 0; i < pInp->num_atoms; i ++ ) {
|
3007
|
+
pInp->atom[i].x =
|
3008
|
+
pInp->atom[i].y =
|
3009
|
+
pInp->atom[i].z = 0.0;
|
3010
|
+
memset( pInp->atom[i].bond_stereo, 0, sizeof(pInp->atom[i].bond_stereo) );
|
3011
|
+
}
|
3012
|
+
return 1;
|
3013
|
+
}
|
3014
|
+
|