rino 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +44 -0
- data/Rakefile +123 -0
- data/ext/extconf.rb +26 -0
- data/ext/ruby_inchi_main.so +0 -0
- data/ext/src/aux2atom.h +2786 -0
- data/ext/src/comdef.h +148 -0
- data/ext/src/e_0dstereo.c +3014 -0
- data/ext/src/e_0dstereo.h +31 -0
- data/ext/src/e_comdef.h +57 -0
- data/ext/src/e_ctl_data.h +147 -0
- data/ext/src/e_ichi_io.c +498 -0
- data/ext/src/e_ichi_io.h +40 -0
- data/ext/src/e_ichi_parms.c +37 -0
- data/ext/src/e_ichi_parms.h +41 -0
- data/ext/src/e_ichicomp.h +50 -0
- data/ext/src/e_ichierr.h +40 -0
- data/ext/src/e_ichimain.c +593 -0
- data/ext/src/e_ichisize.h +43 -0
- data/ext/src/e_inchi_atom.c +75 -0
- data/ext/src/e_inchi_atom.h +33 -0
- data/ext/src/e_inpdef.h +41 -0
- data/ext/src/e_mode.h +706 -0
- data/ext/src/e_mol2atom.c +649 -0
- data/ext/src/e_readinch.c +58 -0
- data/ext/src/e_readmol.c +54 -0
- data/ext/src/e_readmol.h +180 -0
- data/ext/src/e_readstru.c +251 -0
- data/ext/src/e_readstru.h +33 -0
- data/ext/src/e_util.c +284 -0
- data/ext/src/e_util.h +61 -0
- data/ext/src/extr_ct.h +251 -0
- data/ext/src/ichi.h +206 -0
- data/ext/src/ichi_bns.c +7999 -0
- data/ext/src/ichi_bns.h +231 -0
- data/ext/src/ichican2.c +5000 -0
- data/ext/src/ichicano.c +2195 -0
- data/ext/src/ichicano.h +49 -0
- data/ext/src/ichicans.c +1625 -0
- data/ext/src/ichicant.h +379 -0
- data/ext/src/ichicomn.h +260 -0
- data/ext/src/ichicomp.h +50 -0
- data/ext/src/ichidrp.h +119 -0
- data/ext/src/ichierr.h +124 -0
- data/ext/src/ichiisot.c +101 -0
- data/ext/src/ichilnct.c +286 -0
- data/ext/src/ichimain.h +132 -0
- data/ext/src/ichimak2.c +1189 -0
- data/ext/src/ichimake.c +3812 -0
- data/ext/src/ichimake.h +205 -0
- data/ext/src/ichimap1.c +851 -0
- data/ext/src/ichimap2.c +2856 -0
- data/ext/src/ichimap4.c +1609 -0
- data/ext/src/ichinorm.c +741 -0
- data/ext/src/ichinorm.h +67 -0
- data/ext/src/ichiparm.c +45 -0
- data/ext/src/ichiparm.h +1441 -0
- data/ext/src/ichiprt1.c +3612 -0
- data/ext/src/ichiprt2.c +1511 -0
- data/ext/src/ichiprt3.c +3011 -0
- data/ext/src/ichiqueu.c +1003 -0
- data/ext/src/ichiring.c +326 -0
- data/ext/src/ichiring.h +49 -0
- data/ext/src/ichisize.h +35 -0
- data/ext/src/ichisort.c +539 -0
- data/ext/src/ichister.c +3538 -0
- data/ext/src/ichister.h +35 -0
- data/ext/src/ichitaut.c +3843 -0
- data/ext/src/ichitaut.h +387 -0
- data/ext/src/ichitime.h +74 -0
- data/ext/src/inchi_api.h +670 -0
- data/ext/src/inchi_dll.c +1480 -0
- data/ext/src/inchi_dll.h +34 -0
- data/ext/src/inchi_dll_main.c +23 -0
- data/ext/src/inchi_dll_main.h +31 -0
- data/ext/src/inpdef.h +328 -0
- data/ext/src/lreadmol.h +1246 -0
- data/ext/src/mode.h +706 -0
- data/ext/src/ruby_inchi_main.c +558 -0
- data/ext/src/runichi.c +4179 -0
- data/ext/src/strutil.c +3861 -0
- data/ext/src/strutil.h +182 -0
- data/ext/src/util.c +1130 -0
- data/ext/src/util.h +85 -0
- data/lib/clean_tempfile.rb +220 -0
- data/lib/rino.rb +111 -0
- data/test/test.rb +386 -0
- metadata +130 -0
data/ext/src/ichister.c
ADDED
@@ -0,0 +1,3538 @@
|
|
1
|
+
/*
|
2
|
+
* International Union of Pure and Applied Chemistry (IUPAC)
|
3
|
+
* International Chemical Identifier (InChI)
|
4
|
+
* Version 1
|
5
|
+
* Software version 1.00
|
6
|
+
* April 13, 2005
|
7
|
+
* Developed at NIST
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdlib.h>
|
12
|
+
#include <math.h>
|
13
|
+
#include <string.h>
|
14
|
+
|
15
|
+
#include "mode.h"
|
16
|
+
|
17
|
+
#include "ichierr.h"
|
18
|
+
#include "inpdef.h"
|
19
|
+
#include "extr_ct.h"
|
20
|
+
#include "ichister.h"
|
21
|
+
#include "ichiring.h"
|
22
|
+
#include "ichi.h"
|
23
|
+
|
24
|
+
#include "ichicomp.h"
|
25
|
+
#include "util.h"
|
26
|
+
|
27
|
+
#define ZTYPE_DOWN (-1) /* should be equal to -ZTYPE_UP */
|
28
|
+
#define ZTYPE_NONE 0
|
29
|
+
#define ZTYPE_UP 1 /* should be equal to -ZTYPE_DOWN */
|
30
|
+
#define ZTYPE_3D 3
|
31
|
+
#define ZTYPE_EITHER 9999
|
32
|
+
|
33
|
+
/* criteria for ill-defined */
|
34
|
+
#define MIN_ANGLE 0.10 /* 5.73 degrees */
|
35
|
+
#define MIN_SINE 0.03 /* min edge/plane angle in case the tetrahedra has significantly different edge length */
|
36
|
+
#define MIN_ANGLE_DBOND 0.087156 /* 5 degrees = max angle considered as too small for unambiguous double bond stereo */
|
37
|
+
#define MIN_SINE_OUTSIDE 0.06 /* min edge/plane angle to determine whether the central atom is outside of the tetrahedra */
|
38
|
+
#define MIN_SINE_SQUARE 0.125 /* min edge/plane angle in case the tetrahedra is somewhat close to a parallelogram */
|
39
|
+
#define MIN_SINE_EDGE 0.167 /* min sine/(min.edge) ratio to avoid undefined in case of long edges */
|
40
|
+
#define MIN_LEN_STRAIGHT 1.900 /* min length of two normalized to 1 bonds in a straight line */
|
41
|
+
#define MAX_SINE 0.70710678118654752440084436210485 /* 1/sqrt(2)=sin(pi/4) */
|
42
|
+
#define MIN_BOND_LEN 0.000001
|
43
|
+
#define ZERO_LENGTH MIN_BOND_LEN
|
44
|
+
#define ZERO_FLOAT 1.0e-12
|
45
|
+
#define BOND_PARITY_UNDEFINED 64
|
46
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
47
|
+
#define MPY_SINE 1.00 /* was 3.0 */
|
48
|
+
#define MAX_EDGE_RATIO 2.50 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
|
49
|
+
#else
|
50
|
+
#define MPY_SINE 3.00
|
51
|
+
#define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
|
52
|
+
#endif
|
53
|
+
/* local prototypes */
|
54
|
+
int save_a_stereo_bond( int z_prod, int result_action,
|
55
|
+
int at1, int ord1, AT_NUMB *stereo_bond_neighbor1, S_CHAR *stereo_bond_ord1, S_CHAR *stereo_bond_z_prod1, S_CHAR *stereo_bond_parity1,
|
56
|
+
int at2, int ord2, AT_NUMB *stereo_bond_neighbor2, S_CHAR *stereo_bond_ord2, S_CHAR *stereo_bond_z_prod2, S_CHAR *stereo_bond_parity2 );
|
57
|
+
double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
|
58
|
+
double len3( const double c[] );
|
59
|
+
double len2( const double c[] );
|
60
|
+
double* diff3( const double a[], const double b[], double result[] );
|
61
|
+
double* add3( const double a[], const double b[], double result[] );
|
62
|
+
double* mult3( const double a[], double b, double result[] );
|
63
|
+
double* copy3( const double a[], double result[] );
|
64
|
+
double* change_sign3( const double a[], double result[] );
|
65
|
+
double dot_prod3( const double a[], const double b[] );
|
66
|
+
int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
|
67
|
+
double* cross_prod3( const double a[], const double b[], double result[] );
|
68
|
+
double triple_prod( double a[], double b[], double c[], double *sine_value );
|
69
|
+
double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
|
70
|
+
double sp3_triple_prod_and_min_abs_sine(double at_coord[][3], double central_at_coord[], double *min_sine, int *bAmbiguous);
|
71
|
+
int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
|
72
|
+
int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
|
73
|
+
int at_2, int i_next_at_2, S_CHAR *z_dir2 );
|
74
|
+
|
75
|
+
int CompDble( const void *a1, const void *a2 );
|
76
|
+
int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor );
|
77
|
+
double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
|
78
|
+
int are_4at_in_one_plane( double at_coord[][3], double min_sine);
|
79
|
+
int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds );
|
80
|
+
int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical );
|
81
|
+
int bIsSuitableHeteroInpAtom( inp_ATOM *at );
|
82
|
+
int bIsOxide( inp_ATOM *at, int cur_at );
|
83
|
+
int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo );
|
84
|
+
int get_allowed_stereo_bond_type( int bond_type );
|
85
|
+
int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode );
|
86
|
+
int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic );
|
87
|
+
int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
|
88
|
+
INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo );
|
89
|
+
int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at );
|
90
|
+
int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, int bPointedEdgeStereo );
|
91
|
+
/*
|
92
|
+
int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_removed_H,
|
93
|
+
int *nMaxNumStereoAtoms, int *nMaxNumStereoBonds, INCHI_MODE nMode, int bPointedEdgeStereo );
|
94
|
+
int get_opposite_sb_atom( inp_ATOM *at, int cur_atom, int icur2nxt, int *pnxt_atom, int *pinxt2cur, int *pinxt_sb_parity_ord );
|
95
|
+
*/
|
96
|
+
int ReconcileCmlIncidentBondParities( inp_ATOM *at, int cur_atom, int prev_atom, S_CHAR *visited, int bDisconnected );
|
97
|
+
int comp_AT_NUMB( const void* a1, const void* a2);
|
98
|
+
int GetHalfStereobond0DParity( inp_ATOM *at, int cur_at, AT_NUMB nSbNeighOrigAtNumb[], int nNumExplictAttachments, int bond_parity, int nFlag );
|
99
|
+
int GetStereocenter0DParity( inp_ATOM *at, int cur_at, int j1, AT_NUMB nSbNeighOrigAtNumb[], int nFlag );
|
100
|
+
int GetSbNeighOrigAtNumb( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, AT_NUMB nSbNeighOrigAtNumb[]);
|
101
|
+
int FixSb0DParities( inp_ATOM *at, /* inp_ATOM *at_removed_H, int num_removed_H,*/ int chain_length,
|
102
|
+
int at_1, int i_next_at_1, S_CHAR z_dir1[],
|
103
|
+
int at_2, int i_next_at_2, S_CHAR z_dir2[],
|
104
|
+
int *pparity1, int *pparity2 );
|
105
|
+
|
106
|
+
/******************************************************************/
|
107
|
+
|
108
|
+
|
109
|
+
static double *pDoubleForSort;
|
110
|
+
|
111
|
+
/**********************************************************************************/
|
112
|
+
int comp_AT_NUMB( const void* a1, const void* a2)
|
113
|
+
{
|
114
|
+
return (int)*(const AT_NUMB*)a1 - (int)*(const AT_NUMB*)a2;
|
115
|
+
}
|
116
|
+
/******************************************************************/
|
117
|
+
double get_z_coord( inp_ATOM* at, int cur_atom, int neigh_no, int *nType, int bPointedEdgeStereo )
|
118
|
+
{
|
119
|
+
int stereo_value = at[cur_atom].bond_stereo[neigh_no];
|
120
|
+
int stereo_type = abs( stereo_value );
|
121
|
+
int neigh = (int)at[cur_atom].neighbor[neigh_no];
|
122
|
+
double z = at[neigh].z - at[cur_atom].z;
|
123
|
+
int bFlat;
|
124
|
+
|
125
|
+
if ( bFlat = (fabs(z) < ZERO_LENGTH) ) {
|
126
|
+
int i;
|
127
|
+
for ( i = 0; i < at[cur_atom].valence; i ++ ) {
|
128
|
+
if ( fabs(at[cur_atom].z - at[(int)at[cur_atom].neighbor[i]].z) > ZERO_LENGTH ) {
|
129
|
+
bFlat = 0;
|
130
|
+
break;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
if ( bFlat ) {
|
136
|
+
if ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) {
|
137
|
+
/* bPointedEdgeStereo > 0: define stereo from pointed end of the stereo bond only */
|
138
|
+
/* bPointedEdgeStereo < 0: define stereo from wide end of the stereo bond only (case of removed H) */
|
139
|
+
switch( stereo_type ) {
|
140
|
+
/* 1=Up (solid triangle), 6=Down (Dashed triangle), 4=Either (zigzag triangle) */
|
141
|
+
case 0: /* No stereo */
|
142
|
+
*nType = ZTYPE_NONE;
|
143
|
+
break;
|
144
|
+
case STEREO_SNGL_UP: /* 1= Up */
|
145
|
+
*nType = ZTYPE_UP;
|
146
|
+
break;
|
147
|
+
case STEREO_SNGL_EITHER: /* 4 = Either */
|
148
|
+
*nType = ZTYPE_EITHER;
|
149
|
+
break;
|
150
|
+
case STEREO_SNGL_DOWN: /* 6 = Down */
|
151
|
+
*nType = ZTYPE_DOWN;
|
152
|
+
break;
|
153
|
+
default:
|
154
|
+
*nType = ZTYPE_NONE; /* ignore unexpected values */
|
155
|
+
}
|
156
|
+
if ( stereo_value < 0 && (*nType == ZTYPE_DOWN || *nType == ZTYPE_UP) )
|
157
|
+
*nType = -*nType;
|
158
|
+
} else {
|
159
|
+
*nType = ZTYPE_NONE; /* no stereo */
|
160
|
+
}
|
161
|
+
} else
|
162
|
+
if ( stereo_type == STEREO_SNGL_EITHER &&
|
163
|
+
( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) ) {
|
164
|
+
*nType = ZTYPE_EITHER;
|
165
|
+
} else {
|
166
|
+
*nType = ZTYPE_3D;
|
167
|
+
}
|
168
|
+
return z;
|
169
|
+
}
|
170
|
+
/******************************************************************/
|
171
|
+
double len3( const double c[] )
|
172
|
+
{
|
173
|
+
return sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] );
|
174
|
+
}
|
175
|
+
/******************************************************************/
|
176
|
+
double len2( const double c[] )
|
177
|
+
{
|
178
|
+
return sqrt( c[0]*c[0] + c[1]*c[1] );
|
179
|
+
}
|
180
|
+
/******************************************************************/
|
181
|
+
double* diff3( const double a[], const double b[], double result[] )
|
182
|
+
{
|
183
|
+
|
184
|
+
result[0] = a[0] - b[0];
|
185
|
+
result[1] = a[1] - b[1];
|
186
|
+
result[2] = a[2] - b[2];
|
187
|
+
|
188
|
+
return result;
|
189
|
+
}
|
190
|
+
/******************************************************************/
|
191
|
+
double* add3( const double a[], const double b[], double result[] )
|
192
|
+
{
|
193
|
+
result[0] = a[0] + b[0];
|
194
|
+
result[1] = a[1] + b[1];
|
195
|
+
result[2] = a[2] + b[2];
|
196
|
+
|
197
|
+
return result;
|
198
|
+
}
|
199
|
+
/******************************************************************/
|
200
|
+
double* mult3( const double a[], double b, double result[] )
|
201
|
+
{
|
202
|
+
result[0] = a[0] * b;
|
203
|
+
result[1] = a[1] * b;
|
204
|
+
result[2] = a[2] * b;
|
205
|
+
|
206
|
+
return result;
|
207
|
+
}
|
208
|
+
/*************************************************************/
|
209
|
+
double* copy3( const double a[], double result[] )
|
210
|
+
{
|
211
|
+
result[0] = a[0];
|
212
|
+
result[1] = a[1];
|
213
|
+
result[2] = a[2];
|
214
|
+
|
215
|
+
return result;
|
216
|
+
}
|
217
|
+
/*************************************************************/
|
218
|
+
double* change_sign3( const double a[], double result[] )
|
219
|
+
{
|
220
|
+
result[0] = -a[0];
|
221
|
+
result[1] = -a[1];
|
222
|
+
result[2] = -a[2];
|
223
|
+
|
224
|
+
return result;
|
225
|
+
}
|
226
|
+
/*************************************************************/
|
227
|
+
double dot_prod3( const double a[], const double b[] )
|
228
|
+
{
|
229
|
+
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
|
230
|
+
}
|
231
|
+
/*************************************************************/
|
232
|
+
int dot_prodchar3( const S_CHAR a[], const S_CHAR b[] )
|
233
|
+
{
|
234
|
+
int prod = ((int)a[0]*(int)b[0] + (int)a[1]*(int)b[1] + (int)a[2]*(int)b[2])/100;
|
235
|
+
if ( prod > 100 )
|
236
|
+
prod = 100;
|
237
|
+
else
|
238
|
+
if ( prod < -100 )
|
239
|
+
prod = -100;
|
240
|
+
return prod;
|
241
|
+
}
|
242
|
+
/*************************************************************/
|
243
|
+
double* cross_prod3( const double a[], const double b[], double result[] )
|
244
|
+
{
|
245
|
+
double tmp[3];
|
246
|
+
|
247
|
+
tmp[0] = (a[1]*b[2]-a[2]*b[1]);
|
248
|
+
tmp[1] = -(a[0]*b[2]-a[2]*b[0]);
|
249
|
+
tmp[2] = (a[0]*b[1]-a[1]*b[0]);
|
250
|
+
|
251
|
+
result[0] = tmp[0];
|
252
|
+
result[1] = tmp[1];
|
253
|
+
result[2] = tmp[2];
|
254
|
+
|
255
|
+
return result;
|
256
|
+
}
|
257
|
+
/*************************************************************/
|
258
|
+
double triple_prod( double a[], double b[], double c[], double *sine_value )
|
259
|
+
{
|
260
|
+
double ab[3], dot_prod_ab_c, abs_c, abs_ab;
|
261
|
+
cross_prod3( a, b, ab );
|
262
|
+
/* ab[0] = (a[1]*b[2]-a[2]*b[1]); */
|
263
|
+
/* ab[1] = -(a[0]*b[2]-a[2]*b[0]); */
|
264
|
+
/* ab[2] = (a[0]*b[1]-a[1]*b[0]); */
|
265
|
+
dot_prod_ab_c = dot_prod3( ab, c );
|
266
|
+
/* dot_prod_ab_c = ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2]; */
|
267
|
+
if ( sine_value ) {
|
268
|
+
abs_c = len3( c );
|
269
|
+
/* abs_c = sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ); */
|
270
|
+
abs_ab = len3( ab );
|
271
|
+
/* abs_ab = sqrt( ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2] ); */
|
272
|
+
|
273
|
+
if ( abs_c > 1.e-7 /* otherwise c has zero length */ && abs_ab > 1.e-7 /* otherwise a is parallel to b*/ ) {
|
274
|
+
*sine_value = MPY_SINE * dot_prod_ab_c / ( abs_c * abs_ab);
|
275
|
+
/* *sine_value = dot_prod_ab_c / ( abs_c * abs_ab); */
|
276
|
+
} else {
|
277
|
+
*sine_value = 0.0;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
return dot_prod_ab_c;
|
281
|
+
}
|
282
|
+
/*************************************************************/
|
283
|
+
int CompDble( const void *a1, const void *a2 )
|
284
|
+
{
|
285
|
+
double diff = pDoubleForSort[*(const int*)a1] - pDoubleForSort[*(const int*)a2];
|
286
|
+
if ( diff > 0.0 )
|
287
|
+
return 1;
|
288
|
+
if ( diff < 0.0 )
|
289
|
+
return -1;
|
290
|
+
return 0;
|
291
|
+
}
|
292
|
+
/*************************************************************/
|
293
|
+
#define T2D_OKAY 1
|
294
|
+
#define T2D_WARN 2
|
295
|
+
#define T2D_UNDF 4
|
296
|
+
int Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
|
297
|
+
{
|
298
|
+
const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
|
299
|
+
const double two_pi = 2.0*one_pi;
|
300
|
+
const double dAngleAndPiMaxDiff = 2.0*atan2(1.0, sqrt(7.0)); /* min sine between 2 InPlane bonds */
|
301
|
+
int nBondType[MAX_NUM_STEREO_ATOM_NEIGH], nBondOrder[MAX_NUM_STEREO_ATOM_NEIGH];
|
302
|
+
double dBondDirection[MAX_NUM_STEREO_ATOM_NEIGH], dAngle, dAlpha, dLimit, dBisector;
|
303
|
+
int nNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH - (bAddExplicitNeighbor != 0);
|
304
|
+
int i, num_Up, num_Dn, bPrev_Up, cur_len_Up, cur_first_Up, len_Up, first_Up;
|
305
|
+
int ret;
|
306
|
+
|
307
|
+
ret = 0;
|
308
|
+
for ( i = 0, num_Up = num_Dn = 0; i < nNumNeigh; i ++ ) {
|
309
|
+
dAngle = atan2( at_coord[i][1], at_coord[i][0] ); /* range from -pi to +pi */
|
310
|
+
if ( dAngle < 0.0 ) {
|
311
|
+
dAngle += two_pi;
|
312
|
+
}
|
313
|
+
dBondDirection[i] = dAngle;
|
314
|
+
nBondType[i] = (at_coord[i][2] > 0.0)? 1 : (at_coord[i][2] < 0.0)? -1 : 0; /* z-coord sign */
|
315
|
+
if ( nBondType[i] > 0 ) {
|
316
|
+
num_Up ++;
|
317
|
+
} else
|
318
|
+
if ( nBondType[i] < 0 ) {
|
319
|
+
num_Dn ++;
|
320
|
+
}
|
321
|
+
nBondOrder[i] = i;
|
322
|
+
}
|
323
|
+
if ( num_Up < num_Dn ) {
|
324
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
325
|
+
nBondType[i] = -nBondType[i];
|
326
|
+
}
|
327
|
+
swap( (char*)&num_Dn, (char*)&num_Up, sizeof(num_Dn) );
|
328
|
+
}
|
329
|
+
if ( !num_Up ) {
|
330
|
+
return T2D_UNDF;
|
331
|
+
}
|
332
|
+
/* sort according to the bond orientations */
|
333
|
+
pDoubleForSort = dBondDirection;
|
334
|
+
insertions_sort( nBondOrder, nNumNeigh, sizeof(nBondOrder[0]), CompDble );
|
335
|
+
|
336
|
+
/* find the longest contiguous sequence of Up bonds */
|
337
|
+
if ( num_Up == nNumNeigh ) {
|
338
|
+
/* all bonds are Up */
|
339
|
+
len_Up = cur_len_Up = nNumNeigh; /* added cur_len_Up initialization 1/8/2002 */
|
340
|
+
first_Up = 0;
|
341
|
+
} else {
|
342
|
+
/* at least one bond is not Up */
|
343
|
+
cur_len_Up = len_Up = bPrev_Up = 0;
|
344
|
+
/* prev. cycle header version ---
|
345
|
+
for ( i = 0; 1; i ++ ) {
|
346
|
+
if ( i >= nNumNeigh && !bPrev_Up ) {
|
347
|
+
break;
|
348
|
+
}
|
349
|
+
----------} */
|
350
|
+
/* look at all bonds and continue (circle therough the beginning) as long as the current bond is Up */
|
351
|
+
for ( i = 0; i < nNumNeigh || bPrev_Up; i ++ ) {
|
352
|
+
if ( nBondType[nBondOrder[i % nNumNeigh]] > 0 ) {
|
353
|
+
if ( bPrev_Up ) {
|
354
|
+
cur_len_Up ++; /* uncrement number of Up bonds in current contiguous sequence of them */
|
355
|
+
} else {
|
356
|
+
bPrev_Up = 1; /* start new contiguous sequence of Up bonds */
|
357
|
+
cur_len_Up = 1;
|
358
|
+
cur_first_Up = i % nNumNeigh;
|
359
|
+
}
|
360
|
+
} else
|
361
|
+
if ( bPrev_Up ) { /* end of contiguous sequence of Up bonds */
|
362
|
+
if ( cur_len_Up > len_Up ) {
|
363
|
+
first_Up = cur_first_Up; /* store the sequence because it is longer than the ptrvious one */
|
364
|
+
len_Up = cur_len_Up;
|
365
|
+
}
|
366
|
+
bPrev_Up = 0;
|
367
|
+
}
|
368
|
+
}
|
369
|
+
}
|
370
|
+
/* Turn all the bonds around the center so that */
|
371
|
+
/* the 1st Up bond has zero radian direction */
|
372
|
+
dAlpha = dBondDirection[nBondOrder[first_Up]];
|
373
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
374
|
+
if ( i == nBondOrder[first_Up] ) {
|
375
|
+
dBondDirection[i] = 0.0;
|
376
|
+
} else {
|
377
|
+
dAngle = dBondDirection[i] - dAlpha;
|
378
|
+
if ( dAngle < 0.0 ) {
|
379
|
+
dAngle += two_pi;
|
380
|
+
}
|
381
|
+
dBondDirection[i] = dAngle;
|
382
|
+
}
|
383
|
+
}
|
384
|
+
|
385
|
+
/********************************************************
|
386
|
+
* Process particular cases
|
387
|
+
********************************************************/
|
388
|
+
|
389
|
+
switch( nNumNeigh ) {
|
390
|
+
|
391
|
+
/************************ 3 bonds ***********************
|
392
|
+
*/
|
393
|
+
case 3:
|
394
|
+
switch( num_Up ) {
|
395
|
+
/* -------------------------- 0 Up ------------ */
|
396
|
+
case 0:
|
397
|
+
return T2D_UNDF;
|
398
|
+
/* -------------------------- 1 Up ------------ */
|
399
|
+
case 1:
|
400
|
+
if ( num_Dn ) {
|
401
|
+
#ifdef _DEBUG
|
402
|
+
if ( num_Dn != 1 ) /* debug only */
|
403
|
+
return -1;
|
404
|
+
#endif
|
405
|
+
ret = (T2D_UNDF | T2D_WARN);
|
406
|
+
} else {
|
407
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
|
408
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
409
|
+
if ( dAngle < 0.0 ) {
|
410
|
+
dAngle += two_pi;
|
411
|
+
}
|
412
|
+
if ( dAngle - one_pi < -MIN_ANGLE || dAngle - one_pi > MIN_ANGLE ) {
|
413
|
+
ret = T2D_OKAY;
|
414
|
+
} else {
|
415
|
+
ret = (T2D_UNDF | T2D_WARN);
|
416
|
+
}
|
417
|
+
}
|
418
|
+
break;
|
419
|
+
/* -------------------------- 2 Up ------------ */
|
420
|
+
case 2:
|
421
|
+
if ( num_Dn ) {
|
422
|
+
dAlpha = dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]] -
|
423
|
+
dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]];
|
424
|
+
if ( dAlpha < 0.0 ) {
|
425
|
+
dAlpha += two_pi;
|
426
|
+
}
|
427
|
+
if ( dAlpha > one_pi - MIN_ANGLE ) {
|
428
|
+
ret = T2D_OKAY;
|
429
|
+
} else
|
430
|
+
if ( dAlpha < two_pi / 3.0 - MIN_ANGLE ) {
|
431
|
+
ret = (T2D_UNDF | T2D_WARN);
|
432
|
+
} else {
|
433
|
+
/* angle between 2 Up bonds is between 120 and 180 degrees */
|
434
|
+
/* direction of the (Alpha angle bisector) + 180 degrees */
|
435
|
+
dBisector = (dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]] +
|
436
|
+
dBondDirection[nBondOrder[(first_Up + 1 ) % nNumNeigh]] ) / 2.0 - one_pi;
|
437
|
+
if ( dBisector < 0.0 ) {
|
438
|
+
dBisector += two_pi;
|
439
|
+
}
|
440
|
+
if ( dAlpha < two_pi / 3.0 + MIN_ANGLE ) {
|
441
|
+
/* dAlpha is inside ( 2pi/3 - eps, 2pi/3 + eps ) interval */
|
442
|
+
dLimit = MIN_ANGLE * 3.0 / 2.0;
|
443
|
+
} else {
|
444
|
+
dLimit = dAlpha * 3.0 / 2.0 - one_pi;
|
445
|
+
}
|
446
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2 ) % nNumNeigh]];
|
447
|
+
if ( dBisector - dAngle < -dLimit ||
|
448
|
+
dBisector - dAngle > dLimit ) {
|
449
|
+
ret = (T2D_UNDF | T2D_WARN);
|
450
|
+
} else {
|
451
|
+
ret = T2D_OKAY;
|
452
|
+
}
|
453
|
+
}
|
454
|
+
} else {
|
455
|
+
ret = T2D_OKAY;
|
456
|
+
}
|
457
|
+
|
458
|
+
break;
|
459
|
+
/* -------------------------- 3 Up ------------ */
|
460
|
+
case 3:
|
461
|
+
ret = T2D_OKAY;
|
462
|
+
break;
|
463
|
+
/* -------------------------- other Up -------- */
|
464
|
+
default:
|
465
|
+
return -1;
|
466
|
+
|
467
|
+
}
|
468
|
+
|
469
|
+
break;
|
470
|
+
|
471
|
+
/************************************** 4 bonds **************************
|
472
|
+
*/
|
473
|
+
case 4:
|
474
|
+
switch( num_Up ) {
|
475
|
+
/* -------------------------- 0 Up ------------ */
|
476
|
+
case 0:
|
477
|
+
return T2D_UNDF;
|
478
|
+
/* -------------------------- 1 Up ------------ */
|
479
|
+
case 1:
|
480
|
+
if ( num_Dn ) {
|
481
|
+
if ( nBondType[nBondOrder[(first_Up + 2) % nNumNeigh]] < 0 ) {
|
482
|
+
/*
|
483
|
+
* Up, In Plane, Dn, In Plane. Undefined if angle between
|
484
|
+
* two In Plane bonds is wuthin pi +/- 2*arcsine(1/sqrt(8)) interval
|
485
|
+
* That is, 138.5 to 221.4 degrees; for certainty the interval is
|
486
|
+
* increased by 5.7 degrees at each end to
|
487
|
+
* 134.8 to 227.1 degrees
|
488
|
+
*/
|
489
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
|
490
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
491
|
+
if ( dAngle < 0.0 ) {
|
492
|
+
dAngle += two_pi;
|
493
|
+
}
|
494
|
+
if ( fabs( dAngle - one_pi ) < dAngleAndPiMaxDiff + MIN_ANGLE ) {
|
495
|
+
ret = (T2D_UNDF | T2D_WARN);
|
496
|
+
} else {
|
497
|
+
ret = T2D_OKAY;
|
498
|
+
}
|
499
|
+
} else {
|
500
|
+
ret = T2D_OKAY;
|
501
|
+
}
|
502
|
+
#ifdef _DEBUG
|
503
|
+
if ( num_Dn != 1 ) /* debug only */
|
504
|
+
return -1;
|
505
|
+
#endif
|
506
|
+
} else {
|
507
|
+
ret = T2D_OKAY;
|
508
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
|
509
|
+
dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
|
510
|
+
if ( dAngle < 0.0 ) {
|
511
|
+
dAngle += two_pi;
|
512
|
+
}
|
513
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
514
|
+
ret |= T2D_WARN;
|
515
|
+
}
|
516
|
+
}
|
517
|
+
break;
|
518
|
+
/* -------------------------- 2 Up ------------ */
|
519
|
+
case 2:
|
520
|
+
if ( cur_len_Up == 1 ) {
|
521
|
+
ret = T2D_OKAY;
|
522
|
+
} else {
|
523
|
+
ret = (T2D_UNDF | T2D_WARN);
|
524
|
+
}
|
525
|
+
break;
|
526
|
+
/* -------------------------- 3 Up ------------ */
|
527
|
+
case 3:
|
528
|
+
ret = T2D_OKAY;
|
529
|
+
dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
|
530
|
+
dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
|
531
|
+
if ( dAngle < 0.0 ) {
|
532
|
+
dAngle += two_pi;
|
533
|
+
}
|
534
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
535
|
+
ret |= T2D_WARN;
|
536
|
+
}
|
537
|
+
break;
|
538
|
+
/* -------------------------- 4 Up ------------ */
|
539
|
+
case 4:
|
540
|
+
ret = (T2D_UNDF | T2D_WARN);
|
541
|
+
break;
|
542
|
+
/* -------------------------- other Up -------- */
|
543
|
+
default:
|
544
|
+
return -1; /* program error */
|
545
|
+
}
|
546
|
+
|
547
|
+
if ( ret == T2D_OKAY ) {
|
548
|
+
/* check whether all bonds are inside a less than 180 degrees sector */
|
549
|
+
for ( i = 0; i < nNumNeigh; i ++ ) {
|
550
|
+
dAngle = dBondDirection[nBondOrder[(i + nNumNeigh - 1) % nNumNeigh]] -
|
551
|
+
dBondDirection[nBondOrder[ i % nNumNeigh]];
|
552
|
+
if ( dAngle < 0.0 ) {
|
553
|
+
dAngle += two_pi;
|
554
|
+
}
|
555
|
+
if ( dAngle < one_pi - MIN_ANGLE ) {
|
556
|
+
ret |= T2D_WARN;
|
557
|
+
break;
|
558
|
+
}
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
break;
|
563
|
+
/*************************** other nuber of bonds ******************/
|
564
|
+
default:
|
565
|
+
return -1; /* error */
|
566
|
+
}
|
567
|
+
|
568
|
+
return ret;
|
569
|
+
|
570
|
+
}
|
571
|
+
/*************************************************************/
|
572
|
+
double triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous)
|
573
|
+
{
|
574
|
+
double min_sine_value=9999.0, sine_value, min_edge_len, max_edge_len, min_edge_len_NoExplNeigh, max_edge_len_NoExplNeigh;
|
575
|
+
double s0, s1, s2, s3, e01, e02, e03, e12, e13, e23, tmp[3], e[3][3];
|
576
|
+
double prod, ret, central_prod[4];
|
577
|
+
int bLongEdges;
|
578
|
+
|
579
|
+
if ( !min_sine ) {
|
580
|
+
return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
|
581
|
+
}
|
582
|
+
|
583
|
+
ret = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
|
584
|
+
sine_value = MPY_SINE * fabs( sine_value );
|
585
|
+
|
586
|
+
diff3( at_coord[1], at_coord[0], e[2] );
|
587
|
+
diff3( at_coord[0], at_coord[2], e[1] );
|
588
|
+
diff3( at_coord[2], at_coord[1], e[0] );
|
589
|
+
|
590
|
+
/* lengths of the 6 edges of the tetrahedra */
|
591
|
+
e03 = len3( at_coord[0] ); /* 1 */
|
592
|
+
e13 = len3( at_coord[1] );
|
593
|
+
e23 = len3( at_coord[2] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
594
|
+
e02 = len3( e[1] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
595
|
+
e12 = len3( e[0] ); /* includes added neighbor if bAddedExplicitNeighbor*/
|
596
|
+
e01 = len3( e[2] );
|
597
|
+
|
598
|
+
/* min & max edge length */
|
599
|
+
max_edge_len =
|
600
|
+
min_edge_len = e03;
|
601
|
+
|
602
|
+
if ( min_edge_len > e13 )
|
603
|
+
min_edge_len = e13;
|
604
|
+
if ( min_edge_len > e01 )
|
605
|
+
min_edge_len = e01;
|
606
|
+
min_edge_len_NoExplNeigh = min_edge_len;
|
607
|
+
|
608
|
+
if ( min_edge_len > e23 )
|
609
|
+
min_edge_len = e23;
|
610
|
+
if ( min_edge_len > e02 )
|
611
|
+
min_edge_len = e02;
|
612
|
+
if ( min_edge_len > e12 )
|
613
|
+
min_edge_len = e12;
|
614
|
+
|
615
|
+
if ( max_edge_len < e13 )
|
616
|
+
max_edge_len = e13;
|
617
|
+
if ( max_edge_len < e01 )
|
618
|
+
max_edge_len = e01;
|
619
|
+
max_edge_len_NoExplNeigh = max_edge_len;
|
620
|
+
|
621
|
+
if ( max_edge_len < e23 )
|
622
|
+
max_edge_len = e23;
|
623
|
+
if ( max_edge_len < e02 )
|
624
|
+
max_edge_len = e02;
|
625
|
+
if ( max_edge_len < e12 )
|
626
|
+
max_edge_len = e12;
|
627
|
+
|
628
|
+
if ( !bAddedExplicitNeighbor ) {
|
629
|
+
min_edge_len_NoExplNeigh = min_edge_len;
|
630
|
+
max_edge_len_NoExplNeigh = max_edge_len;
|
631
|
+
}
|
632
|
+
|
633
|
+
bLongEdges = bAddedExplicitNeighbor?
|
634
|
+
( max_edge_len_NoExplNeigh < MAX_EDGE_RATIO * min_edge_len_NoExplNeigh ) :
|
635
|
+
( max_edge_len < MAX_EDGE_RATIO * min_edge_len );
|
636
|
+
|
637
|
+
if ( sine_value > MIN_SINE && ( min_sine || bAmbiguous ) ) {
|
638
|
+
if ( min_sine ) {
|
639
|
+
prod = fabs( ret );
|
640
|
+
/* tetrahedra height = volume(prod) / area of a plane(cross_prod) */
|
641
|
+
/* (instead of a tetrahedra calculate parallelogram/parallelepiped area/volume) */
|
642
|
+
|
643
|
+
/* 4 heights from each of the 4 vertices to the opposite plane */
|
644
|
+
s0 = prod / len3( cross_prod3( at_coord[1], at_coord[2], tmp ) );
|
645
|
+
s1 = prod / len3( cross_prod3( at_coord[0], at_coord[2], tmp ) );
|
646
|
+
s2 = prod / len3( cross_prod3( at_coord[0], at_coord[1], tmp ) );
|
647
|
+
s3 = prod / len3( cross_prod3( e[0], e[1], tmp ) );
|
648
|
+
/* abs. value of a sine of an angle between each tetrahedra edge and plane */
|
649
|
+
/* sine = height / edge length */
|
650
|
+
if ( (sine_value = s0/e01) < min_sine_value )
|
651
|
+
min_sine_value = sine_value;
|
652
|
+
if ( (sine_value = s0/e02) < min_sine_value )
|
653
|
+
min_sine_value = sine_value;
|
654
|
+
if ( (sine_value = s0/e03) < min_sine_value )
|
655
|
+
min_sine_value = sine_value;
|
656
|
+
|
657
|
+
if ( (sine_value = s1/e01) < min_sine_value )
|
658
|
+
min_sine_value = sine_value;
|
659
|
+
if ( (sine_value = s1/e12) < min_sine_value )
|
660
|
+
min_sine_value = sine_value;
|
661
|
+
if ( (sine_value = s1/e13) < min_sine_value )
|
662
|
+
min_sine_value = sine_value;
|
663
|
+
|
664
|
+
if ( (sine_value = s2/e02) < min_sine_value )
|
665
|
+
min_sine_value = sine_value;
|
666
|
+
if ( (sine_value = s2/e12) < min_sine_value )
|
667
|
+
min_sine_value = sine_value;
|
668
|
+
if ( (sine_value = s2/e23) < min_sine_value )
|
669
|
+
min_sine_value = sine_value;
|
670
|
+
|
671
|
+
if ( (sine_value = s3/e03) < min_sine_value )
|
672
|
+
min_sine_value = sine_value;
|
673
|
+
if ( (sine_value = s3/e13) < min_sine_value )
|
674
|
+
min_sine_value = sine_value;
|
675
|
+
if ( (sine_value = s3/e23) < min_sine_value )
|
676
|
+
min_sine_value = sine_value;
|
677
|
+
/* actually use triple sine */
|
678
|
+
*min_sine = sine_value = MPY_SINE * min_sine_value;
|
679
|
+
}
|
680
|
+
|
681
|
+
if ( bAmbiguous && sine_value >= MIN_SINE ) {
|
682
|
+
/* check whether the central atom is outside the tetrahedra (0,0,0), at_coord[0,1,2] */
|
683
|
+
/* compare the tetrahedra volume and the volume of a tetrahedra having central_at_coord[] vertex */
|
684
|
+
int i;
|
685
|
+
diff3( central_at_coord, at_coord[0], tmp );
|
686
|
+
central_prod[0] = triple_prod( at_coord[0], at_coord[1], central_at_coord, NULL );
|
687
|
+
central_prod[1] = triple_prod( at_coord[1], at_coord[2], central_at_coord, NULL );
|
688
|
+
central_prod[2] = triple_prod( at_coord[2], at_coord[0], central_at_coord, NULL );
|
689
|
+
central_prod[3] = triple_prod( e[2], e[1], tmp, NULL );
|
690
|
+
for ( i = 0; i <= 3; i ++ ) {
|
691
|
+
if ( central_prod[i] / ret < -MIN_SINE_OUTSIDE ) {
|
692
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
693
|
+
break;
|
694
|
+
}
|
695
|
+
}
|
696
|
+
}
|
697
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
698
|
+
|
699
|
+
if ( bLongEdges && !bAddedExplicitNeighbor && max_edge_len >= MIN_LEN_STRAIGHT ) {
|
700
|
+
/* possible planar tetragon */
|
701
|
+
if ( sine_value < MIN_SINE_SQUARE ) {
|
702
|
+
*min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
|
703
|
+
if ( bAmbiguous && !*bAmbiguous ) {
|
704
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
705
|
+
}
|
706
|
+
}
|
707
|
+
}
|
708
|
+
|
709
|
+
if ( bLongEdges && sine_value < MIN_SINE_SQUARE && sine_value < MIN_SINE_EDGE * min_edge_len_NoExplNeigh ) {
|
710
|
+
*min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
|
711
|
+
if ( bAmbiguous && !*bAmbiguous ) {
|
712
|
+
*bAmbiguous |= AMBIGUOUS_STEREO;
|
713
|
+
}
|
714
|
+
}
|
715
|
+
#endif
|
716
|
+
|
717
|
+
} else
|
718
|
+
if ( min_sine ) {
|
719
|
+
*min_sine = sine_value;
|
720
|
+
}
|
721
|
+
|
722
|
+
return ret;
|
723
|
+
}
|
724
|
+
/*************************************************************/
|
725
|
+
double triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine)
|
726
|
+
{
|
727
|
+
double min_sine_value=9999.0, sine_value;
|
728
|
+
double prod=0.0;
|
729
|
+
|
730
|
+
if ( !min_sine ) {
|
731
|
+
return triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
|
732
|
+
}
|
733
|
+
|
734
|
+
prod = triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
|
735
|
+
sine_value = fabs( sine_value );
|
736
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
737
|
+
|
738
|
+
prod = triple_prod( at_coord[1], at_coord[2], at_coord[0], &sine_value );
|
739
|
+
sine_value = fabs( sine_value );
|
740
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
741
|
+
|
742
|
+
prod = triple_prod( at_coord[2], at_coord[0], at_coord[1], &sine_value );
|
743
|
+
sine_value = fabs( sine_value );
|
744
|
+
min_sine_value = inchi_min( min_sine_value, sine_value );
|
745
|
+
|
746
|
+
*min_sine = min_sine_value;
|
747
|
+
|
748
|
+
return prod;
|
749
|
+
}
|
750
|
+
/*************************************************************/
|
751
|
+
/* Find if point (0,0,0)a and 3 atoms are in one plane */
|
752
|
+
int are_3_vect_in_one_plane( double at_coord[][3], double min_sine)
|
753
|
+
{
|
754
|
+
double actual_min_sine;
|
755
|
+
double prod;
|
756
|
+
prod = triple_prod_and_min_abs_sine( at_coord, &actual_min_sine);
|
757
|
+
return actual_min_sine <= min_sine;
|
758
|
+
}
|
759
|
+
/*************************************************************/
|
760
|
+
/* Find if 4 atoms are in one plane */
|
761
|
+
int are_4at_in_one_plane( double at_coord[][3], double min_sine)
|
762
|
+
{
|
763
|
+
double actual_min_sine, min_actual_min_sine;
|
764
|
+
double coord[3][3], prod;
|
765
|
+
int i, k, j;
|
766
|
+
for ( k = 0; k < 4; k ++ ) { /* cycle added 4004-08-15 */
|
767
|
+
for ( i = j = 0; i < 4; i ++ ) {
|
768
|
+
if ( i != k ) {
|
769
|
+
diff3( at_coord[i], at_coord[k], coord[j] );
|
770
|
+
j ++;
|
771
|
+
}
|
772
|
+
}
|
773
|
+
prod = triple_prod_and_min_abs_sine( coord, &actual_min_sine);
|
774
|
+
if ( !k || actual_min_sine < min_actual_min_sine ) {
|
775
|
+
min_actual_min_sine = actual_min_sine;
|
776
|
+
}
|
777
|
+
}
|
778
|
+
return min_actual_min_sine <= min_sine;
|
779
|
+
}
|
780
|
+
/*************************************************************/
|
781
|
+
int triple_prod_char( inp_ATOM *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
|
782
|
+
int at_2, int i_next_at_2, S_CHAR *z_dir2 )
|
783
|
+
{
|
784
|
+
inp_ATOM *at1, *at2;
|
785
|
+
double pnt[3][3], len;
|
786
|
+
int i;
|
787
|
+
int ret = 0;
|
788
|
+
|
789
|
+
at1 = at + at_1;
|
790
|
+
at2 = at + at[at_1].neighbor[i_next_at_1];
|
791
|
+
|
792
|
+
pnt[0][0] = at2->x - at1->x;
|
793
|
+
pnt[0][1] = at2->y - at1->y;
|
794
|
+
pnt[0][2] = at2->z - at1->z;
|
795
|
+
|
796
|
+
at2 = at + at_2;
|
797
|
+
at1 = at + at[at_2].neighbor[i_next_at_2];
|
798
|
+
|
799
|
+
pnt[1][0] = at2->x - at1->x;
|
800
|
+
pnt[1][1] = at2->y - at1->y;
|
801
|
+
pnt[1][2] = at2->z - at1->z;
|
802
|
+
/*
|
803
|
+
* resultant pnt vector directions:
|
804
|
+
*
|
805
|
+
* pnt[0] pnt[1]
|
806
|
+
*
|
807
|
+
* [at_1]---->[...] [...]---->[at_2]
|
808
|
+
*
|
809
|
+
*
|
810
|
+
* add3 below: (pnt[0] + pnt[1]) -> pnt[1]
|
811
|
+
*/
|
812
|
+
add3( pnt[0], pnt[1], pnt[1] );
|
813
|
+
|
814
|
+
|
815
|
+
|
816
|
+
for ( i = 0; i < 3; i ++ ) {
|
817
|
+
pnt[0][i] = (double)z_dir1[i];
|
818
|
+
pnt[2][i] = (double)z_dir2[i];
|
819
|
+
}
|
820
|
+
for ( i = 0; i < 3; i ++ ) {
|
821
|
+
len = len3( pnt[i] );
|
822
|
+
if ( len < MIN_BOND_LEN ) {
|
823
|
+
if ( i == 1 && (at[at_1].bUsed0DParity || at[at_2].bUsed0DParity) ) {
|
824
|
+
pnt[i][0] = 0.0;
|
825
|
+
pnt[i][1] = 1.0;
|
826
|
+
pnt[i][2] = 0.0;
|
827
|
+
len = 1.0; /* standard at_1-->at_2 vector coordinates in case of 0D allene */
|
828
|
+
} else {
|
829
|
+
goto exit_function; /* too short bond */
|
830
|
+
}
|
831
|
+
}
|
832
|
+
mult3( pnt[i], 1.0/len, pnt[i] );
|
833
|
+
}
|
834
|
+
len = 100.0*triple_prod(pnt[0], pnt[1], pnt[2], NULL );
|
835
|
+
/*
|
836
|
+
* ^ pnt[0]
|
837
|
+
* | The orientation on this diagram
|
838
|
+
* | produces len = -100
|
839
|
+
* [at_1]------>[at_2]
|
840
|
+
* pnt[1] /
|
841
|
+
* /
|
842
|
+
* / pnt[2] (up from the plane)
|
843
|
+
* v
|
844
|
+
*
|
845
|
+
* Note: len is invariant upon at_1 <--> at_2 transposition because
|
846
|
+
* triple product changes sign upon pnt[0]<-->pnt[2] transposition and
|
847
|
+
* triple product changes sign upon pnt[1]--> -pnt[1] change of direction:
|
848
|
+
*
|
849
|
+
* triple_prod(pnt[0], pnt[1], pnt[2], NULL ) =
|
850
|
+
* triple_prod(pnt[2], -pnt[1], pnt[0], NULL )
|
851
|
+
*
|
852
|
+
*/
|
853
|
+
|
854
|
+
ret = len >= 0.0? (int)floor(len+0.5) : -(int)floor(0.5-len);
|
855
|
+
|
856
|
+
exit_function:
|
857
|
+
|
858
|
+
return ret;
|
859
|
+
}
|
860
|
+
|
861
|
+
|
862
|
+
/****************************************************************/
|
863
|
+
|
864
|
+
#if( NEW_STEREOCENTER_CHECK == 1 ) /* { */
|
865
|
+
|
866
|
+
/********************************************************************************************/
|
867
|
+
int bInpAtomHasRequirdNeigh ( inp_ATOM *at, int cur_at, int RequirdNeighType, int NumDbleBonds )
|
868
|
+
{
|
869
|
+
/* RequirdNeighType:
|
870
|
+
reqired neighbor types (bitmap):
|
871
|
+
0 => any neighbors
|
872
|
+
1 => no terminal hydrogen atom neighbors
|
873
|
+
2 => no terminal -X and -XH together (don't care about -X, -XH bond type, charge, radical)
|
874
|
+
(X = tautomeric endpoint atom)
|
875
|
+
NumDbleBonds:
|
876
|
+
if non-zero then allow double, alternating and tautomeric bonds
|
877
|
+
*/
|
878
|
+
int i, j, ni, nj, bond_type, num_1s, num_mult, num_other;
|
879
|
+
|
880
|
+
if ( at[cur_at].endpoint ) { /* tautomeric endpoint cannot be a stereo center */
|
881
|
+
return 0;
|
882
|
+
}
|
883
|
+
|
884
|
+
if ( (1 & RequirdNeighType) && at[cur_at].num_H ) {
|
885
|
+
return 0;
|
886
|
+
}
|
887
|
+
|
888
|
+
if ( 2 & RequirdNeighType ) {
|
889
|
+
for ( i = 0; i < at[cur_at].valence; i ++ ) {
|
890
|
+
ni = (int)at[cur_at].neighbor[i];
|
891
|
+
if ( at[ni].valence != 1 ||
|
892
|
+
!get_endpoint_valence( at[ni].el_number ) ) {
|
893
|
+
continue;
|
894
|
+
}
|
895
|
+
for ( j = i+1; j < at[cur_at].valence; j ++ ) {
|
896
|
+
nj = (int)at[cur_at].neighbor[j];
|
897
|
+
if ( at[nj].valence != 1 ||
|
898
|
+
at[ni].el_number != at[nj].el_number ||
|
899
|
+
!get_endpoint_valence( at[nj].el_number ) ) {
|
900
|
+
continue;
|
901
|
+
}
|
902
|
+
/*
|
903
|
+
* if (at[ni].num_H != at[nj].num_H) then the atoms (neighbors of at[cur_at]
|
904
|
+
* are tautomeric endpoints and are indistinguishable => cur_at is not stereogenic
|
905
|
+
* if (at[ni].num_H == at[nj].num_H) then the neighbors are indistinguishable
|
906
|
+
* and cur_at will be found non-sterogenic later
|
907
|
+
* get_endpoint_valence() check will not allow the neighbors to be carbons
|
908
|
+
* Therefore the following "if" is not needed; we may just return 0.
|
909
|
+
*/
|
910
|
+
if ( at[ni].num_H != at[nj].num_H && strcmp(at[ni].elname, "C" ) ) {
|
911
|
+
return 0; /* found -X and -XH neighbors */
|
912
|
+
}
|
913
|
+
}
|
914
|
+
}
|
915
|
+
}
|
916
|
+
|
917
|
+
num_1s = num_mult = num_other = 0;
|
918
|
+
|
919
|
+
for ( i = 0; i < at[cur_at].valence; i ++ ) {
|
920
|
+
bond_type = (at[cur_at].bond_type[i] & ~BOND_MARK_ALL);
|
921
|
+
switch( bond_type ) {
|
922
|
+
case BOND_SINGLE:
|
923
|
+
num_1s ++;
|
924
|
+
break;
|
925
|
+
case BOND_DOUBLE:
|
926
|
+
case BOND_ALTERN:
|
927
|
+
case BOND_TAUTOM:
|
928
|
+
case BOND_ALT12NS:
|
929
|
+
num_mult ++;
|
930
|
+
break;
|
931
|
+
default:
|
932
|
+
num_other ++;
|
933
|
+
break;
|
934
|
+
}
|
935
|
+
}
|
936
|
+
|
937
|
+
if ( num_other ) {
|
938
|
+
return 0;
|
939
|
+
}
|
940
|
+
|
941
|
+
if ( NumDbleBonds && NumDbleBonds > num_mult ||
|
942
|
+
!NumDbleBonds && at[cur_at].valence != num_1s ) {
|
943
|
+
return 0;
|
944
|
+
}
|
945
|
+
return 1;
|
946
|
+
}
|
947
|
+
/********************************************************************************************/
|
948
|
+
int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at )
|
949
|
+
{
|
950
|
+
|
951
|
+
/*************************************************************************************
|
952
|
+
* current version
|
953
|
+
*************************************************************************************
|
954
|
+
* Use #define to split the stereocenter description table into parts
|
955
|
+
* to make it easier to read
|
956
|
+
*
|
957
|
+
* --------- 4 single bonds stereocenters -------
|
958
|
+
*
|
959
|
+
* | | | | | |
|
960
|
+
* -C- -Si- -Ge- -Sn- >As[+] >B[-]
|
961
|
+
* | | | | | |
|
962
|
+
*/
|
963
|
+
#define SZELEM1 "C\000","Si", "Ge", "Sn", "As", "B\000",
|
964
|
+
#define CCHARGE1 0, 0, 0, 0, 1, -1,
|
965
|
+
#define CNUMBONDSANDH1 4, 4, 4, 4, 4, 4,
|
966
|
+
#define CCHEMVALENCEH1 4, 4, 4, 4, 4, 4,
|
967
|
+
#define CHAS3MEMBRING1 0, 0, 0, 0, 0, 0,
|
968
|
+
#define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
|
969
|
+
/*
|
970
|
+
* --------------- S, Se stereocenters ----------
|
971
|
+
*
|
972
|
+
* | | || | | ||
|
973
|
+
* -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
|
974
|
+
* | | | | | | | |
|
975
|
+
*/
|
976
|
+
#define SZELEM2 "S\000","S\000","S\000","S\000","Se", "Se", "Se", "Se",
|
977
|
+
#define CCHARGE2 0, 0, 1, 1, 0, 0, 1, 1,
|
978
|
+
#define CNUMBONDSANDH2 3, 4, 3, 4, 3, 4, 3, 4,
|
979
|
+
#define CCHEMVALENCEH2 4, 6, 3, 5, 4, 6, 3, 5,
|
980
|
+
#define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
|
981
|
+
#define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
|
982
|
+
/*
|
983
|
+
* ------------------ N, P stereocenters --------
|
984
|
+
*
|
985
|
+
* X---Y
|
986
|
+
* | | \ / | |
|
987
|
+
* =N- >N[+] N >P[+] =P-
|
988
|
+
* | | | | |
|
989
|
+
*/
|
990
|
+
#define SZELEM3 "N\000","N\000","N\000","P\000","P\000",
|
991
|
+
#define CCHARGE3 0, 1, 0, 1, 0,
|
992
|
+
#define CNUMBONDSANDH3 4, 4, 3, 4, 4,
|
993
|
+
#define CCHEMVALENCEH3 5, 4, 3, 4, 5,
|
994
|
+
#define CHAS3MEMBRING3 0, 0, 1, 0, 0,
|
995
|
+
#define CREQUIRDNEIGH3 3, 3, 1, 3, 3,
|
996
|
+
|
997
|
+
|
998
|
+
|
999
|
+
static char szElem[][3]={ SZELEM1 SZELEM2 SZELEM3 };
|
1000
|
+
static S_CHAR cCharge[]={ CCHARGE1 CCHARGE2 CCHARGE3 };
|
1001
|
+
static S_CHAR cNumBondsAndH[]={ CNUMBONDSANDH1 CNUMBONDSANDH2 CNUMBONDSANDH3 };
|
1002
|
+
static S_CHAR cChemValenceH[]={ CCHEMVALENCEH1 CCHEMVALENCEH2 CCHEMVALENCEH3 };
|
1003
|
+
static S_CHAR cHas3MembRing[]={ CHAS3MEMBRING1 CHAS3MEMBRING2 CHAS3MEMBRING3 };
|
1004
|
+
static S_CHAR cRequirdNeigh[]={ CREQUIRDNEIGH1 CREQUIRDNEIGH2 CREQUIRDNEIGH3 };
|
1005
|
+
|
1006
|
+
static int n = sizeof(szElem)/sizeof(szElem[0]);
|
1007
|
+
/* reqired neighbor types (bitmap):
|
1008
|
+
0 => check bonds only
|
1009
|
+
1 => no terminal hydrogen atom neighbors
|
1010
|
+
2 => no terminal -X and -XH together (don't care the bond type, charge, radical)
|
1011
|
+
(X = tautomeric endpoint atom)
|
1012
|
+
Note: whenever cChemValenceH[] > cNumBondsAndH[]
|
1013
|
+
the tautomeric and/or alternating bonds
|
1014
|
+
are permitted
|
1015
|
+
|
1016
|
+
*/
|
1017
|
+
int i, ret = 0;
|
1018
|
+
for ( i = 0; i < n; i++ ) {
|
1019
|
+
if ( !strcmp( at[cur_at].elname, szElem[i]) &&
|
1020
|
+
at[cur_at].charge == cCharge[i] &&
|
1021
|
+
(!at[cur_at].radical || at[cur_at].radical == 1) &&
|
1022
|
+
at[cur_at].valence +at[cur_at].num_H == cNumBondsAndH[i] &&
|
1023
|
+
at[cur_at].chem_bonds_valence+at[cur_at].num_H == cChemValenceH[i] &&
|
1024
|
+
(cHas3MembRing[i]? is_atom_in_3memb_ring( at, cur_at ) : 1) &&
|
1025
|
+
bInpAtomHasRequirdNeigh ( at, cur_at, cRequirdNeigh[i], cChemValenceH[i]-cNumBondsAndH[i]) ) {
|
1026
|
+
ret = cNumBondsAndH[i];
|
1027
|
+
break;
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
return ret;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
#else /* } NEW_STEREOCENTER_CHECK { */
|
1034
|
+
|
1035
|
+
/********************************************************************************************/
|
1036
|
+
int bCanAtomBeAStereoCenter( char *elname, S_CHAR charge, S_CHAR radical )
|
1037
|
+
{
|
1038
|
+
static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "P\000", "As", "B\000" };
|
1039
|
+
static S_CHAR cCharge[] = { 0, 0, 0, 1, 1, 1, -1 };
|
1040
|
+
int i, ret = 0;
|
1041
|
+
for ( i = 0; i < sizeof(szElem)/sizeof(szElem[0]); i++ ) {
|
1042
|
+
if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
|
1043
|
+
ret = (!radical || radical == RADICAL_SINGLET);
|
1044
|
+
break;
|
1045
|
+
}
|
1046
|
+
}
|
1047
|
+
return ret;
|
1048
|
+
}
|
1049
|
+
#endif /* } NEW_STEREOCENTER_CHECK */
|
1050
|
+
|
1051
|
+
/****************************************************************/
|
1052
|
+
/* used for atoms adjacent to stereogenic bonds only */
|
1053
|
+
int bAtomHasValence3( char *elname, S_CHAR charge, S_CHAR radical )
|
1054
|
+
{
|
1055
|
+
static char szElem[][3] = { "N\000" };
|
1056
|
+
static S_CHAR cCharge[] = { 0, };
|
1057
|
+
int i, ret = 0;
|
1058
|
+
for ( i = 0; i < (int)(sizeof(szElem)/sizeof(szElem[0])); i++ ) {
|
1059
|
+
if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
|
1060
|
+
ret = ( !radical || radical == RADICAL_SINGLET );
|
1061
|
+
break;
|
1062
|
+
}
|
1063
|
+
}
|
1064
|
+
return ret;
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
/****************************************************************/
|
1068
|
+
/* used for atoms adjacent to stereogenic bonds only */
|
1069
|
+
int bCanAtomHaveAStereoBond( char *elname, S_CHAR charge, S_CHAR radical )
|
1070
|
+
{
|
1071
|
+
static char szElem[][3] = { "C\000", "Si", "Ge", "N\000", "N\000" };
|
1072
|
+
static S_CHAR cCharge[] = { 0, 0, 0, 0, 1, };
|
1073
|
+
static int n = sizeof(szElem)/sizeof(szElem[0]);
|
1074
|
+
int i, ret = 0;
|
1075
|
+
for ( i = 0; i < n; i++ ) {
|
1076
|
+
if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
|
1077
|
+
ret = (!radical || radical == RADICAL_SINGLET);
|
1078
|
+
break;
|
1079
|
+
}
|
1080
|
+
}
|
1081
|
+
return ret;
|
1082
|
+
}
|
1083
|
+
/****************************************************************/
|
1084
|
+
/* used for atoms adjacent to stereogenic bonds only */
|
1085
|
+
int bCanAtomBeMiddleAllene( char *elname, S_CHAR charge, S_CHAR radical )
|
1086
|
+
{
|
1087
|
+
static char szElem[][3] = { "C\000", "Si", "Ge", };
|
1088
|
+
static S_CHAR cCharge[] = { 0, 0, 0, };
|
1089
|
+
static int n = sizeof(szElem)/sizeof(szElem[0]);
|
1090
|
+
int i, ret = 0;
|
1091
|
+
for ( i = 0; i < n; i++ ) {
|
1092
|
+
if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
|
1093
|
+
ret = (!radical || radical == RADICAL_SINGLET);
|
1094
|
+
break;
|
1095
|
+
}
|
1096
|
+
}
|
1097
|
+
return ret;
|
1098
|
+
}
|
1099
|
+
/*****************************************************************/
|
1100
|
+
int bIsSuitableHeteroInpAtom( inp_ATOM *at )
|
1101
|
+
{
|
1102
|
+
int val, num_H;
|
1103
|
+
if ( 0 == at->charge &&
|
1104
|
+
(!at->radical || RADICAL_SINGLET == at->radical) &&
|
1105
|
+
0 < (val=get_endpoint_valence( at->el_number ) )) {
|
1106
|
+
num_H = at->num_H;
|
1107
|
+
if ( val == at->chem_bonds_valence + num_H ) {
|
1108
|
+
switch( val ) {
|
1109
|
+
case 2: /* O */
|
1110
|
+
if ( !num_H && 1 == at->valence )
|
1111
|
+
return 0; /* =O */
|
1112
|
+
break; /* not found */
|
1113
|
+
case 3: /* N */
|
1114
|
+
if ( 1 == at->valence && 1 == num_H ||
|
1115
|
+
2 == at->valence && 0 == num_H )
|
1116
|
+
return 1; /* =N- or =NH */
|
1117
|
+
break; /* not found */
|
1118
|
+
}
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
return -1;
|
1122
|
+
}
|
1123
|
+
/****************************************************************/
|
1124
|
+
int bIsOxide( inp_ATOM *at, int cur_at )
|
1125
|
+
{
|
1126
|
+
int i, bond_type;
|
1127
|
+
inp_ATOM *a = at + cur_at, *an;
|
1128
|
+
for ( i = 0; i < a->valence; i ++ ) {
|
1129
|
+
bond_type = (a->bond_type[i] &= ~BOND_MARK_ALL);
|
1130
|
+
if ( bond_type == BOND_DOUBLE ) {
|
1131
|
+
an = at + (int)a->neighbor[i];
|
1132
|
+
if ( 1 == an->valence &&
|
1133
|
+
!an->charge && !an->num_H && !an->radical &&
|
1134
|
+
2 == get_endpoint_valence( an->el_number ) ) {
|
1135
|
+
return 1;
|
1136
|
+
}
|
1137
|
+
} else
|
1138
|
+
if ( bond_type == BOND_TAUTOM || bond_type == BOND_ALT12NS ) {
|
1139
|
+
an = at + (int)a->neighbor[i];
|
1140
|
+
if ( 1 == an->valence &&
|
1141
|
+
2 == get_endpoint_valence( an->el_number ) ) {
|
1142
|
+
return 1;
|
1143
|
+
}
|
1144
|
+
}
|
1145
|
+
}
|
1146
|
+
return 0;
|
1147
|
+
}
|
1148
|
+
/****************************************************************/
|
1149
|
+
/* used for atoms adjacent to stereogenic bonds only */
|
1150
|
+
int bCanAtomBeTerminalAllene( char *elname, S_CHAR charge, S_CHAR radical )
|
1151
|
+
{
|
1152
|
+
static char szElem[][3] = { "C\000", "Si", "Ge", };
|
1153
|
+
static S_CHAR cCharge[] = { 0, 0, 0, };
|
1154
|
+
static int n = sizeof(szElem)/sizeof(szElem[0]);
|
1155
|
+
int i, ret = 0;
|
1156
|
+
for ( i = 0; i < n; i++ ) {
|
1157
|
+
if ( !strcmp( elname, szElem[i] ) && (charge == cCharge[i]) ) {
|
1158
|
+
ret = (!radical || radical == RADICAL_SINGLET);
|
1159
|
+
break;
|
1160
|
+
}
|
1161
|
+
}
|
1162
|
+
return ret;
|
1163
|
+
}
|
1164
|
+
/************************************************************************/
|
1165
|
+
int GetHalfStereobond0DParity( inp_ATOM *at, int cur_at, AT_NUMB nSbNeighOrigAtNumb[],
|
1166
|
+
int nNumExplictAttachments, int bond_parity, int nFlag )
|
1167
|
+
{
|
1168
|
+
int m, last_parity, cur_parity;
|
1169
|
+
int i, icur2nxt, icur2neigh, cur_order_parity, nxt_at;
|
1170
|
+
AT_NUMB nNextSbAtOrigNumb;
|
1171
|
+
/* find atom parities for all valid streobonds incident to at[cur_at] */
|
1172
|
+
for ( m = 0, last_parity = 0; m < MAX_NUM_STEREO_BONDS && at[cur_at].sb_parity[m]; m ++ ) {
|
1173
|
+
icur2nxt = icur2neigh = -1; /* ordering number of neighbors in nSbNeighOrigAtNumb[] */
|
1174
|
+
cur_parity = 0; /* parity for mth stereobond incident to the cur_at */
|
1175
|
+
if ( 0 <= at[cur_at].sb_ord[m] && at[cur_at].sb_ord[m] < at[cur_at].valence &&
|
1176
|
+
0 <= (nxt_at = at[cur_at].neighbor[(int)at[cur_at].sb_ord[m]]) &&
|
1177
|
+
at[nxt_at].valence <= MAX_NUM_STEREO_BONDS && /* make sure it is a valid stereobond */
|
1178
|
+
(nNextSbAtOrigNumb = at[nxt_at].orig_at_number) ) {
|
1179
|
+
/* since at[cur_at].sn_ord[m] = -1 for explicit H use at[cur_at].sn_orig_at_num[m] */
|
1180
|
+
for ( i = 0; i < nNumExplictAttachments; i ++ ) {
|
1181
|
+
if ( at[cur_at].sn_orig_at_num[m] == nSbNeighOrigAtNumb[i] ) {
|
1182
|
+
icur2neigh = i; /* neighbor */
|
1183
|
+
} else
|
1184
|
+
if ( nNextSbAtOrigNumb == nSbNeighOrigAtNumb[i] ) {
|
1185
|
+
icur2nxt = i; /* atom connected by a stereobond */
|
1186
|
+
}
|
1187
|
+
}
|
1188
|
+
if ( icur2neigh >= 0 && icur2nxt >= 0 ) {
|
1189
|
+
if ( ATOM_PARITY_WELL_DEF(at[cur_at].sb_parity[m]) ) {
|
1190
|
+
/* parity of at[cur_atom] neighbor permutation to reach this order: { next_atom, neigh_atom, ...} */
|
1191
|
+
cur_order_parity = (icur2nxt + icur2neigh + (icur2nxt > icur2neigh) - 1) % 2;
|
1192
|
+
cur_parity = 2 - (cur_order_parity + at[cur_at].sb_parity[m]) % 2;
|
1193
|
+
} else {
|
1194
|
+
/* unknowm/undef parities do not depend on the neighbor order */
|
1195
|
+
cur_parity = at[cur_at].sb_parity[m];
|
1196
|
+
}
|
1197
|
+
}
|
1198
|
+
} else {
|
1199
|
+
continue;
|
1200
|
+
}
|
1201
|
+
/* use a well-known parity if available; if not then use preferably the unknown */
|
1202
|
+
if ( !last_parity ) {
|
1203
|
+
last_parity = cur_parity;
|
1204
|
+
} else
|
1205
|
+
if ( last_parity != cur_parity && cur_parity ) {
|
1206
|
+
if ( ATOM_PARITY_WELL_DEF(last_parity) ) {
|
1207
|
+
if ( ATOM_PARITY_WELL_DEF(cur_parity) ) {
|
1208
|
+
last_parity = 0; /* error: all well-defined parities should be same */
|
1209
|
+
break;
|
1210
|
+
}
|
1211
|
+
} else
|
1212
|
+
if ( ATOM_PARITY_WELL_DEF(cur_parity) ) {
|
1213
|
+
/* replace unknown/undefined parity with well-known */
|
1214
|
+
last_parity = cur_parity;
|
1215
|
+
} else {
|
1216
|
+
/* select min unknown/undefined parity (out of AB_PARITY_UNKN and AB_PARITY_UNDF) */
|
1217
|
+
last_parity = inchi_min(cur_parity, last_parity);
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
if ( last_parity ) {
|
1222
|
+
bond_parity = last_parity;
|
1223
|
+
at[cur_at].bUsed0DParity |= nFlag; /* set flag: used stereobond 0D parity */
|
1224
|
+
}
|
1225
|
+
return bond_parity;
|
1226
|
+
}
|
1227
|
+
/*******************************************************************************************/
|
1228
|
+
int FixSb0DParities( inp_ATOM *at, /* inp_ATOM *at_removed_H, int num_removed_H,*/ int chain_length,
|
1229
|
+
int at_1, int i_next_at_1, S_CHAR z_dir1[],
|
1230
|
+
int at_2, int i_next_at_2, S_CHAR z_dir2[],
|
1231
|
+
int *pparity1, int *pparity2 )
|
1232
|
+
{
|
1233
|
+
int k, parity1, parity2, abs_parity1, abs_parity2;
|
1234
|
+
int j1, j2, parity_sign;
|
1235
|
+
/*
|
1236
|
+
AT_NUMB nSbNeighOrigAtNumb1[MAX_NUM_STEREO_BOND_NEIGH], nSbNeighOrigAtNumb2[MAX_NUM_STEREO_BOND_NEIGH];
|
1237
|
+
int nNumExplictAttachments1, nNumExplictAttachments2;
|
1238
|
+
*/
|
1239
|
+
parity1 = parity2 = AB_PARITY_NONE;
|
1240
|
+
j1 = j2 = -1;
|
1241
|
+
parity_sign = ( *pparity1 < 0 || *pparity2 < 0 )? -1 : 1;
|
1242
|
+
|
1243
|
+
abs_parity1 = abs(*pparity1);
|
1244
|
+
abs_parity2 = abs(*pparity2);
|
1245
|
+
|
1246
|
+
for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k ++ ) {
|
1247
|
+
if ( at[at_1].sb_ord[k] == i_next_at_1 ) {
|
1248
|
+
parity1 = at[at_1].sb_parity[k];
|
1249
|
+
j1 = k;
|
1250
|
+
}
|
1251
|
+
}
|
1252
|
+
for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_2].sb_parity[k]; k ++ ) {
|
1253
|
+
if ( at[at_2].sb_ord[k] == i_next_at_2 ) {
|
1254
|
+
parity2 = at[at_2].sb_parity[k];
|
1255
|
+
j2 = k;
|
1256
|
+
}
|
1257
|
+
}
|
1258
|
+
switch( (j1 >= 0) + 2*(j2 >= 0) ) {
|
1259
|
+
case 0:
|
1260
|
+
/* the bond has no 0D parity */
|
1261
|
+
*pparity1 = *pparity2 = parity_sign * AB_PARITY_UNDF;
|
1262
|
+
return 0;
|
1263
|
+
case 1:
|
1264
|
+
case 2:
|
1265
|
+
/* 0D parity data error */
|
1266
|
+
*pparity1 = *pparity2 = AB_PARITY_NONE;
|
1267
|
+
return -1;
|
1268
|
+
case 3:
|
1269
|
+
/* the bond has 0D parity */
|
1270
|
+
switch ( !(ATOM_PARITY_WELL_DEF( abs_parity1 ) && ATOM_PARITY_WELL_DEF( parity1 )) +
|
1271
|
+
2 * !(ATOM_PARITY_WELL_DEF( abs_parity2 ) && ATOM_PARITY_WELL_DEF( parity2 )) ) {
|
1272
|
+
case 0:
|
1273
|
+
/* both parities are well-defined; continue */
|
1274
|
+
break;
|
1275
|
+
case 1:
|
1276
|
+
/* 0D parity not well-defined for at_1 */
|
1277
|
+
*pparity1 = parity_sign * (ATOM_PARITY_WELL_DEF( parity1 )? abs_parity1 :
|
1278
|
+
ATOM_PARITY_WELL_DEF( abs_parity1 )? parity1 :
|
1279
|
+
inchi_min(abs_parity1, parity1));
|
1280
|
+
*pparity2 = parity_sign * abs_parity2;
|
1281
|
+
return -1;
|
1282
|
+
case 2:
|
1283
|
+
/* 0D parity not well-defined for at_2 */
|
1284
|
+
*pparity1 = parity_sign * abs_parity1;
|
1285
|
+
*pparity2 = parity_sign * (ATOM_PARITY_WELL_DEF( parity2 )? abs_parity2 :
|
1286
|
+
ATOM_PARITY_WELL_DEF( abs_parity2 )? parity2 :
|
1287
|
+
inchi_min(abs_parity2, parity2));
|
1288
|
+
return -1;
|
1289
|
+
case 3:
|
1290
|
+
abs_parity1 = (ATOM_PARITY_WELL_DEF( parity1 )? abs_parity1 :
|
1291
|
+
ATOM_PARITY_WELL_DEF( abs_parity1 )? parity1 :
|
1292
|
+
inchi_min(abs_parity1, parity1));
|
1293
|
+
abs_parity2 = (ATOM_PARITY_WELL_DEF( parity2 )? abs_parity2 :
|
1294
|
+
ATOM_PARITY_WELL_DEF( abs_parity2 )? parity2 :
|
1295
|
+
inchi_min(abs_parity2, parity2));
|
1296
|
+
*pparity1 = *pparity2 = parity_sign * inchi_min(abs_parity1, abs_parity2);
|
1297
|
+
/*return (parity1 == parity2)? 0 : -1;*/
|
1298
|
+
return -1;
|
1299
|
+
}
|
1300
|
+
break;
|
1301
|
+
}
|
1302
|
+
/* we are here if both end-atoms of the bond have well-defined 0D parities */
|
1303
|
+
/*
|
1304
|
+
nNumExplictAttachments1 = GetSbNeighOrigAtNumb( at, at_1, at_removed_H, num_removed_H, nSbNeighOrigAtNumb1 );
|
1305
|
+
nNumExplictAttachments2 = GetSbNeighOrigAtNumb( at, at_2, at_removed_H, num_removed_H, nSbNeighOrigAtNumb2 );
|
1306
|
+
parity1 = GetHalfStereobond0DParity( at, at_1, nSbNeighOrigAtNumb1, nNumExplictAttachments1, *pparity1, 0 );
|
1307
|
+
parity2 = GetHalfStereobond0DParity( at, at_2, nSbNeighOrigAtNumb2, nNumExplictAttachments2, *pparity2, 0 );
|
1308
|
+
*/
|
1309
|
+
*pparity1 = parity_sign * abs_parity1;
|
1310
|
+
*pparity2 = parity_sign * abs_parity2;
|
1311
|
+
|
1312
|
+
if ( chain_length % 2 ) {
|
1313
|
+
/* allene; chain_length = (number of double bonds) - 1 */
|
1314
|
+
/*
|
1315
|
+
int zer1 = ( !z_dir1[0] && !z_dir1[1] && !z_dir1[2] );
|
1316
|
+
int zer2 = ( !z_dir2[0] && !z_dir2[1] && !z_dir2[2] );
|
1317
|
+
*/
|
1318
|
+
int bWrong_z_dir1 = (0 != (at[at_1].bUsed0DParity & FlagSB_0D));
|
1319
|
+
int bWrong_z_dir2 = (0 != (at[at_2].bUsed0DParity & FlagSB_0D));
|
1320
|
+
|
1321
|
+
if ( bWrong_z_dir1 && bWrong_z_dir2 ) {
|
1322
|
+
goto set_default;
|
1323
|
+
} else
|
1324
|
+
if ( bWrong_z_dir1 || bWrong_z_dir2 ) {
|
1325
|
+
double r12[3], zi1[3], zi2[3], abs_r12, abs_zi2;
|
1326
|
+
int at_i1, at_i2, j;
|
1327
|
+
S_CHAR z_dir[3];
|
1328
|
+
r12[0] = at[at_2].x - at[at_1].x;
|
1329
|
+
r12[1] = at[at_2].y - at[at_1].y;
|
1330
|
+
r12[2] = at[at_2].z - at[at_1].z;
|
1331
|
+
abs_r12 = len3( r12 );
|
1332
|
+
if ( abs_r12 < MIN_BOND_LEN ) {
|
1333
|
+
goto set_default;
|
1334
|
+
}
|
1335
|
+
/* make r12[] point to the atom with 'good' z_dir[] */
|
1336
|
+
if ( bWrong_z_dir1 ) {
|
1337
|
+
at_i1 = at_2; /* has good z_dir2[] */
|
1338
|
+
at_i2 = at_1; /* has bad z_dir1[] */
|
1339
|
+
zi1[0] = z_dir2[0];
|
1340
|
+
zi1[1] = z_dir2[1];
|
1341
|
+
zi1[2] = z_dir2[2];
|
1342
|
+
mult3( r12, 1.0/abs_r12, r12 ); /* make length = 1 */
|
1343
|
+
} else {
|
1344
|
+
at_i1 = at_1; /* has good z_dir1[] */
|
1345
|
+
at_i2 = at_2; /* has bad z_dir2[] */
|
1346
|
+
zi1[0] = z_dir1[0];
|
1347
|
+
zi1[1] = z_dir1[1];
|
1348
|
+
zi1[2] = z_dir1[2];
|
1349
|
+
mult3( r12, -1.0/abs_r12, r12 ); /* make length = 1 */
|
1350
|
+
}
|
1351
|
+
cross_prod3( r12, zi1, zi2 );
|
1352
|
+
abs_zi2 = len3( zi2 );
|
1353
|
+
mult3( zi2, 100.0/abs_zi2, zi2 ); /* make length = 100 */
|
1354
|
+
for ( j = 0; j < 3; j ++ ) {
|
1355
|
+
z_dir[j] = (S_CHAR) (zi2[j]>= 0.0? floor(0.5 + zi2[j]) :
|
1356
|
+
-floor(0.5 - zi2[j])); /* abs(z_dir) = 100 */
|
1357
|
+
}
|
1358
|
+
if ( bWrong_z_dir1 ) {
|
1359
|
+
memcpy( z_dir1, z_dir, sizeof(z_dir) );
|
1360
|
+
} else {
|
1361
|
+
memcpy( z_dir2, z_dir, sizeof(z_dir) );
|
1362
|
+
}
|
1363
|
+
}
|
1364
|
+
return 0;
|
1365
|
+
|
1366
|
+
set_default:
|
1367
|
+
/* z_dir1[] = x-direction; z_dir2[] = z-direction; r12[] = y-direction */
|
1368
|
+
z_dir1[0] = 100;
|
1369
|
+
z_dir1[1] = z_dir1[2] = 0;
|
1370
|
+
z_dir2[0] = z_dir2[1] = 0;
|
1371
|
+
z_dir2[2] = 100;
|
1372
|
+
}
|
1373
|
+
return 0;
|
1374
|
+
}
|
1375
|
+
|
1376
|
+
/*======================================================================================================
|
1377
|
+
|
1378
|
+
half_stereo_bond_parity() General Description:
|
1379
|
+
|
1380
|
+
A) find projections of 3 bonds on a reasonable plane defined
|
1381
|
+
by a vector z_dir perpendicular to the plane
|
1382
|
+
B) calculate parity
|
1383
|
+
|
1384
|
+
half_stereo_bond_parity() Detailed Description:
|
1385
|
+
|
1386
|
+
1) Find at_coord[] = vectors from the central atoms to its neighbors
|
1387
|
+
2) If only 2 neighbors are present, then create a reasonable 3rd neighbor
|
1388
|
+
(an implicit H or a fictitious atom in case of =NX) coordinates
|
1389
|
+
3) Normalize at_coord[] to unit length
|
1390
|
+
4) Find unit vector pnt[2] perpendicular to the plane containing
|
1391
|
+
at_coord[] arrow ends.
|
1392
|
+
Even though it is not necessary, make z-coordinate of pnt[2] positive.
|
1393
|
+
** pnt[2] has the new z-axis direction **
|
1394
|
+
5) Let pnt[0] = perpendicular to pnt[2] component of at_coord[0];
|
1395
|
+
Normalize pnt[0] to unit length.
|
1396
|
+
** pnt[0] has the new x-axis direction **
|
1397
|
+
6) Let pnt[1] = pnt[2] x pnt[0] (cross-product);
|
1398
|
+
** pnt[1] has the new y-axis direction **
|
1399
|
+
7) Find at_coord[] in the new xyz-basis and normalize their xy-projections
|
1400
|
+
to a unit length
|
1401
|
+
8) In the new xy-plane find (counterclockwise) angles:
|
1402
|
+
tmp1 = (from at_coord[0] to at_coord[1])
|
1403
|
+
tmp2 = (from at_coord[0] to at_coord[2])
|
1404
|
+
9) Calculate the parity: if tmp1 < tmp2 then 1 (odd) else 2 (even)
|
1405
|
+
(even: looking from the arrow end of the new z-axis, 0, 1, and 2 neighbors
|
1406
|
+
are in clockwise order)
|
1407
|
+
10) Calculate z_dir = 100*pnt[2].
|
1408
|
+
|
1409
|
+
Note1. If z_dir vectors of atoms located at the opposite ends of a double bond have approximately
|
1410
|
+
opposite directions (that is, their dot-product is negative) then the parity of the
|
1411
|
+
stereogenic bond calculated from half-bond-parities should be inverted
|
1412
|
+
|
1413
|
+
Note2. In case of a tetrahedral cumulene a triple product (z_dir1, (1->2), z_dir2) is used instead
|
1414
|
+
of the dot-product. (1->2) is a vector from the atom#1 to the atom #2. This triple product
|
1415
|
+
is invariant with respect to the atom numbering because it does not change upon (1,2)
|
1416
|
+
permutation.
|
1417
|
+
|
1418
|
+
Stereo ambiguity in case of 2 neighbors:
|
1419
|
+
----------------------------------------
|
1420
|
+
Undefined: single-double bond angle > pi - arcsin(0.03) = 178.28164199834454285275613218975 degrees
|
1421
|
+
Ambiguous: single-double bond angle > 175 degrees = pi - 0.087156 Rad
|
1422
|
+
|
1423
|
+
Return values
|
1424
|
+
(cases: I=only in case of isotopic H atoms the neighbors are different,
|
1425
|
+
N=in case of non-isotopic H atoms the neighbors are different)
|
1426
|
+
|
1427
|
+
-4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, I
|
1428
|
+
-3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, I
|
1429
|
+
-2 =-AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, I
|
1430
|
+
-1 =-AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, I
|
1431
|
+
0 = AB_PARITY_NONE => the atom is not adjacent to a stereogenic bond
|
1432
|
+
1 = AB_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, N&I
|
1433
|
+
2 = AB_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, N&I
|
1434
|
+
3 = AB_PARITY_UNKN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, N&I
|
1435
|
+
4 = AB_PARITY_UNDF => atom is adjacent to a stereogenic bond, but the geometry is undefined, N&I
|
1436
|
+
5 = AB_PARITY_IISO => atom constitutionally equivalent to this atom may be adjacent to a stereogenic bond, I
|
1437
|
+
|
1438
|
+
|
1439
|
+
=====================================================================================================*/
|
1440
|
+
|
1441
|
+
int half_stereo_bond_parity( inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H, int num_removed_H, S_CHAR *z_dir, int bPointedEdgeStereo )
|
1442
|
+
{
|
1443
|
+
double at_coord[MAX_NUM_STEREO_BOND_NEIGH][3], c, s, tmp[3], tmp1, tmp2, min_tmp, max_tmp, z;
|
1444
|
+
double temp[3], pnt[3][3];
|
1445
|
+
int j, k, p0, p1, p2, next, bValence3=0, num_z, nType, num_either_single, num_either_double;
|
1446
|
+
int nNumExplictAttachments;
|
1447
|
+
int bond_parity = AB_PARITY_UNDF;
|
1448
|
+
int num_H=0, num_iH, num_eH=0, num_nH=0 /* = num_iso_H[0] */;
|
1449
|
+
int num_iso_H[NUM_H_ISOTOPES+1];
|
1450
|
+
int index_H[5]; /* cannot have more than 4 elements: 1 H, 1 1H, 1 D, 1 T atom(s) */
|
1451
|
+
const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
|
1452
|
+
const double two_pi = 2.0*one_pi;
|
1453
|
+
int bIgnoreIsotopicH = (0 != (at[cur_at].cFlags & AT_FLAG_ISO_H_POINT));
|
1454
|
+
AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_BOND_NEIGH];
|
1455
|
+
|
1456
|
+
|
1457
|
+
if ( z_dir && !z_dir[0] && !z_dir[1] && !z_dir[2] ) {
|
1458
|
+
z_dir[2]=100;
|
1459
|
+
}
|
1460
|
+
|
1461
|
+
num_H = at[cur_at].num_H;
|
1462
|
+
if ( num_H > NUM_H_ISOTOPES )
|
1463
|
+
return 0; /* at least 2 H atoms are isotopically identical */
|
1464
|
+
|
1465
|
+
if ( MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence + num_H ||
|
1466
|
+
MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence + num_H )
|
1467
|
+
return 0;
|
1468
|
+
|
1469
|
+
if ( !bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) )
|
1470
|
+
return 0;
|
1471
|
+
if ( !bIgnoreIsotopicH ) {
|
1472
|
+
for ( j = 0, num_nH = num_H; j < NUM_H_ISOTOPES; j ++ ) {
|
1473
|
+
if ( (k = (int)at[cur_at].num_iso_H[j]) > 1 ) {
|
1474
|
+
return AB_PARITY_IISO; /* two or more identical isotopic H atoms */
|
1475
|
+
}
|
1476
|
+
num_nH -= k;
|
1477
|
+
}
|
1478
|
+
}
|
1479
|
+
/* at this point num_nH = number of non-isotopic H atoms */
|
1480
|
+
if ( num_nH > 1 )
|
1481
|
+
return AB_PARITY_IISO; /* two or more identical non-isotopic H atoms */
|
1482
|
+
if ( num_nH < 0 )
|
1483
|
+
return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
|
1484
|
+
|
1485
|
+
/********************************************************************
|
1486
|
+
* Note. At this point all (implicit and explicit) isotopic
|
1487
|
+
* terminal H neighbors are either different or not present.
|
1488
|
+
********************************************************************/
|
1489
|
+
|
1490
|
+
/* locate explicit hydrogen atoms */
|
1491
|
+
/* (at_removed_H are sorted in ascending isotopic H mass order, non-isotopic first) */
|
1492
|
+
memset( num_iso_H, 0, sizeof(num_iso_H) );
|
1493
|
+
if ( at_removed_H && num_removed_H > 0 ) {
|
1494
|
+
for ( j = 0; j < num_removed_H; j ++ ) {
|
1495
|
+
if ( at_removed_H[j].neighbor[0] == cur_at ) {
|
1496
|
+
k = bIgnoreIsotopicH? 0 : at_removed_H[j].iso_atw_diff;
|
1497
|
+
if ( 0 <= k && k <= NUM_H_ISOTOPES ) {
|
1498
|
+
if ( ++num_iso_H[k] > 1 ) /* num_iso_H[0] = number of non-isotopic H atoms */
|
1499
|
+
return CT_ISO_H_ERR; /* program error in counting hydrogens */ /* <BRKPT> */
|
1500
|
+
index_H[num_eH++] = j;
|
1501
|
+
} else {
|
1502
|
+
return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
|
1503
|
+
}
|
1504
|
+
}
|
1505
|
+
}
|
1506
|
+
num_iH = num_H - num_eH; /* number of implicit non-isotopic and isotopic H atoms */
|
1507
|
+
if ( num_iH > 1 ) {
|
1508
|
+
/* more than one implicit H: cannot reconstruct the geometry */
|
1509
|
+
bond_parity = -AB_PARITY_UNDF;
|
1510
|
+
goto exit_function;
|
1511
|
+
}
|
1512
|
+
} else {
|
1513
|
+
num_iH = num_H;
|
1514
|
+
}
|
1515
|
+
/* at this point num_iH = number of implicit non-isotopic and isotopic H atoms */
|
1516
|
+
if ( at[cur_at].valence + num_eH < MIN_NUM_STEREO_BOND_NEIGH ) {
|
1517
|
+
/* =NH or =CHD when no explicit H is present */
|
1518
|
+
return num_H == 1? AB_PARITY_UNDF : -AB_PARITY_UNDF;
|
1519
|
+
}
|
1520
|
+
|
1521
|
+
bValence3 = bAtomHasValence3( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical );
|
1522
|
+
/*
|
1523
|
+
* Can one explicit hydrogen be added to make asymmetric configuration?
|
1524
|
+
* For now we can add 1 H atom in case of an appropriate geometry if:
|
1525
|
+
* (a) one non-isotopic H (even if explicit isotopic H atoms are present), or
|
1526
|
+
* (b) one isotopic or non-isotopic H if NO explicit isotopic or non-isotopic H atom is present
|
1527
|
+
* This makes sense only in case chem. valence = 4. In case of chem. valence = 3, do not check.
|
1528
|
+
*/
|
1529
|
+
if ( at[cur_at].valence + num_eH == MIN_NUM_STEREO_BOND_NEIGH && !bValence3 &&
|
1530
|
+
!(/*(a)*/ 1 == num_nH && !num_iso_H[0] ||
|
1531
|
+
/*(b)*/ 1 == num_H && !num_eH)
|
1532
|
+
) {
|
1533
|
+
goto exit_function;
|
1534
|
+
/* return num_H == 1? AB_PARITY_UNDF : -AB_PARITY_UNDF; */
|
1535
|
+
}
|
1536
|
+
|
1537
|
+
/* store neighbors coordinates */
|
1538
|
+
num_z = num_either_single = num_either_double = 0;
|
1539
|
+
for ( k = nNumExplictAttachments = 0; k < 2; k ++ ) {
|
1540
|
+
switch( k ) {
|
1541
|
+
case 0:
|
1542
|
+
for ( j = 0; j < num_eH; j ++, nNumExplictAttachments ++ ) {
|
1543
|
+
next = index_H[j];
|
1544
|
+
at_coord[nNumExplictAttachments][0] = at_removed_H[next].x - at[cur_at].x;
|
1545
|
+
at_coord[nNumExplictAttachments][1] = at_removed_H[next].y - at[cur_at].y;
|
1546
|
+
nSbNeighOrigAtNumb[nNumExplictAttachments] = at_removed_H[next].orig_at_number;
|
1547
|
+
/* use the fact that (at_removed_H - at) = (number of atoms except removed explicit H) */
|
1548
|
+
z = -get_z_coord( at, (at_removed_H-at)+next, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
|
1549
|
+
switch ( nType ) {
|
1550
|
+
case ZTYPE_EITHER:
|
1551
|
+
num_either_single ++; /* bond in "Either" direction. */
|
1552
|
+
break;
|
1553
|
+
case ZTYPE_UP:
|
1554
|
+
case ZTYPE_DOWN:
|
1555
|
+
nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
|
1556
|
+
z = len2( at_coord[nNumExplictAttachments] );
|
1557
|
+
/*
|
1558
|
+
z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
|
1559
|
+
+ at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
|
1560
|
+
*/
|
1561
|
+
if ( nType == ZTYPE_DOWN )
|
1562
|
+
z = -z;
|
1563
|
+
/* no break; here */
|
1564
|
+
case ZTYPE_3D:
|
1565
|
+
num_z ++;
|
1566
|
+
}
|
1567
|
+
at_coord[nNumExplictAttachments][2] = z;
|
1568
|
+
}
|
1569
|
+
break;
|
1570
|
+
case 1:
|
1571
|
+
for ( j = 0; j < at[cur_at].valence; j ++, nNumExplictAttachments ++ ) {
|
1572
|
+
next = at[cur_at].neighbor[j];
|
1573
|
+
at_coord[nNumExplictAttachments][0] = at[next].x - at[cur_at].x;
|
1574
|
+
at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
|
1575
|
+
nSbNeighOrigAtNumb[nNumExplictAttachments] = at[next].orig_at_number;
|
1576
|
+
|
1577
|
+
z = get_z_coord( at, cur_at, j /*neighbor #*/, &nType, bPointedEdgeStereo );
|
1578
|
+
switch ( nType ) {
|
1579
|
+
case ZTYPE_EITHER:
|
1580
|
+
num_either_single ++; /* bond in "Either" direction. */
|
1581
|
+
break;
|
1582
|
+
case ZTYPE_UP:
|
1583
|
+
case ZTYPE_DOWN:
|
1584
|
+
z = len2( at_coord[nNumExplictAttachments] );
|
1585
|
+
/*
|
1586
|
+
z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
|
1587
|
+
+ at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
|
1588
|
+
*/
|
1589
|
+
if ( nType == ZTYPE_DOWN )
|
1590
|
+
z = -z;
|
1591
|
+
/* no break; here */
|
1592
|
+
case ZTYPE_3D:
|
1593
|
+
num_z ++;
|
1594
|
+
}
|
1595
|
+
at_coord[nNumExplictAttachments][2] = z;
|
1596
|
+
}
|
1597
|
+
break;
|
1598
|
+
}
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
if ( num_either_single ) {
|
1602
|
+
bond_parity = AB_PARITY_UNKN; /* single bond is 'unknown' */
|
1603
|
+
goto exit_function;
|
1604
|
+
}
|
1605
|
+
|
1606
|
+
/* nNumExplictAttachments is a total number of attachments, including removed explicit terminal hydrogens */
|
1607
|
+
if ( nNumExplictAttachments == 2 ) {
|
1608
|
+
/* create coordinates of the implicit hydrogen (or a fictitious atom in case of ==N-X ), */
|
1609
|
+
/* coord[2][], attached to the cur_at. */
|
1610
|
+
for ( j = 0; j < 3; j ++ ) {
|
1611
|
+
at_coord[2][j] = - ( at_coord[0][j] + at_coord[1][j] );
|
1612
|
+
}
|
1613
|
+
nSbNeighOrigAtNumb[nNumExplictAttachments] = 0; /* implicit H or lone pair */
|
1614
|
+
}
|
1615
|
+
for ( j = 0; j < 3; j ++ ) {
|
1616
|
+
tmp[j] = len3( at_coord[j] );
|
1617
|
+
}
|
1618
|
+
min_tmp = inchi_min( tmp[0], inchi_min(tmp[1], tmp[2]) );
|
1619
|
+
max_tmp = inchi_max( tmp[0], inchi_max(tmp[1], tmp[2]) );
|
1620
|
+
if ( min_tmp < MIN_BOND_LEN || min_tmp < MIN_SINE*max_tmp ) {
|
1621
|
+
/* all bonds or some of bonds are too short */
|
1622
|
+
if ( at[cur_at].sb_parity[0] ) {
|
1623
|
+
/* use bond psrity; the reconciliation in ReconcileAllCmlBondParities()
|
1624
|
+
* has made all ways to calculate parity produce same result
|
1625
|
+
*/
|
1626
|
+
bond_parity = GetHalfStereobond0DParity( at, cur_at, nSbNeighOrigAtNumb,
|
1627
|
+
nNumExplictAttachments, bond_parity, FlagSB_0D );
|
1628
|
+
}
|
1629
|
+
|
1630
|
+
goto exit_function;
|
1631
|
+
}
|
1632
|
+
/* normalize lengths to 1 */
|
1633
|
+
for ( j = 0; j < 3; j ++ ) {
|
1634
|
+
mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
|
1635
|
+
}
|
1636
|
+
|
1637
|
+
/* find projections of at_coord vector differences on the plane containing their arrowhead ends */
|
1638
|
+
for ( j = 0; j < 3; j ++ ) {
|
1639
|
+
/* pnt[0..2] = {0-1, 1-2, 2-0} */
|
1640
|
+
tmp[j] = len3(diff3( at_coord[j], at_coord[(j+1)%3], pnt[j] ));
|
1641
|
+
if ( tmp[j] < MIN_SINE ) {
|
1642
|
+
goto exit_function; /* angle #i-cur_at-#j is too small */
|
1643
|
+
}
|
1644
|
+
mult3( pnt[j], 1.0/tmp[j], pnt[j] ); /* 2003-10-06 */
|
1645
|
+
}
|
1646
|
+
/* find pnt[p2], a vector perpendicular to the plane, and its length tmp[p2] */
|
1647
|
+
/* replace previous pnt[p2], tmp[p2] with new values; the old values do not have any additional */
|
1648
|
+
/* information because pnt[p0]+pnt[p1]+pnt[p2]=0 */
|
1649
|
+
/* 10-6-2003: a cross-product of one pair pnt[j], pnt[(j+1)%3] can be very small. Find the larges one */
|
1650
|
+
tmp1 = len3( cross_prod3( pnt[0], pnt[1], temp ) );
|
1651
|
+
for (j = 1, k = 0; j < 3; j ++ ) {
|
1652
|
+
tmp2 = len3( cross_prod3( pnt[j], pnt[(j+1)%3], temp ) );
|
1653
|
+
if ( tmp2 > tmp1 ) {
|
1654
|
+
tmp1 = tmp2;
|
1655
|
+
k = j;
|
1656
|
+
}
|
1657
|
+
}
|
1658
|
+
/* previously p0=0, p1=1, p2=2 */
|
1659
|
+
p0 = k;
|
1660
|
+
p1 = (k+1)%3;
|
1661
|
+
p2 = (k+2)%3;
|
1662
|
+
tmp[p2] = len3( cross_prod3( pnt[p0], pnt[p1], pnt[p2] ) );
|
1663
|
+
if ( tmp[p2] < MIN_SINE*tmp[p0]*tmp[p1] ) {
|
1664
|
+
goto exit_function; /* pnt[p0] is almost colinear to pnt[p1] */
|
1665
|
+
}
|
1666
|
+
/* new basis: pnt[p0], pnt[p1], pnt[p2]; set z-coord sign and make abs(pnt[p2]) = 1 */
|
1667
|
+
mult3( pnt[p2], (pnt[p2][2]>0.0? 1.0:-1.0)/tmp[p2], pnt[p2] ); /* unit vector in the new z-axis direction */
|
1668
|
+
|
1669
|
+
min_tmp = dot_prod3( at_coord[0], pnt[p2] ); /* non-planarity measure (sine): hight of at_coord[] pyramid */
|
1670
|
+
mult3( pnt[p2], min_tmp, pnt[p0] ); /* vector height of the pyramid, ideally 0 */
|
1671
|
+
/* find new pnt[p0] = projection of at_coord[p0] on plane orthogonal to pnt[p2] */
|
1672
|
+
tmp[p0] = len3(diff3( at_coord[0], pnt[p0], pnt[p0] ));
|
1673
|
+
mult3( pnt[p0], 1.0/tmp[p0], pnt[p0] ); /* new x axis basis vector */
|
1674
|
+
cross_prod3( pnt[p2], pnt[p0], pnt[p1] ); /* new y axis basis vector */
|
1675
|
+
/* find at_coord in the new basis of {pnt[p0], pnt[p1], pnt[p2]} */
|
1676
|
+
for ( j = 0; j < 3; j ++ ) {
|
1677
|
+
copy3( at_coord[j], temp );
|
1678
|
+
for ( k = 0; k < 3; k ++ ) {
|
1679
|
+
at_coord[j][k] = dot_prod3( temp, pnt[(k+p0)%3] );
|
1680
|
+
}
|
1681
|
+
/* new xy plane projection length */
|
1682
|
+
tmp[j] = sqrt(at_coord[j][0]*at_coord[j][0] + at_coord[j][1]*at_coord[j][1]);
|
1683
|
+
/* make new xy plane projection length = 1 */
|
1684
|
+
mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
|
1685
|
+
}
|
1686
|
+
|
1687
|
+
s = fabs( at_coord[1][0]*at_coord[2][1] - at_coord[1][1]*at_coord[2][0] ); /* 1-2 sine */
|
1688
|
+
c = at_coord[1][0]*at_coord[2][0] + at_coord[1][1]*at_coord[2][1]; /* 1-2 cosine */
|
1689
|
+
if ( s < MIN_SINE && c > 0.5 ) {
|
1690
|
+
goto exit_function; /* bonds to neigh. 1 and 2 have almost same direction; relative angles are undefined */
|
1691
|
+
}
|
1692
|
+
c = at_coord[0][0]; /* cosine of the angle between new Ox axis and a bond to the neighbor 0. Should be 1 */
|
1693
|
+
s = at_coord[0][1]; /* sine. Should be 0 */
|
1694
|
+
/* turn vectors so that vector #1 (at_coord[0]) becomes {1, 0} */
|
1695
|
+
for ( j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j ++ ) {
|
1696
|
+
tmp1 = c*at_coord[j][0] + s*at_coord[j][1];
|
1697
|
+
tmp2 = -s*at_coord[j][0] + c*at_coord[j][1];
|
1698
|
+
at_coord[j][0] = tmp1;
|
1699
|
+
at_coord[j][1] = tmp2;
|
1700
|
+
}
|
1701
|
+
/* counterclockwise angles from the direction to neigh 0 to to directions to neighbors 1 and 2: */
|
1702
|
+
tmp1 = atan2( at_coord[1][1], at_coord[1][0] ); /* range -pi and +pi */
|
1703
|
+
tmp2 = atan2( at_coord[2][1], at_coord[2][0] );
|
1704
|
+
if ( tmp1 < 0.0 )
|
1705
|
+
tmp1 += two_pi; /* range 0 to 2*pi */
|
1706
|
+
if ( tmp2 < 0.0 )
|
1707
|
+
tmp2 += two_pi;
|
1708
|
+
/*-----------------------------------
|
1709
|
+
Example
|
1710
|
+
1 \ case tmp1 < tmp2
|
1711
|
+
\ parity is odd
|
1712
|
+
\ (counterclockwise)
|
1713
|
+
A------- 0
|
1714
|
+
/
|
1715
|
+
/
|
1716
|
+
2 /
|
1717
|
+
|
1718
|
+
------------------------------------*/
|
1719
|
+
bond_parity = 2 - ( tmp1 < tmp2 );
|
1720
|
+
for ( j = 0; j < 3; j ++ ) {
|
1721
|
+
z_dir[j] = (S_CHAR) (pnt[p2][j]>= 0.0? floor(0.5 + 100.0 * pnt[p2][j]) :
|
1722
|
+
-floor(0.5 - 100.0 * pnt[p2][j])); /* abs(z_dir) = 100 */
|
1723
|
+
}
|
1724
|
+
/* check for ambiguity */
|
1725
|
+
if ( nNumExplictAttachments > 2 ) {
|
1726
|
+
min_tmp = inchi_min( tmp1, tmp2 );
|
1727
|
+
max_tmp = inchi_max( tmp1, tmp2 );
|
1728
|
+
if ( min_tmp > one_pi-MIN_SINE || max_tmp < one_pi+MIN_SINE || max_tmp-min_tmp > one_pi - MIN_SINE ) {
|
1729
|
+
at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
1730
|
+
} else /* 3D ambiguity 8-28-2002 */
|
1731
|
+
if ( fabs(at_coord[0][2]) > MAX_SINE ) { /* all fabs(at_coord[j][2] (j=0..2) must be equal */
|
1732
|
+
at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
1733
|
+
}
|
1734
|
+
} else
|
1735
|
+
if ( nNumExplictAttachments == 2 ) { /* 10-6-2003: added */
|
1736
|
+
min_tmp = fabs(tmp1 - one_pi);
|
1737
|
+
if ( min_tmp < MIN_SINE ) {
|
1738
|
+
bond_parity = AB_PARITY_UNDF; /* consider as undefined 10-6-2003 */
|
1739
|
+
} else
|
1740
|
+
if ( min_tmp < MIN_ANGLE_DBOND ) {
|
1741
|
+
at[cur_at].bAmbiguousStereo |= AMBIGUOUS_STEREO;
|
1742
|
+
}
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
|
1746
|
+
/* for 3 neighbors moving implicit H to the index=0 from index=2 position */
|
1747
|
+
/* can be done in 2 transpositions and does not change atom's parity */
|
1748
|
+
exit_function:
|
1749
|
+
if ( num_H > 1 && bond_parity > 0 && !(bond_parity & AB_PARITY_0D) /*&& PARITY_WELL_DEF(bond_parity)*/ ) {
|
1750
|
+
/*
|
1751
|
+
* stereo only if isotopes are counted. Do not inverse
|
1752
|
+
* Examples: sign for this:
|
1753
|
+
* H D
|
1754
|
+
* / / H
|
1755
|
+
* ==C or ==CH /
|
1756
|
+
* \ ==N (bValence3=1)
|
1757
|
+
* D
|
1758
|
+
* two explicit one explicit H isotope (D),
|
1759
|
+
* isotopic H atoms one implicit H
|
1760
|
+
*/
|
1761
|
+
bond_parity = -bond_parity; /* refers to isotopically substituted structure only */
|
1762
|
+
}
|
1763
|
+
return bond_parity;
|
1764
|
+
}
|
1765
|
+
|
1766
|
+
/*************************************************************/
|
1767
|
+
int save_a_stereo_bond( int z_prod, int result_action,
|
1768
|
+
int at1, int ord1, AT_NUMB *stereo_bond_neighbor1, S_CHAR *stereo_bond_ord1, S_CHAR *stereo_bond_z_prod1, S_CHAR *stereo_bond_parity1,
|
1769
|
+
int at2, int ord2, AT_NUMB *stereo_bond_neighbor2, S_CHAR *stereo_bond_ord2, S_CHAR *stereo_bond_z_prod2, S_CHAR *stereo_bond_parity2 )
|
1770
|
+
{
|
1771
|
+
int i1, i2;
|
1772
|
+
for ( i1 = 0; i1 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor1[i1]; i1 ++ )
|
1773
|
+
;
|
1774
|
+
for ( i2 = 0; i2 < MAX_NUM_STEREO_BONDS && stereo_bond_neighbor2[i2]; i2 ++ )
|
1775
|
+
;
|
1776
|
+
if ( i1 == MAX_NUM_STEREO_BONDS || i2 == MAX_NUM_STEREO_BONDS )
|
1777
|
+
return 0;
|
1778
|
+
|
1779
|
+
stereo_bond_parity1[i1] =
|
1780
|
+
stereo_bond_parity2[i2] = result_action;
|
1781
|
+
|
1782
|
+
stereo_bond_neighbor1[i1] = (AT_NUMB) (at2+1);
|
1783
|
+
stereo_bond_ord1[i1] = (S_CHAR)ord1;
|
1784
|
+
stereo_bond_neighbor2[i2] = (AT_NUMB) (at1+1);
|
1785
|
+
stereo_bond_ord2[i2] = (S_CHAR)ord2;
|
1786
|
+
stereo_bond_z_prod1[i1] =
|
1787
|
+
stereo_bond_z_prod2[i2] = (S_CHAR)z_prod;
|
1788
|
+
return 1;
|
1789
|
+
}
|
1790
|
+
/***************************************************************/
|
1791
|
+
int get_allowed_stereo_bond_type( int bond_type )
|
1792
|
+
{
|
1793
|
+
#if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 0 )
|
1794
|
+
if ( (bond_type & ~BOND_MARK_ALL) == BOND_TAUTOM )
|
1795
|
+
return 0; /* no tautomer bonds allowed */
|
1796
|
+
else
|
1797
|
+
#endif
|
1798
|
+
#if ( EXCL_ALL_AROM_BOND_PARITY == 1 ) /* { */
|
1799
|
+
/* a stereo bond cannot belong to an aromatic atom */
|
1800
|
+
if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN )
|
1801
|
+
{
|
1802
|
+
return 0;
|
1803
|
+
}
|
1804
|
+
#else /* } { */
|
1805
|
+
#if ( ADD_6MEMB_AROM_BOND_PARITY == 1 )
|
1806
|
+
/* accept any aromatic bond as a stereo bond */
|
1807
|
+
if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN )
|
1808
|
+
#else
|
1809
|
+
/* accept only aromatic bonds in non-6-member rings */
|
1810
|
+
if ( (bond_type &= ~BOND_MARK_ALL) == BOND_ALTERN ) )
|
1811
|
+
#endif
|
1812
|
+
{
|
1813
|
+
return BOND_ALTERN;
|
1814
|
+
}
|
1815
|
+
#endif /* } */
|
1816
|
+
else
|
1817
|
+
/* at this point BOND_MARK_ALL bits have been removed from bond_type */
|
1818
|
+
if ( bond_type == BOND_DOUBLE || bond_type == BOND_SINGLE ) {
|
1819
|
+
return bond_type;
|
1820
|
+
}
|
1821
|
+
#if (ALLOW_TAUT_ATTACHMENTS_TO_STEREO_BONDS == 1 )
|
1822
|
+
else
|
1823
|
+
if ( bond_type == BOND_TAUTOM ) {
|
1824
|
+
return BOND_TAUTOM;
|
1825
|
+
}
|
1826
|
+
#endif
|
1827
|
+
|
1828
|
+
return 0; /* wrong bond type */
|
1829
|
+
}
|
1830
|
+
|
1831
|
+
/*************************************************************/
|
1832
|
+
int can_be_a_stereo_bond_with_isotopic_H( inp_ATOM *at, int cur_at, INCHI_MODE nMode )
|
1833
|
+
{
|
1834
|
+
int i, j, next_at, num_stereo_bonds, bFound;
|
1835
|
+
int bond_type, num_2s, num_alt;
|
1836
|
+
int num_2s_next, num_alt_next, num_wrong_bonds_1, num_wrong_bonds_2;
|
1837
|
+
#if( N_V_STEREOBONDS == 1 )
|
1838
|
+
int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
|
1839
|
+
#endif
|
1840
|
+
if ( MAX_NUM_STEREO_BOND_NEIGH < at[cur_at].valence+at[cur_at].num_H ||
|
1841
|
+
MIN_NUM_STEREO_BOND_NEIGH > at[cur_at].valence+at[cur_at].num_H )
|
1842
|
+
return 0;
|
1843
|
+
if ( !bCanAtomHaveAStereoBond( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) )
|
1844
|
+
return 0;
|
1845
|
+
/* count bonds and find the second atom on the stereo bond */
|
1846
|
+
num_2s = num_alt = num_wrong_bonds_1 = 0;
|
1847
|
+
#if( N_V_STEREOBONDS == 1 )
|
1848
|
+
num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
|
1849
|
+
if ( 0 == at[cur_at].num_H && 0 == at[cur_at].charge && 0 == at[cur_at].radical &&
|
1850
|
+
3 == get_endpoint_valence( at[cur_at].el_number ) ) {
|
1851
|
+
if ( 2 == at[cur_at].valence && 3 == at[cur_at].chem_bonds_valence ) {
|
1852
|
+
type_N = 1;
|
1853
|
+
} else
|
1854
|
+
if ( 3 == at[cur_at].valence && 5 == at[cur_at].chem_bonds_valence ) {
|
1855
|
+
type_N = 2; /* unfortunately includes >N# */
|
1856
|
+
}
|
1857
|
+
}
|
1858
|
+
#endif
|
1859
|
+
for ( i = 0, num_stereo_bonds = 0; i < at[cur_at].valence; i ++ ) {
|
1860
|
+
bFound = 0;
|
1861
|
+
next_at = at[cur_at].neighbor[i];
|
1862
|
+
bond_type = get_allowed_stereo_bond_type( (int)at[cur_at].bond_type[i] );
|
1863
|
+
if ( bond_type == BOND_ALTERN ) {
|
1864
|
+
num_alt ++;
|
1865
|
+
if ( cur_at > next_at && !(nMode & CMODE_NO_ALT_SBONDS) )
|
1866
|
+
bFound = 1;
|
1867
|
+
} else
|
1868
|
+
if ( bond_type == BOND_DOUBLE ) {
|
1869
|
+
num_2s ++;
|
1870
|
+
#if( N_V_STEREOBONDS == 1 )
|
1871
|
+
if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_at )) ) {
|
1872
|
+
num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
|
1873
|
+
}
|
1874
|
+
#endif
|
1875
|
+
if ( cur_at > next_at )
|
1876
|
+
bFound = 1;
|
1877
|
+
} else
|
1878
|
+
if ( bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM ) {
|
1879
|
+
num_wrong_bonds_1 ++;
|
1880
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
1881
|
+
if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[cur_at].valence ) {
|
1882
|
+
return 0; /* wrong bond type */
|
1883
|
+
} else {
|
1884
|
+
continue;
|
1885
|
+
}
|
1886
|
+
#else
|
1887
|
+
return 0; /* wrong bond type */
|
1888
|
+
#endif
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
if ( bFound ) {
|
1892
|
+
/* check "next_at" atom on the opposite side of the bond */
|
1893
|
+
if ( MAX_NUM_STEREO_BOND_NEIGH < at[next_at].valence+at[next_at].num_H ||
|
1894
|
+
MIN_NUM_STEREO_BOND_NEIGH > at[next_at].valence+at[next_at].num_H )
|
1895
|
+
continue;
|
1896
|
+
if ( !bCanAtomHaveAStereoBond( at[next_at].elname, at[next_at].charge, at[next_at].radical ) )
|
1897
|
+
continue;
|
1898
|
+
/* next atom neighbors */
|
1899
|
+
num_2s_next = num_alt_next = num_wrong_bonds_2 = 0;
|
1900
|
+
#if( N_V_STEREOBONDS == 1 )
|
1901
|
+
num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
|
1902
|
+
if ( 0 == at[next_at].num_H && 0 == at[next_at].charge && 0 == at[next_at].radical &&
|
1903
|
+
3 == get_endpoint_valence( at[next_at].el_number ) ) {
|
1904
|
+
if ( 2 == at[next_at].valence && 3 == at[next_at].chem_bonds_valence ) {
|
1905
|
+
type_N_next = 1; /* -N= */
|
1906
|
+
} else
|
1907
|
+
if ( 3 == at[next_at].valence && 5 == at[next_at].chem_bonds_valence ) {
|
1908
|
+
type_N_next = 2; /* unfortunately includes >N# */
|
1909
|
+
}
|
1910
|
+
}
|
1911
|
+
#endif
|
1912
|
+
for ( j = 0; j < at[next_at].valence; j ++ ) {
|
1913
|
+
bond_type = get_allowed_stereo_bond_type( (int)at[next_at].bond_type[j] );
|
1914
|
+
if ( bond_type == BOND_ALTERN )
|
1915
|
+
num_alt_next ++;
|
1916
|
+
else
|
1917
|
+
if ( bond_type == BOND_DOUBLE ) {
|
1918
|
+
num_2s_next ++;
|
1919
|
+
#if( N_V_STEREOBONDS == 1 )
|
1920
|
+
next_next_at = at[next_at].neighbor[j];
|
1921
|
+
if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_next_at )) ) {
|
1922
|
+
num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
|
1923
|
+
}
|
1924
|
+
#endif
|
1925
|
+
} else
|
1926
|
+
if ( bond_type != BOND_SINGLE && bond_type != BOND_TAUTOM ) {
|
1927
|
+
num_wrong_bonds_2 ++;
|
1928
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
1929
|
+
if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[cur_at].valence ) {
|
1930
|
+
break; /* wrong bond type */
|
1931
|
+
} else {
|
1932
|
+
continue;
|
1933
|
+
}
|
1934
|
+
#else
|
1935
|
+
break; /* wrong bond type */
|
1936
|
+
#endif
|
1937
|
+
}
|
1938
|
+
}
|
1939
|
+
/* figure out whether the at[cur_at]--at[next_at] bond may not be stereogenic */
|
1940
|
+
|
1941
|
+
#if( N_V_STEREOBONDS == 1 )
|
1942
|
+
if ( 3 == (type_N | type_N_next) &&
|
1943
|
+
( 2 == type_N && !bIsOxide( at, cur_at ) ||
|
1944
|
+
2 == type_N_next && !bIsOxide( at, next_at ) ) ) {
|
1945
|
+
bFound = 0;
|
1946
|
+
} else
|
1947
|
+
#endif
|
1948
|
+
if ( j < at[next_at].valence || /* at[next_at] has a wrong bond type*/
|
1949
|
+
(num_alt_next>0) + (num_2s_next>0) != 1 /* only one type of stereogenic bond permitted */
|
1950
|
+
) {
|
1951
|
+
bFound = 0;
|
1952
|
+
} else
|
1953
|
+
if ( 2 < num_2s_next ) {
|
1954
|
+
bFound = 0;
|
1955
|
+
} else
|
1956
|
+
if ( 2 == num_2s_next ) {
|
1957
|
+
if ( 2 == at[next_at].valence ) {
|
1958
|
+
; /* only one double bond permitted except cumulenes */
|
1959
|
+
#if( N_V_STEREOBONDS == 1 )
|
1960
|
+
} else
|
1961
|
+
if ( 1 == (num_2s_hetero_next[0] | num_2s_hetero_next[1]) &&
|
1962
|
+
3 == at[next_at].valence + at[next_at].num_H &&
|
1963
|
+
5 == at[next_at].chem_bonds_valence + at[next_at].num_H &&
|
1964
|
+
3 == get_endpoint_valence( at[next_at].el_number ) &&
|
1965
|
+
(!type_N || bIsOxide( at, next_at )) ) {
|
1966
|
+
; /*
|
1967
|
+
* found:
|
1968
|
+
*
|
1969
|
+
* \ / \ / \ /
|
1970
|
+
* \ / \ / \ /
|
1971
|
+
* N==C or N==C or N==N
|
1972
|
+
* // \ // \ // \
|
1973
|
+
* O ^ \ N ^ \ O ^ \
|
1974
|
+
* | | |
|
1975
|
+
* | | |
|
1976
|
+
* at[next_at] at[next_at] at[next_at]
|
1977
|
+
*/
|
1978
|
+
#endif
|
1979
|
+
} else {
|
1980
|
+
bFound = 0;
|
1981
|
+
}
|
1982
|
+
}
|
1983
|
+
|
1984
|
+
}
|
1985
|
+
if ( bFound ) {
|
1986
|
+
num_stereo_bonds++;
|
1987
|
+
}
|
1988
|
+
}
|
1989
|
+
|
1990
|
+
if ( (num_alt>0) + (num_2s>0) != 1 || !num_stereo_bonds )
|
1991
|
+
return 0;
|
1992
|
+
if ( num_2s > 1 ) {
|
1993
|
+
#if( N_V_STEREOBONDS == 1 )
|
1994
|
+
if ( 2 == num_2s &&
|
1995
|
+
1 == (num_2s_hetero[0] | num_2s_hetero[1]) &&
|
1996
|
+
3 == at[cur_at].valence + at[cur_at].num_H &&
|
1997
|
+
5 == at[cur_at].chem_bonds_valence + at[cur_at].num_H &&
|
1998
|
+
3 == get_endpoint_valence( at[cur_at].el_number ) ) {
|
1999
|
+
;
|
2000
|
+
} else {
|
2001
|
+
return 0;
|
2002
|
+
}
|
2003
|
+
#else
|
2004
|
+
return 0;
|
2005
|
+
#endif
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
return num_stereo_bonds;
|
2009
|
+
}
|
2010
|
+
/*************************************************************/
|
2011
|
+
int half_stereo_bond_action( int nParity, int bUnknown, int bIsotopic )
|
2012
|
+
{
|
2013
|
+
#define AB_NEGATIVE 0x10
|
2014
|
+
#define AB_UNKNOWN 0x20
|
2015
|
+
int nAction;
|
2016
|
+
|
2017
|
+
if ( nParity == AB_PARITY_NONE )
|
2018
|
+
return AB_PARITY_NONE;
|
2019
|
+
|
2020
|
+
/* Unknown (type 1) in the parity value may come from the 'Either' single bond only */
|
2021
|
+
/* Treat it as a known single bond geometry and unknown (Either) double bond */
|
2022
|
+
if ( nParity == AB_PARITY_UNKN )
|
2023
|
+
nParity = AB_PARITY_ODD | AB_UNKNOWN;
|
2024
|
+
if ( nParity == -AB_PARITY_UNKN )
|
2025
|
+
nParity = AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE;
|
2026
|
+
|
2027
|
+
/* make positive, replace AB_PARITY_EVEN with AB_PARITY_ODD */
|
2028
|
+
if ( nParity < 0 )
|
2029
|
+
nParity = ((nParity == -AB_PARITY_EVEN)? AB_PARITY_ODD : (-nParity)) | AB_NEGATIVE;
|
2030
|
+
else
|
2031
|
+
if (nParity == AB_PARITY_EVEN)
|
2032
|
+
nParity = AB_PARITY_ODD;
|
2033
|
+
|
2034
|
+
/* Unknown (type 2): was detected in the double bond attribute */
|
2035
|
+
/* (this 'unknown' came from 'Either' double bond) */
|
2036
|
+
/* Treat both unknowns in the same way */
|
2037
|
+
if ( bUnknown )
|
2038
|
+
nParity |= AB_UNKNOWN;
|
2039
|
+
|
2040
|
+
if ( bIsotopic ) {
|
2041
|
+
switch ( nParity ) {
|
2042
|
+
case AB_PARITY_ODD:
|
2043
|
+
case AB_PARITY_ODD | AB_NEGATIVE:
|
2044
|
+
nAction = AB_PARITY_CALC;
|
2045
|
+
break;
|
2046
|
+
case AB_PARITY_ODD | AB_UNKNOWN:
|
2047
|
+
case AB_PARITY_UNDF | AB_UNKNOWN:
|
2048
|
+
case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
|
2049
|
+
case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
|
2050
|
+
nAction = AB_PARITY_UNKN;
|
2051
|
+
break;
|
2052
|
+
case AB_PARITY_IISO:
|
2053
|
+
case AB_PARITY_IISO | AB_UNKNOWN:
|
2054
|
+
nAction = AB_PARITY_NONE;
|
2055
|
+
break;
|
2056
|
+
case AB_PARITY_UNDF:
|
2057
|
+
case AB_PARITY_UNDF | AB_NEGATIVE:
|
2058
|
+
nAction = AB_PARITY_UNDF;
|
2059
|
+
break;
|
2060
|
+
default:
|
2061
|
+
nAction = -1; /* program error */
|
2062
|
+
}
|
2063
|
+
} else {
|
2064
|
+
/* Non-isotopic */
|
2065
|
+
switch ( nParity ) {
|
2066
|
+
case AB_PARITY_ODD:
|
2067
|
+
nAction = AB_PARITY_CALC;
|
2068
|
+
break;
|
2069
|
+
case AB_PARITY_ODD | AB_UNKNOWN:
|
2070
|
+
case AB_PARITY_UNDF | AB_UNKNOWN:
|
2071
|
+
nAction = AB_PARITY_UNKN;
|
2072
|
+
break;
|
2073
|
+
/* case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE: */
|
2074
|
+
case AB_PARITY_UNDF:
|
2075
|
+
nAction = AB_PARITY_UNDF;
|
2076
|
+
break;
|
2077
|
+
case AB_PARITY_ODD | AB_UNKNOWN | AB_NEGATIVE:
|
2078
|
+
case AB_PARITY_ODD | AB_NEGATIVE:
|
2079
|
+
case AB_PARITY_IISO:
|
2080
|
+
case AB_PARITY_IISO | AB_UNKNOWN:
|
2081
|
+
case AB_PARITY_UNDF | AB_NEGATIVE:
|
2082
|
+
case AB_PARITY_UNDF | AB_UNKNOWN | AB_NEGATIVE:
|
2083
|
+
nAction = AB_PARITY_NONE;
|
2084
|
+
break;
|
2085
|
+
default:
|
2086
|
+
nAction = -1; /* program error */
|
2087
|
+
}
|
2088
|
+
}
|
2089
|
+
return nAction;
|
2090
|
+
#undef AB_NEGATIVE
|
2091
|
+
#undef AB_UNKNOWN
|
2092
|
+
}
|
2093
|
+
/*************************************************************/
|
2094
|
+
int set_stereo_bonds_parity( sp_ATOM *out_at, inp_ATOM *at, int at_1, inp_ATOM *at_removed_H, int num_removed_H,
|
2095
|
+
INCHI_MODE nMode, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK min_sb_ring_size, int bPointedEdgeStereo )
|
2096
|
+
{
|
2097
|
+
int j, k, next_at_1, i_next_at_1, i_next_at_2, at_2, next_at_2, num_stereo_bonds, bFound, bAllene;
|
2098
|
+
int bond_type, num_2s_1, num_alt_1;
|
2099
|
+
int num_2s_2, num_alt_2;
|
2100
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2101
|
+
int num_wrong_bonds_1, num_wrong_bonds_2;
|
2102
|
+
#endif
|
2103
|
+
#if( N_V_STEREOBONDS == 1 )
|
2104
|
+
int n2sh, num_2s_hetero[2], num_2s_hetero_next[2], next_next_at, type_N, type_N_next;
|
2105
|
+
#endif
|
2106
|
+
int num_stored_stereo_bonds, num_stored_isotopic_stereo_bonds;
|
2107
|
+
int chain_length, num_chains, cur_chain_length;
|
2108
|
+
int all_at_2[MAX_NUM_STEREO_BONDS];
|
2109
|
+
int all_pos_1[MAX_NUM_STEREO_BONDS], all_pos_2[MAX_NUM_STEREO_BONDS];
|
2110
|
+
S_CHAR all_unkn[MAX_NUM_STEREO_BONDS];
|
2111
|
+
int /*at_1_parity, at_2_parity,*/ nUnknown, stop=0;
|
2112
|
+
|
2113
|
+
/* at_1_parity = AB_PARITY_NONE; */ /* do not know */
|
2114
|
+
/* check valence */
|
2115
|
+
if ( MAX_NUM_STEREO_BOND_NEIGH < at[at_1].valence+at[at_1].num_H ||
|
2116
|
+
MIN_NUM_STEREO_BOND_NEIGH > at[at_1].valence+at[at_1].num_H )
|
2117
|
+
return 0;
|
2118
|
+
if ( !bCanAtomHaveAStereoBond( at[at_1].elname, at[at_1].charge, at[at_1].radical ) )
|
2119
|
+
return 0;
|
2120
|
+
if ( at[at_1].c_point )
|
2121
|
+
return 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
|
2122
|
+
|
2123
|
+
/* middle cumulene atoms, for example, =C=, should be ignored here */
|
2124
|
+
/* only atoms at the ends of cumulene chains are considered. */
|
2125
|
+
if ( !at[at_1].num_H && 2 == at[at_1].valence &&
|
2126
|
+
BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_1].bond_type[0] ) &&
|
2127
|
+
BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_1].bond_type[1] ) ) {
|
2128
|
+
return 0;
|
2129
|
+
}
|
2130
|
+
|
2131
|
+
/* count bonds and find the second atom on the stereo bond */
|
2132
|
+
num_2s_1 = num_alt_1 = 0;
|
2133
|
+
chain_length = 0;
|
2134
|
+
num_chains = 0;
|
2135
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2136
|
+
num_wrong_bonds_1 = 0;
|
2137
|
+
#endif
|
2138
|
+
#if( N_V_STEREOBONDS == 1 )
|
2139
|
+
num_2s_hetero[0] = num_2s_hetero[1] = type_N = 0;
|
2140
|
+
if ( 0 == at[at_1].num_H && 0 == at[at_1].charge && 0 == at[at_1].radical &&
|
2141
|
+
3 == get_endpoint_valence( at[at_1].el_number ) ) {
|
2142
|
+
if ( 2 == at[at_1].valence && 3 == at[at_1].chem_bonds_valence ) {
|
2143
|
+
type_N = 1;
|
2144
|
+
} else
|
2145
|
+
if ( 3 == at[at_1].valence && 5 == at[at_1].chem_bonds_valence ) {
|
2146
|
+
type_N = 2; /* unfortunately includes >N# */
|
2147
|
+
}
|
2148
|
+
}
|
2149
|
+
#endif
|
2150
|
+
for ( i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].valence; i_next_at_1 ++ ) {
|
2151
|
+
nUnknown = (at[at_1].bond_stereo[i_next_at_1] == STEREO_DBLE_EITHER);
|
2152
|
+
bond_type = get_allowed_stereo_bond_type( (int)at[at_1].bond_type[i_next_at_1] );
|
2153
|
+
if ( bond_type == BOND_ALTERN ||
|
2154
|
+
bond_type == BOND_DOUBLE ) {
|
2155
|
+
at_2 = next_at_1 = at[at_1].neighbor[i_next_at_1];
|
2156
|
+
next_at_2 = at_1;
|
2157
|
+
}
|
2158
|
+
switch ( bond_type ) {
|
2159
|
+
case BOND_ALTERN:
|
2160
|
+
num_alt_1 ++;
|
2161
|
+
#if( FIND_RING_SYSTEMS == 1 )
|
2162
|
+
if ( at[at_1].nRingSystem != at[at_2].nRingSystem )
|
2163
|
+
continue; /* reject alt. bond connecting different ring systems */
|
2164
|
+
#endif
|
2165
|
+
if ( (nMode & CMODE_NO_ALT_SBONDS) ||
|
2166
|
+
!bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
|
2167
|
+
continue; /* reject non-stereogenic bond to neighbor ord. #i_next_at_1 */
|
2168
|
+
}
|
2169
|
+
break;
|
2170
|
+
case BOND_DOUBLE:
|
2171
|
+
/* check for cumulene/allene */
|
2172
|
+
num_2s_1++;
|
2173
|
+
cur_chain_length = 0;
|
2174
|
+
if ( bCanAtomBeTerminalAllene( at[at_1].elname, at[at_1].charge, at[at_1].radical ) ) {
|
2175
|
+
/*
|
2176
|
+
* Example of cumulene
|
2177
|
+
* chain length = 2: >X=C=C=Y<
|
2178
|
+
* | | | |
|
2179
|
+
* 1st cumulene atom= at_1 | | at_2 =last cumlene chain atom
|
2180
|
+
* next to at_1= next_at_1 next_at_2 =previous to at_2
|
2181
|
+
*
|
2182
|
+
* chain length odd: stereocenter on the middle atom ( 1=> allene )
|
2183
|
+
* chain length even: "long stereogenic bond"
|
2184
|
+
*/
|
2185
|
+
while ((bAllene =
|
2186
|
+
!at[at_2].num_H && at[at_2].valence == 2 &&
|
2187
|
+
BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_2].bond_type[0] ) &&
|
2188
|
+
BOND_DOUBLE == get_allowed_stereo_bond_type( (int)at[at_2].bond_type[1] )) &&
|
2189
|
+
bCanAtomBeMiddleAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
|
2190
|
+
k = ((int)at[at_2].neighbor[0]==next_at_2); /* opposite neighbor position */
|
2191
|
+
next_at_2 = at_2;
|
2192
|
+
nUnknown += (at[at_2].bond_stereo[k] == STEREO_DBLE_EITHER);
|
2193
|
+
at_2 = (int)at[at_2].neighbor[k];
|
2194
|
+
cur_chain_length ++; /* count =C= atoms */
|
2195
|
+
}
|
2196
|
+
if ( cur_chain_length ) {
|
2197
|
+
num_chains ++;
|
2198
|
+
if ( bAllene /* at the end of the chain atom Y is =Y=, not =Y< or =Y- */ ||
|
2199
|
+
!bCanAtomBeTerminalAllene( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
|
2200
|
+
cur_chain_length = 0;
|
2201
|
+
continue; /* ignore: does not fit cumulene description; go to check next at_1 neighbor */
|
2202
|
+
}
|
2203
|
+
chain_length = cur_chain_length; /* accept a stereogenic cumulele */
|
2204
|
+
}
|
2205
|
+
}
|
2206
|
+
#if( N_V_STEREOBONDS == 1 )
|
2207
|
+
if ( !cur_chain_length &&
|
2208
|
+
0 <= (n2sh = bIsSuitableHeteroInpAtom( at + at_2 )) ) {
|
2209
|
+
num_2s_hetero[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
|
2210
|
+
}
|
2211
|
+
#endif
|
2212
|
+
if ( !cur_chain_length &&
|
2213
|
+
!bCanAtomHaveAStereoBond( at[at_2].elname, at[at_2].charge, at[at_2].radical ) ) {
|
2214
|
+
continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
break;
|
2218
|
+
|
2219
|
+
case BOND_SINGLE:
|
2220
|
+
case BOND_TAUTOM:
|
2221
|
+
continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
|
2222
|
+
default:
|
2223
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2224
|
+
num_wrong_bonds_1 ++;
|
2225
|
+
continue;
|
2226
|
+
#else
|
2227
|
+
return 0; /* wrong bond type; */
|
2228
|
+
#endif
|
2229
|
+
}
|
2230
|
+
|
2231
|
+
/* check atom at the opposite end of possibly stereogenic bond */
|
2232
|
+
|
2233
|
+
bFound = ( at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
|
2234
|
+
|
2235
|
+
if ( bFound ) {
|
2236
|
+
/* check "at_2" atom on the opposite side of the bond or cumulene chain */
|
2237
|
+
if ( MAX_NUM_STEREO_BOND_NEIGH < at[at_2].valence+at[at_2].num_H ||
|
2238
|
+
MIN_NUM_STEREO_BOND_NEIGH > at[at_2].valence+at[at_2].num_H )
|
2239
|
+
continue;
|
2240
|
+
|
2241
|
+
/* check at_2 neighbors and bonds */
|
2242
|
+
num_2s_2 = num_alt_2 = 0;
|
2243
|
+
#if( N_V_STEREOBONDS == 1 )
|
2244
|
+
num_2s_hetero_next[0] = num_2s_hetero_next[1] = type_N_next = 0;
|
2245
|
+
if ( 0 == at[at_2].num_H && 0 == at[at_2].charge && 0 == at[at_2].radical &&
|
2246
|
+
3 == get_endpoint_valence( at[at_2].el_number ) ) {
|
2247
|
+
if ( 2 == at[at_2].valence && 3 == at[at_2].chem_bonds_valence ) {
|
2248
|
+
type_N_next = 1; /* -N= */
|
2249
|
+
} else
|
2250
|
+
if ( 3 == at[at_2].valence && 5 == at[at_2].chem_bonds_valence ) {
|
2251
|
+
type_N_next = 2; /* unfortunately includes >N# */
|
2252
|
+
}
|
2253
|
+
}
|
2254
|
+
#endif
|
2255
|
+
i_next_at_2 = -1; /* unassigned mark */
|
2256
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2257
|
+
num_wrong_bonds_2 = 0;
|
2258
|
+
#endif
|
2259
|
+
for ( j = 0; j < at[at_2].valence; j ++ ) {
|
2260
|
+
bond_type = get_allowed_stereo_bond_type( (int)at[at_2].bond_type[j] );
|
2261
|
+
if ( !bond_type ) {
|
2262
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2263
|
+
num_wrong_bonds_2 ++;
|
2264
|
+
continue; /* this bond type is not allowed to be adjacent to a stereo bond */
|
2265
|
+
#else
|
2266
|
+
break;
|
2267
|
+
#endif
|
2268
|
+
}
|
2269
|
+
if ( bond_type == BOND_DOUBLE ) {
|
2270
|
+
num_2s_2 ++;
|
2271
|
+
#if( N_V_STEREOBONDS == 1 )
|
2272
|
+
next_next_at = at[at_2].neighbor[j];
|
2273
|
+
if ( 0 <= (n2sh = bIsSuitableHeteroInpAtom( at + next_next_at )) ) {
|
2274
|
+
num_2s_hetero_next[n2sh] ++; /* n2sh=0 -> =N- or =NH; n2sh=1 -> =O */
|
2275
|
+
}
|
2276
|
+
#endif
|
2277
|
+
} else {
|
2278
|
+
num_alt_2 += ( bond_type == BOND_ALTERN );
|
2279
|
+
}
|
2280
|
+
if ( (int)at[at_2].neighbor[j] == next_at_2 )
|
2281
|
+
i_next_at_2 = j; /* assigned */
|
2282
|
+
}
|
2283
|
+
if (
|
2284
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2285
|
+
num_wrong_bonds_2 > 1 || num_wrong_bonds_2 && 2 >= at[at_2].valence ||
|
2286
|
+
#else
|
2287
|
+
j < at[at_2].valence /* "next" has a wrong bond type*/ ||
|
2288
|
+
#endif
|
2289
|
+
(num_alt_2>0) + (num_2s_2>0) != 1 || /* all double XOR all alt bonds only */
|
2290
|
+
/* num_2s_2 > 1 ||*/ /* only one double bond permitted */
|
2291
|
+
i_next_at_2 < 0 /* atom next to the opposite atom not found */ ) {
|
2292
|
+
bFound = 0;
|
2293
|
+
} else
|
2294
|
+
if ( at[at_2].c_point ) {
|
2295
|
+
bFound = 0; /* rejects atoms that can lose or gain a (positive) charge. 01-24-2003 */
|
2296
|
+
} else
|
2297
|
+
if ( num_2s_2 > 2 ) {
|
2298
|
+
bFound = 0;
|
2299
|
+
} else
|
2300
|
+
#if( N_V_STEREOBONDS == 1 )
|
2301
|
+
if ( 3 == (type_N | type_N_next) &&
|
2302
|
+
( 2 == type_N && !bIsOxide( at, at_1 ) ||
|
2303
|
+
2 == type_N_next && !bIsOxide( at, at_2 ) ) ) {
|
2304
|
+
bFound = 0;
|
2305
|
+
} else
|
2306
|
+
#endif
|
2307
|
+
if ( 2 == num_2s_2 ) {
|
2308
|
+
#if( N_V_STEREOBONDS == 1 )
|
2309
|
+
if ( !chain_length &&
|
2310
|
+
1 == (num_2s_hetero_next[0] | num_2s_hetero_next[1]) &&
|
2311
|
+
3 == at[at_2].valence + at[at_2].num_H &&
|
2312
|
+
5 == at[at_2].chem_bonds_valence + at[at_2].num_H &&
|
2313
|
+
3 == get_endpoint_valence( at[at_2].el_number ) &&
|
2314
|
+
(!type_N || bIsOxide( at, at_2 )) ) {
|
2315
|
+
/*
|
2316
|
+
* found:
|
2317
|
+
*
|
2318
|
+
* \ / \ / \ /
|
2319
|
+
* \ / \ / \ /
|
2320
|
+
* N==C or N==C or N==N
|
2321
|
+
* // \ // \ // \
|
2322
|
+
* O ^ \ N ^ \ O ^ \
|
2323
|
+
* | | |
|
2324
|
+
* | | |
|
2325
|
+
* at[at_2] at[at_2] at[at_2]
|
2326
|
+
*/
|
2327
|
+
;
|
2328
|
+
} else {
|
2329
|
+
bFound = 0;
|
2330
|
+
}
|
2331
|
+
#else
|
2332
|
+
bFound = 0;
|
2333
|
+
#endif
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
|
2337
|
+
if ( chain_length && num_alt_2 )
|
2338
|
+
return 0; /* allow no alt bonds in cumulenes */
|
2339
|
+
}
|
2340
|
+
if ( bFound ) {
|
2341
|
+
all_pos_1[num_stereo_bonds] = i_next_at_1; /* neighbor to at_1 position */
|
2342
|
+
all_pos_2[num_stereo_bonds] = i_next_at_2; /* neighbor to at_2 position */
|
2343
|
+
all_at_2[num_stereo_bonds] = at_2; /* at_2 */
|
2344
|
+
all_unkn[num_stereo_bonds] = nUnknown; /* stereogenic bond has Unknown configuration */
|
2345
|
+
/*
|
2346
|
+
if ( (at[at_1].bUsed0DParity & 2) || (at[at_2].bUsed0DParity & 2) ) {
|
2347
|
+
for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[at_1].sb_parity[k]; k ++ ) {
|
2348
|
+
if ( at[at_1].sb_neigh[k] == i_next_at_1 ) {
|
2349
|
+
if ( at[at_1].sb_parity[k] == AB_PARITY_UNKN && !nUnknown ) {
|
2350
|
+
all_unkn[num_stereo_bonds] = 1;
|
2351
|
+
}
|
2352
|
+
break;
|
2353
|
+
}
|
2354
|
+
}
|
2355
|
+
}
|
2356
|
+
*/
|
2357
|
+
num_stereo_bonds ++;
|
2358
|
+
}
|
2359
|
+
}
|
2360
|
+
if ( num_chains > 1 ) {
|
2361
|
+
return 0; /* cannot be more than 1 cumulene chain. */
|
2362
|
+
}
|
2363
|
+
#if( ONE_BAD_SB_NEIGHBOR == 1 )
|
2364
|
+
if ( num_wrong_bonds_1 > 1 || num_wrong_bonds_1 && 2 >= at[at_1].valence ) {
|
2365
|
+
return 0; /* wrong bond type */
|
2366
|
+
}
|
2367
|
+
#endif
|
2368
|
+
/* accept only short chains for now */
|
2369
|
+
/* chain_length=1: >C=C=C< tetrahedral center, allene */
|
2370
|
+
/* chain_length=2: >C=C=C=C< stereogenic bond, cumulene */
|
2371
|
+
if ( chain_length && (num_stereo_bonds != 1 || num_alt_1 || chain_length > MAX_CUMULENE_LEN) ) {
|
2372
|
+
return 0;
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
/* we need 1 double bond/chain XOR up to 3 arom. bonds */
|
2376
|
+
/* to have a stereogenic bond */
|
2377
|
+
if ( (num_alt_1>0) + (num_2s_1>0) != 1 || !num_stereo_bonds /*|| num_2s_1 > 1*/ )
|
2378
|
+
return 0;
|
2379
|
+
|
2380
|
+
if ( num_2s_1 > 1 ) {
|
2381
|
+
#if( N_V_STEREOBONDS == 1 )
|
2382
|
+
if ( 2 == num_2s_1 &&
|
2383
|
+
2 == type_N &&
|
2384
|
+
1 == (num_2s_hetero[0] | num_2s_hetero[1]) &&
|
2385
|
+
3 == at[at_1].valence + at[at_1].num_H &&
|
2386
|
+
5 == at[at_1].chem_bonds_valence + at[at_1].num_H &&
|
2387
|
+
3 == get_endpoint_valence( at[at_1].el_number ) ) {
|
2388
|
+
;
|
2389
|
+
} else {
|
2390
|
+
return 0;
|
2391
|
+
}
|
2392
|
+
#else
|
2393
|
+
return 0;
|
2394
|
+
#endif
|
2395
|
+
}
|
2396
|
+
|
2397
|
+
/* ================== calculate parities ====================== */
|
2398
|
+
|
2399
|
+
|
2400
|
+
/* find possibly stereo bonds and save them */
|
2401
|
+
num_stored_isotopic_stereo_bonds = 0;
|
2402
|
+
num_stored_stereo_bonds = 0;
|
2403
|
+
for ( k = 0; k < num_stereo_bonds; k ++ ) {
|
2404
|
+
|
2405
|
+
int cur_parity, next_parity, abs_cur_parity, abs_next_parity, dot_prod_z;
|
2406
|
+
S_CHAR z_dir1[3], z_dir2[3]; /* 3D vectors for half stereo bond parity direction */
|
2407
|
+
int chain_len_bits = MAKE_BITS_CUMULENE_LEN(chain_length);
|
2408
|
+
int cur_parity_defined, next_parity_defined;
|
2409
|
+
int cur_action, next_action, result_action;
|
2410
|
+
|
2411
|
+
at_2 = all_at_2[k];
|
2412
|
+
i_next_at_1 = all_pos_1[k];
|
2413
|
+
|
2414
|
+
#if( MIN_SB_RING_SIZE > 0 )
|
2415
|
+
if( at[at_1].nRingSystem == at[at_2].nRingSystem ) {
|
2416
|
+
/* check min. ring size only if both double bond/cumulene */
|
2417
|
+
/* ending atoms belong to the same ring system */
|
2418
|
+
j = is_bond_in_Nmax_memb_ring( at, at_1, i_next_at_1, q, nAtomLevel, cSource, min_sb_ring_size );
|
2419
|
+
if ( j > 0 ) {
|
2420
|
+
continue;
|
2421
|
+
} else
|
2422
|
+
if ( j < 0 ) {
|
2423
|
+
return CT_STEREOBOND_ERROR;
|
2424
|
+
}
|
2425
|
+
}
|
2426
|
+
#endif
|
2427
|
+
|
2428
|
+
i_next_at_2 = all_pos_2[k];
|
2429
|
+
nUnknown = all_unkn[k];
|
2430
|
+
memset(z_dir1, 0, sizeof(z_dir1));
|
2431
|
+
memset(z_dir2, 0, sizeof(z_dir2));
|
2432
|
+
|
2433
|
+
/********************************************************************************
|
2434
|
+
* find atom parities (negative means parity due to H-isotopes only)
|
2435
|
+
* and half stereo bond parity directions z_dir1, z_dir2.
|
2436
|
+
*
|
2437
|
+
* Bond can have unknown or undefined parity or no parity because of:
|
2438
|
+
* 1. Geometry (poorly defined, cannot calculate, for example linear =C-F
|
2439
|
+
* or =CHD with no geometry) -- Undefined parity
|
2440
|
+
* H
|
2441
|
+
* 2. Identical H atoms (no parity in principle, for example =C< )
|
2442
|
+
* -- No parity H
|
2443
|
+
*
|
2444
|
+
* 3. The user said double bond stereo is unknown
|
2445
|
+
* or at least one of single bonds is in unknown direction
|
2446
|
+
* -- Unknown parity
|
2447
|
+
*
|
2448
|
+
* These 3 cases (see above) are referred below as 1, 2, 3.
|
2449
|
+
* Each of the cases may be present or not (2 possibilities)
|
2450
|
+
* Total number of combination is 2*2*2=8
|
2451
|
+
*
|
2452
|
+
* Since a case when all 3 are not present is a well-defined parity,
|
2453
|
+
* we do not consider this case here. Then 2*2*2-1=7 cases are left.
|
2454
|
+
*
|
2455
|
+
* If several cases are present, list them below separated by "+".
|
2456
|
+
* For example, 1+2 means (1) undefined geometry and (2) no parity
|
2457
|
+
* is possible because of identical H atoms.
|
2458
|
+
*
|
2459
|
+
* N) Decision table, Non-isotopic, 2*2*2-1=7 cases:
|
2460
|
+
* =================================================
|
2461
|
+
* none : 2+any: 1+2(e.g.=CH2); 1+2+3; 2; 2+3 AB_PARITY_NONE=0
|
2462
|
+
* undefined: 1 AB_PARITY_UNDF
|
2463
|
+
* unknown : 1+3; 3 AB_PARITY_UNKN
|
2464
|
+
*
|
2465
|
+
* I) Decision table, Isotopic, 2*2*2-1=7 cases:
|
2466
|
+
* =============================================
|
2467
|
+
* none : none
|
2468
|
+
* undefined: 1; 1+2; 1+2+3; 2; 2+3
|
2469
|
+
* unknown : 1+3; 3
|
2470
|
+
*
|
2471
|
+
* Note: When defining identical atoms H atoms in case 2,
|
2472
|
+
* Isotopic and Non-isotopic cases are different:
|
2473
|
+
* N: do NOT take into account the isotopic composition of H atoms
|
2474
|
+
* I: DO take into account the isotopic composition of H atoms
|
2475
|
+
* (it is assumed that H isotopes are always different)
|
2476
|
+
*
|
2477
|
+
* half_stereo_bond_parity() returns:
|
2478
|
+
* ==================================
|
2479
|
+
* Note: half_stereo_bond_parity() is unaware of case 3.
|
2480
|
+
*
|
2481
|
+
* can't be a half of a stereo bond AB_PARITY_NONE
|
2482
|
+
* 1, isotopic & non-isotopic: AB_PARITY_UNDF
|
2483
|
+
* 1, isotopic only -AB_PARITY_UNDF
|
2484
|
+
* 2, no parity: identical H isotopes AB_PARITY_IISO
|
2485
|
+
* 3, 'Either' single bond(s) AB_PARITY_UNKN ???
|
2486
|
+
* 3, 'Either' single bond(s), iso H -AB_PARITY_UNKN ???
|
2487
|
+
* defined parity AB_PARITY_ODD, AB_PARITY_EVEN
|
2488
|
+
* defined parity for isotopic only: -AB_PARITY_ODD, -AB_PARITY_EVEN
|
2489
|
+
*
|
2490
|
+
* Resultant value for the stereo bond parity
|
2491
|
+
* ---+-------------------+-------+--------+----------------+
|
2492
|
+
* 3? | half_stereo_bond_ | N or I| case 1,| bond parity |
|
2493
|
+
* | parity()= | | 2 or 3 | |
|
2494
|
+
* ---+-------------------+-------+--------+----------------+
|
2495
|
+
* ( AB_PARITY_ODD/EVEN) => N&I: - => AB_PARITY_CALC (=6, calc.later)
|
2496
|
+
* 3+( AB_PARITY_ODD/EVEN) => N&I: 3 => AB_PARITY_UNKN (=3)
|
2497
|
+
* (-AB_PARITY_ODD/EVEN) => N: 2 => AB_PARITY_NONE (=0)
|
2498
|
+
* (-AB_PARITY_ODD/EVEN) => I: - => AB_PARITY_CALC
|
2499
|
+
* 3+(-AB_PARITY_ODD/EVEN) => N: 2+3 => AB_PARITY_UNDF (=4)
|
2500
|
+
* 3+(-AB_PARITY_ODD/EVEN) => I: 3 => AB_PARITY_UNKN
|
2501
|
+
* ( AB_PARITY_IISO ) => N: 1+2, 2 => AB_PARITY_NONE (=0)
|
2502
|
+
* ( AB_PARITY_IISO ) => I: 1+2, 2 => AB_PARITY_UNDF
|
2503
|
+
* 3+( AB_PARITY_IISO ) => N: 1+2+3,2+3=> AB_PARITY_NONE
|
2504
|
+
* 3+( AB_PARITY_IISO ) => I: 1+2+3,2+3=> AB_PARITY_UNDF
|
2505
|
+
* ( AB_PARITY_UNDF ) => N&I: 1 => AB_PARITY_UNDF
|
2506
|
+
* 3+( AB_PARITY_UNDF ) => N&I: 1+3 => AB_PARITY_UNKN
|
2507
|
+
* (-AB_PARITY_UNDF ) => N: 1+2 => AB_PARITY_NONE
|
2508
|
+
* (-AB_PARITY_UNDF ) => I: 1 => AB_PARITY_UNDF
|
2509
|
+
* 3+(-AB_PARITY_UNDF ) => N: 1+2+3 => AB_PARITY_NONE
|
2510
|
+
* 3+(-AB_PARITY_UNDF ) => I: 1+3 => AB_PARITY_UNKN
|
2511
|
+
* ---+-------------------+-------+--------+----------------+
|
2512
|
+
|
2513
|
+
* If bond parity is undefined because abs(dot_prod_z) < MIN_DOT_PROD
|
2514
|
+
* then replace: AB_PARITY_CALC
|
2515
|
+
* with: AB_PARITY_UNDF
|
2516
|
+
* Joining two half_bond_parity() results:
|
2517
|
+
*
|
2518
|
+
*
|
2519
|
+
* atom1 \ atom2 | AB_PARITY_NONE AB_PARITY_UNKN AB_PARITY_UNDF AB_PARITY_CALC
|
2520
|
+
* ----------------+---------------------------------------------------------------
|
2521
|
+
*0=AB_PARITY_NONE | AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE AB_PARITY_NONE
|
2522
|
+
*3=AB_PARITY_UNKN | AB_PARITY_UNKN AB_PARITY_UNKN AB_PARITY_UNKN
|
2523
|
+
*4=AB_PARITY_UNDF | AB_PARITY_UNDF AB_PARITY_UNDF
|
2524
|
+
*6=AB_PARITY_CALC | AB_PARITY_CALC
|
2525
|
+
*
|
2526
|
+
* that is, take min out of the two
|
2527
|
+
*********************************************************************************/
|
2528
|
+
|
2529
|
+
cur_parity = half_stereo_bond_parity( at, at_1, at_removed_H, num_removed_H, z_dir1, bPointedEdgeStereo );
|
2530
|
+
next_parity = half_stereo_bond_parity( at, at_2, at_removed_H, num_removed_H, z_dir2, bPointedEdgeStereo );
|
2531
|
+
|
2532
|
+
if ( RETURNED_ERROR(cur_parity) || RETURNED_ERROR(next_parity) ) {
|
2533
|
+
return CT_CALC_STEREO_ERR;
|
2534
|
+
}
|
2535
|
+
if ( (at[at_1].bUsed0DParity & FlagSB_0D) || (at[at_1].bUsed0DParity & FlagSB_0D) ) {
|
2536
|
+
FixSb0DParities( at, /* at_removed_H, num_removed_H,*/ chain_length,
|
2537
|
+
at_1, i_next_at_1, z_dir1,
|
2538
|
+
at_2, i_next_at_2, z_dir2, &cur_parity, &next_parity );
|
2539
|
+
}
|
2540
|
+
|
2541
|
+
if ( cur_parity == AB_PARITY_NONE || abs(cur_parity) == AB_PARITY_IISO ) {
|
2542
|
+
continue;
|
2543
|
+
}
|
2544
|
+
if ( next_parity == AB_PARITY_NONE || abs(next_parity) == AB_PARITY_IISO ) {
|
2545
|
+
continue;
|
2546
|
+
}
|
2547
|
+
|
2548
|
+
cur_action = half_stereo_bond_action( cur_parity, nUnknown, 0 ); /* -1 => program error */
|
2549
|
+
next_action = half_stereo_bond_action( next_parity, nUnknown, 0 );
|
2550
|
+
result_action = inchi_min(cur_action, next_action);
|
2551
|
+
|
2552
|
+
if ( result_action == -1 ) {
|
2553
|
+
stop = 1; /* program error <BRKPT> */
|
2554
|
+
}
|
2555
|
+
|
2556
|
+
abs_cur_parity = abs( cur_parity );
|
2557
|
+
abs_next_parity = abs( next_parity );
|
2558
|
+
cur_parity_defined = ATOM_PARITY_WELL_DEF(abs_cur_parity);
|
2559
|
+
next_parity_defined = ATOM_PARITY_WELL_DEF(abs_next_parity);
|
2560
|
+
|
2561
|
+
|
2562
|
+
if ( cur_parity_defined && next_parity_defined ) {
|
2563
|
+
/* find how the whole bond parity depend on geometry */
|
2564
|
+
/* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
|
2565
|
+
/* can be done only for a well-defined geometry */
|
2566
|
+
/*
|
2567
|
+
dot_prod_z = (chain_len_bits & BIT_CUMULENE_CHI)?
|
2568
|
+
triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
|
2569
|
+
dot_prodchar3(z_dir1, z_dir2);
|
2570
|
+
*/
|
2571
|
+
dot_prod_z = (chain_len_bits && BOND_CHAIN_LEN(chain_len_bits)%2)?
|
2572
|
+
triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
|
2573
|
+
dot_prodchar3(z_dir1, z_dir2);
|
2574
|
+
|
2575
|
+
if ( abs(dot_prod_z) < MIN_DOT_PROD ) {
|
2576
|
+
/* The geometry is not well-defined. Eliminate AB_PARITY_CALC */
|
2577
|
+
result_action = inchi_min( result_action, AB_PARITY_UNDF );
|
2578
|
+
}
|
2579
|
+
} else {
|
2580
|
+
dot_prod_z = 0;
|
2581
|
+
}
|
2582
|
+
|
2583
|
+
if ( result_action != AB_PARITY_NONE && result_action != -1 ) {
|
2584
|
+
/* stereo, no isotopes (only positive) */
|
2585
|
+
if ( cur_parity > 0 && next_parity > 0 ) {
|
2586
|
+
if ( save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
|
2587
|
+
at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor,
|
2588
|
+
out_at[at_1].stereo_bond_ord, out_at[at_1].stereo_bond_z_prod,
|
2589
|
+
out_at[at_1].stereo_bond_parity,
|
2590
|
+
at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor,
|
2591
|
+
out_at[at_2].stereo_bond_ord, out_at[at_2].stereo_bond_z_prod,
|
2592
|
+
out_at[at_2].stereo_bond_parity) ) {
|
2593
|
+
if ( !out_at[at_1].parity ||
|
2594
|
+
cur_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_1].parity)) ) {
|
2595
|
+
out_at[at_1].parity = cur_parity;
|
2596
|
+
memcpy( out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir) );
|
2597
|
+
}
|
2598
|
+
if ( !out_at[at_2].parity ||
|
2599
|
+
next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity)) ) {
|
2600
|
+
out_at[at_2].parity = next_parity;
|
2601
|
+
memcpy( out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir) );
|
2602
|
+
}
|
2603
|
+
out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
|
2604
|
+
out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
|
2605
|
+
num_stored_stereo_bonds ++;
|
2606
|
+
}
|
2607
|
+
}
|
2608
|
+
}
|
2609
|
+
|
2610
|
+
/* stereo + isotopic (all non-zero) */
|
2611
|
+
cur_action = half_stereo_bond_action( cur_parity, nUnknown, 1 ); /* -1 => program error */
|
2612
|
+
next_action = half_stereo_bond_action( next_parity, nUnknown, 1 );
|
2613
|
+
result_action = inchi_min(cur_action, next_action);
|
2614
|
+
cur_parity = abs_cur_parity;
|
2615
|
+
next_parity = abs_next_parity;
|
2616
|
+
if ( result_action != AB_PARITY_NONE && result_action != -1 ) {
|
2617
|
+
/* stero, isotopic */
|
2618
|
+
if ( cur_parity > 0 && next_parity > 0 ) {
|
2619
|
+
if( save_a_stereo_bond( dot_prod_z, result_action | chain_len_bits,
|
2620
|
+
at_1, i_next_at_1, out_at[at_1].stereo_bond_neighbor2,
|
2621
|
+
out_at[at_1].stereo_bond_ord2, out_at[at_1].stereo_bond_z_prod2,
|
2622
|
+
out_at[at_1].stereo_bond_parity2,
|
2623
|
+
at_2, i_next_at_2, out_at[at_2].stereo_bond_neighbor2,
|
2624
|
+
out_at[at_2].stereo_bond_ord2, out_at[at_2].stereo_bond_z_prod2,
|
2625
|
+
out_at[at_2].stereo_bond_parity2) ) {
|
2626
|
+
if ( !out_at[at_1].parity2 ||
|
2627
|
+
cur_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_1].parity2)) ) {
|
2628
|
+
out_at[at_1].parity2 = cur_parity /*| chain_len_bits*/;
|
2629
|
+
if ( !out_at[at_1].parity ) {
|
2630
|
+
memcpy( out_at[at_1].z_dir, z_dir1, sizeof(out_at[0].z_dir) );
|
2631
|
+
}
|
2632
|
+
}
|
2633
|
+
if ( !out_at[at_2].parity2 ||
|
2634
|
+
next_parity_defined && !ATOM_PARITY_WELL_DEF(abs(out_at[at_2].parity)) ) {
|
2635
|
+
out_at[at_2].parity2 = next_parity /*| chain_len_bits*/;
|
2636
|
+
if ( !out_at[at_2].parity ) {
|
2637
|
+
memcpy( out_at[at_2].z_dir, z_dir2, sizeof(out_at[0].z_dir) );
|
2638
|
+
}
|
2639
|
+
}
|
2640
|
+
out_at[at_1].bAmbiguousStereo |= at[at_1].bAmbiguousStereo;
|
2641
|
+
out_at[at_2].bAmbiguousStereo |= at[at_2].bAmbiguousStereo;
|
2642
|
+
num_stored_isotopic_stereo_bonds ++;
|
2643
|
+
}
|
2644
|
+
}
|
2645
|
+
} else
|
2646
|
+
if ( result_action == -1 ) {
|
2647
|
+
stop = 1; /* program error? <BRKPT> */
|
2648
|
+
}
|
2649
|
+
|
2650
|
+
}
|
2651
|
+
if ( stop ) {
|
2652
|
+
return CT_CALC_STEREO_ERR;
|
2653
|
+
}
|
2654
|
+
return /*num_stored_stereo_bonds+*/ num_stored_isotopic_stereo_bonds;
|
2655
|
+
}
|
2656
|
+
|
2657
|
+
|
2658
|
+
/*********************************************************************/
|
2659
|
+
/* if isotopic H, D, T added, can the atom be a stereo center? */
|
2660
|
+
#if( NEW_STEREOCENTER_CHECK == 1 )
|
2661
|
+
/* int bCanInpAtomBeAStereoCenter( inp_ATOM *at, int cur_at ) */
|
2662
|
+
int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
|
2663
|
+
{
|
2664
|
+
int nNumNeigh;
|
2665
|
+
if ( (nNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at )) &&
|
2666
|
+
at[cur_at].valence + at[cur_at].num_H == nNumNeigh &&
|
2667
|
+
at[cur_at].num_H <= NUM_H_ISOTOPES
|
2668
|
+
) {
|
2669
|
+
return 1;
|
2670
|
+
}
|
2671
|
+
return 0;
|
2672
|
+
}
|
2673
|
+
#else
|
2674
|
+
int can_be_a_stereo_atom_with_isotopic_H( inp_ATOM *at, int cur_at )
|
2675
|
+
{
|
2676
|
+
int j, ret = 0;
|
2677
|
+
if ( bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) &&
|
2678
|
+
at[cur_at].valence + at[cur_at].num_H == MAX_NUM_STEREO_ATOM_NEIGH &&
|
2679
|
+
at[cur_at].num_H < MAX_NUM_STEREO_ATOM_NEIGH
|
2680
|
+
) {
|
2681
|
+
|
2682
|
+
for ( j = 0, ret=1; ret && j < at[cur_at].valence; j ++ ) {
|
2683
|
+
if ( (at[cur_at].bond_type[j] & ~BOND_MARK_ALL) != BOND_SINGLE ) {
|
2684
|
+
ret = 0;
|
2685
|
+
}
|
2686
|
+
}
|
2687
|
+
}
|
2688
|
+
return ret;
|
2689
|
+
}
|
2690
|
+
#endif
|
2691
|
+
/***************************************************************/
|
2692
|
+
int GetStereocenter0DParity( inp_ATOM *at, int cur_at, int j1, AT_NUMB nSbNeighOrigAtNumb[], int nFlag )
|
2693
|
+
{
|
2694
|
+
int parity = AB_PARITY_NONE;
|
2695
|
+
if ( at[cur_at].p_parity && (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH) ) {
|
2696
|
+
int i, num_trans_inp, num_trans_neigh;
|
2697
|
+
AT_NUMB nInpNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
|
2698
|
+
for ( i = 0; i < MAX_NUM_STEREO_ATOM_NEIGH; i ++ ) {
|
2699
|
+
nInpNeighOrigAtNumb[i] = at[cur_at].p_orig_at_num[i];
|
2700
|
+
if ( nInpNeighOrigAtNumb[i] == at[cur_at].orig_at_number ) {
|
2701
|
+
nInpNeighOrigAtNumb[i] = 0; /* lone pair or explicit H */
|
2702
|
+
}
|
2703
|
+
}
|
2704
|
+
num_trans_inp = insertions_sort( nInpNeighOrigAtNumb, MAX_NUM_STEREO_ATOM_NEIGH, sizeof(nInpNeighOrigAtNumb[0]), comp_AT_NUMB );
|
2705
|
+
num_trans_neigh = insertions_sort( nSbNeighOrigAtNumb, j1, sizeof(nSbNeighOrigAtNumb[0]), comp_AT_NUMB );
|
2706
|
+
if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2707
|
+
; /*num_trans_neigh += j1;*/ /* the lone pair or implicit H is implicitly at the top of the list */
|
2708
|
+
}
|
2709
|
+
if ( !memcmp( nInpNeighOrigAtNumb + MAX_NUM_STEREO_ATOM_NEIGH-j1, nSbNeighOrigAtNumb, j1*sizeof(AT_NUMB) ) ) {
|
2710
|
+
if ( ATOM_PARITY_WELL_DEF(at[cur_at].p_parity) ) {
|
2711
|
+
parity = 2 - (num_trans_inp + num_trans_neigh + at[cur_at].p_parity) % 2;
|
2712
|
+
} else {
|
2713
|
+
parity = at[cur_at].p_parity;
|
2714
|
+
}
|
2715
|
+
at[cur_at].bUsed0DParity |= nFlag; /* 0D parity used for streocenter parity */
|
2716
|
+
}
|
2717
|
+
}
|
2718
|
+
return parity;
|
2719
|
+
}
|
2720
|
+
|
2721
|
+
/***************************************************************
|
2722
|
+
* Get stereo atom parity for the current order of attachments
|
2723
|
+
* The result in at[cur_at].parity is valid for previously removed
|
2724
|
+
* explicit hydrogen atoms, including isotopic ones, that are located in at_removed_H[]
|
2725
|
+
* The return value is a calculated parity.
|
2726
|
+
*/
|
2727
|
+
#define ADD_EXPLICIT_HYDROGEN_NEIGH 1
|
2728
|
+
#define ADD_EXPLICIT_LONE_PAIR_NEIGH 2
|
2729
|
+
int set_stereo_atom_parity( sp_ATOM *out_at, inp_ATOM *at, int cur_at, inp_ATOM *at_removed_H,
|
2730
|
+
int num_removed_H, int bPointedEdgeStereo )
|
2731
|
+
{
|
2732
|
+
int j, k, next_at, num_z, j1, nType, num_explicit_H, tot_num_iso_H, nMustHaveNumNeigh;
|
2733
|
+
int num_explicit_iso_H[NUM_H_ISOTOPES+1]; /* numbers of removed hydrogen atoms */
|
2734
|
+
int index_H[MAX_NUM_STEREO_ATOM_NEIGH]; /* cannot have more than 4 elements: 1 H, 1 D, 1 T atom(s) */
|
2735
|
+
double z, sum_xyz[3], min_sine, triple_product;
|
2736
|
+
double at_coord[MAX_NUM_STEREO_ATOM_NEIGH][3];
|
2737
|
+
double bond_len_xy[4], rmax, rmin;
|
2738
|
+
double at_coord_center[3];
|
2739
|
+
int parity, bAmbiguous = 0, bAddExplicitNeighbor = 0, b2D = 0, n2DTetrahedralAmbiguity = 0;
|
2740
|
+
int bIgnoreIsotopicH = (0 != (at[cur_at].cFlags & AT_FLAG_ISO_H_POINT));
|
2741
|
+
AT_NUMB nSbNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
|
2742
|
+
|
2743
|
+
out_at[cur_at].parity =
|
2744
|
+
out_at[cur_at].parity2 =
|
2745
|
+
out_at[cur_at].stereo_atom_parity =
|
2746
|
+
out_at[cur_at].stereo_atom_parity2 = AB_PARITY_NONE;
|
2747
|
+
parity = AB_PARITY_NONE;
|
2748
|
+
|
2749
|
+
memset(num_explicit_iso_H, 0, sizeof(num_explicit_iso_H));
|
2750
|
+
num_explicit_H = 0;
|
2751
|
+
|
2752
|
+
#if( NEW_STEREOCENTER_CHECK == 1 )
|
2753
|
+
if ( !(nMustHaveNumNeigh = bCanInpAtomBeAStereoCenter( at, cur_at ) ) ||
|
2754
|
+
at[cur_at].num_H > NUM_H_ISOTOPES
|
2755
|
+
) {
|
2756
|
+
goto exit_function;
|
2757
|
+
}
|
2758
|
+
#else
|
2759
|
+
nMustHaveNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH;
|
2760
|
+
if ( !bCanAtomBeAStereoCenter( at[cur_at].elname, at[cur_at].charge, at[cur_at].radical ) ||
|
2761
|
+
at[cur_at].valence + at[cur_at].num_H != nMustHaveNumNeigh ||
|
2762
|
+
at[cur_at].num_H > NUM_H_ISOTOPES
|
2763
|
+
) {
|
2764
|
+
goto exit_function;
|
2765
|
+
}
|
2766
|
+
for ( j = 0; j < at[cur_at].valence; j ++ ) {
|
2767
|
+
if ( (at[cur_at].bond_type[j] & ~BOND_MARK_ALL) != BOND_SINGLE ) {
|
2768
|
+
goto exit_function;
|
2769
|
+
}
|
2770
|
+
}
|
2771
|
+
#endif
|
2772
|
+
|
2773
|
+
/* numbers of isotopic H atoms */
|
2774
|
+
for ( j = 0, tot_num_iso_H = 0; j < NUM_H_ISOTOPES; j ++ ) {
|
2775
|
+
if ( at[cur_at].num_iso_H[j] > 1 ) {
|
2776
|
+
goto exit_function; /* two or more identical hydrogen isotopic neighbors */
|
2777
|
+
}
|
2778
|
+
tot_num_iso_H += at[cur_at].num_iso_H[j];
|
2779
|
+
}
|
2780
|
+
if ( bIgnoreIsotopicH ) {
|
2781
|
+
tot_num_iso_H = 0; /* isotopic H considered subject to exchange => ignore isotopic */
|
2782
|
+
}
|
2783
|
+
/* number of non-isotopic H atoms */
|
2784
|
+
if ( at[cur_at].num_H - tot_num_iso_H > 1 ) {
|
2785
|
+
goto exit_function; /* two or more identical hydrogen non-isotopic neighbors */
|
2786
|
+
}
|
2787
|
+
|
2788
|
+
/* count removed explicit terminal hydrogens attached to at[cur_at]. */
|
2789
|
+
/* the result is num_explicit_H. */
|
2790
|
+
/* Removed hydrogens are sorted in increasing isotopic shift order */
|
2791
|
+
if ( at_removed_H && num_removed_H > 0 ) {
|
2792
|
+
for ( j = 0; j < num_removed_H; j ++ ) {
|
2793
|
+
if ( at_removed_H[j].neighbor[0] == cur_at ) {
|
2794
|
+
k = at_removed_H[j].iso_atw_diff;
|
2795
|
+
/* iso_atw_diff values: H=>0, 1H=>1, D=2H=>2, T=3H=>3 */
|
2796
|
+
if ( k < 0 || k > NUM_H_ISOTOPES || bIgnoreIsotopicH )
|
2797
|
+
k = 0; /* treat wrong H isotopes as non-isotopic H */
|
2798
|
+
num_explicit_iso_H[k] ++;
|
2799
|
+
index_H[num_explicit_H++] = j;
|
2800
|
+
}
|
2801
|
+
}
|
2802
|
+
}
|
2803
|
+
|
2804
|
+
/* coordinates initialization */
|
2805
|
+
num_z = 0;
|
2806
|
+
sum_xyz[0] = sum_xyz[1] = sum_xyz[2] = 0.0;
|
2807
|
+
|
2808
|
+
at_coord_center[0] =
|
2809
|
+
at_coord_center[1] =
|
2810
|
+
at_coord_center[2] = 0.0;
|
2811
|
+
|
2812
|
+
/* fill out stereo center neighbors coordinates */
|
2813
|
+
/* and obtain the parity from the geometry */
|
2814
|
+
|
2815
|
+
for ( k = 0, j1 = 0; k < 2; k ++ ) {
|
2816
|
+
switch( k ) {
|
2817
|
+
|
2818
|
+
case 0:
|
2819
|
+
/* add coordinates of removed hydrogens */
|
2820
|
+
for ( j = 0; j < num_explicit_H; j ++, j1 ++ ) {
|
2821
|
+
next_at = index_H[j];
|
2822
|
+
/* use bond description located at removed_H atom */
|
2823
|
+
/* minus sign at get_z_coord: at_removed_H[] contains bonds TO at[cur_at], not FROM it. */
|
2824
|
+
/* Note: &at[(at_removed_H-at)+ next_at] == &at_removed_H[next_at] */
|
2825
|
+
z = -get_z_coord( at, (at_removed_H-at)+ next_at, 0 /*neighbor #*/, &nType, -bPointedEdgeStereo );
|
2826
|
+
switch ( nType ) {
|
2827
|
+
case ZTYPE_EITHER:
|
2828
|
+
parity = AB_PARITY_UNKN; /* no parity: bond in "Either" direction. */
|
2829
|
+
goto exit_function;
|
2830
|
+
case ZTYPE_UP:
|
2831
|
+
case ZTYPE_DOWN:
|
2832
|
+
nType = -nType; /* at_removed_H[] contains bonds TO the center, not from */
|
2833
|
+
b2D ++;
|
2834
|
+
/* no break; here */
|
2835
|
+
case ZTYPE_3D:
|
2836
|
+
num_z ++;
|
2837
|
+
}
|
2838
|
+
|
2839
|
+
nSbNeighOrigAtNumb[j1] = at_removed_H[next_at].orig_at_number;
|
2840
|
+
at_coord[j1][0] = at_removed_H[next_at].x-at[cur_at].x;
|
2841
|
+
at_coord[j1][1] = at_removed_H[next_at].y-at[cur_at].y;
|
2842
|
+
bond_len_xy[j1] = len2(at_coord[j1]);
|
2843
|
+
/* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
|
2844
|
+
at_coord[j1][2] = (nType==ZTYPE_3D? z :
|
2845
|
+
nType==ZTYPE_UP? bond_len_xy[j1] :
|
2846
|
+
nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
|
2847
|
+
}
|
2848
|
+
break;
|
2849
|
+
case 1:
|
2850
|
+
/* add all coordinates of other neighboring atoms */
|
2851
|
+
for ( j = 0; j < at[cur_at].valence; j ++, j1 ++ ) {
|
2852
|
+
next_at = at[cur_at].neighbor[j];
|
2853
|
+
z = get_z_coord( at, cur_at, j, &nType, bPointedEdgeStereo );
|
2854
|
+
switch ( nType ) {
|
2855
|
+
case ZTYPE_EITHER:
|
2856
|
+
parity = AB_PARITY_UNKN; /* unknown parity: bond in "Either" direction. */
|
2857
|
+
goto exit_function;
|
2858
|
+
case ZTYPE_UP:
|
2859
|
+
case ZTYPE_DOWN:
|
2860
|
+
b2D ++;
|
2861
|
+
case ZTYPE_3D:
|
2862
|
+
num_z ++;
|
2863
|
+
}
|
2864
|
+
|
2865
|
+
nSbNeighOrigAtNumb[j1] = at[next_at].orig_at_number;
|
2866
|
+
at_coord[j1][0] = at[next_at].x-at[cur_at].x;
|
2867
|
+
at_coord[j1][1] = at[next_at].y-at[cur_at].y;
|
2868
|
+
bond_len_xy[j1] = len2(at_coord[j1]);
|
2869
|
+
/* bond_len_xy[j1] = sqrt(at_coord[j1][0]*at_coord[j1][0]+at_coord[j1][1]*at_coord[j1][1]); */
|
2870
|
+
at_coord[j1][2] = (nType==ZTYPE_3D? z :
|
2871
|
+
nType==ZTYPE_UP? bond_len_xy[j1] :
|
2872
|
+
nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
|
2873
|
+
}
|
2874
|
+
break;
|
2875
|
+
}
|
2876
|
+
}
|
2877
|
+
/* j1 is the number of explicit neighbors (that is, all neighbors except implicit H) */
|
2878
|
+
|
2879
|
+
b2D = (b2D == num_z && num_z); /* 1 => two-dimensional */
|
2880
|
+
|
2881
|
+
if ( MAX_NUM_STEREO_ATOM_NEIGH != at[cur_at].valence+num_explicit_H &&
|
2882
|
+
MAX_NUM_STEREO_ATOM_NEIGH-1 != at[cur_at].valence+num_explicit_H ) {
|
2883
|
+
/* not enough geometry data to find the central atom parity */
|
2884
|
+
if ( nMustHaveNumNeigh == at[cur_at].valence+at[cur_at].num_H &&
|
2885
|
+
at[cur_at].num_H > 1 ) {
|
2886
|
+
/* only isotopic parity is possible; no non-isotopic parity */
|
2887
|
+
if ( parity == AB_PARITY_UNKN ) {
|
2888
|
+
parity = -AB_PARITY_UNKN; /* the user marked the center as "unknown" */
|
2889
|
+
} else {
|
2890
|
+
parity = -AB_PARITY_UNDF; /* not enough geometry; only isotopic parity is possible */
|
2891
|
+
}
|
2892
|
+
} else {
|
2893
|
+
parity = AB_PARITY_NONE; /* not a stereocenter at all */
|
2894
|
+
}
|
2895
|
+
goto exit_function;
|
2896
|
+
}
|
2897
|
+
/* make all vector lengths equal to 1; exit if too short. 9-10-2002 */
|
2898
|
+
for ( j = 0; j < j1; j ++ ) {
|
2899
|
+
z = len3( at_coord[j] );
|
2900
|
+
if ( z < MIN_BOND_LEN ) {
|
2901
|
+
/* bond length is too small: use 0D parities */
|
2902
|
+
if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
|
2903
|
+
parity = AB_PARITY_UNDF;
|
2904
|
+
}
|
2905
|
+
goto exit_function;
|
2906
|
+
}
|
2907
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
2908
|
+
else {
|
2909
|
+
mult3( at_coord[j], 1.0/z, at_coord[j] );
|
2910
|
+
}
|
2911
|
+
#endif
|
2912
|
+
rmax = j? inchi_max( rmax, z) : z;
|
2913
|
+
rmin = j? inchi_min( rmin, z) : z;
|
2914
|
+
}
|
2915
|
+
if ( rmin / rmax < MIN_SINE ) {
|
2916
|
+
/* bond ratio is too small: use 0D parities */
|
2917
|
+
if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
|
2918
|
+
parity = AB_PARITY_UNDF;
|
2919
|
+
}
|
2920
|
+
goto exit_function;
|
2921
|
+
}
|
2922
|
+
for ( j = 0; j < j1; j ++ ) {
|
2923
|
+
add3( sum_xyz, at_coord[j], sum_xyz );
|
2924
|
+
}
|
2925
|
+
|
2926
|
+
|
2927
|
+
|
2928
|
+
/* here j1 is a number of neighbors including explicit terminal isotopic H */
|
2929
|
+
/* num_explicit_iso_H[0] = number of explicit non-isotopic hydrogen atom neighbors */
|
2930
|
+
j = j1;
|
2931
|
+
/* Add Explicit Neighbor */
|
2932
|
+
if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2933
|
+
/* add an explicit neighbor if possible */
|
2934
|
+
if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
2935
|
+
bAddExplicitNeighbor = ADD_EXPLICIT_LONE_PAIR_NEIGH;
|
2936
|
+
} else
|
2937
|
+
if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH ) {
|
2938
|
+
/* check whether an explicit non-isotopic hydrogen can be added */
|
2939
|
+
/* to an atom that is a stereogenic atom */
|
2940
|
+
if ( 1 == at[cur_at].num_H - num_explicit_H && /* the atom has only one one implicit hydrogen */
|
2941
|
+
1 == at[cur_at].num_H - tot_num_iso_H ) { /* this hydrogen is non-isotopic */
|
2942
|
+
bAddExplicitNeighbor = ADD_EXPLICIT_HYDROGEN_NEIGH;
|
2943
|
+
}
|
2944
|
+
}
|
2945
|
+
}
|
2946
|
+
|
2947
|
+
if ( bAddExplicitNeighbor ) {
|
2948
|
+
/***********************************************************
|
2949
|
+
* May happen only if (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1)
|
2950
|
+
* 3 neighbors only, no H-neighbors. Create and add coordinates of an implicit H
|
2951
|
+
* or a fake 4th neighbor, that is, a lone pair
|
2952
|
+
*/
|
2953
|
+
if ( parity == AB_PARITY_UNKN ) {
|
2954
|
+
goto exit_function; /* the user insists the parity is unknown and the isotopic */
|
2955
|
+
/* composition of the neighbors does not contradict */
|
2956
|
+
} else
|
2957
|
+
if ( num_z == 0 || are_3_vect_in_one_plane(at_coord, MIN_SINE) ) {
|
2958
|
+
/* "hydrogen down" rule is needed to resolve an ambiguity */
|
2959
|
+
if ( num_z > 0 ) {
|
2960
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
2961
|
+
}
|
2962
|
+
#if( APPLY_IMPLICIT_H_DOWN_RULE == 1 ) /* { */
|
2963
|
+
/* Although H should be at the top of the list, add it to the bottom. */
|
2964
|
+
/* This will be taken care of later by inverting parity 1<->2 */
|
2965
|
+
at_coord[j][0] = 0.0;
|
2966
|
+
at_coord[j][1] = 0.0;
|
2967
|
+
#if( STEREO_CENTER_BONDS_NORM == 1 )
|
2968
|
+
at_coord[j][2] = -1.0;
|
2969
|
+
#else
|
2970
|
+
at_coord[j][2] = -(bond_len_xy[0]+bond_len_xy[1]+bond_len_xy[2])/3.0;
|
2971
|
+
#endif
|
2972
|
+
#else /* } APPLY_IMPLICIT_H_DOWN_RULE { */
|
2973
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
2974
|
+
parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
2975
|
+
#else
|
2976
|
+
/* all 3 bonds are in one plain: try to get 0D parities */
|
2977
|
+
if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
|
2978
|
+
parity = AB_PARITY_UNDF;
|
2979
|
+
}
|
2980
|
+
/*parity = AB_PARITY_UNDF;*/ /* no parity can be calculated found */
|
2981
|
+
#endif
|
2982
|
+
goto exit_function;
|
2983
|
+
#endif /* } APPLY_IMPLICIT_H_DOWN_RULE */
|
2984
|
+
} else {
|
2985
|
+
/* we have enough information to find implicit hydrogen coordinates */
|
2986
|
+
/*
|
2987
|
+
at_coord[j][0] = -sum_x;
|
2988
|
+
at_coord[j][1] = -sum_y;
|
2989
|
+
at_coord[j][2] = -sum_z;
|
2990
|
+
*/
|
2991
|
+
copy3( sum_xyz, at_coord[j] );
|
2992
|
+
change_sign3( at_coord[j], at_coord[j] );
|
2993
|
+
z = len3( at_coord[j] );
|
2994
|
+
rmax = inchi_max( rmax, z );
|
2995
|
+
rmin = inchi_min( rmin, z );
|
2996
|
+
if ( z < MIN_BOND_LEN || rmin/rmax < MIN_SINE ) {
|
2997
|
+
/* the new 4th bond is too short: try to get 0D parities */
|
2998
|
+
if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
|
2999
|
+
parity = AB_PARITY_UNDF;
|
3000
|
+
}
|
3001
|
+
goto exit_function;
|
3002
|
+
}
|
3003
|
+
#if( STEREO_CENTER_BOND4_NORM == 1 )
|
3004
|
+
else {
|
3005
|
+
mult3( at_coord[j], 1.0/z, at_coord[j] );
|
3006
|
+
}
|
3007
|
+
#endif
|
3008
|
+
}
|
3009
|
+
} else
|
3010
|
+
if ( j1 != MAX_NUM_STEREO_ATOM_NEIGH ) {
|
3011
|
+
if ( parity == AB_PARITY_UNKN ) {
|
3012
|
+
parity = -AB_PARITY_UNDF; /* isotopic composition of H-neighbors contradicts 'unknown' */
|
3013
|
+
}
|
3014
|
+
goto exit_function;
|
3015
|
+
} else /* j1 == MAX_NUM_STEREO_ATOM_NEIGH */
|
3016
|
+
if ( num_z == 0 || are_4at_in_one_plane(at_coord, MIN_SINE) ) {
|
3017
|
+
/* all four neighours in xy plane: undefined geometry. */
|
3018
|
+
if ( num_z > 0 ) {
|
3019
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
3020
|
+
}
|
3021
|
+
if ( parity != AB_PARITY_UNKN ) {
|
3022
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
3023
|
+
parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
3024
|
+
#else
|
3025
|
+
/* all 4 bonds are in one plain: try to get 0D parities */
|
3026
|
+
if ( AB_PARITY_NONE == (parity = GetStereocenter0DParity( at, cur_at, j1, nSbNeighOrigAtNumb, FlagSC_0D )) ) {
|
3027
|
+
parity = AB_PARITY_UNDF;
|
3028
|
+
} else
|
3029
|
+
if ( ATOM_PARITY_WELL_DEF( parity ) ) {
|
3030
|
+
bAmbiguous &= ~AMBIGUOUS_STEREO; /* 0D parity has resolved the ambiguity */
|
3031
|
+
}
|
3032
|
+
#endif
|
3033
|
+
}
|
3034
|
+
goto exit_function;
|
3035
|
+
}
|
3036
|
+
/***********************************************************
|
3037
|
+
* At this point we have 4 neighboring atoms.
|
3038
|
+
* check for tetrahedral ambiguity in 2D case
|
3039
|
+
*/
|
3040
|
+
if ( b2D ) {
|
3041
|
+
if ( 0 < (n2DTetrahedralAmbiguity = Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor )) ) {
|
3042
|
+
if ( T2D_WARN & n2DTetrahedralAmbiguity ) {
|
3043
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
3044
|
+
}
|
3045
|
+
if ( T2D_UNDF & n2DTetrahedralAmbiguity ) {
|
3046
|
+
if ( parity != AB_PARITY_UNKN ) {
|
3047
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
3048
|
+
parity = AB_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
3049
|
+
#else
|
3050
|
+
parity = AB_PARITY_UNDF; /* no parity */
|
3051
|
+
#endif
|
3052
|
+
}
|
3053
|
+
goto exit_function;
|
3054
|
+
}
|
3055
|
+
} else
|
3056
|
+
if ( n2DTetrahedralAmbiguity < 0 ) {
|
3057
|
+
bAmbiguous |= AMBIGUOUS_STEREO_ERROR; /* error */
|
3058
|
+
parity = AB_PARITY_UNDF;
|
3059
|
+
goto exit_function;
|
3060
|
+
}
|
3061
|
+
}
|
3062
|
+
|
3063
|
+
/************************************************************/
|
3064
|
+
/* Move coordinates origin to the neighbor #0 */
|
3065
|
+
for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
|
3066
|
+
diff3(at_coord[j], at_coord[0], at_coord[j]);
|
3067
|
+
}
|
3068
|
+
diff3(at_coord_center, at_coord[0], at_coord_center);
|
3069
|
+
|
3070
|
+
/*
|
3071
|
+
for ( k = 0; k < 3; k++ ) {
|
3072
|
+
for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
|
3073
|
+
at_coord[j][k] -= at_coord[0][k];
|
3074
|
+
}
|
3075
|
+
at_coord_center[k] -= at_coord[0][k];
|
3076
|
+
}
|
3077
|
+
*/
|
3078
|
+
/********************************************************
|
3079
|
+
* find the central (cur_at) atom's parity
|
3080
|
+
* (orientation of atoms #1-3 when looking from #0)
|
3081
|
+
********************************************************/
|
3082
|
+
triple_product = triple_prod_and_min_abs_sine2(&at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous);
|
3083
|
+
/*
|
3084
|
+
*triple_product = triple_prod_and_min_abs_sine( &at_coord[1], &min_sine);
|
3085
|
+
* check for tetrahedral ambiguity -- leave it out for now
|
3086
|
+
*triple_product = sp3_triple_prod_and_min_abs_sine( &at_coord[1], at_coord_center, &min_sine, &bAmbiguous);
|
3087
|
+
*/
|
3088
|
+
if ( fabs(triple_product) > ZERO_FLOAT && (min_sine > MIN_SINE || fabs(min_sine) > ZERO_FLOAT && (n2DTetrahedralAmbiguity & T2D_OKAY ) ) ) {
|
3089
|
+
/* Even => sorted in correct order, Odd=>transposed */
|
3090
|
+
parity = triple_product > 0.0? AB_PARITY_EVEN : AB_PARITY_ODD;
|
3091
|
+
/* if ( num_explicit_H && at[cur_at].removed_H_parity % 2 ) */
|
3092
|
+
/* odd transposition of the removed implicit H */
|
3093
|
+
/* out_at[cur_at].parity = 3 - out_at[cur_at].parity; */
|
3094
|
+
|
3095
|
+
/* moved; see below */
|
3096
|
+
/* out_at[cur_at].bAmbiguousStereo |= bAmbiguous; */
|
3097
|
+
/* at[cur_at].bAmbiguousStereo |= bAmbiguous; */
|
3098
|
+
|
3099
|
+
/* for 4 attached atoms, moving the implicit H from index=3 to index=0 */
|
3100
|
+
/* can be done in odd number (3) transpositions: (23)(12)(01), which inverts the parity */
|
3101
|
+
if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
|
3102
|
+
parity = 3 - parity;
|
3103
|
+
}
|
3104
|
+
} else {
|
3105
|
+
#if (ALWAYS_SET_STEREO_PARITY == 1)
|
3106
|
+
parity = AT_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
|
3107
|
+
#else
|
3108
|
+
if ( num_z > 0 ) {
|
3109
|
+
bAmbiguous |= AMBIGUOUS_STEREO;
|
3110
|
+
}
|
3111
|
+
parity = AB_PARITY_UNDF; /* no parity: 4 bonds are in one plane. */
|
3112
|
+
#endif
|
3113
|
+
}
|
3114
|
+
exit_function:
|
3115
|
+
|
3116
|
+
if ( parity ) {
|
3117
|
+
out_at[cur_at].bAmbiguousStereo |= bAmbiguous;
|
3118
|
+
at[cur_at].bAmbiguousStereo |= bAmbiguous;
|
3119
|
+
}
|
3120
|
+
|
3121
|
+
|
3122
|
+
/* non-isotopic parity */
|
3123
|
+
if ( at[cur_at].num_H > 1 || parity <= 0 )
|
3124
|
+
; /* no non-isotopic parity */
|
3125
|
+
else
|
3126
|
+
out_at[cur_at].parity = parity;
|
3127
|
+
|
3128
|
+
/* isotopic parity */
|
3129
|
+
if ( parity == -AB_PARITY_UNDF || parity == -AB_PARITY_UNKN )
|
3130
|
+
parity = -parity;
|
3131
|
+
if ( parity < 0 )
|
3132
|
+
parity = AB_PARITY_NONE;
|
3133
|
+
out_at[cur_at].parity2 = parity;
|
3134
|
+
|
3135
|
+
|
3136
|
+
parity = PARITY_VAL(out_at[cur_at].parity);
|
3137
|
+
out_at[cur_at].stereo_atom_parity = ATOM_PARITY_WELL_DEF( parity )? AB_PARITY_CALC : parity;
|
3138
|
+
parity = PARITY_VAL(out_at[cur_at].parity2);
|
3139
|
+
out_at[cur_at].stereo_atom_parity2 = ATOM_PARITY_WELL_DEF( parity )? AB_PARITY_CALC : parity;
|
3140
|
+
/*
|
3141
|
+
out_at[cur_at].parity2 = out_at[cur_at].parity; // save for stereo + isotopic canon.
|
3142
|
+
if ( out_at[cur_at].parity ) {
|
3143
|
+
if ( num_explicit_H > 1 || j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 && num_explicit_H ) {
|
3144
|
+
// X H X
|
3145
|
+
// for example, >C< or >C-D
|
3146
|
+
// Y D Y
|
3147
|
+
// parity exists for stereo + isotopic atoms canonicalization only
|
3148
|
+
out_at[cur_at].parity = 0;
|
3149
|
+
}
|
3150
|
+
}
|
3151
|
+
// returning 0 means this can be an adjacent to a stereogenic bond atom
|
3152
|
+
*/
|
3153
|
+
return (int)out_at[cur_at].parity2;
|
3154
|
+
|
3155
|
+
}
|
3156
|
+
#undef ADD_EXPLICIT_HYDROGEN_NEIGH
|
3157
|
+
#undef ADD_EXPLICIT_LONE_PAIR_NEIGH
|
3158
|
+
|
3159
|
+
/*************************************************************/
|
3160
|
+
int set_stereo_parity( inp_ATOM* at, sp_ATOM* at_output, int num_at, int num_removed_H,
|
3161
|
+
int *nMaxNumStereoAtoms, int *nMaxNumStereoBonds, INCHI_MODE nMode,
|
3162
|
+
int bPointedEdgeStereo )
|
3163
|
+
{
|
3164
|
+
int num_3D_stereo_atoms=0;
|
3165
|
+
|
3166
|
+
int i, is_stereo, num_stereo, max_stereo_atoms=0, max_stereo_bonds=0;
|
3167
|
+
QUEUE *q = NULL;
|
3168
|
+
AT_RANK *nAtomLevel = NULL;
|
3169
|
+
S_CHAR *cSource = NULL;
|
3170
|
+
AT_RANK min_sb_ring_size = 0;
|
3171
|
+
|
3172
|
+
/**********************************************************
|
3173
|
+
*
|
3174
|
+
* Note: this parity reflects only relative positions of
|
3175
|
+
* the atoms-neighbors and their ordering in the
|
3176
|
+
* lists of neighbors.
|
3177
|
+
*
|
3178
|
+
* To obtain the actual parity, the parity of a number
|
3179
|
+
* of neighbors transpositions (to obtain a sorted
|
3180
|
+
* list of numbers assigned to the atoms) should be
|
3181
|
+
* added.
|
3182
|
+
*
|
3183
|
+
**********************************************************/
|
3184
|
+
|
3185
|
+
/*********************************************************************************
|
3186
|
+
|
3187
|
+
An example of parity=1 for stereogenic center, tetrahedral asymmetric atom
|
3188
|
+
|
3189
|
+
|
3190
|
+
|
3191
|
+
(1)
|
3192
|
+
|
|
3193
|
+
|
|
3194
|
+
[C] |
|
3195
|
+
|
|
3196
|
+
(2)------(0)
|
3197
|
+
/
|
3198
|
+
/
|
3199
|
+
/
|
3200
|
+
/
|
3201
|
+
(3)
|
3202
|
+
|
3203
|
+
|
3204
|
+
Notation: (n) is a tetrahedral atom neighbor; n is an index of a neighbor in
|
3205
|
+
the central_at->neighbor[] array : neighbor atom number is central_at->neighbor[n].
|
3206
|
+
|
3207
|
+
(0)-(1), (0)-(2), (0)-(3) are lines connecting atom [C] neighbors to neighbor (0)
|
3208
|
+
(0), (1) and (2) are in the plane
|
3209
|
+
(0)-(3) is directed from the plain to the viewer
|
3210
|
+
[C] is somewhere between (0), (1), (2), (3)
|
3211
|
+
Since (1)-(2)-(3) are in a clockwise order when looking from (0), parity is 2, or even;
|
3212
|
+
otherwise parity would be 1, or odd.
|
3213
|
+
|
3214
|
+
**********************************************************************************
|
3215
|
+
|
3216
|
+
Examples of a stereogenic bond.
|
3217
|
+
|
3218
|
+
Notation: [atom number], (index of a neighbor):
|
3219
|
+
[1] and [2] are atoms connected by the stereogenic bond
|
3220
|
+
numbers in () are indexes of neighbors of [1] or [2].
|
3221
|
+
(12 x 16)z = z-component of [1]-[2] and [1]-[6] cross-product
|
3222
|
+
|
3223
|
+
atom [1] atom [2]
|
3224
|
+
[8] [4] prod01 = (12 x 16)z < 0 prod01 = (21 x 24)z < 0
|
3225
|
+
\ / prod02 = (12 x 18)z > 0 prod02 = (21 x 25)z > 0
|
3226
|
+
(2) (1) 0 transpositions because 0 transpositions because
|
3227
|
+
\ / double bond is in 0 posit. double bond is in 0 position
|
3228
|
+
[1]==(0)(0)==[2] 0 = (prod01 > prod02) 0 = (prod01 > prod02)
|
3229
|
+
/ \
|
3230
|
+
(1) (2) result: parity = 2, even result: parity=2, even
|
3231
|
+
/ \
|
3232
|
+
[6] [5]
|
3233
|
+
|
3234
|
+
|
3235
|
+
|
3236
|
+
atom [1] atom [2]
|
3237
|
+
[8] [5] prod01 = (12 x 18)z > 0 prod01 = (21 x 24)z > 0
|
3238
|
+
\ / prod02 = (12 x 16)z < 0 prod02 = (21 x 25)z < 0
|
3239
|
+
(0) (2) 2 transpositions to move 1 transposition to move
|
3240
|
+
\ / at [2] from 2 to 0 pos. at [1] from 1 to 0 position
|
3241
|
+
[1]==(2)(1)==[2] 1 = (prod01 > prod02) 1 = (prod01 > prod02)
|
3242
|
+
/ \
|
3243
|
+
(1) (0) result: parity = (1+2) result: parity=(1+1)
|
3244
|
+
/ \ 2-(1+2)%2 = 1, odd 2-(1+1)%2 = 2, even
|
3245
|
+
[6] [4]
|
3246
|
+
|
3247
|
+
|
3248
|
+
***********************************************************************************
|
3249
|
+
Note: atoms' numbers [1], [2], [4],... are not used to calculate parity at this
|
3250
|
+
point. They will be used for each numbering in the canonicalization.
|
3251
|
+
Note: parity=3 for a stereo atom means entered undefined bond direction
|
3252
|
+
parity=4 for an atom means parity cannot be determined from the given geometry
|
3253
|
+
***********************************************************************************/
|
3254
|
+
|
3255
|
+
if ( !at_output || !at ) {
|
3256
|
+
return -1;
|
3257
|
+
}
|
3258
|
+
|
3259
|
+
/* clear stereo descriptors */
|
3260
|
+
|
3261
|
+
for( i = 0; i < num_at; i ++ ) {
|
3262
|
+
at_output[i].parity = 0;
|
3263
|
+
at_output[i].parity2 = 0;
|
3264
|
+
memset(&at_output[i].stereo_bond_neighbor[0], 0, sizeof(at_output[0].stereo_bond_neighbor) );
|
3265
|
+
memset(&at_output[i].stereo_bond_neighbor2[0], 0, sizeof(at_output[0].stereo_bond_neighbor2) );
|
3266
|
+
memset(&at_output[i].stereo_bond_ord[0], 0, sizeof(at_output[0].stereo_bond_ord) );
|
3267
|
+
memset(&at_output[i].stereo_bond_ord2[0], 0, sizeof(at_output[0].stereo_bond_ord2) );
|
3268
|
+
memset(&at_output[i].stereo_bond_z_prod[0], 0, sizeof(at_output[0].stereo_bond_z_prod) );
|
3269
|
+
memset(&at_output[i].stereo_bond_z_prod2[0], 0, sizeof(at_output[0].stereo_bond_z_prod2) );
|
3270
|
+
memset(&at_output[i].stereo_bond_parity[0], 0, sizeof(at_output[0].stereo_bond_parity) );
|
3271
|
+
memset(&at_output[i].stereo_bond_parity2[0], 0, sizeof(at_output[0].stereo_bond_parity2) );
|
3272
|
+
}
|
3273
|
+
/* estimate max numbers of stereo atoms and bonds if isotopic H are added */
|
3274
|
+
if ( nMaxNumStereoAtoms || nMaxNumStereoBonds ) {
|
3275
|
+
for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
|
3276
|
+
int num;
|
3277
|
+
num = can_be_a_stereo_atom_with_isotopic_H( at, i );
|
3278
|
+
if ( num ) {
|
3279
|
+
max_stereo_atoms += num;
|
3280
|
+
} else
|
3281
|
+
if ( (num = can_be_a_stereo_bond_with_isotopic_H( at, i, nMode ) ) ) { /* accept cumulenes */
|
3282
|
+
max_stereo_bonds += num;
|
3283
|
+
}
|
3284
|
+
}
|
3285
|
+
if ( nMaxNumStereoAtoms )
|
3286
|
+
*nMaxNumStereoAtoms = max_stereo_atoms;
|
3287
|
+
if ( nMaxNumStereoBonds )
|
3288
|
+
*nMaxNumStereoBonds = max_stereo_bonds;
|
3289
|
+
}
|
3290
|
+
/* calculate stereo descriptors */
|
3291
|
+
#if( MIN_SB_RING_SIZE > 0 )
|
3292
|
+
min_sb_ring_size = (AT_RANK)(((nMode & REQ_MODE_MIN_SB_RING_MASK) >> REQ_MODE_MIN_SB_RING_SHFT) & AT_RANK_MASK);
|
3293
|
+
if ( min_sb_ring_size >= 3 ) {
|
3294
|
+
/* create BFS data structure for finding for each stereo bond its min. ring sizes */
|
3295
|
+
q = QueueCreate( num_at+1, sizeof(qInt) );
|
3296
|
+
nAtomLevel = (AT_RANK*)inchi_calloc(sizeof(nAtomLevel[0]),num_at);
|
3297
|
+
cSource = (S_CHAR *)inchi_calloc(sizeof(cSource[0]),num_at);
|
3298
|
+
if ( !q || !cSource || !nAtomLevel ) {
|
3299
|
+
num_3D_stereo_atoms = CT_OUT_OF_RAM;
|
3300
|
+
goto exit_function;
|
3301
|
+
}
|
3302
|
+
} else {
|
3303
|
+
min_sb_ring_size = 2;
|
3304
|
+
}
|
3305
|
+
#endif
|
3306
|
+
/* main cycle: set stereo parities */
|
3307
|
+
for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
|
3308
|
+
|
3309
|
+
if ( is_stereo = set_stereo_atom_parity( at_output, at, i, at+num_at, num_removed_H, bPointedEdgeStereo ) ) {
|
3310
|
+
num_3D_stereo_atoms += ATOM_PARITY_WELL_DEF( is_stereo );
|
3311
|
+
} else {
|
3312
|
+
is_stereo = set_stereo_bonds_parity( at_output, at, i, at+num_at, num_removed_H, nMode,
|
3313
|
+
q, nAtomLevel, cSource, min_sb_ring_size, bPointedEdgeStereo );
|
3314
|
+
if ( RETURNED_ERROR( is_stereo ) ) {
|
3315
|
+
num_3D_stereo_atoms = is_stereo;
|
3316
|
+
break;
|
3317
|
+
}
|
3318
|
+
}
|
3319
|
+
num_stereo += (is_stereo != 0);
|
3320
|
+
}
|
3321
|
+
/*
|
3322
|
+
if ( (nMode & REQ_MODE_SC_IGN_ALL_UU )
|
3323
|
+
REQ_MODE_SC_IGN_ALL_UU
|
3324
|
+
REQ_MODE_SB_IGN_ALL_UU
|
3325
|
+
*/
|
3326
|
+
|
3327
|
+
#if( MIN_SB_RING_SIZE > 0 )
|
3328
|
+
if ( q ) {
|
3329
|
+
q = QueueDelete( q );
|
3330
|
+
}
|
3331
|
+
if ( nAtomLevel )
|
3332
|
+
inchi_free( nAtomLevel );
|
3333
|
+
if ( cSource )
|
3334
|
+
inchi_free( cSource );
|
3335
|
+
exit_function:
|
3336
|
+
#endif
|
3337
|
+
|
3338
|
+
|
3339
|
+
return num_3D_stereo_atoms;
|
3340
|
+
}
|
3341
|
+
/*****************************************************************
|
3342
|
+
* Functions that disconnect bonds
|
3343
|
+
*
|
3344
|
+
*=== During Preprocessing ===
|
3345
|
+
*
|
3346
|
+
* RemoveInpAtBond
|
3347
|
+
* DisconnectMetalSalt (is not aware of bond parities)
|
3348
|
+
* DisconnectAmmoniumSalt
|
3349
|
+
*
|
3350
|
+
*=== Before Normalization ===
|
3351
|
+
*
|
3352
|
+
* remove_terminal_HDT
|
3353
|
+
*
|
3354
|
+
*=== During the Normalization ===
|
3355
|
+
*
|
3356
|
+
* AddOrRemoveExplOrImplH
|
3357
|
+
*
|
3358
|
+
*****************************************************************/
|
3359
|
+
int ReconcileAllCmlBondParities( inp_ATOM *at, int num_atoms, int bDisconnected )
|
3360
|
+
{
|
3361
|
+
int i, ret = 0;
|
3362
|
+
S_CHAR *visited = (S_CHAR*) inchi_calloc( num_atoms, sizeof(*visited) );
|
3363
|
+
if ( !visited )
|
3364
|
+
return -1; /* out of RAM */
|
3365
|
+
for ( i = 0; i < num_atoms; i ++ ) {
|
3366
|
+
if ( at[i].sb_parity[0] && !visited[i] && !(bDisconnected && is_el_a_metal(at[i].el_number)) ) {
|
3367
|
+
if ( ret = ReconcileCmlIncidentBondParities( at, i, -1, visited, bDisconnected ) ) {
|
3368
|
+
break; /* error */
|
3369
|
+
}
|
3370
|
+
}
|
3371
|
+
}
|
3372
|
+
inchi_free ( visited );
|
3373
|
+
return ret;
|
3374
|
+
}
|
3375
|
+
/*****************************************************************/
|
3376
|
+
int ReconcileCmlIncidentBondParities( inp_ATOM *at, int cur_atom, int prev_atom, S_CHAR *visited, int bDisconnected )
|
3377
|
+
{
|
3378
|
+
/* visited = 0 or parity => atom has not been visited
|
3379
|
+
10 + parity => currently is on the stack + its final parity
|
3380
|
+
20 + parity => has been visited; is not on the stack anymore + its final parity */
|
3381
|
+
int i, j, nxt_atom, ret = 0, len;
|
3382
|
+
int icur2nxt, icur2neigh; /* cur atom neighbors */
|
3383
|
+
int inxt2cur, inxt2neigh; /* next atom neighbors */
|
3384
|
+
int cur_parity, nxt_parity;
|
3385
|
+
int cur_order_parity, nxt_order_parity, cur_sb_parity, nxt_sb_parity, bCurMask, bNxtMask;
|
3386
|
+
/* !(bDisconnected && is_el_a_metal(at[i].el_number) */
|
3387
|
+
|
3388
|
+
if ( at[cur_atom].valence > MAX_NUM_STEREO_BONDS )
|
3389
|
+
return 0; /* ignore */
|
3390
|
+
|
3391
|
+
if ( !at[cur_atom].sb_parity[0] )
|
3392
|
+
return 1; /* wrong call */
|
3393
|
+
|
3394
|
+
if ( visited[cur_atom] >= 10 )
|
3395
|
+
return 2; /* program error */
|
3396
|
+
|
3397
|
+
cur_parity = visited[cur_atom] % 10;
|
3398
|
+
|
3399
|
+
visited[cur_atom] += 10;
|
3400
|
+
|
3401
|
+
for ( i = 0; i < MAX_NUM_STEREO_BONDS && at[cur_atom].sb_parity[i]; i ++ ) {
|
3402
|
+
icur2nxt = (int)at[cur_atom].sb_ord[i];
|
3403
|
+
len = get_opposite_sb_atom( at, cur_atom, icur2nxt, &nxt_atom, &inxt2cur, &j );
|
3404
|
+
if ( !len ) {
|
3405
|
+
return 4; /* could not find the opposite atom: bond parity data error */
|
3406
|
+
}
|
3407
|
+
if ( nxt_atom == prev_atom )
|
3408
|
+
continue;
|
3409
|
+
if ( visited[nxt_atom] >= 20 )
|
3410
|
+
continue; /* back edge, second visit: ignore */
|
3411
|
+
if ( at[nxt_atom].valence > MAX_NUM_STEREO_BONDS )
|
3412
|
+
continue; /* may be treated only after metal disconnection */
|
3413
|
+
|
3414
|
+
if ( bDisconnected && (at[cur_atom].sb_parity[i] & SB_PARITY_FLAG) ) {
|
3415
|
+
cur_sb_parity = (at[cur_atom].sb_parity[i] >> SB_PARITY_SHFT);
|
3416
|
+
bCurMask = 3 << SB_PARITY_SHFT;
|
3417
|
+
} else {
|
3418
|
+
cur_sb_parity = (at[cur_atom].sb_parity[i] & SB_PARITY_MASK);
|
3419
|
+
bCurMask = 3;
|
3420
|
+
}
|
3421
|
+
if ( bDisconnected && (at[nxt_atom].sb_parity[j] & SB_PARITY_FLAG) ) {
|
3422
|
+
nxt_sb_parity = (at[nxt_atom].sb_parity[j] >> SB_PARITY_SHFT);
|
3423
|
+
bNxtMask = 3 << SB_PARITY_SHFT;
|
3424
|
+
} else {
|
3425
|
+
nxt_sb_parity = (at[nxt_atom].sb_parity[j] & SB_PARITY_MASK);
|
3426
|
+
bNxtMask = 3;
|
3427
|
+
}
|
3428
|
+
|
3429
|
+
|
3430
|
+
|
3431
|
+
if ( !ATOM_PARITY_WELL_DEF(cur_sb_parity) ||
|
3432
|
+
!ATOM_PARITY_WELL_DEF(nxt_sb_parity) ) {
|
3433
|
+
if ( cur_sb_parity == nxt_sb_parity ) {
|
3434
|
+
continue;
|
3435
|
+
/*goto move_forward;*/ /* bypass unknown/undefined */
|
3436
|
+
}
|
3437
|
+
return 3; /* sb parities do not match: bond parity data error */
|
3438
|
+
}
|
3439
|
+
|
3440
|
+
icur2neigh = (int)at[cur_atom].sn_ord[i];
|
3441
|
+
inxt2neigh = (int)at[nxt_atom].sn_ord[j];
|
3442
|
+
/* parity of at[cur_atom].neighbor[] premutation to reach this order: { next_atom, neigh_atom, ...} */
|
3443
|
+
|
3444
|
+
/* 1. move next_atom from position=icur2nxt to position=0 =>
|
3445
|
+
* icur2nxt permutations
|
3446
|
+
* 2. move neigh_atom from position=inxt2neigh+(inxt2cur > inxt2neigh) to position=1 =>
|
3447
|
+
* inxt2neigh+(inxt2cur > inxt2neigh)-1 permutations.
|
3448
|
+
* Note if (inxt2cur > inxt2neigh) then move #1 increments neigh_atom position
|
3449
|
+
* Note add 4 because icur2neigh may be negative due to isotopic H removal
|
3450
|
+
*/
|
3451
|
+
cur_order_parity = (4+icur2nxt + icur2neigh + (icur2neigh > icur2nxt)) % 2;
|
3452
|
+
/* same for next atom: */
|
3453
|
+
/* parity of at[nxt_atom].neighbor[] premutation to reach this order: { cur_atom, neigh_atom, ...} */
|
3454
|
+
nxt_order_parity = (4+inxt2cur + inxt2neigh + (inxt2neigh > inxt2cur)) % 2;
|
3455
|
+
|
3456
|
+
nxt_parity = visited[nxt_atom] % 10;
|
3457
|
+
|
3458
|
+
if ( !cur_parity ) {
|
3459
|
+
cur_parity = 2 - (cur_order_parity + cur_sb_parity) % 2;
|
3460
|
+
visited[cur_atom] += cur_parity;
|
3461
|
+
} else
|
3462
|
+
if ( cur_parity != 2 - (cur_order_parity + cur_sb_parity) % 2 ) {
|
3463
|
+
|
3464
|
+
/***** reconcile bond parities *****/
|
3465
|
+
|
3466
|
+
/* Each bond parity is split into two values located at the end atoms.
|
3467
|
+
For T (trans) the values are (1,1) or (2,2)
|
3468
|
+
For C (cis) the values are (1,2) or (2,1)
|
3469
|
+
The fact that one pair = another with inverted parities, namely
|
3470
|
+
Inv(1,1) = (2,2) and Inv(1,2) = (2,1), allows to
|
3471
|
+
simultaneouly invert parities of the current bond end atoms
|
3472
|
+
(at[cur_atom].sb_parity[i], at[nxt_atom].sb_parity[j])
|
3473
|
+
so that the final current atom parity cur_parity
|
3474
|
+
calculated later in stereochemical canonicalization for
|
3475
|
+
each stereobond incident with the current atomis same.
|
3476
|
+
Achieving this is called here RECONCILIATION.
|
3477
|
+
If at the closure of an aromatic circuit the parities of
|
3478
|
+
next atom cannot be reconciled with already calculated then
|
3479
|
+
this function returns 5 (error).
|
3480
|
+
*/
|
3481
|
+
|
3482
|
+
at[cur_atom].sb_parity[i] ^= bCurMask;
|
3483
|
+
at[nxt_atom].sb_parity[j] ^= bNxtMask;
|
3484
|
+
cur_sb_parity ^= 3;
|
3485
|
+
nxt_sb_parity ^= 3;
|
3486
|
+
}
|
3487
|
+
|
3488
|
+
if ( !nxt_parity ) {
|
3489
|
+
nxt_parity = 2 - (nxt_order_parity + nxt_sb_parity) % 2;
|
3490
|
+
visited[nxt_atom] += nxt_parity;
|
3491
|
+
} else
|
3492
|
+
if ( nxt_parity != 2 - (nxt_order_parity + nxt_sb_parity) % 2 ) {
|
3493
|
+
return 5; /* algorithm does not work for Mebius-like structures */
|
3494
|
+
}
|
3495
|
+
|
3496
|
+
/* move_forward: */
|
3497
|
+
if ( visited[nxt_atom] < 10 ) {
|
3498
|
+
ret = ReconcileCmlIncidentBondParities( at, nxt_atom, cur_atom, visited, bDisconnected );
|
3499
|
+
if ( ret ) {
|
3500
|
+
break;
|
3501
|
+
}
|
3502
|
+
}
|
3503
|
+
}
|
3504
|
+
visited[cur_atom] += 10; /* all bonds incident to the current atom have
|
3505
|
+
been processed or an error occurred. */
|
3506
|
+
return ret;
|
3507
|
+
}
|
3508
|
+
/*****************************************************************/
|
3509
|
+
int get_opposite_sb_atom( inp_ATOM *at, int cur_atom, int icur2nxt, int *pnxt_atom, int *pinxt2cur, int *pinxt_sb_parity_ord )
|
3510
|
+
{
|
3511
|
+
AT_NUMB nxt_atom;
|
3512
|
+
int j, len;
|
3513
|
+
|
3514
|
+
len = 0;
|
3515
|
+
while ( len ++ < 20 ) { /* arbitrarily set cumulene length limit to avoid infinite loop */
|
3516
|
+
nxt_atom = at[cur_atom].neighbor[icur2nxt];
|
3517
|
+
for ( j = 0; j < MAX_NUM_STEREO_BONDS && at[nxt_atom].sb_parity[j]; j ++ ) {
|
3518
|
+
if ( cur_atom == at[nxt_atom].neighbor[(int)at[nxt_atom].sb_ord[j]] ) {
|
3519
|
+
/* found the opposite atom */
|
3520
|
+
*pnxt_atom = nxt_atom;
|
3521
|
+
*pinxt2cur = at[nxt_atom].sb_ord[j];
|
3522
|
+
*pinxt_sb_parity_ord = j;
|
3523
|
+
return len;
|
3524
|
+
}
|
3525
|
+
}
|
3526
|
+
if ( j ) {
|
3527
|
+
return 0; /* reached atom(s) with stereobond (sb) parity, the opposite atom has not been found */
|
3528
|
+
}
|
3529
|
+
if ( at[nxt_atom].valence == 2 && 2*BOND_TYPE_DOUBLE == at[nxt_atom].chem_bonds_valence ) {
|
3530
|
+
/* follow cumulene =X= path */
|
3531
|
+
icur2nxt = (at[nxt_atom].neighbor[0] == cur_atom);
|
3532
|
+
cur_atom = nxt_atom;
|
3533
|
+
} else {
|
3534
|
+
return 0; /* neither atom with a sb parity not middle cumulene could be reached */
|
3535
|
+
}
|
3536
|
+
}
|
3537
|
+
return 0; /* too long chain of cumulene was found */
|
3538
|
+
}
|