Class: OpenTox::Compound

Inherits:
Substance show all
Defined in:
lib/compound.rb

Overview

Small molecules with defined chemical structures

Constant Summary collapse

DEFAULT_FINGERPRINT =
"MP2D"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.find_or_create_by(params) ⇒ Object

Overwrites standard Mongoid method to create fingerprints before database insertion



22
23
24
25
26
27
# File 'lib/compound.rb', line 22

def self.find_or_create_by params
  compound = self.find_or_initialize_by params
  compound.default_fingerprint_size = compound.fingerprint(DEFAULT_FINGERPRINT).size
  compound.save
  compound
end

.from_inchi(inchi) ⇒ OpenTox::Compound

Create a compound from InChI string



136
137
138
139
# File 'lib/compound.rb', line 136

def self.from_inchi inchi
  smiles = obconversion(inchi,"inchi","can")
  smiles.empty? ? nil : Compound.find_or_create_by(:smiles => smiles)
end

.from_name(name) ⇒ OpenTox::Compound

Create a compound from name. Relies on an external service for name lookups.

Examples:

compound = OpenTox::Compound.from_name("Benzene")


154
155
156
# File 'lib/compound.rb', line 154

def self.from_name name
  Compound.from_smiles RestClientWrapper.get(File.join(PUBCHEM_URI,"compound","name",URI.escape(name),"property","CanonicalSMILES","TXT")).chomp
end

.from_sdf(sdf) ⇒ OpenTox::Compound

Create a compound from SDF



144
145
146
147
# File 'lib/compound.rb', line 144

def self.from_sdf sdf
  # do not store sdf because it might be 2D
  Compound.from_smiles obconversion(sdf,"sdf","can")
end

.from_smiles(smiles) ⇒ OpenTox::Compound

Create a compound from smiles string

Examples:

compound = OpenTox::Compound.from_smiles("c1ccccc1")


127
128
129
130
131
# File 'lib/compound.rb', line 127

def self.from_smiles smiles
  return nil if smiles.match(/\s/) # spaces seem to confuse obconversion and may lead to invalid smiles
  smiles = obconversion(smiles,"smi","can") # test if SMILES is correct and return canonical smiles (for compound comparisons)
  smiles.empty? ? nil : Compound.find_or_create_by(:smiles => smiles)
end

Instance Method Details

#calculate_properties(descriptors = PhysChem::OPENBABEL) ⇒ Array<Float>

Calculate physchem properties



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/compound.rb', line 80

def calculate_properties descriptors=PhysChem::OPENBABEL
  calculated_ids = properties.keys
  # BSON::ObjectId instances are not allowed as keys in a BSON document.
  new_ids = descriptors.collect{|d| d.id.to_s} - calculated_ids
  descs = {}
  algos = {}
  new_ids.each do |id|
    descriptor = PhysChem.find id
    descs[[descriptor.library, descriptor.descriptor]]  = descriptor
    algos[descriptor.name] = descriptor
  end
  # avoid recalculating Cdk features with multiple values
  descs.keys.uniq.each do |k|
    descs[k].send(k[0].downcase,k[1],self).each do |n,v|
      properties[algos[n].id.to_s] = v # BSON::ObjectId instances are not allowed as keys in a BSON document.
    end
  end
  save
  descriptors.collect{|d| properties[d.id.to_s]}
end

#cidString

Get PubChem Compound Identifier (CID), obtained via REST call to PubChem



229
230
231
232
# File 'lib/compound.rb', line 229

def cid
  update(:cid => RestClientWrapper.post(File.join(PUBCHEM_URI, "compound", "inchi", "cids", "TXT"),{:inchi => inchi}).strip) unless self["cid"] 
  self["cid"]
end

#fingerprint(type = DEFAULT_FINGERPRINT) ⇒ Array<String>

Create chemical fingerprint



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/compound.rb', line 32

def fingerprint type=DEFAULT_FINGERPRINT
  unless fingerprints[type]
    return [] unless self.smiles
    if type == "MP2D" # http://openbabel.org/docs/dev/FileFormats/MolPrint2D_format.html#molprint2d-format
      fp = obconversion(smiles,"smi","mpd").strip.split("\t")
      name = fp.shift # remove Title
      fingerprints[type] = fp.uniq # no fingerprint counts
    elsif type== "MNA" # http://openbabel.org/docs/dev/FileFormats/Multilevel_Neighborhoods_of_Atoms_(MNA).html
      level = 2 # TODO: level as parameter, evaluate level 1, see paper
      fp = obconversion(smiles,"smi","mna","xL\"#{level}\"").split("\n")
      fp.shift # remove Title
      fingerprints[type] = fp
    else # standard fingerprints
      fp = OpenBabel::OBFingerprint.find_fingerprint(type)
      obmol = OpenBabel::OBMol.new
      obconversion = OpenBabel::OBConversion.new
      obconversion.set_in_format "smi"
      obconversion.read_string obmol, self.smiles
      result = OpenBabel::VectorUnsignedInt.new
      fp.get_fingerprint(obmol,result)
      # TODO: %ignore *::DescribeBits @ line 163 openbabel/scripts/openbabel-ruby.i
      #p OpenBabel::OBFingerprint.describe_bits(result)
      # convert result to a list of the bits that are set
      # from openbabel/scripts/python/pybel.py line 830
      # see also http://openbabel.org/docs/dev/UseTheLibrary/Python_Pybel.html#fingerprints
      result = result.to_a
      bitsperint = OpenBabel::OBFingerprint.getbitsperint()
      bits_set = []
      start = 1
      result.each do |x|
        i = start
        while x > 0 do
          bits_set << i if (x % 2) == 1
          x >>= 1
          i += 1
        end
        start += bitsperint
      end
      fingerprints[type] = bits_set
    end
    save
  end
  fingerprints[type]
end

#inchiString

Get InChI



160
161
162
163
164
165
166
# File 'lib/compound.rb', line 160

def inchi
  unless self["inchi"]
    result = obconversion(smiles,"smi","inchi")
    update(:inchi => result.chomp) if result and !result.empty?
  end
  self["inchi"]
end

#inchikeyString

Get InChIKey



170
171
172
173
# File 'lib/compound.rb', line 170

def inchikey
  update(:inchikey => obconversion(smiles,"smi","inchikey")) unless self["inchikey"]
  self["inchikey"]
end

#mg_to_mmol(mg) ⇒ Float

Convert mg to mmol



242
243
244
# File 'lib/compound.rb', line 242

def mg_to_mmol mg
  mg.to_f/molecular_weight
end

#mmol_to_mg(mmol) ⇒ Float

Convert mmol to mg



236
237
238
# File 'lib/compound.rb', line 236

def mmol_to_mg mmol
  mmol.to_f*molecular_weight
end

#molecular_weightFloat

Calculate molecular weight of Compound with OB and store it in compound object



248
249
250
251
# File 'lib/compound.rb', line 248

def molecular_weight
  mw_feature = PhysChem.find_or_create_by(:name => "Openbabel.MW")
  calculate_properties([mw_feature]).first
end

#namesArray<String>

Get all known compound names. Relies on an external service for name lookups.

Examples:

names = compound.names


222
223
224
225
# File 'lib/compound.rb', line 222

def names
  update(:names => RestClientWrapper.get(File.join(PUBCHEM_URI,"compound","smiles",URI.escape(smiles),"synonyms","TXT")).split("\n")) #unless self["names"] 
  self["names"]
end

#pngimage/png

Get png image

Examples:

image = compound.png


209
210
211
212
213
214
215
216
# File 'lib/compound.rb', line 209

def png
  if self.png_id.nil?
   png = obconversion(smiles,"smi","_png2")
   file = Mongo::Grid::File.new(Base64.encode64(png), :filename => "#{id}.png", :content_type => "image/png")
   update(:png_id => $gridfs.insert_one(file))
  end
  Base64.decode64($gridfs.find_one(_id: self.png_id).data)
end

#sdfString

Get SDF



184
185
186
187
188
189
190
191
192
# File 'lib/compound.rb', line 184

def sdf
  if self.sdf_id.nil? 
    sdf = obconversion(smiles,"smi","sdf")
    file = Mongo::Grid::File.new(sdf, :filename => "#{id}.sdf",:content_type => "chemical/x-mdl-sdfile")
    sdf_id = $gridfs.insert_one file
    update :sdf_id => sdf_id
  end
  $gridfs.find_one(_id: self.sdf_id).data
end

#smarts_match(smarts, count = false) ⇒ TrueClass, ...

Match a SMARTS substructure



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/compound.rb', line 105

def smarts_match smarts, count=false
  obconversion = OpenBabel::OBConversion.new
  obmol = OpenBabel::OBMol.new
  obconversion.set_in_format('smi')
  obconversion.read_string(obmol,self.smiles)
  smarts_pattern = OpenBabel::OBSmartsPattern.new
  smarts.collect do |sma|
    smarts_pattern.init(sma.smarts)
    if smarts_pattern.match(obmol)
      count ? value = smarts_pattern.get_map_list.to_a.size : value = 1
    else
      value = 0 
    end
    value
  end
end

#smilesString

Get (canonical) smiles



177
178
179
180
# File 'lib/compound.rb', line 177

def smiles
  update(:smiles => obconversion(self["smiles"],"smi","can")) unless self["smiles"] 
  self["smiles"]
end

#svgimage/svg

Get SVG image



196
197
198
199
200
201
202
203
# File 'lib/compound.rb', line 196

def svg
  if self.svg_id.nil?
   svg = obconversion(smiles,"smi","svg")
   file = Mongo::Grid::File.new(svg, :filename => "#{id}.svg", :content_type => "image/svg")
   update(:svg_id => $gridfs.insert_one(file))
  end
  $gridfs.find_one(_id: self.svg_id).data
end