mspire 0.7.13 → 0.7.17
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/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
|