opentox-ruby 3.0.1 → 3.1.0

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.
data/lib/authorization.rb CHANGED
@@ -37,13 +37,15 @@ module OpenTox
37
37
 
38
38
  #Loads and sends Policyfile(XML) to open-sso server
39
39
  # @param [String] URI to create a policy for
40
- def send(uri)
40
+ def send(uri)
41
41
  xml = get_xml(uri)
42
42
  ret = false
43
- ret = Authorization.create_policy(xml, @subjectid)
43
+ ret = Authorization.create_policy(xml, @subjectid)
44
+ LOGGER.warn "Create policy on openSSO failed for URI: #{uri} subjectid: #{@subjectid}. Will try again." if !ret
45
+ ret = Authorization.create_policy(xml, @subjectid) if !ret
44
46
  LOGGER.debug "Policy send with subjectid: #{@subjectid}"
45
47
  LOGGER.warn "Not created Policy is: #{xml}" if !ret
46
- ret
48
+ ret
47
49
  end
48
50
 
49
51
  end
@@ -337,7 +339,7 @@ module OpenTox
337
339
  # @param [String] subjectid
338
340
  # @return [Boolean] true if access granted, else otherwise
339
341
  def self.authorized?(uri, request_method, subjectid)
340
- if CONFIG[:authorization][:free_request].include?(request_method)
342
+ if CONFIG[:authorization][:free_request].include?(request_method)
341
343
  #LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
342
344
  true
343
345
  elsif OpenTox::Authorization.free_uri?(uri, request_method)
@@ -360,7 +362,7 @@ module OpenTox
360
362
  false
361
363
  end
362
364
  end
363
-
365
+
364
366
  private
365
367
  def self.free_uri?(uri, request_method)
366
368
  if CONFIG[:authorization][:free_uris]
@@ -374,7 +376,7 @@ module OpenTox
374
376
  end
375
377
  return false
376
378
  end
377
-
379
+
378
380
  def self.authorize_exception?(uri, request_method)
379
381
  if CONFIG[:authorization][:authorize_exceptions]
380
382
  CONFIG[:authorization][:authorize_exceptions].each do |request_methods,uris|
@@ -387,6 +389,6 @@ module OpenTox
387
389
  end
388
390
  return false
389
391
  end
390
-
392
+
391
393
  end
392
- end
394
+ end
data/lib/compound.rb CHANGED
@@ -6,13 +6,15 @@ module OpenTox
6
6
  # Ruby wrapper for OpenTox Compound Webservices (http://opentox.org/dev/apis/api-1.2/structure).
7
7
  class Compound
8
8
 
9
+ include OpenTox
10
+
9
11
  attr_accessor :inchi, :uri
10
12
 
11
13
  # Create compound with optional uri
12
14
  # @example
13
- # compound = OpenTox::Compound.new("http://webservices.in-silico.ch/compound/InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H"")
15
+ # compound = Compound.new("http://webservices.in-silico.ch/compound/InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H"")
14
16
  # @param [optional, String] uri Compound URI
15
- # @return [OpenTox::Compound] Compound
17
+ # @return [Compound] Compound
16
18
  def initialize(uri=nil)
17
19
  @uri = uri
18
20
  case @uri
@@ -36,9 +38,9 @@ module OpenTox
36
38
 
37
39
  # Create a compound from smiles string
38
40
  # @example
39
- # compound = OpenTox::Compound.from_smiles("c1ccccc1")
41
+ # compound = Compound.from_smiles("c1ccccc1")
40
42
  # @param [String] smiles Smiles string
41
- # @return [OpenTox::Compound] Compound
43
+ # @return [Compound] Compound
42
44
  def self.from_smiles(smiles)
43
45
  c = Compound.new
44
46
  c.inchi = Compound.smiles2inchi(smiles)
@@ -48,7 +50,7 @@ module OpenTox
48
50
 
49
51
  # Create a compound from inchi string
50
52
  # @param [String] smiles InChI string
51
- # @return [OpenTox::Compound] Compound
53
+ # @return [Compound] Compound
52
54
  def self.from_inchi(inchi)
53
55
  c = Compound.new
54
56
  c.inchi = inchi
@@ -58,7 +60,7 @@ module OpenTox
58
60
 
59
61
  # Create a compound from sdf string
60
62
  # @param [String] smiles SDF string
61
- # @return [OpenTox::Compound] Compound
63
+ # @return [Compound] Compound
62
64
  def self.from_sdf(sdf)
63
65
  c = Compound.new
64
66
  c.inchi = Compound.sdf2inchi(sdf)
@@ -68,9 +70,9 @@ module OpenTox
68
70
 
69
71
  # Create a compound from name. Relies on an external service for name lookups.
70
72
  # @example
71
- # compound = OpenTox::Compound.from_name("Benzene")
73
+ # compound = Compound.from_name("Benzene")
72
74
  # @param [String] name name can be also an InChI/InChiKey, CAS number, etc
73
- # @return [OpenTox::Compound] Compound
75
+ # @return [Compound] Compound
74
76
  def self.from_name(name)
75
77
  c = Compound.new
76
78
  # paranoid URI encoding to keep SMILES charges and brackets
@@ -131,7 +133,7 @@ module OpenTox
131
133
 
132
134
  # Match a smarts string
133
135
  # @example
134
- # compound = OpenTox::Compound.from_name("Benzene")
136
+ # compound = Compound.from_name("Benzene")
135
137
  # compound.match?("cN") # returns false
136
138
  # @param [String] smarts Smarts string
137
139
  def match?(smarts)
@@ -146,7 +148,7 @@ module OpenTox
146
148
 
147
149
  # Match an array of smarts strings, returns array with matching smarts
148
150
  # @example
149
- # compound = OpenTox::Compound.from_name("Benzene")
151
+ # compound = Compound.from_name("Benzene")
150
152
  # compound.match(['cc','cN']) # returns ['cc']
151
153
  # @param [Array] smarts_array Array with Smarts strings
152
154
  # @return [Array] Array with matching Smarts strings
@@ -166,7 +168,7 @@ module OpenTox
166
168
 
167
169
  # Match_hits an array of smarts strings, returns hash with matching smarts as key and number of non-unique hits as value
168
170
  # @example
169
- # compound = OpenTox::Compound.from_name("Benzene")
171
+ # compound = Compound.from_name("Benzene")
170
172
  # compound.match(['cc','cN']) # returns ['cc']
171
173
  # @param [Array] smarts_array Array with Smarts strings
172
174
  # @return [Hash] Hash with matching smarts as key and number of non-unique hits as value
@@ -191,6 +193,40 @@ module OpenTox
191
193
  return smarts_hits
192
194
  #smarts_array.collect { |s| s if match?(s)}.compact
193
195
  end
196
+
197
+ # Lookup numerical values, returns hash with feature name as key and value as value
198
+ # @param [Array] Array of feature names
199
+ # @param [String] Feature dataset uri
200
+ # @return [Hash] Hash with feature name as key and value as value
201
+ def lookup(feature_array,feature_dataset_uri,pc_type,subjectid=nil)
202
+ ds = OpenTox::Dataset.find(feature_dataset_uri,subjectid)
203
+ #entry = ds.data_entries[self.uri]
204
+ entry = nil
205
+ ds.data_entries.each { |c_uri, values|
206
+ if c_uri.split('/compound/').last == self.to_inchi
207
+ entry = ds.data_entries[self.uri]
208
+ break
209
+ end
210
+ }
211
+ LOGGER.debug "#{entry.size} entries in feature ds for query." unless entry.nil?
212
+
213
+ if entry.nil?
214
+ uri, smiles_to_inchi = OpenTox::Algorithm.get_pc_descriptors({:compounds => [self.uri], :pc_type => pc_type})
215
+ uri = OpenTox::Algorithm.load_ds_csv(uri, smiles_to_inchi, subjectid)
216
+ ds = OpenTox::Dataset.find(uri,subjectid)
217
+ entry = ds.data_entries[self.uri]
218
+ ds.delete(subjectid)
219
+ end
220
+ features = entry.keys
221
+ features.each { |feature|
222
+ new_feature = File.join(feature_dataset_uri, "feature", feature.split("/").last)
223
+ entry[new_feature] = entry[feature].flatten.first.to_f # see algorithm/lazar.rb:182, to_f because feature type detection doesn't work w 1 entry
224
+ entry.delete(feature) unless feature == new_feature # e.g. when loading from ambit
225
+ }
226
+ #res = feature_array.collect {|v| entry[v]}
227
+ #LOGGER.debug "----- am #{entry.to_yaml}"
228
+ entry
229
+ end
194
230
 
195
231
 
196
232
  # Get URI of compound image with highlighted fragments
data/lib/dataset.rb CHANGED
@@ -288,7 +288,7 @@ module OpenTox
288
288
 
289
289
  # Insert a statement (compound_uri,feature_uri,value)
290
290
  # @example Insert a statement (compound_uri,feature_uri,value)
291
- # dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", true
291
+ # dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", 1
292
292
  # @param [String] compound Compound URI
293
293
  # @param [String] feature Compound URI
294
294
  # @param [Boolean,Float] value Feature value
@@ -315,6 +315,16 @@ module OpenTox
315
315
  @features[feature] = metadata
316
316
  end
317
317
 
318
+ # Complete feature values by adding zeroes
319
+ def complete_data_entries
320
+ all_features = @features.keys
321
+ @data_entries.each { |c, e|
322
+ (Set.new(all_features.collect)).subtract(Set.new e.keys).to_a.each { |f|
323
+ self.add(c,f,0)
324
+ }
325
+ }
326
+ end
327
+
318
328
  # Add/modify metadata for a feature
319
329
  # @param [String] feature Feature URI
320
330
  # @param [Hash] metadata Hash with feature metadata
@@ -363,7 +373,45 @@ module OpenTox
363
373
  dataset.save(subjectid)
364
374
  dataset
365
375
  end
366
-
376
+
377
+ # merges two dataset into a new dataset (by default uses all compounds and features)
378
+ # precondition: both datasets are fully loaded
379
+ # @param [OpenTox::Dataset] dataset1 to merge
380
+ # @param [OpenTox::Dataset] dataset2 to merge
381
+ # @param [Hash] metadata
382
+ # @param [optional,String] subjectid
383
+ # @param [optional,Array] features1, if specified only this features of dataset1 are used
384
+ # @param [optional,Array] features2, if specified only this features of dataset2 are used
385
+ # @param [optional,Array] compounds1, if specified only this compounds of dataset1 are used
386
+ # @param [optional,Array] compounds2, if specified only this compounds of dataset2 are used
387
+ # example: if you want no features from dataset2, give empty array as features2
388
+ def self.merge( dataset1, dataset2, metadata, subjectid=nil, features1=nil, features2=nil, compounds1=nil, compounds2=nil )
389
+ features1 = dataset1.features.keys unless features1
390
+ features2 = dataset2.features.keys unless features2
391
+ compounds1 = dataset1.compounds unless compounds1
392
+ compounds2 = dataset2.compounds unless compounds2
393
+ data_combined = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],subjectid)
394
+ LOGGER.debug("merging datasets #{dataset1.uri} and #{dataset2.uri} to #{data_combined.uri}")
395
+ [[dataset1, features1, compounds1], [dataset2, features2, compounds2]].each do |dataset,features,compounds|
396
+ compounds.each{|c| data_combined.add_compound(c)}
397
+ features.each do |f|
398
+ m = dataset.features[f]
399
+ m[OT.hasSource] = dataset.uri unless m[OT.hasSource]
400
+ data_combined.add_feature(f,m)
401
+ compounds.each do |c|
402
+ dataset.data_entries[c][f].each do |v|
403
+ data_combined.add(c,f,v)
404
+ end if dataset.data_entries[c] and dataset.data_entries[c][f]
405
+ end
406
+ end
407
+ end
408
+ metadata = {} unless metadata
409
+ metadata[OT.hasSource] = "Merge from #{dataset1.uri} and #{dataset2.uri}" unless metadata[OT.hasSource]
410
+ data_combined.add_metadata(metadata)
411
+ data_combined.save(subjectid)
412
+ data_combined
413
+ end
414
+
367
415
  # Save dataset at the dataset service
368
416
  # - creates a new dataset if uri is not set
369
417
  # - overwrites dataset if uri exists
data/lib/environment.rb CHANGED
@@ -24,7 +24,11 @@ end
24
24
 
25
25
  # database
26
26
  #`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid" # removed by AM
27
- Ohm.connect :thread_safe => true
27
+ ohm_port=6379
28
+ if !CONFIG[:ohm_port].nil?
29
+ ohm_port=CONFIG[:ohm_port].to_i
30
+ end
31
+ Ohm.connect(:thread_safe => true, :port => ohm_port)
28
32
 
29
33
  # load mail settings for error messages
30
34
  #load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
@@ -87,4 +91,5 @@ DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
87
91
  OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
88
92
  OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
89
93
  XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
94
+ #BO = OwlNamespace.new 'http://www.blueobelisk.org/ontologies/chemoinformatics-algorithms/#'
90
95
 
data/lib/model.rb CHANGED
@@ -102,8 +102,8 @@ module OpenTox
102
102
  include Algorithm
103
103
  include Model
104
104
 
105
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel, :value_map, :nr_hits, :transform, :conf_stdev, :prediction_min_max
106
105
 
106
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :subjectid, :value_map, :compound_fingerprints, :feature_calculation_algorithm, :neighbors
107
107
  def initialize(uri=nil)
108
108
 
109
109
  if uri
@@ -120,18 +120,11 @@ module OpenTox
120
120
  @p_values = {}
121
121
  @fingerprints = {}
122
122
  @value_map = {}
123
- @prediction_min_max = []
124
123
 
125
124
  @feature_calculation_algorithm = "Substructure.match"
126
125
  @similarity_algorithm = "Similarity.tanimoto"
127
126
  @prediction_algorithm = "Neighbors.weighted_majority_vote"
128
127
 
129
- @nr_hits = false
130
- @min_sim = 0.3
131
- @prop_kernel = false
132
- @transform = { "class" => "NOP" }
133
- @conf_stdev = false
134
-
135
128
  end
136
129
 
137
130
  # Get URIs of all lazar models
@@ -174,19 +167,14 @@ module OpenTox
174
167
  lazar.feature_calculation_algorithm = hash["feature_calculation_algorithm"] if hash["feature_calculation_algorithm"]
175
168
  lazar.similarity_algorithm = hash["similarity_algorithm"] if hash["similarity_algorithm"]
176
169
  lazar.prediction_algorithm = hash["prediction_algorithm"] if hash["prediction_algorithm"]
177
- lazar.min_sim = hash["min_sim"] if hash["min_sim"]
178
170
  lazar.subjectid = hash["subjectid"] if hash["subjectid"]
179
- lazar.prop_kernel = hash["prop_kernel"] if hash["prop_kernel"]
180
171
  lazar.value_map = hash["value_map"] if hash["value_map"]
181
- lazar.nr_hits = hash["nr_hits"] if hash["nr_hits"]
182
- lazar.transform = hash["transform"] if hash["transform"]
183
- lazar.conf_stdev = hash["conf_stdev"] if hash["conf_stdev"]
184
- lazar.prediction_min_max = hash["prediction_min_max"] if hash["prediction_min_max"]
172
+
185
173
  lazar
186
174
  end
187
175
 
188
176
  def to_json
189
- Yajl::Encoder.encode({:uri => @uri,:metadata => @metadata, :compound => @compound, :prediction_dataset => @prediction_dataset, :features => @features, :effects => @effects, :activities => @activities, :p_values => @p_values, :fingerprints => @fingerprints, :feature_calculation_algorithm => @feature_calculation_algorithm, :similarity_algorithm => @similarity_algorithm, :prediction_algorithm => @prediction_algorithm, :min_sim => @min_sim, :subjectid => @subjectid, :prop_kernel => @prop_kernel, :value_map => @value_map, :nr_hits => @nr_hits, :transform => @transform, :conf_stdev => @conf_stdev, :prediction_min_max => @prediction_min_max})
177
+ Yajl::Encoder.encode({:uri => @uri,:metadata => @metadata, :compound => @compound, :prediction_dataset => @prediction_dataset, :features => @features, :effects => @effects, :activities => @activities, :p_values => @p_values, :fingerprints => @fingerprints, :feature_calculation_algorithm => @feature_calculation_algorithm, :similarity_algorithm => @similarity_algorithm, :prediction_algorithm => @prediction_algorithm, :subjectid => @subjectid, :value_map => @value_map})
190
178
  end
191
179
 
192
180
  def run( params, accept_header=nil, waiting_task=nil )
@@ -230,8 +218,11 @@ module OpenTox
230
218
  predict(compound_uri,false,subjectid)
231
219
  count += 1
232
220
  waiting_task.progress( count/d.compounds.size.to_f*100.0 ) if waiting_task
233
- rescue => ex
234
- LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+ex.message+" subjectid: #{subjectid}"
221
+ rescue => e
222
+ LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+e.message+" subjectid: #{subjectid}"
223
+ #LOGGER.debug "#{e.class}: #{e.message}"
224
+ #LOGGER.debug "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
225
+
235
226
  end
236
227
  end
237
228
  #@prediction_dataset.save(subjectid)
@@ -246,7 +237,6 @@ module OpenTox
246
237
 
247
238
  @compound = Compound.new compound_uri
248
239
  features = {}
249
-
250
240
  #LOGGER.debug self.to_yaml
251
241
  unless @prediction_dataset
252
242
  @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@@ -257,29 +247,42 @@ module OpenTox
257
247
  OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
258
248
  } )
259
249
  end
260
-
261
250
  if OpenTox::Feature.find(metadata[OT.dependentVariables], subjectid).feature_type == "regression"
262
251
  all_activities = []
263
252
  all_activities = @activities.values.flatten.collect! { |i| i.to_f }
264
- @prediction_min_max[0] = (all_activities.to_scale.min/2)
265
- @prediction_min_max[1] = (all_activities.to_scale.max*2)
266
253
  end
267
-
268
254
  unless database_activity(subjectid) # adds database activity to @prediction_dataset
255
+ # Calculation of needed values for query compound
256
+ @compound_features = eval("#{@feature_calculation_algorithm}({
257
+ :compound => @compound,
258
+ :features => @features,
259
+ :feature_dataset_uri => @metadata[OT.featureDataset],
260
+ :pc_type => self.parameter(\"pc_type\"),
261
+ :subjectid => subjectid
262
+ })")
263
+ # Adding fingerprint of query compound with features and values(p_value*nr_hits)
264
+ @compound_fingerprints = {}
265
+ @compound_features.each do |feature, value| # value is nil if "Substructure.match"
266
+ if @feature_calculation_algorithm == "Substructure.match_hits"
267
+ @compound_fingerprints[feature] = @p_values[feature] * value
268
+ elsif @feature_calculation_algorithm == "Substructure.match"
269
+ @compound_fingerprints[feature] = @p_values[feature]
270
+ elsif @feature_calculation_algorithm == "Substructure.lookup"
271
+ @compound_fingerprints[feature] = value
272
+ end
273
+ end
269
274
 
270
- neighbors
271
- prediction = eval("#{@prediction_algorithm} ( { :neighbors => @neighbors,
272
- :compound => @compound,
273
- :features => @features,
274
- :p_values => @p_values,
275
- :fingerprints => @fingerprints,
276
- :similarity_algorithm => @similarity_algorithm,
277
- :prop_kernel => @prop_kernel,
275
+ # Transform model data to machine learning scheme (tables of data)
276
+ mtf = OpenTox::Algorithm::Transform::ModelTransformer.new(self)
277
+ mtf.transform
278
+
279
+ # Make a prediction
280
+ prediction = eval("#{@prediction_algorithm}( { :props => mtf.props,
281
+ :acts => mtf.acts,
282
+ :sims => mtf.sims,
278
283
  :value_map => @value_map,
279
- :nr_hits => @nr_hits,
280
- :conf_stdev => @conf_stdev,
281
- :prediction_min_max => @prediction_min_max,
282
- :transform => @transform } ) ")
284
+ :min_train_performance => self.parameter(\"min_train_performance\")
285
+ } ) ")
283
286
 
284
287
  value_feature_uri = File.join( @uri, "predicted", "value")
285
288
  confidence_feature_uri = File.join( @uri, "predicted", "confidence")
@@ -355,44 +358,6 @@ module OpenTox
355
358
  @prediction_dataset
356
359
  end
357
360
 
358
-
359
-
360
- # Find neighbors and store them as object variable, access all compounds for that.
361
- def neighbors
362
- @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
363
- @neighbors = []
364
- @fingerprints.keys.each do |training_compound| # AM: access all compounds
365
- add_neighbor @fingerprints[training_compound].keys, training_compound
366
- end
367
- end
368
-
369
- # Adds a neighbor to @neighbors if it passes the similarity threshold.
370
- def add_neighbor(training_features, training_compound)
371
- compound_features_hits = {}
372
- training_compound_features_hits = {}
373
- if @nr_hits
374
- compound_features_hits = @compound.match_hits(@compound_features)
375
- training_compound_features_hits = @fingerprints[training_compound]
376
- #LOGGER.debug "dv ------------ training_compound_features_hits:#{training_compound_features_hits.class} #{training_compound_features_hits}"
377
- end
378
- params = {}
379
- params[:nr_hits] = @nr_hits
380
- params[:compound_features_hits] = compound_features_hits
381
- params[:training_compound_features_hits] = training_compound_features_hits
382
-
383
- sim = eval("#{@similarity_algorithm}(training_features, @compound_features, @p_values, params)")
384
- if sim > @min_sim
385
- @activities[training_compound].each do |act|
386
- @neighbors << {
387
- :compound => training_compound,
388
- :similarity => sim,
389
- :features => training_features,
390
- :activity => act
391
- }
392
- end
393
- end
394
- end
395
-
396
361
  # Find database activities and store them in @prediction_dataset
397
362
  # @return [Boolean] true if compound has databasse activities, false if not
398
363
  def database_activity(subjectid)
data/lib/opentox-ruby.rb CHANGED
@@ -9,6 +9,6 @@ rescue LoadError
9
9
  end
10
10
 
11
11
  ['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
12
- 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology' ].each do |lib|
12
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology', 'r-util' ].each do |lib|
13
13
  require lib
14
14
  end