ms-msrun 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +16 -0
- data/README +62 -0
- data/Rakefile +113 -0
- data/bin/base64_to_array.rb +13 -0
- data/bin/ms_to_obiwarp.rb +69 -0
- data/bin/ms_to_search.rb +44 -0
- data/lib/bsearch.rb +120 -0
- data/lib/lmat.rb +171 -0
- data/lib/ms/msrun.rb +297 -0
- data/lib/ms/msrun/axml/mzxml.rb +141 -0
- data/lib/ms/msrun/search.rb +118 -0
- data/lib/ms/precursor.rb +27 -0
- data/lib/ms/scan.rb +93 -0
- data/lib/ms/spectrum.rb +373 -0
- data/lib/ms/spectrum/compare.rb +118 -0
- data/lib/ms/spectrum/filter.rb +46 -0
- data/spec/lmat_spec.rb +29 -0
- data/spec/ms/msrun/search_spec.rb +56 -0
- data/spec/ms/msrun_spec.rb +50 -0
- data/spec/ms/scan_spec.rb +34 -0
- data/spec/ms/spectrum/compare_spec.rb +44 -0
- data/spec/ms/spectrum/filter_spec.rb +33 -0
- metadata +97 -0
data/LICENSE
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Copyright (c) 2006, 2007, 2008 The University of Texas at Austin
|
2
|
+
Copyright (c) 2009, University of Colorado at Boulder and Howard Hughes
|
3
|
+
Medical Institute
|
4
|
+
|
5
|
+
The above copyright holders are collectively designated "COPYRIGHT HOLDER"
|
6
|
+
|
7
|
+
Software by John T. Prince under the direction of Edward M. Marcotte and
|
8
|
+
Natalie Ahn.
|
9
|
+
|
10
|
+
By using this software the USER indicates that he or she has read, understood and will comply with the following:
|
11
|
+
|
12
|
+
COPYRIGHT HOLDER hereby grants USER permission to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this software and its documentation for any purpose and without fee, provided that a full copy of this notice is included with the software and its documentation.
|
13
|
+
|
14
|
+
Title to copyright this software and its associated documentation shall at all times remain with COPYRIGHT HOLDER. No right is granted to use in advertising, publicity or otherwise any trademark, service mark, or the name of COPYRIGHT HOLDER.
|
15
|
+
|
16
|
+
This software and any associated documentation are provided "as is," and COPYRIGHT HOLDER MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING THOSE OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT USE OF THE SOFTWARE, MODIFICATIONS, OR ASSOCIATED DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER INTELLECTUAL PROPERTY RIGHTS OF A THIRD PARTY. COPYRIGHT HOLDER and associated Regents, officers, and employees shall not be liable under any circumstances for any direct, indirect, special, incidental, or consequential damages with respect to any claim by USER or any third party on account of or arising from the use, or inability to use, this software or its associated documentation, even if COPYRIGHT HOLDER has been advised of the possibility of those damages.
|
data/README
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= {ms-msrun}[http://mspire.rubyforge.org/projects/ms-msrun]
|
2
|
+
|
3
|
+
A library for working with LC/MS runs.
|
4
|
+
|
5
|
+
== Examples
|
6
|
+
|
7
|
+
The following example will work on *mzXML*, *mzData* ( and *mzML* files, shortly)!
|
8
|
+
|
9
|
+
require "ms/msrun"
|
10
|
+
|
11
|
+
Ms::Msrun.open("file.mzXML") do |ms|
|
12
|
+
ms.start_time # in seconds
|
13
|
+
ms.end_time # in seconds
|
14
|
+
|
15
|
+
ms.scan_count # number of scans
|
16
|
+
ms.scan_count(1) # number of MS scans
|
17
|
+
ms.scan_count(2) # number of MS/MS scans, etc.
|
18
|
+
|
19
|
+
ms.parent_basename_noext # "file" (as recorded _in the xml_)
|
20
|
+
ms.filename # "file.mzXML"
|
21
|
+
|
22
|
+
ms.scans.each do |scan|
|
23
|
+
scan.num # scan number
|
24
|
+
scan.ms_level # ms_level
|
25
|
+
scan.time # retention time in seconds
|
26
|
+
scan.start_mz # the first m/z value
|
27
|
+
scan.end_mz # the last m/z value
|
28
|
+
|
29
|
+
# Precursor information
|
30
|
+
pr = scan.precursor # an Ms::Precursor object
|
31
|
+
pr.mz
|
32
|
+
pr.intensity # does fast binary search if info not already given
|
33
|
+
pr.parent # the parent scan
|
34
|
+
pr.charge_states # Array of possible charge states
|
35
|
+
|
36
|
+
# Spectral information
|
37
|
+
spectrum = scan.spectrum
|
38
|
+
spectrum.mzs # Array of m/z values
|
39
|
+
spectrum.intensities # Array of m/z values
|
40
|
+
spectrum.peaks do |mz, inten|
|
41
|
+
puts "#{mz} #{inten}" # print each peak on own line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
== Features
|
47
|
+
|
48
|
+
[*Fast*] uses xmlparser under the hood.
|
49
|
+
[*Unified*] one interface for all formats
|
50
|
+
[<b>Lazy evaluation of spectra</b>] By default, reads from IO when data is required.
|
51
|
+
[<b>Minimal Dependencies</b>] xmlparser (available for most distros and windows one-click installer) and axml. Very nearly have supoort for LibXML.
|
52
|
+
|
53
|
+
== Installation
|
54
|
+
|
55
|
+
gem install ms-msrun
|
56
|
+
|
57
|
+
The library currently relies on xmlparser (though LibXML is close to being
|
58
|
+
supported). After installation of ms-msrun (which will automatically install
|
59
|
+
`axml`) issue this command to get instructions on installing xmlparser:
|
60
|
+
|
61
|
+
ruby -rubygems -e 'require "axml" \
|
62
|
+
puts AXML::Autoload.install_instructions(:xmlparser)'
|
data/Rakefile
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/clean'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
###############################################
|
10
|
+
# GLOBAL
|
11
|
+
###############################################
|
12
|
+
|
13
|
+
FL = FileList
|
14
|
+
NAME = "ms-msrun"
|
15
|
+
FU = FileUtils
|
16
|
+
|
17
|
+
readme = "README"
|
18
|
+
|
19
|
+
rdoc_dir = 'rdoc'
|
20
|
+
rdoc_extra_includes = [readme, "LICENSE"]
|
21
|
+
rdoc_options = ['--main', readme, '--title', NAME, '--line-numbers', '--inline-source']
|
22
|
+
|
23
|
+
lib_files = FL["lib/**/*.rb"]
|
24
|
+
dist_files = lib_files + FL[readme, "LICENSE", "Rakefile", "{specs}/**/*"]
|
25
|
+
changelog = 'CHANGELOG'
|
26
|
+
|
27
|
+
###############################################
|
28
|
+
# DOC
|
29
|
+
###############################################
|
30
|
+
Rake::RDocTask.new do |rd|
|
31
|
+
rd.rdoc_dir = rdoc_dir
|
32
|
+
rd.main = readme
|
33
|
+
rd.rdoc_files.include( rdoc_extra_includes )
|
34
|
+
rd.rdoc_files.include( lib_files.uniq )
|
35
|
+
rd.options.push( *rdoc_options )
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "create and upload docs to server"
|
39
|
+
task :upload_docs => [:rdoc] do
|
40
|
+
sh "scp -r #{rdoc_dir}/* jtprince@rubyforge.org:/var/www/gforge-projects/mspire/ms-msrun/"
|
41
|
+
end
|
42
|
+
|
43
|
+
###############################################
|
44
|
+
# TESTS
|
45
|
+
###############################################
|
46
|
+
|
47
|
+
desc 'Default: Run specs.'
|
48
|
+
task :default => :spec
|
49
|
+
|
50
|
+
desc 'Run specs.'
|
51
|
+
Rake::TestTask.new(:spec) do |t|
|
52
|
+
#t.verbose = true
|
53
|
+
#t.warning = true
|
54
|
+
ENV['TEST'] = ENV['SPEC'] if ENV['SPEC']
|
55
|
+
t.libs = ['lib']
|
56
|
+
t.test_files = Dir.glob( File.join('spec', ENV['pattern'] || '**/*_spec.rb') )
|
57
|
+
#t.options = "-v"
|
58
|
+
end
|
59
|
+
|
60
|
+
###############################################
|
61
|
+
# PACKAGE / INSTALL / UNINSTALL
|
62
|
+
###############################################
|
63
|
+
|
64
|
+
tm = Time.now
|
65
|
+
gemspec = Gem::Specification.new do |t|
|
66
|
+
description = 'A library for working with LC/MS runs. Part of mspire. Has parsers for mzXML v1, 2, and 3, mzData and mzML. Can convert to commonly desired search output (such as mgf)'
|
67
|
+
summary = "A library for working with LC/MS runs"
|
68
|
+
t.platform = Gem::Platform::RUBY
|
69
|
+
t.name = NAME
|
70
|
+
t.version = IO.readlines(changelog).grep(/##.*version/).pop.split(/\s+/).last.chomp
|
71
|
+
t.homepage = 'http://mspire.rubyforge.org/projects/ms-msrun'
|
72
|
+
t.rubyforge_project = 'mspire'
|
73
|
+
t.summary = summary
|
74
|
+
t.date = "#{tm.year}-#{tm.month}-#{tm.day}"
|
75
|
+
t.email = "jtprince@gmail.com"
|
76
|
+
t.description = description
|
77
|
+
t.has_rdoc = true
|
78
|
+
t.authors = ["John Prince"]
|
79
|
+
t.files = dist_files
|
80
|
+
t.add_dependency 'axml', '~> 0.0.5'
|
81
|
+
t.add_dependency 'runarray'
|
82
|
+
t.rdoc_options = rdoc_options
|
83
|
+
t.extra_rdoc_files = rdoc_extra_includes
|
84
|
+
t.executables = FL["bin/*"].map {|file| File.basename(file) }
|
85
|
+
t.requirements << 'xmlparser (preferrably) or libxml'
|
86
|
+
t.test_files = FL["spec/**/*_spec.rb"]
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "Create packages."
|
90
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
91
|
+
#pkg.need_zip = true
|
92
|
+
#pkg.need_tar = true
|
93
|
+
end
|
94
|
+
|
95
|
+
task :remove_pkg do
|
96
|
+
FileUtils.rm_rf "pkg"
|
97
|
+
end
|
98
|
+
|
99
|
+
task :install => [:reinstall]
|
100
|
+
|
101
|
+
desc "uninstalls the package, packages a fresh one, and installs"
|
102
|
+
task :reinstall => [:remove_pkg, :clean, :package] do
|
103
|
+
reply = `#{$gemcmd} list -l #{NAME}`
|
104
|
+
if reply.include?(NAME + " (")
|
105
|
+
%x( #{$gemcmd} uninstall -a -x #{NAME} )
|
106
|
+
end
|
107
|
+
FileUtils.cd("pkg") do
|
108
|
+
cmd = "#{$gemcmd} install #{NAME}*.gem"
|
109
|
+
puts "EXECUTING: #{cmd}"
|
110
|
+
system cmd
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
require 'ms/spectrum'
|
3
|
+
|
4
|
+
if ARGV.size == 0
|
5
|
+
puts "usage: #{File.basename(__FILE__)} <base64_string>"
|
6
|
+
puts "outputs the array of values"
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
precision = 32
|
11
|
+
network_order = true
|
12
|
+
ar = Ms::Spectrum.base64_to_array(ARGV.shift, precision, network_order)
|
13
|
+
puts "[ " + ar.join(", ") + " ]"
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ms/msrun'
|
5
|
+
require 'lmat'
|
6
|
+
require 'optparse'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'runarray'
|
9
|
+
|
10
|
+
# defaults:
|
11
|
+
opt = {}
|
12
|
+
opt[:baseline] = 0.0
|
13
|
+
opt[:newext] = ".lmat"
|
14
|
+
opt[:inc_mz] = 1.0
|
15
|
+
|
16
|
+
# get options:
|
17
|
+
opts = OptionParser.new do |op|
|
18
|
+
op.banner = "usage: #{File.basename(__FILE__)} [options] <msfile> ..."
|
19
|
+
op.separator "input: .mzdata or .mzXML"
|
20
|
+
op.separator ""
|
21
|
+
op.separator "(sums m/z values that round to the same bin)"
|
22
|
+
op.separator ""
|
23
|
+
op.on("--mz-inc N", Float, "m/z increment (def: 1.0)") {|n| opt[:mz_inc] = n.to_f}
|
24
|
+
op.on("--mz-start N", Float, "m/z start (def: start of 1st full scan)") {|n| opt[:start_mz] = n.to_f}
|
25
|
+
op.on("--mz-end N", Float, "m/z end (def: end of 1st full scan)") {|n| opt[:end_mz] = n.to_f}
|
26
|
+
op.on("--baseline N", Float, "value for missing indices (def: #{opt[:baseline]})") {|n| opt[:baseline] = n.to_f}
|
27
|
+
op.on("--ascii", "generates an lmata file instead") {opt[:ascii] = true}
|
28
|
+
op.on("-v", "--verbose") {$VERBOSE = true}
|
29
|
+
end
|
30
|
+
opts.parse!
|
31
|
+
|
32
|
+
if ARGV.size < 1
|
33
|
+
puts opts
|
34
|
+
end
|
35
|
+
|
36
|
+
ARGV.each do |file|
|
37
|
+
Ms::Msrun.open(file) do |msrun|
|
38
|
+
mslevel = 1
|
39
|
+
(start_mz, end_mz) = msrun.start_and_end_mz(mslevel)
|
40
|
+
(times, spectra) = msrun.times_and_spectra(mslevel)
|
41
|
+
args = {
|
42
|
+
:start_mz => start_mz,
|
43
|
+
:end_mz => end_mz,
|
44
|
+
|
45
|
+
:start_tm => times.first,
|
46
|
+
:end_tm => times.last,
|
47
|
+
:inc_tm => nil,
|
48
|
+
}
|
49
|
+
args.merge!(opt)
|
50
|
+
lmat = Ms::Msrun::Lmat.new.from_times_and_spectra(times, spectra, args)
|
51
|
+
ext = File.extname(file)
|
52
|
+
outfile = file.sub(/#{Regexp.escape(ext)}$/, opt[:newext])
|
53
|
+
if args[:ascii]
|
54
|
+
outfile << "a"
|
55
|
+
lmat.print(outfile)
|
56
|
+
else
|
57
|
+
lmat.write(outfile)
|
58
|
+
end
|
59
|
+
puts("OUTPUT: #{outfile}") if $VERBOSE
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
data/bin/ms_to_search.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'tap'
|
5
|
+
|
6
|
+
|
7
|
+
module Ms ; end
|
8
|
+
class Ms::Msrun ; end
|
9
|
+
|
10
|
+
# Documentation here
|
11
|
+
class Ms::Msrun::Search < Tap::Task
|
12
|
+
|
13
|
+
#config :first_scan, 0, :short => 'F', &c.integer # first scan
|
14
|
+
#config :last_scan, 1e12, :short => 'L', &c.integer # last scan
|
15
|
+
## if not determined to be +1, then create these charge states
|
16
|
+
#config( :charge_states, [2,3], :short => 'c') {|v| v.split(',') }
|
17
|
+
#config :bottom_mh, 0, :short => 'B', &c.float # bottom MH+
|
18
|
+
#config :top_mh, -1.0, :short => 'T', &c.float # top MH+
|
19
|
+
#config :min_peaks, 0, :short => 'P', &c.integer # minimum peak count
|
20
|
+
#config :ms_levels, 2..-1, :short => 'M', &c.range # ms levels to export
|
21
|
+
|
22
|
+
|
23
|
+
def process(filename)
|
24
|
+
Ms::Msrun.open(filename) do |ms|
|
25
|
+
ms.to_mgf(ms.filename.chomp(File.extname(ms.filename)))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Ms::Msrun::Search.execute
|
31
|
+
|
32
|
+
# extract_msn.exe -M0.2 -B85 -T4500 -S0 -G1 -I35 -C0 -P2 -D output smallraw.RAW
|
33
|
+
|
34
|
+
|
35
|
+
#config :group_mass_tol, 1.4, :short => 'M', &c.float # prec. mass tolerance for grouping
|
36
|
+
#config :bottom_mw, 0.0, :short => 'B', &c.float # bottom MW for data file creation
|
37
|
+
#config :top_mw, 999999.0, :short => 'T', &c.float # top MW for data file creation
|
38
|
+
#config :interm_scans, 0, :short => 'S', &c.integer # allowed num intermediate scans between groups
|
39
|
+
#config :min_group, 1, :short => 'G', &c.integer # minimum # of related grouped scans needed for a .dta file
|
40
|
+
#config :min_ions, 0, :short => 'I', &c.integer # minimum num of ions needed for a .dta file
|
41
|
+
# What the heck is the -P option?? Not listed in the help!
|
42
|
+
# Ahn lab sets this to: 2
|
43
|
+
# config : :short => 'P',
|
44
|
+
|
data/lib/bsearch.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#
|
2
|
+
# Ruby/Bsearch - a binary search library for Ruby.
|
3
|
+
#
|
4
|
+
# Copyright (C) 2001 Satoru Takabayashi <satoru@namazu.org>
|
5
|
+
# All rights reserved.
|
6
|
+
# This is free software with ABSOLUTELY NO WARRANTY.
|
7
|
+
#
|
8
|
+
# You can redistribute it and/or modify it under the terms of
|
9
|
+
# the Ruby's licence.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# % irb -r ./bsearch.rb
|
14
|
+
# >> %w(a b c c c d e f).bsearch_first {|x| x <=> "c"}
|
15
|
+
# => 2
|
16
|
+
# >> %w(a b c c c d e f).bsearch_last {|x| x <=> "c"}
|
17
|
+
# => 4
|
18
|
+
# >> %w(a b c e f).bsearch_first {|x| x <=> "c"}
|
19
|
+
# => 2
|
20
|
+
# >> %w(a b e f).bsearch_first {|x| x <=> "c"}
|
21
|
+
# => nil
|
22
|
+
# >> %w(a b e f).bsearch_last {|x| x <=> "c"}
|
23
|
+
# => nil
|
24
|
+
# >> %w(a b e f).bsearch_lower_boundary {|x| x <=> "c"}
|
25
|
+
# => 2
|
26
|
+
# >> %w(a b e f).bsearch_upper_boundary {|x| x <=> "c"}
|
27
|
+
# => 2
|
28
|
+
# >> %w(a b c c c d e f).bsearch_range {|x| x <=> "c"}
|
29
|
+
# => 2...5
|
30
|
+
# >> %w(a b c d e f).bsearch_range {|x| x <=> "c"}
|
31
|
+
# => 2...3
|
32
|
+
# >> %w(a b d e f).bsearch_range {|x| x <=> "c"}
|
33
|
+
# => 2...2
|
34
|
+
|
35
|
+
module Bsearch
|
36
|
+
VERSION = '1.5'
|
37
|
+
end
|
38
|
+
|
39
|
+
class Array
|
40
|
+
#
|
41
|
+
# The binary search algorithm is extracted from Jon Bentley's
|
42
|
+
# Programming Pearls 2nd ed. p.93
|
43
|
+
#
|
44
|
+
|
45
|
+
#
|
46
|
+
# Return the lower boundary. (inside)
|
47
|
+
#
|
48
|
+
def bsearch_lower_boundary (range = 0 ... self.length, &block)
|
49
|
+
lower = range.first() -1
|
50
|
+
upper = if range.exclude_end? then range.last else range.last + 1 end
|
51
|
+
while lower + 1 != upper
|
52
|
+
mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
|
53
|
+
if yield(self[mid]) < 0
|
54
|
+
lower = mid
|
55
|
+
else
|
56
|
+
upper = mid
|
57
|
+
end
|
58
|
+
end
|
59
|
+
return upper
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# This method searches the FIRST occurrence which satisfies a
|
64
|
+
# condition given by a block in binary fashion and return the
|
65
|
+
# index of the first occurrence. Return nil if not found.
|
66
|
+
#
|
67
|
+
def bsearch_first (range = 0 ... self.length, &block)
|
68
|
+
boundary = bsearch_lower_boundary(range, &block)
|
69
|
+
if boundary >= self.length || yield(self[boundary]) != 0
|
70
|
+
return nil
|
71
|
+
else
|
72
|
+
return boundary
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
alias bsearch bsearch_first
|
77
|
+
|
78
|
+
#
|
79
|
+
# Return the upper boundary. (outside)
|
80
|
+
#
|
81
|
+
def bsearch_upper_boundary (range = 0 ... self.length, &block)
|
82
|
+
lower = range.first() -1
|
83
|
+
upper = if range.exclude_end? then range.last else range.last + 1 end
|
84
|
+
while lower + 1 != upper
|
85
|
+
mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
|
86
|
+
if yield(self[mid]) <= 0
|
87
|
+
lower = mid
|
88
|
+
else
|
89
|
+
upper = mid
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return lower + 1 # outside of the matching range.
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# This method searches the LAST occurrence which satisfies a
|
97
|
+
# condition given by a block in binary fashion and return the
|
98
|
+
# index of the last occurrence. Return nil if not found.
|
99
|
+
#
|
100
|
+
def bsearch_last (range = 0 ... self.length, &block)
|
101
|
+
# `- 1' for canceling `lower + 1' in bsearch_upper_boundary.
|
102
|
+
boundary = bsearch_upper_boundary(range, &block) - 1
|
103
|
+
|
104
|
+
if (boundary <= -1 || yield(self[boundary]) != 0)
|
105
|
+
return nil
|
106
|
+
else
|
107
|
+
return boundary
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Return the search result as a Range object.
|
113
|
+
#
|
114
|
+
def bsearch_range (range = 0 ... self.length, &block)
|
115
|
+
lower = bsearch_lower_boundary(range, &block)
|
116
|
+
upper = bsearch_upper_boundary(range, &block)
|
117
|
+
return lower ... upper
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
data/lib/lmat.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
|
2
|
+
require 'runarray'
|
3
|
+
include Runarray
|
4
|
+
|
5
|
+
## Labeled matrix
|
6
|
+
|
7
|
+
class Lmat
|
8
|
+
attr_accessor :mvec
|
9
|
+
attr_accessor :nvec
|
10
|
+
# an array of narray objects
|
11
|
+
attr_accessor :mat
|
12
|
+
|
13
|
+
## Takes an array of narray objects
|
14
|
+
def initialize(mat=nil, mvec=nil, nvec=nil)
|
15
|
+
@mat = mat
|
16
|
+
@mvec = mvec
|
17
|
+
@nvec = nvec
|
18
|
+
end
|
19
|
+
|
20
|
+
def max
|
21
|
+
max = mat[0][0]
|
22
|
+
mat.each do |row|
|
23
|
+
row.each do |v|
|
24
|
+
max = v if v > max
|
25
|
+
end
|
26
|
+
end
|
27
|
+
max
|
28
|
+
end
|
29
|
+
|
30
|
+
# returns self
|
31
|
+
def from_lmat(file)
|
32
|
+
string = IO.read(file)
|
33
|
+
mdim = string.unpack("i")
|
34
|
+
@mvec = NArray.new(string.unpack("f#{mdim}"))
|
35
|
+
ndim = string.unpack("i")
|
36
|
+
@nvec = NArray.new(string.unpack("f#{ndim}"))
|
37
|
+
rows = []
|
38
|
+
mdim.times do
|
39
|
+
rows << string.unpack("f#{ndim}")
|
40
|
+
end
|
41
|
+
@mat = rows
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
# returns self
|
46
|
+
def from_lmata(file)
|
47
|
+
# this can probably be made faster
|
48
|
+
File.open(file) do |io|
|
49
|
+
num_m = io.readline.to_i
|
50
|
+
mline = io.readline.chomp
|
51
|
+
@mvec = NArray.new( mline.split(' ').map {|v| v.to_f } )
|
52
|
+
raise RuntimeError, "bad m vec size" if mvec.size != num_m
|
53
|
+
num_n = io.readline.to_i
|
54
|
+
nline = io.readline.chomp
|
55
|
+
@nvec = NArray.new( nline.split(' ').map {|v| v.to_f } )
|
56
|
+
raise RuntimeError, "bad n vec size" if nvec.size != num_n
|
57
|
+
@mat = NArray.new(num_m)
|
58
|
+
num_m.times do |m|
|
59
|
+
line = io.readline
|
60
|
+
line.chomp!
|
61
|
+
@mat[m] = NArray.new(line.split(' ').map {|v| v.to_f })
|
62
|
+
end
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
# converts raw times and spectrum to a labeled matrix
|
68
|
+
# times is an array (or VecI object)
|
69
|
+
# where each row = [mz,inten,mz,inten...]
|
70
|
+
# takes hash with symbols as keys
|
71
|
+
# if inc_tm is undefined, then times from the times array will be used
|
72
|
+
def from_times_and_spectra(times, spectra, args)
|
73
|
+
opt = {
|
74
|
+
:start_mz => 400.0,
|
75
|
+
:end_mz => 1500.0,
|
76
|
+
:inc_mz => 1.0,
|
77
|
+
:behave_mz => 'sum',
|
78
|
+
|
79
|
+
:start_tm => 0.0,
|
80
|
+
:end_tm => 3600.0,
|
81
|
+
:inc_tm => nil,
|
82
|
+
|
83
|
+
:baseline=> 0.0,
|
84
|
+
}
|
85
|
+
opt.merge!(args)
|
86
|
+
unless opt[:start_tm] then opt[:start_tm] = times.first end
|
87
|
+
unless opt[:end_tm] then opt[:end_tm] = times.last end
|
88
|
+
|
89
|
+
if opt[:inc_tm]
|
90
|
+
raise NotImplementedError, "haven't implemented interpolation in ruby yet! (#{File.basename(__FILE__)}: #{__LINE__})"
|
91
|
+
else ## No interpolation
|
92
|
+
if times.first != opt[:start_tm] || times.last != opt[:end_tm]
|
93
|
+
abort "haven't implemented yet! (#{File.basename(__FILE__)}: #{__LINE__})"
|
94
|
+
else
|
95
|
+
@mvec = NArray.new(times)
|
96
|
+
give_vecs = true
|
97
|
+
vecs = spectra.map do |spectrum|
|
98
|
+
#(mz,inten) = spectrum_to_mz_and_inten(spectrum, VecD)
|
99
|
+
# TODO: Figure out a shallow copy here:
|
100
|
+
# perhaps we'll make spectra Vec objects by default in future and
|
101
|
+
# then we'd be set...
|
102
|
+
mzs = NArray.new(spectrum.mzs)
|
103
|
+
intens = NArray.new(spectrum.intensities)
|
104
|
+
(x,y) = mzs.inc_x(intens, opt[:start_mz], opt[:end_mz], opt[:inc_mz], opt[:baseline], opt[:behave_mz])
|
105
|
+
@nvec = x # ends up being the last one, but that's OK
|
106
|
+
y
|
107
|
+
end
|
108
|
+
@mat = vecs
|
109
|
+
end
|
110
|
+
end
|
111
|
+
self
|
112
|
+
end
|
113
|
+
|
114
|
+
# outputs vec lengths if set to true
|
115
|
+
def to_s(with_vec_lengths=false)
|
116
|
+
arr = []
|
117
|
+
if with_vec_lengths; arr.push(@mvec.size) end
|
118
|
+
arr.push(@mvec.join(" "))
|
119
|
+
if with_vec_lengths; arr.push(@nvec.size) end
|
120
|
+
arr.push(@nvec.join(" "), @mat.map {|v| v.join(" " ) }.join("\n")).join("\n")
|
121
|
+
end
|
122
|
+
|
123
|
+
def ==(other)
|
124
|
+
other != nil && self.class == other.class && @nvec == other.nvec && @mvec == other.mvec && @mat == other.mat
|
125
|
+
end
|
126
|
+
|
127
|
+
# converts a single array of alternating m/z intensity values to two
|
128
|
+
# separate arrays
|
129
|
+
# (maybe implement in Ruby::Inline?)
|
130
|
+
# the answer is given in terms of arrs_as (object of class "arrs_as" must
|
131
|
+
# respond to "[]" and create a certain sized array with arrs_as.new(size))
|
132
|
+
def spectrum_to_mz_and_inten(spectrum, arrs_as=Array)
|
133
|
+
half_size = spectrum.size / 2
|
134
|
+
mzs = arrs_as.new(half_size)
|
135
|
+
intens = arrs_as.new(half_size)
|
136
|
+
mz = true
|
137
|
+
spectrum.each_index do |i|
|
138
|
+
if mz
|
139
|
+
mzs[i/2] = spectrum[i]
|
140
|
+
mz = false
|
141
|
+
else
|
142
|
+
mz = true
|
143
|
+
intens[(i-1)/2] = spectrum[i]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
[mzs, intens]
|
147
|
+
end
|
148
|
+
|
149
|
+
def write(file=nil)
|
150
|
+
handle = $>
|
151
|
+
if file; handle = File.open(file, "wb") end
|
152
|
+
bin_string = ""
|
153
|
+
bin_string << [@mvec.size].pack("i")
|
154
|
+
bin_string << @mvec.pack("f*")
|
155
|
+
bin_string << [@nvec.size].pack("i")
|
156
|
+
bin_string << @nvec.pack("f*")
|
157
|
+
bin_string << @mat.flatten.pack("f*")
|
158
|
+
handle.print bin_string
|
159
|
+
if file; handle.close end
|
160
|
+
end
|
161
|
+
|
162
|
+
def print(file=nil)
|
163
|
+
handle = $>
|
164
|
+
if file; handle = File.new(file, "w") end
|
165
|
+
handle.print( self.to_s(true) )
|
166
|
+
#$stdout.print( self.to_s(true) )
|
167
|
+
if file; handle.close end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|