summaryrefslogtreecommitdiff
path: root/descriptor.rb
blob: 5a7717e70c86867942c0962cf8b5f86302004d2d (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
# descriptors.rb
# Calculation of physico-chemical descriptors
# Author: Andreas Maunz, Christoph Helma
require 'openbabel'

module OpenTox

  class Application < Service

    before '/descriptor/:method/?' do
      if request.get?
        @algorithm = OpenTox::Algorithm::Descriptor.new @uri
        @algorithm.parameters = [ {
          RDF::DC.description => "Dataset URI", 
          RDF::OT.paramScope => "optional", 
          RDF::DC.title => "dataset_uri"
        },{
          RDF::DC.description => "Compound URI", 
          RDF::OT.paramScope => "optional", 
          RDF::DC.title => "compound_uri"
        } ]
        @algorithm.metadata = {
          RDF.type => [RDF::OT.Algorithm, RDF::OTA.DescriptorCalculation],
        }
      end
    end

    get '/descriptor/?' do
      render [ uri('/descriptor/physchem'), uri('/descriptor/smarts_match'), uri('/descriptor/smarts_count'), uri('/descriptor/lookup')].sort
    end

    get '/descriptor/smarts_match/?' do
      @algorithm.parameters += [ {
        RDF::DC.description => "SMARTS strings", 
        RDF::OT.paramScope => "mandatory", 
        RDF::DC.title => "descriptors"
      } ]
      @algorithm.metadata[RDF::DC.title] = "SMARTS matcher"
      render @algorithm
    end

    get '/descriptor/smarts_count/?' do
      @algorithm.parameters += [ {
        RDF::DC.description => "Counts SMARTS matches", 
        RDF::OT.paramScope => "mandatory", 
        RDF::DC.title => "descriptors"
      } ]
      @algorithm.metadata[RDF::DC.title] = "SMARTS count"
      render @algorithm
    end

    get '/descriptor/physchem/?' do
      @algorithm.parameters += [ {
        RDF::DC.description => "Physical-chemical descriptors (see #{File.join @uri, 'list'} for a list of supported parameters)", 
        RDF::OT.paramScope => "mandatory", 
        RDF::DC.title => "descriptors"
      } ]
      @algorithm.metadata[RDF::DC.title] = "Physical-chemical descriptors"
      render @algorithm
    end

    get '/descriptor/physchem/list/?' do
      response['Content-Type'] = 'text/plain'
      OpenTox::Algorithm::Descriptor::DESCRIPTORS.collect{|k,v| "#{k}\t#{v}"}.join "\n"
    end

    get '/descriptor/physchem/unique/?' do
      response['Content-Type'] = 'text/plain'
      OpenTox::Algorithm::Descriptor::UNIQUEDESCRIPTORS.collect{|d| "#{d}\t#{OpenTox::Algorithm::Descriptor::DESCRIPTORS[d]}"}.join "\n"
    end

    get '/descriptor/lookup/?' do
      @algorithm.parameters += [ {
        RDF::DC.description => "Read feature values from a dataset", 
        RDF::OT.paramScope => "mandatory", 
        RDF::DC.title => "feature_dataset_uri"
      } ]
      @algorithm.metadata[RDF::DC.title] = "Dataset lookup"
      render @algorithm
    end

    post '/descriptor/:method' do
      if params[:method] == "physchem"
        params[:descriptors] = OpenTox::Algorithm::Descriptor::UNIQUEDESCRIPTORS if !params[:descriptors] or params[:descriptors] == [""]
      else
        bad_request_error "Please provide 'descriptors' parameters.", @uri unless params[:descriptors]
      end
      if params[:compound_uri] # return json
        @compounds = [params[:compound_uri]].flatten.collect{|u| OpenTox::Compound.new u}
        result = OpenTox::Algorithm::Descriptor.send(params[:method].to_sym, @compounds, params[:descriptors])
        Hash[result.map {|compound, v| [compound.uri, v] }].to_json
      elsif params[:dataset_uri] # return dataset
        task = OpenTox::Task.run("Calculating #{params[:method]} descriptors for dataset #{params[:dataset_uri]}.", @uri) do |task|
          @compounds = OpenTox::Dataset.new(params[:dataset_uri]).compounds
          result = OpenTox::Algorithm::Descriptor.send(params[:method].to_sym, @compounds, params[:descriptors])
          internal_server_error "internal error: wrong num results" if (@compounds.size != result.size)

          dataset = OpenTox::Dataset.new
          dataset.metadata = {
            RDF::DC.title => "Physico-chemical descriptors",
            RDF::DC.creator => @uri,
            RDF::OT.hasSource => @uri,
          }
          dataset.parameters = [
            { RDF::DC.title => "dataset_uri", RDF::OT.paramValue => params[:dataset_uri] },
            { RDF::DC.title => "descriptors", RDF::OT.paramValue => params[:descriptors] },
          ]
          params[:method] == "smarts_match" ? feature_type = RDF::OT.NominalFeature : feature_type = RDF::OT.NumericFeature 

          #get descriptor names as returned from calculation (names may differ from params[:descriptors] because of CDK descriptors)
          descriptors = []
          result.each do |compound,values|
            values.each do |desc,val|
              descriptors << desc unless descriptors.include?(desc)
            end
          end
          #try to preserve descriptor order
          sorted_descriptors = []
          params[:descriptors].each do |d|
            sorted_descriptors << descriptors.delete(d) if descriptors.include?(d)
          end
          sorted_descriptors += descriptors
          
          sorted_descriptors.each do |name|
            dataset.features << OpenTox::Feature.find_or_create({
                RDF::DC.title => name,
                RDF.type => [RDF::OT.Feature, feature_type],
                RDF::DC.description => OpenTox::Algorithm::Descriptor.description(name)
              })
          end
          result.each do |compound,values|
            dataset << ([compound] + sorted_descriptors.collect{|name| values[name]})
          end
          dataset.put
          dataset.uri
        end
        response['Content-Type'] = 'text/uri-list'
        halt 202,task.uri
      else
        bad_request_error "Please provide a dataset_uri or compound_uri parameter", @uri
      end
    end

  end

end