chemruby 0.9.3 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. data/README +2 -2
  2. data/Rakefile +67 -63
  3. data/ext/extconf.rb +2 -0
  4. data/ext/subcomp.c +461 -320
  5. data/ext/utils.c +56 -0
  6. data/ext/utils.h +13 -0
  7. data/lib/chem.rb +34 -8
  8. data/lib/chem/db.rb +8 -0
  9. data/lib/chem/db/cansmi.rb +1 -1
  10. data/lib/chem/db/cdx.rb +1 -1
  11. data/lib/chem/db/cml.rb +52 -0
  12. data/lib/chem/db/gd.rb +64 -0
  13. data/lib/chem/db/gspan.rb +2 -2
  14. data/lib/chem/db/kcf_rpair.rb +34 -0
  15. data/lib/chem/db/kegg.rb +35 -1
  16. data/lib/chem/db/mdl.rb +75 -34
  17. data/lib/chem/db/opsin.rb +24 -0
  18. data/lib/chem/db/pdb.rb +105 -0
  19. data/lib/chem/db/pdf.rb +2 -0
  20. data/lib/chem/db/pubchem.rb +1071 -88
  21. data/lib/chem/db/rmagick.rb +5 -3
  22. data/lib/chem/db/sdf.rb +28 -2
  23. data/lib/chem/db/smiles/smiles.ry +27 -25
  24. data/lib/chem/db/smiles/smiparser.rb +29 -27
  25. data/lib/chem/db/types/type_gd.rb +35 -0
  26. data/lib/chem/db/types/type_gspan.rb +2 -2
  27. data/lib/chem/db/types/type_kcf.rb +19 -0
  28. data/lib/chem/db/types/type_kegg.rb +2 -0
  29. data/lib/chem/db/types/type_mdl.rb +1 -1
  30. data/lib/chem/db/types/type_png.rb +5 -1
  31. data/lib/chem/db/types/type_rdf.rb +22 -0
  32. data/lib/chem/db/types/type_xyz.rb +1 -1
  33. data/lib/chem/db/vector.rb +19 -3
  34. data/lib/chem/model.rb +5 -2
  35. data/lib/chem/utils.rb +17 -1
  36. data/lib/chem/utils/bitdb.rb +49 -0
  37. data/lib/chem/utils/cas.rb +28 -0
  38. data/lib/chem/utils/cdk.rb +403 -0
  39. data/lib/chem/utils/fingerprint.rb +98 -0
  40. data/lib/chem/utils/geometry.rb +8 -0
  41. data/lib/chem/utils/net.rb +303 -0
  42. data/lib/chem/utils/once.rb +28 -0
  43. data/lib/chem/utils/openbabel.rb +204 -0
  44. data/lib/chem/utils/sssr.rb +33 -25
  45. data/lib/chem/utils/sub.rb +6 -0
  46. data/lib/chem/utils/transform.rb +9 -8
  47. data/lib/chem/utils/ullmann.rb +138 -95
  48. data/lib/graph.rb +5 -6
  49. data/lib/graph/utils.rb +8 -0
  50. data/sample/calc_maximum_common_subgraph.rb +27 -0
  51. data/sample/calc_properties.rb +9 -0
  52. data/sample/data/atp.mol +69 -0
  53. data/sample/data/pioglitazone.mol +58 -0
  54. data/sample/data/rosiglitazone.mol +55 -0
  55. data/sample/data/troglitazone.mol +70 -0
  56. data/sample/find_compound_by_keggapi.rb +19 -0
  57. data/sample/generate_inchi.rb +7 -0
  58. data/sample/generate_substructurekey.rb +11 -0
  59. data/sample/images/ex6.rb +17 -0
  60. data/sample/images/ex7.rb +18 -0
  61. data/sample/iupac2mol.rb +8 -0
  62. data/sample/kekule.rb +13 -0
  63. data/sample/logp.rb +4 -0
  64. data/sample/mcs.rb +13 -0
  65. data/sample/mol2pdf.rb +8 -0
  66. data/sample/pubchem_fetch.rb +8 -0
  67. data/sample/pubchem_search.rb +12 -0
  68. data/sample/rosiglitazone.mol +57 -0
  69. data/sample/smarts.rb +10 -0
  70. data/sample/structure_match.rb +8 -0
  71. data/sample/structure_match_color.rb +22 -0
  72. data/sample/thiazolidinedione.mol +19 -0
  73. data/sample/troglitazone.mol +232 -0
  74. data/sample/vicinity.rb +8 -0
  75. data/test/data/CID_704.sdf +236 -0
  76. data/test/data/CID_994.sdf +146 -0
  77. data/test/data/db_EXPT03276.txt +321 -0
  78. data/test/data/pioglitazone.mol +58 -0
  79. data/test/data/rosiglitazone.mol +55 -0
  80. data/test/data/thiazolidinedione.mol +19 -0
  81. data/test/data/troglitazone.mol +70 -0
  82. data/test/{test_adj.rb → tc_adj.rb} +0 -0
  83. data/test/{test_canonical_smiles.rb → tc_canonical_smiles.rb} +0 -0
  84. data/test/tc_casrn.rb +17 -0
  85. data/test/tc_cdk.rb +89 -0
  86. data/test/{test_cdx.rb → tc_cdx.rb} +0 -0
  87. data/test/{test_chem.rb → tc_chem.rb} +0 -0
  88. data/test/{test_cluster.rb → tc_cluster.rb} +0 -0
  89. data/test/{test_db.rb → tc_db.rb} +0 -0
  90. data/test/tc_develop.rb +38 -0
  91. data/test/tc_drugbank.rb +13 -0
  92. data/test/{test_eps.rb → tc_eps.rb} +0 -0
  93. data/test/tc_gd.rb +8 -0
  94. data/test/{test_geometry.rb → tc_geometry.rb} +0 -0
  95. data/test/tc_graph.rb +15 -0
  96. data/test/{test_gspan.rb → tc_gspan.rb} +0 -0
  97. data/test/{test_iupac.rb → tc_iupac.rb} +0 -0
  98. data/test/{test_kcf.rb → tc_kcf.rb} +0 -0
  99. data/test/{test_kcf_glycan.rb → tc_kcf_glycan.rb} +0 -0
  100. data/test/{test_kegg.rb → tc_kegg.rb} +13 -0
  101. data/test/{test_linucs.rb → tc_linucs.rb} +0 -0
  102. data/test/{test_mdl.rb → tc_mdl.rb} +20 -0
  103. data/test/{test_mol2.rb → tc_mol2.rb} +1 -1
  104. data/test/{test_morgan.rb → tc_morgan.rb} +0 -0
  105. data/test/tc_net.rb +5 -0
  106. data/test/tc_once.rb +29 -0
  107. data/test/tc_openbabel.rb +57 -0
  108. data/test/{test_pdf.rb → tc_pdf.rb} +0 -0
  109. data/test/{test_prop.rb → tc_prop.rb} +1 -1
  110. data/test/tc_pubchem.rb +32 -0
  111. data/test/{test_rmagick.rb → tc_rmagick.rb} +0 -0
  112. data/test/{test_sbdb.rb → tc_sbdb.rb} +0 -0
  113. data/test/{test_sdf.rb → tc_sdf.rb} +2 -0
  114. data/test/{test_smiles.rb → tc_smiles.rb} +46 -30
  115. data/test/tc_sssr.rb +1 -0
  116. data/test/{test_sub.rb → tc_sub.rb} +0 -0
  117. data/test/tc_subcomp.rb +59 -0
  118. data/test/{test_traverse.rb → tc_traverse.rb} +0 -0
  119. data/test/{test_writer.rb → tc_writer.rb} +0 -0
  120. data/test/{test_xyz.rb → tc_xyz.rb} +0 -0
  121. data/test/ts_current.rb +11 -0
  122. data/test/ts_image.rb +6 -0
  123. data/test/ts_main.rb +12 -0
  124. metadata +259 -194
  125. data/lib/chem/utils/graph_db.rb +0 -146
  126. data/test/test_sssr.rb +0 -18
  127. data/test/test_subcomp.rb +0 -37
@@ -0,0 +1,98 @@
1
+ require 'set'
2
+
3
+ class Integer
4
+
5
+ def to_bit_positions
6
+ ary = []
7
+ i = 0
8
+ pow = 0
9
+ while pow <= self
10
+ pow = 1 << i
11
+ if((pow & self) != 0)
12
+ ary << i
13
+ end
14
+ i += 1
15
+ end
16
+ ary
17
+ end
18
+
19
+ end
20
+
21
+
22
+ module Chem
23
+
24
+ module Atom
25
+ attr_accessor :rings
26
+ end
27
+
28
+ module Molecule
29
+
30
+ def f_dfs node, path, max, &block
31
+ if not path.length > max
32
+ yield path
33
+ self.adjacent_to(node).each do |bond, n|
34
+ next if n.element == :H
35
+ if not path.include?(n)
36
+ path.push(n)
37
+ f_dfs(n, path, max, &block)
38
+ path.pop
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ # ELEMNUM = {
45
+ # :C => 0,
46
+ # :N => 1,
47
+ # :O => 2,
48
+ # :P => 4}
49
+ # ELEMNUM.default = 32
50
+
51
+ ELEMNUM = Element2Number.inject({}) do |ret, (elem, num)|
52
+ ret[elem] = 1 << num
53
+ ret
54
+ end
55
+ ELEMNUM.default = 32
56
+
57
+ #
58
+ def fingerprint(max = 3, n_bits = 32)
59
+
60
+ find_sssr.each do |rings|
61
+ len = rings.length
62
+ rings.each do |atom|
63
+ (atom.rings ||= []) << len
64
+ end
65
+ end
66
+
67
+ fp = 0
68
+ set = Set.new
69
+
70
+ nodes.each do |node|
71
+ f_dfs(node, [node], max) do |path|
72
+ # Exclude unwanted path
73
+ key = path.collect{|atom| atom.element.to_s}.join(".")
74
+ next if set.include?(key)
75
+
76
+ set.add(key)
77
+ set.add(path.reverse.collect{|atom| atom.element.to_s}.join("."))
78
+ # seed calculation
79
+ seed = 0
80
+ path.each_with_index do |atom, idx|
81
+ seed += (1 << ( 5 * idx)) *
82
+ ELEMNUM[atom.element] *
83
+ (atom.rings.nil? ? 1 : (1 << atom.rings.length))
84
+ end
85
+ srand(seed)
86
+ 1.times do |n|
87
+ fp |= 1 << rand(n_bits)
88
+ end
89
+ end
90
+ end
91
+ fp
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
98
+
@@ -3,6 +3,14 @@ module Chem
3
3
 
4
4
  module Molecule
5
5
 
6
+ # Return size of molecule with Array [x, y, z]
7
+ def box_size
8
+ size_x = nodes().max{|a1, a2| a1.x <=> a2.x}.x - nodes().min{|a1, a2| a1.x <=> a2.x}.x
9
+ size_y = nodes().max{|a1, a2| a1.y <=> a2.y}.y - nodes().min{|a1, a2| a1.y <=> a2.y}.y
10
+ size_z = nodes().max{|a1, a2| a1.z <=> a2.z}.z - nodes().min{|a1, a2| a1.z <=> a2.z}.z
11
+ [size_x, size_y, size_z]
12
+ end
13
+
6
14
  # Automatically assigns 2-dimensional geometry
7
15
  # This method may implicitly called from ChemRuby
8
16
  # if nil is assigned to Atom#x
@@ -0,0 +1,303 @@
1
+ # Copyright (C) 2005, 2006 KADOWAKI Tadashi <tadakado@gmail.com>
2
+ # TANAKA Nobuya <nobuya.tanaka@gmail.com>
3
+ # APODACA Richard <r_apodaca@users.sf.net>
4
+
5
+ require 'net/http'
6
+ require 'net/ftp'
7
+ require 'date'
8
+ require 'rexml/document'
9
+ require 'cgi'
10
+
11
+ module Chem
12
+
13
+ module NetUtils
14
+
15
+ def http_get(str)
16
+ Net::HTTP.get(URI.parse(str))
17
+ end
18
+
19
+ end
20
+
21
+ def self.search_net(term, options)
22
+ case options[:db]
23
+ when :pubmed
24
+ Chem::NCBI::ESearch.query(term, options)
25
+ when :pubchem
26
+ Chem::NCBI::ESearch.query(term, options)
27
+ end
28
+ end
29
+
30
+ class NCBI
31
+ EUtilsURI = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/'
32
+ PubChemURI = 'http://pubchem.ncbi.nlm.nih.gov/'
33
+
34
+ # EInfo
35
+ module EInfo
36
+ extend Chem::NetUtils
37
+
38
+ EInfoURI = EUtilsURI + 'einfo.fcgi?'
39
+
40
+ def self.query(params = {})
41
+ if params.empty?
42
+ xml = REXML::Document.new(http_get(EInfoURI))
43
+ dbs = []
44
+ xml.elements.each("eInfoResult/DbList/DbName") do |element|
45
+ dbs << element.text
46
+ end
47
+ dbs
48
+ elsif params[:db]
49
+ DbInfo.new(REXML::Document.new(http_get(EInfoURI + "db=" + params[:db].to_s)))
50
+ end
51
+ end
52
+
53
+ class DbInfo
54
+ attr_reader :db_name, :menu_name, :description, :count, :last_update
55
+ def initialize(xml)
56
+ @db_name = xml.elements["eInfoResult/DbInfo/DbName"].text
57
+ @menu_name = xml.elements["eInfoResult/DbInfo/MenuName"].text
58
+ @description = xml.elements["eInfoResult/DbInfo/Description"].text
59
+ @count = xml.elements["eInfoResult/DbInfo/Count"].text
60
+ @last_update = xml.elements["eInfoResult/DbInfo/LastUpdate"].text
61
+ @fields = []
62
+ xml.elements.each("eInfoResult/DbInfo/FieldList/Field") do |element|
63
+ @fields << {
64
+ :name => element.elements["Name" ].text,
65
+ :full_name => element.elements["FullName" ].text,
66
+ :description => element.elements["Description"].text,
67
+ :term_count => element.elements["TermCount" ].text,
68
+ :is_date => element.elements["IsDate" ].text == "Y",
69
+ :is_numerical => element.elements["IsNumerical"].text == "Y",
70
+ :single_token => element.elements["SingleToken"].text == "Y",
71
+ :hierarchy => element.elements["Hierarchy" ].text == "Y",
72
+ :is_hidden => element.elements["IsHidden" ].text == "Y",
73
+ }
74
+ end
75
+ end
76
+ end
77
+
78
+ end # EInfo module
79
+
80
+ module ESearch
81
+ extend Chem::NetUtils
82
+
83
+ ESearchURI = EUtilsURI + 'esearch.fcgi?'
84
+
85
+ def self.search(params)
86
+ result = {}
87
+ uri = ESearchURI + params.collect{|key, value| key.to_s + "=" + CGI.escape(value.to_s)}.join("&")
88
+ doc = http_get(uri)
89
+ xml = REXML::Document.new(doc)
90
+ raise "Error no result" unless xml.elements["eSearchResult/ERROR"].nil?
91
+
92
+ result[:count] = xml.elements["eSearchResult/Count" ].text.to_i
93
+ result[:retmax] = xml.elements["eSearchResult/RetMax" ].text.to_i
94
+ result[:retstart] = xml.elements["eSearchResult/RetStart"].text.to_i
95
+
96
+ result[:id_list] = list = []
97
+ xml.elements.each("eSearchResult/IdList/Id") do |element|
98
+ list << element.text.to_i
99
+ end
100
+ result
101
+ end
102
+
103
+ end
104
+
105
+ module PCFetch
106
+
107
+ extend Chem::NetUtils
108
+
109
+ PCFetchURI = PubChemURI + 'pc_fetch/pc_fetch.cgi?'
110
+
111
+ def self.fetch(params)
112
+ raise "You need to specify :retmode" if params[:retmode].nil?
113
+
114
+ uri = PCFetchURI + params.collect{|key, value| key.to_s + "=" + value.to_s}.join("&")
115
+ doc = http_get(uri)
116
+ num = 0
117
+ if m = /pubchem\/\.fetch\/(\d+).sdf/.match(doc)
118
+ puts 'ftp'
119
+ num = m[1].to_i
120
+ elsif m = /reqid=(\d+)/.match(doc)
121
+ puts 'http'
122
+ num = m[1].to_i
123
+ else
124
+ raise "Cannot retrieve file"
125
+ end
126
+
127
+ params[:localfilename] ||= "%s%d.sdf" % [params[:db], params[:id]]
128
+
129
+ begin
130
+ ftp = Net::FTP.open("ftp.ncbi.nih.gov")
131
+ ftp.login
132
+ ftp.gettextfile("pubchem/.fetch/%d.sdf" % num, params[:localfilename])
133
+ rescue Net::FTPPermError
134
+ puts "error : num"
135
+ retry
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+
142
+ module ESummary
143
+
144
+ extend Chem::NetUtils
145
+ ESummaryURI = EUtilsURI + 'esummary.fcgi?'
146
+
147
+ def self.get(params)
148
+ uri = ESummaryURI + params.collect{|key, value| key.to_s + "=" + value.to_s}.join("&")
149
+ http_get(uri)
150
+ end
151
+
152
+ def self.get_parsed(params)
153
+ tree = {}
154
+ xml = REXML::Document.new(get(params))
155
+ xml.elements.each("eSummaryResult/DocSum/Item") do |element|
156
+ tree[element.attributes["Name"]] =
157
+ case element.attributes["Type"]
158
+ when "String"
159
+ element.text
160
+ when "Integer"
161
+ element.text.to_i
162
+ when "Date"
163
+ element.text
164
+ when "List"
165
+ ary = []
166
+ element.elements.each("Item"){|el|
167
+ ary << case el.attributes["Type"]
168
+ when "String"
169
+ el.text
170
+ when "Integer"
171
+ el.text.to_i
172
+ else
173
+ ""
174
+ end
175
+ }
176
+ ary
177
+ end
178
+ end
179
+ tree
180
+ end
181
+ end
182
+
183
+ # obsolete
184
+ class EFetch
185
+
186
+ include Chem::NetUtils
187
+
188
+ EFetchURI = EUtilsURI + 'efetch.fcgi' + '?'
189
+
190
+ def initialize(query_key, web_env)
191
+ uri = [PCFetchURI]
192
+ uri << 'db=pccompound'
193
+ uri << '&WebEnv=' + web_env
194
+ uri << '&query_key=' + query_key
195
+ uri << '&retmode=sdf'
196
+ uri << '&compression=none'
197
+ #"retmode=xml&"
198
+ #uri = EFetchURI + "&db=pccompound&retmode=xml&WebEnv=" + web_env + "&query_key=" + query_key + "&tool=oscar3&email=nobuya.tanaka%40gmail.com"
199
+ p uri.join
200
+ doc = http_get(uri.join)
201
+ if m = /bookmarking this page or by going to<\/p><p><a href=\"([^"]+)/.match(doc)
202
+ sleep 1
203
+ p m[1]
204
+ d = http_get(m[1])
205
+ m = /"ftp:\/\/([^"]+)/.match(d)
206
+ p m[1]
207
+ require 'net/ftp'
208
+ begin
209
+ sleep 0.5
210
+ ftp = Net::FTP.open("ftp.ncbi.nih.gov")
211
+ ftp.login
212
+ ftp.gettextfile("pubchem/.fetch/606874731181068179.sdf")
213
+ rescue Net::FTPPermError
214
+ sleep 1
215
+ puts 'OK'
216
+ end
217
+
218
+ end
219
+ end
220
+
221
+ def self.fetch_all(query_key, web_env)
222
+ new(query_key, web_env)
223
+ end
224
+
225
+ end
226
+
227
+ end
228
+ end
229
+
230
+ if __FILE__ == $0
231
+ # search PubChem compounds using InChI
232
+ query = {
233
+ :db => :pccompound,
234
+ :term => '"InChI=1/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12)/f/h11H"'
235
+ }
236
+
237
+ p Chem::NCBI::ESearch.search(query)
238
+
239
+ # search PubChem substance with term
240
+
241
+ query = {
242
+ :db => "pcsubstance",
243
+ :term => 'benzene'
244
+ }
245
+
246
+ p Chem::NCBI::ESearch.search(query)
247
+
248
+ # search PubChem substance with complete synonyms
249
+
250
+ query = {
251
+ :db => "pcsubstance",
252
+ :term => 'benzene',
253
+ :field => 'CSYN',
254
+ }
255
+
256
+ p Chem::NCBI::ESearch.search(query)
257
+
258
+ # search PubMed
259
+ query = {
260
+ :db => "pubmed",
261
+ :term => "asthma[mh]+OR+hay+fever[mh]",
262
+ }
263
+
264
+ p query
265
+ p Chem::NCBI::ESearch.search(query)
266
+
267
+ # Retrieving more entries
268
+
269
+ query = {
270
+ :db => "pubmed",
271
+ :term => "cancer",
272
+ :reldate => 60,
273
+ :datetype => "edat",
274
+ :retmax => 100,
275
+ :retstart => 300,
276
+ }
277
+
278
+ p Chem::NCBI::ESearch.search(query)
279
+
280
+ # Retrieving Eutils database information
281
+ p Chem::NCBI::EInfo.query
282
+
283
+
284
+ # Rerieving information about PubChem Compounds
285
+
286
+ pp Chem::NCBI::EInfo.query(:db => :pccompound)
287
+
288
+ # Retrieving pccompound using PC_Fetch
289
+ # Not recommended
290
+ # It seems that EFetch does not accept db=pccompound
291
+ # PCFetch could be alternatives for EFetch.
292
+
293
+ 100.upto(110) do |n|
294
+ puts n
295
+ Chem::NCBI::PCFetch::fetch({:db => :pccompound, :id => n, :retmode => :sdf})
296
+ end
297
+
298
+ # Retrieving parsed summary for entries
299
+ # CID:100
300
+ p Chem::NCBI::ESummary::get_parsed({:db => :pccompound, :id => 100})
301
+
302
+ end
303
+
@@ -0,0 +1,28 @@
1
+ module Once
2
+
3
+ def self.append_features(base)
4
+ super
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def once(*ids) # :nodoc:
10
+ for id in ids
11
+ module_eval <<-"end;", __FILE__, __LINE__
12
+ alias_method :__#{id.to_i}__, :#{id.to_s}
13
+ private :__#{id.to_i}__
14
+ def #{id.to_s}(*args, &block)
15
+ if defined? @__#{id.to_i}__
16
+ @__#{id.to_i}__
17
+ elsif ! self.frozen?
18
+ @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block)
19
+ else
20
+ __#{id.to_i}__(*args, &block)
21
+ end
22
+ end
23
+ end;
24
+ end
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,204 @@
1
+ # Copyright (C) 2006 Richard L. Apodaca
2
+ # Nobuya Tanaka
3
+
4
+ require 'chem'
5
+
6
+ module Chem
7
+
8
+ module Atom
9
+ attr_accessor :ob_atom
10
+ end
11
+
12
+ module Molecule
13
+
14
+ attr_reader :ob_mol
15
+ def ob_save_as(path, filetype)
16
+ use_open_babel if @ob_mol.nil?
17
+ conv = ::OpenBabel::OBConversion.new
18
+ conv.set_out_format(filetype.to_s)
19
+ conv.write_file(@ob_mol, path)
20
+ end
21
+
22
+ def ob_export_as(filetype)
23
+ use_open_babel if @ob_mol.nil?
24
+ conv = ::OpenBabel::OBConversion.new
25
+ conv.set_out_format(filetype.to_s)
26
+ conv.write_string(@ob_mol)
27
+ end
28
+
29
+ def to_inchi
30
+ use_open_babel
31
+ ob_export_as("inchi").chop
32
+ end
33
+
34
+ # set OpenBabel OBMol object to instance variable @ob_mol
35
+ def use_open_babel
36
+ begin
37
+ require 'openbabel'
38
+ rescue Exception
39
+ require 'OpenBabel'
40
+ end
41
+ @ob_mol = ::OpenBabel::OBMol.new
42
+ nodes.each do |node|
43
+ atom = @ob_mol.new_atom
44
+ atom.set_atomic_num(Element2Number[node.element])
45
+ atom.set_vector(node.x.to_f, node.y.to_f, node.z.to_f)
46
+ node.ob_atom = atom
47
+ end
48
+ edges.each do |bond, atom1, atom2|
49
+ @ob_mol.add_bond(
50
+ atom1.ob_atom.get_idx,
51
+ atom2.ob_atom.get_idx,
52
+ bond.v.to_i
53
+ )
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ module OpenBabel
60
+
61
+ def self.parse_smiles(smiles)
62
+
63
+ require 'openbabel'
64
+
65
+ converter = ::OpenBabel::OBConversion.new
66
+ converter.set_in_format("smi")
67
+ mol = ::OpenBabel::OBMol.new
68
+ converter.read_string(mol, smiles)
69
+ OBMolecule.new(mol)
70
+ end
71
+
72
+ def self.load_sdf(path)
73
+ require 'openbabel'
74
+
75
+ conv = ::OpenBabel::OBConversion.new
76
+ conv.set_in_format("sdf")
77
+ mol = ::OpenBabel::OBMol.new
78
+ cond = conv.read_file(mol, path)
79
+ mols = [OBMolecule.new(mol)]
80
+ while cond
81
+ mol = ::OpenBabel::OBMol.new
82
+ cond = conv.read(mol)
83
+ mols << OBMolecule.new(mol) if cond
84
+ end
85
+ mols
86
+ end
87
+
88
+ class OBSmarts
89
+
90
+ def initialize(smarts)
91
+ require 'openbabel'
92
+ @pat = ::OpenBabel::OBSmartsPattern.new
93
+ @pat.init(smarts)
94
+ @pat
95
+ end
96
+
97
+ def match(mol)
98
+ mol.use_open_babel if mol.ob_mol.nil?
99
+ @pat.match(mol.ob_mol)
100
+ end
101
+
102
+ def get_umap_list
103
+ @pat.get_umap_list.collect{|ary| ary.collect{|i| i.to_i}}
104
+ end
105
+
106
+ end
107
+
108
+ def self.parse_smarts(smarts)
109
+ OBSmarts.new(smarts)
110
+ end
111
+
112
+ # load_as(path, filetype)
113
+ # path : path to input file
114
+ # filetype : "alc", "bgf"
115
+ # see http://openbabel.sourceforge.net/wiki/Babel
116
+ def self.load_as(path, filetype)
117
+ conv = ::OpenBabel::OBConversion.new
118
+ conv.set_in_format(filetype.to_s)
119
+ mol = ::OpenBabel::OBMol.new
120
+ conv.read_file(mol, path)
121
+ OBMolecule.new(mol)
122
+ end
123
+
124
+ module OBAtom
125
+ include Atom
126
+ end
127
+
128
+ class OBMolecule
129
+ include Molecule
130
+
131
+ attr_reader :ob_mol
132
+ attr_reader :nodes
133
+ def initialize(ob_mol)
134
+ @ob_mol = ob_mol
135
+ @nodes = []
136
+ 1.upto(@ob_mol.num_atoms) do |n|
137
+ atom = @ob_mol.get_atom(n)
138
+ @nodes << atom.extend(OBAtom)
139
+ end
140
+ end
141
+
142
+ end
143
+ end # OpenBabel module
144
+
145
+ end
146
+
147
+ if __FILE__ == $0
148
+ mol = SMILES("CCC")
149
+ mol.use_open_babel
150
+ p mol.num_atoms
151
+ p mol.num_bonds
152
+ p mol.get_mol_wt
153
+ p mol.get_exact_mass
154
+ # p mol.add_hydrogens # BUS Error !?
155
+ elsif false
156
+ ob = Chem::OpenBabel.parse_smiles('CC(C)CCCC(C)C1CCC2C1(CCC3C2CC=C4C3(CCC(C4)O)C)C')
157
+ p ob.get_mol_wt
158
+ p ob.num_atoms
159
+ p ob.num_bonds
160
+ # read
161
+ # is_last
162
+
163
+ atom = ob.new_atom
164
+
165
+ # creating new molecule
166
+
167
+ mol = OBMol.new
168
+ atom1 = mol.add_atom
169
+ atom2 = mol.add_atom
170
+
171
+ # Atom
172
+
173
+ atom1 = mol.get_first_atom
174
+ atom1 = mol.get_atom(1)
175
+
176
+ # Atom setter and getter
177
+
178
+ atom1.set_atomic_num(6) # Carbon
179
+
180
+ atom1.get_atomic_mass # Carbon : 12.0107
181
+
182
+ atom1.set_aromatic # aromatic
183
+ atom1.unset_aromatic # not aromatic
184
+ atom1.is_aromatic # return true or false
185
+
186
+ atom1.is_amide_nitrogen # return true or false
187
+
188
+
189
+ # atom count starts from 1 (not 0)
190
+ # mol.add_bond(0, 1, 1) fails!
191
+ mol.add_bond(1, 2, 1)# from, to, bond_order
192
+ # bond count starts from 0 (not 1)
193
+
194
+ bond = mol.get_bond(0)
195
+ bond.is_double
196
+ bond.is_single
197
+ bond.is_amide
198
+ bond.get_bond_order # bond.get_bo
199
+
200
+ # bond length
201
+
202
+ bond.get_length
203
+ bond.set_length# arguments ?
204
+ end