rino 0.1.0 → 0.2.0

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