summaryrefslogtreecommitdiff
path: root/openbabel.rb
blob: 463663e5647209b19ca00ac7a26ebff320bb7061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
OBMOL_METHODS = {
  "NumAtoms" =>       "Number of atoms",
  "NumBonds" =>       "Number of bonds",
  "NumHvyAtoms" =>    "Number of heavy atoms",
  "NumResidues" =>    "Number of residues",
  "NumRotors" =>      "Number of rotatable bonds",
  "GetEnergy" =>      "Heat of formation for this molecule (in kcal/mol)",
  "GetMolWt" =>       "Standard molar mass given by IUPAC atomic masses (amu)",
  "GetExactMass" =>   "Mass given by isotopes (or most abundant isotope, if not specified)",
  "GetTotalCharge" => "Total charge",
}

OBDESCRIPTOR_METHODS = { 
  "HBA1" =>           "Number of hydrogen bond acceptors 1 (JoelLib)",
  "HBA2" =>           "Number of hydrogen bond acceptors 2 (JoelLib)",
  "HBD" =>            "Number of hydrogen bond donors (JoelLib)",
  "L5" =>             "Lipinski rule of five",
  "logP" =>           "Octanol/water partition coefficient",
  "MR" =>             "Molar refractivity",
  "MW" =>             "Molecular weight",
  "nF" =>             "Number of fluorine atoms",
  "nHal" =>           "Number of halogen atoms",
  "spinMult" =>       "Total spin multiplicity",
  "TPSA" =>           "Topological polar surface area",
}

# Get a list of OpenBabel algorithms
# @return [text/uri-list] URIs of OpenBabel algorithms
get '/openbabel' do
  algorithms = OBMOL_METHODS.collect{|name,description| url_for("/openbabel/#{name}",:full)}
  algorithms << OBDESCRIPTOR_METHODS.collect{|name,description| url_for("/openbabel/#{name}",:full)}
  response['Content-Type'] = 'text/uri-list'
  algorithms.join("\n")
end

# Get RDF/XML representation of OpenBabel algorithm
# @return [application/rdf+xml] OWL-DL representation of OpenBabel algorithm
get '/openbabel/:property' do
  description = OBMOL_METHODS[params[:property]] if OBMOL_METHODS.include? params[:property]
  description = OBDESCRIPTOR_METHODS[params[:property]] if OBDESCRIPTOR_METHODS.include? params[:property]
  if description
    algorithm = OpenTox::Algorithm::Generic.new(url_for("/openbabel/#{params[:property]}",:full))
    algorithm.metadata = {
      DC.title => params[:property],
      DC.creator => "helma@in-silico.ch",
      DC.description => description,
      RDF.type => [OTA.DescriptorCalculation],
    }
    response['Content-Type'] = 'application/rdf+xml'
    algorithm.to_rdfxml
  else
    raise OpenTox::NotFoundError.new "Unknown OpenBabel descriptor #{params[:property]}."
  end
end

# Calculate OpenBabel descriptors
# Supports the following OpenBabel methods (see OpenBabel API http://openbabel.org/api/2.2.0/)
#   - NumAtoms       Number of atoms
#   - NumBonds       Number of bonds
#   - NumHvyAtoms    Number of heavy atoms
#   - NumResidues    Number of residues
#   - NumRotors      Number of rotatable bonds
#   - GetEnergy      Heat of formation for this molecule (in kcal/mol)
#   - GetMolWt       Standard molar mass given by IUPAC atomic masses (amu)
#   - GetExactMass   Mass given by isotopes (or most abundant isotope, if not specified)
#   - GetTotalCharge Total charge
#   - HBA1           Number of hydrogen bond acceptors 1 (JoelLib)
#   - HBA2           Number of hydrogen bond acceptors 2 (JoelLib)
#   - HBD            Number of hydrogen bond donors (JoelLib)
#   - L5             Lipinski rule of five
#   - logP           Octanol/water partition coefficient
#   - MR             Molar refractivity
#   - MW             Molecular weight
#   - nF             Number of fluorine atoms
#   - nHal           Number of halogen atoms
#   - spinMult       Total spin multiplicity
#   - TPSA           Topological polar surface area
# @param [String] compound_uri Compound URI
# @return [String] descriptor value
post '/openbabel/:property' do
	obconversion = OpenBabel::OBConversion.new
	obmol = OpenBabel::OBMol.new
  compound = OpenTox::Compound.new params[:compound_uri]
	obconversion.set_in_and_out_formats 'inchi', 'can'
  obconversion.read_string obmol, compound.to_inchi
  if OBMOL_METHODS.keys.include? params[:property]
    eval("obmol.#{params[:property].underscore}").to_s
  elsif OBDESCRIPTOR_METHODS.keys.include? params[:property]
    descriptor = OpenBabel::OBDescriptor.find_type(params[:property])
    descriptor.predict(obmol).to_s
  else
    raise OpenTox::NotFoundError.new "Cannot calculate property #{params[:property]} with OpenBabel"
  end
end

# Calculate all OpenBabel descriptors for a dataset
# @param [String] dataset_uri Dataset URI
# @return [text/uri-list] Task URI
post '/openbabel' do
  task = OpenTox::Task.create("Calculating OpenBabel descriptors for #{params[:dataset_uri]}", url_for('/openbabel',:full)) do 

    dataset = OpenTox::Dataset.find(params[:dataset_uri])
    result_dataset = OpenTox::Dataset.create
    result_dataset.add_metadata({
      DC.title => "OpenBabel descriptors for " + dataset.metadata[DC.title].to_s,
      DC.creator => url_for('/openbabel',:full),
      OT.hasSource => url_for('/openbabel', :full),
      OT.parameters => [
        { DC.title => "dataset_uri", OT.paramValue => params[:dataset_uri] },
      ]
    })

    obconversion = OpenBabel::OBConversion.new
    obmol = OpenBabel::OBMol.new
    obconversion.set_in_and_out_formats 'inchi', 'can'

    OBMOL_METHODS.merge(OBDESCRIPTOR_METHODS).each do |name,description|
      feature_uri = File.join result_dataset.uri, "feature", "openbabel", name
      metadata = {
        OT.hasSource => url_for("/openbabel/#{name}", :full),
        DC.description => description,
        DC.title => name,
      }
      result_dataset.add_feature feature_uri, metadata
    end

    dataset.compounds.each do |compound_uri|
      compound = OpenTox::Compound.new(compound_uri)
      obconversion.read_string obmol, compound.to_inchi
      #result_dataset.add_compound compound_uri
      OBMOL_METHODS.keys.each do |name|
        feature_uri = File.join result_dataset.uri, "feature", "openbabel", name
        value = eval("obmol.#{name.underscore}").to_f
        result_dataset.add compound_uri, feature_uri, value
      end
      OBDESCRIPTOR_METHODS.keys.each do |name|
        feature_uri = File.join result_dataset.uri, "feature", "openbabel", name
        value = OpenBabel::OBDescriptor.find_type(params[:property]).predict(obmol).to_f
        result_dataset.add compound_uri, feature_uri, value
      end
    end
    result_dataset.save
    result_dataset.uri
  end
  response['Content-Type'] = 'text/uri-list'
  raise OpenTox::ServiceUnavailableError.newtask.uri+"\n" if task.status == "Cancelled"
  halt 202,task.uri.to_s+"\n"
end