mspire 0.7.13 → 0.7.17
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/mspire/isotope/distribution.rb +2 -2
- data/lib/mspire/mass.rb +3 -4
- data/lib/mspire/molecular_formula.rb +110 -24
- data/spec/mspire/isotope/distribution_spec.rb +1 -1
- data/spec/mspire/molecular_formula_spec.rb +92 -35
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.17
|
@@ -107,12 +107,12 @@ module Mspire
|
|
107
107
|
class Isotope
|
108
108
|
module Distribution
|
109
109
|
def self.calculate(molecular_formula_like, normalize=Mspire::Isotope::Distribution::NORMALIZE, percent_cutoff=nil)
|
110
|
-
mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.
|
110
|
+
mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.from_any(molecular_formula_like)
|
111
111
|
mf.isotope_distribution(normalize, percent_cutoff)
|
112
112
|
end
|
113
113
|
|
114
114
|
def self.spectrum(molecular_formula_like, normalize=Mspire::Isotope::Distribution::NORMALIZE, percent_cutoff=nil)
|
115
|
-
mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.
|
115
|
+
mf = molecular_formula_like.is_a?(Mspire::MolecularFormula) ? molecular_formula_like : Mspire::MolecularFormula.from_any(molecular_formula_like)
|
116
116
|
mf.isotope_distribution_spectrum(normalize, percent_cutoff)
|
117
117
|
end
|
118
118
|
end
|
data/lib/mspire/mass.rb
CHANGED
@@ -4,11 +4,10 @@ require 'mspire/molecular_formula'
|
|
4
4
|
module Mspire
|
5
5
|
module Mass
|
6
6
|
|
7
|
-
# takes a molecular formula
|
7
|
+
# takes a molecular formula as a string, hash or MolecularFormula object
|
8
|
+
# and returns the exact mass.
|
8
9
|
def self.formula_to_exact_mass(formula)
|
9
|
-
Mspire::MolecularFormula.
|
10
|
-
MONO[el] * cnt
|
11
|
-
end.reduce(:+)
|
10
|
+
Mspire::MolecularFormula.from_any(formula).mass
|
12
11
|
end
|
13
12
|
|
14
13
|
MONO_STR = {
|
@@ -4,46 +4,132 @@ require 'mspire/mass'
|
|
4
4
|
module Mspire
|
5
5
|
class MolecularFormula < Hash
|
6
6
|
|
7
|
+
class << self
|
8
|
+
def from_aaseq(aaseq)
|
9
|
+
hash = aaseq.each_char.inject({}) do |hash,aa|
|
10
|
+
hash.merge(Mspire::Isotope::AA::FORMULAS[aa]) {|h,o,n| (o ? o : 0) +n }
|
11
|
+
end
|
12
|
+
hash[:h] += 2
|
13
|
+
hash[:o] += 1
|
14
|
+
self.new(hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
# takes a string, with properly capitalized elements making up the
|
18
|
+
# formula. The elements may be in any order.
|
19
|
+
def from_string(mol_form_str, charge=0)
|
20
|
+
mf = self.new({}, charge)
|
21
|
+
mol_form_str.scan(/([A-Z][a-z]?)(\d*)/).each do |k,v|
|
22
|
+
mf[k.downcase.to_sym] = (v == '' ? 1 : v.to_i)
|
23
|
+
end
|
24
|
+
mf
|
25
|
+
end
|
26
|
+
|
27
|
+
# arg may be a String, Hash, or MolecularFormula object.
|
28
|
+
def from_any(arg, charge=0)
|
29
|
+
if arg.is_a?(String)
|
30
|
+
from_string(arg, charge)
|
31
|
+
else
|
32
|
+
self.new(arg, arg.respond_to?(:charge) ? arg.charge : 0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
alias_method :[], :from_any
|
36
|
+
|
37
|
+
end
|
38
|
+
|
7
39
|
# integer desribing the charge state
|
8
40
|
# mass calculations will add/remove electron mass from this
|
9
41
|
attr_accessor :charge
|
10
|
-
|
11
|
-
#
|
12
|
-
# "H22C12N1O3S2BeLi2" # <= order doesn't matter
|
42
|
+
|
43
|
+
# Takes a hash and an optional Integer expressing the charge
|
13
44
|
# {h: 22, c: 12, n: 1, o: 3, s: 2} # case and string/sym doesn't matter
|
14
|
-
def initialize(
|
45
|
+
def initialize(hash={}, charge=0)
|
15
46
|
@charge = charge
|
16
|
-
|
17
|
-
arg.scan(/([A-Z][a-z]?)(\d*)/).each do |k,v|
|
18
|
-
self[k.downcase.to_sym] = (v == '' ? 1 : v.to_i)
|
19
|
-
end
|
20
|
-
else
|
21
|
-
self.merge!(arg)
|
22
|
-
end
|
47
|
+
self.merge!(hash)
|
23
48
|
end
|
24
49
|
|
25
50
|
# returns a new formula object where all the atoms have been added up
|
26
51
|
def +(*others)
|
27
|
-
|
28
|
-
|
29
|
-
|
52
|
+
self.dup.add!(*others)
|
53
|
+
end
|
54
|
+
|
55
|
+
# returns self
|
56
|
+
def add!(*others)
|
57
|
+
others.each do |other|
|
58
|
+
self.merge!(other) {|key, oldval, newval| self[key] = oldval + newval }
|
59
|
+
self.charge += other.charge
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns a new formula object where all the formulas have been subtracted
|
65
|
+
# from the caller
|
66
|
+
def -(*others)
|
67
|
+
self.dup.sub!(*others)
|
68
|
+
end
|
69
|
+
|
70
|
+
def sub!(*others)
|
71
|
+
others.each do |other|
|
72
|
+
oth = other.dup
|
73
|
+
self.each do |k,v|
|
74
|
+
if oth.key?(k)
|
75
|
+
self[k] -= oth.delete(k)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
oth.each do |k,v|
|
79
|
+
self[k] = -v
|
80
|
+
end
|
81
|
+
self.charge -= other.charge
|
82
|
+
end
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
def *(int)
|
87
|
+
self.dup.mul!(int)
|
88
|
+
end
|
89
|
+
|
90
|
+
def mul!(int, also_do_charge=true)
|
91
|
+
raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
|
92
|
+
self.each do |k,v|
|
93
|
+
self[k] = v * int
|
30
94
|
end
|
31
|
-
|
95
|
+
self.charge *= int if also_do_charge
|
96
|
+
self
|
32
97
|
end
|
33
98
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
99
|
+
def /(int)
|
100
|
+
self.dup.div!(int)
|
101
|
+
end
|
102
|
+
|
103
|
+
def div!(int, also_do_charge=true)
|
104
|
+
raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
|
105
|
+
self.each do |k,v|
|
106
|
+
quotient, modulus = v.divmod(int)
|
107
|
+
raise ArgumentError "all numbers must be divisible by int" unless modulus == 0
|
108
|
+
self[k] = quotient
|
109
|
+
end
|
110
|
+
if also_do_charge
|
111
|
+
quotient, modulus = self.charge.divmod(int)
|
112
|
+
raise ArgumentError "charge must be divisible by int" unless modulus == 0
|
113
|
+
self.charge = quotient
|
37
114
|
end
|
38
|
-
|
39
|
-
hash[:o] += 1
|
40
|
-
self.new(hash)
|
115
|
+
self
|
41
116
|
end
|
42
117
|
|
43
|
-
# gives the monoisotopic mass adjusted by the current charge
|
44
|
-
|
118
|
+
# gives the monoisotopic mass adjusted by the current charge (i.e.,
|
119
|
+
# adds/subtracts electron masses for the charges)
|
120
|
+
def mass(consider_electron_masses = true)
|
45
121
|
mss = inject(0.0) {|sum,(el,cnt)| sum + (Mspire::Mass::MONO[el]*cnt) }
|
46
|
-
mss
|
122
|
+
mss -= (Mspire::Mass::ELECTRON * charge) if consider_electron_masses
|
123
|
+
mss
|
124
|
+
end
|
125
|
+
|
126
|
+
# returns nil if the charge == 0
|
127
|
+
def mz(consider_electron_masses = true)
|
128
|
+
if charge == 0
|
129
|
+
nil
|
130
|
+
else
|
131
|
+
mass(consider_electron_masses) / charge
|
132
|
+
end
|
47
133
|
end
|
48
134
|
|
49
135
|
def to_s(alphabetize=true)
|
@@ -49,7 +49,7 @@ describe 'Mspire::Isotope::Distribution class methods' do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'gives proper m/z values if the molecule is charged' do
|
52
|
-
charged_molecule = Mspire::MolecularFormula.
|
52
|
+
charged_molecule = Mspire::MolecularFormula.from_any( subject )
|
53
53
|
charged_molecule.charge = -3
|
54
54
|
spec = Mspire::Isotope::Distribution.spectrum( charged_molecule )
|
55
55
|
[:mzs, :intensities].each {|att| spec.send(att).size.should == 253 }
|
@@ -2,52 +2,109 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'mspire/molecular_formula'
|
4
4
|
|
5
|
+
MF = Mspire::MolecularFormula
|
5
6
|
describe Mspire::MolecularFormula do
|
6
7
|
|
7
|
-
|
8
|
-
data = {h: 22, c: 12, n: 1, o: 3, s: 2}
|
9
|
-
mf = Mspire::MolecularFormula.new "H22BeC12N1O3S2Li2"
|
10
|
-
mf.to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
|
11
|
-
mf = Mspire::MolecularFormula.new(data)
|
12
|
-
mf.to_hash.should == data
|
13
|
-
end
|
8
|
+
describe 'initialization' do
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
it 'is initialized with Hash' do
|
11
|
+
data = {h: 22, c: 12, n: 1, o: 3, s: 2}
|
12
|
+
mf = Mspire::MolecularFormula.new(data)
|
13
|
+
mf.to_hash.should == {:h=>22, :c=>12, :n=>1, :o=>3, :s=>2}
|
14
|
+
mf.to_hash.should == data
|
15
|
+
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
it 'can be initialized with charge, too' do
|
18
|
+
mf = Mspire::MolecularFormula["H22BeC12N1O3S2Li2", 2]
|
19
|
+
mf.to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
|
20
|
+
mf.charge.should == 2
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'from_string or ::[] to make from a capitalized string formula' do
|
24
|
+
Mspire::MolecularFormula.from_string("H22BeC12N1O3S2Li2").to_hash.should == {:h=>22, :be=>1, :c=>12, :n=>1, :o=>3, :s=>2, :li=>2}
|
25
|
+
|
26
|
+
mf = Mspire::MolecularFormula['Ni7Se3', 1]
|
27
|
+
mf.charge.should == 1
|
28
|
+
mf.to_hash.should == {:ni=>7, :se=>3}
|
29
|
+
|
30
|
+
# there is no such thing as the E element, so this is going to get the
|
31
|
+
# user in trouble. However, this is the proper interpretation of the
|
32
|
+
# formula.
|
33
|
+
Mspire::MolecularFormula['Ni7SE3'].to_hash.should == {:ni=>7, :s=>1, :e=>3}
|
34
|
+
end
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
subject {
|
32
|
-
data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
33
|
-
Mspire::MolecularFormula.new(data)
|
34
|
-
}
|
36
|
+
describe 'conversion' do
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
subject {
|
39
|
+
data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
40
|
+
Mspire::MolecularFormula.new(data)
|
41
|
+
}
|
42
|
+
|
43
|
+
it 'the string output is a standard molecular formula' do
|
44
|
+
subject.to_s.should == "BeC12H22NO3S2"
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'can be converted to a hash' do
|
48
|
+
subject.to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
49
|
+
end
|
38
50
|
end
|
39
51
|
|
40
|
-
|
41
|
-
subject
|
52
|
+
describe 'equality' do
|
53
|
+
subject {
|
54
|
+
data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
55
|
+
Mspire::MolecularFormula.new(data)
|
56
|
+
}
|
57
|
+
it 'is only equal if the charge is equal' do
|
58
|
+
another = subject.dup
|
59
|
+
another.should == subject
|
60
|
+
another.charge = 2
|
61
|
+
another.should_not == subject
|
62
|
+
end
|
42
63
|
end
|
43
64
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
65
|
+
describe 'arithmetic' do
|
66
|
+
subject {
|
67
|
+
data = {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
68
|
+
Mspire::MolecularFormula.new(data, 2)
|
69
|
+
}
|
70
|
+
it 'can do non-destructive arithmetic' do
|
71
|
+
orig = subject.dup
|
72
|
+
reply = subject + MF["H2C3P2", 2]
|
73
|
+
reply.to_hash.should == {h: 24, c: 15, n: 1, o: 3, s: 2, be: 1, p: 2}
|
74
|
+
reply.charge.should == 4
|
75
|
+
subject.should == orig
|
76
|
+
|
77
|
+
reply = subject - MF["H2C3P2", 2]
|
78
|
+
reply.to_hash.should == {h: 20, c: 9, n: 1, o: 3, s: 2, be: 1, p: -2}
|
79
|
+
reply.charge.should == 0
|
80
|
+
subject.should == orig
|
81
|
+
|
82
|
+
by2 = subject * 2
|
83
|
+
by2.to_hash.should == {h: 44, c: 24, n: 2, o: 6, s: 4, be: 2}
|
84
|
+
by2.charge.should == 4
|
85
|
+
subject.should == orig
|
86
|
+
|
87
|
+
reply = by2 / 2
|
88
|
+
reply.to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
89
|
+
reply.charge.should == 2
|
90
|
+
subject.should == orig
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'can do destructive arithmetic' do
|
94
|
+
orig = subject.dup
|
95
|
+
subject.sub!(MF["H2C3"]).to_hash.should == {h: 20, c: 9, n: 1, o: 3, s: 2, be: 1}
|
96
|
+
subject.should_not == orig
|
97
|
+
subject.add!(MF["H2C3"]).to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
98
|
+
subject.should == orig
|
99
|
+
|
100
|
+
by2 = subject.mul!(2)
|
101
|
+
subject.should_not == orig
|
102
|
+
by2.to_hash.should == {h: 44, c: 24, n: 2, o: 6, s: 4, be: 2}
|
103
|
+
by2.div!(2).to_hash.should == {h: 22, c: 12, n: 1, o: 3, s: 2, be: 1}
|
104
|
+
by2.to_hash.should == orig
|
105
|
+
end
|
106
|
+
|
49
107
|
end
|
50
108
|
|
51
109
|
end
|
52
|
-
|
53
110
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mspire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.17
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -390,7 +390,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
390
390
|
version: '0'
|
391
391
|
requirements: []
|
392
392
|
rubyforge_project:
|
393
|
-
rubygems_version: 1.8.
|
393
|
+
rubygems_version: 1.8.24
|
394
394
|
signing_key:
|
395
395
|
specification_version: 3
|
396
396
|
summary: mass spectrometry proteomics, lipidomics, and tools
|