mspire-lipid 0.2.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.
@@ -0,0 +1,183 @@
1
+ #<OpenBabel::OBMol:0x00000000b71c90>
2
+ ---
3
+ - add
4
+ - reserve_atoms
5
+ - create_atom
6
+ - create_bond
7
+ - create_residue
8
+ - destroy_atom
9
+ - destroy_bond
10
+ - destroy_residue
11
+ - add_atom
12
+ - insert_atom
13
+ - add_bond
14
+ - add_residue
15
+ - new_atom
16
+ - new_bond
17
+ - new_residue
18
+ - delete_atom
19
+ - delete_bond
20
+ - delete_residue
21
+ - begin_modify
22
+ - end_modify
23
+ - get_mod
24
+ - increment_mod
25
+ - decrement_mod
26
+ - get_flags
27
+ - get_title
28
+ - num_atoms
29
+ - num_bonds
30
+ - num_hvy_atoms
31
+ - num_residues
32
+ - num_rotors
33
+ - get_atom
34
+ - get_atom_by_id
35
+ - get_first_atom
36
+ - get_bond_by_id
37
+ - get_bond
38
+ - get_residue
39
+ - get_internal_coord
40
+ - get_torsion
41
+ - get_angle
42
+ - get_formula
43
+ - get_spaced_formula
44
+ - get_mol_wt
45
+ - get_exact_mass
46
+ - get_total_charge
47
+ - get_total_spin_multiplicity
48
+ - get_dimension
49
+ - get_coordinates
50
+ - get_sssr
51
+ - get_lssr
52
+ - automatic_formal_charge
53
+ - automatic_partial_charge
54
+ - set_title
55
+ - set_formula
56
+ - set_energy
57
+ - set_dimension
58
+ - set_total_charge
59
+ - set_total_spin_multiplicity
60
+ - set_internal_coord
61
+ - set_automatic_formal_charge
62
+ - set_automatic_partial_charge
63
+ - set_aromatic_perceived
64
+ - set_sssrperceived
65
+ - set_lssrperceived
66
+ - set_ring_atoms_and_bonds_perceived
67
+ - set_atom_types_perceived
68
+ - set_ring_types_perceived
69
+ - set_chains_perceived
70
+ - set_chirality_perceived
71
+ - set_partial_charges_perceived
72
+ - set_hybridization_perceived
73
+ - set_implicit_valence_perceived
74
+ - set_kekule_perceived
75
+ - set_closure_bonds_perceived
76
+ - set_hydrogens_added
77
+ - set_corrected_for_ph
78
+ - set_aromatic_corrected
79
+ - set_spin_multiplicity_assigned
80
+ - set_flags
81
+ - unset_aromatic_perceived
82
+ - unset_sssrperceived
83
+ - unset_ring_types_perceived
84
+ - unset_partial_charges_perceived
85
+ - unset_implicit_valence_perceived
86
+ - unset_hydrogens_added
87
+ - unset_flag
88
+ - renumber_atoms
89
+ - set_coordinates
90
+ - to_inertial_frame
91
+ - translate
92
+ - rotate
93
+ - kekulize
94
+ - perceive_kekule_bonds
95
+ - new_perceive_kekule_bonds
96
+ - delete_hydrogens
97
+ - delete_non_polar_hydrogens
98
+ - delete_hydrogen
99
+ - add_hydrogens
100
+ - add_polar_hydrogens
101
+ - strip_salts
102
+ - separate
103
+ - get_next_fragment
104
+ - convert_dative_bonds
105
+ - correct_for_ph
106
+ - assign_spin_multiplicity
107
+ - set_is_pattern_structure
108
+ - center
109
+ - set_torsion
110
+ - find_sssr
111
+ - find_lssr
112
+ - find_ring_atoms_and_bonds
113
+ - find_chiral_centers
114
+ - find_children
115
+ - find_largest_fragment
116
+ - contig_frag_list
117
+ - align
118
+ - connect_the_dots
119
+ - perceive_bond_orders
120
+ - find_angles
121
+ - find_torsions
122
+ - get_gtdvector
123
+ - get_givector
124
+ - get_gidvector
125
+ - has_2d
126
+ - has_3d
127
+ - has_non_zero_coords
128
+ - has_aromatic_perceived
129
+ - has_sssrperceived
130
+ - has_lssrperceived
131
+ - has_ring_atoms_and_bonds_perceived
132
+ - has_atom_types_perceived
133
+ - has_ring_types_perceived
134
+ - has_chirality_perceived
135
+ - has_partial_charges_perceived
136
+ - has_hybridization_perceived
137
+ - has_implicit_valence_perceived
138
+ - has_kekule_perceived
139
+ - has_closure_bonds_perceived
140
+ - has_chains_perceived
141
+ - has_hydrogens_added
142
+ - has_aromatic_corrected
143
+ - is_corrected_for_ph
144
+ - has_spin_multiplicity_assigned
145
+ - is_chiral
146
+ - empty
147
+ - num_conformers
148
+ - set_conformers
149
+ - add_conformer
150
+ - set_conformer
151
+ - copy_conformer
152
+ - delete_conformer
153
+ - get_conformer
154
+ - set_energies
155
+ - get_energies
156
+ - get_energy
157
+ - begin_conformer
158
+ - next_conformer
159
+ - get_conformers
160
+ - begin_atoms
161
+ - end_atoms
162
+ - begin_bonds
163
+ - end_bonds
164
+ - begin_residues
165
+ - end_residues
166
+ - begin_atom
167
+ - next_atom
168
+ - begin_bond
169
+ - next_bond
170
+ - begin_residue
171
+ - next_residue
172
+ - begin_internal_coord
173
+ - next_internal_coord
174
+ - clear
175
+ - do_transformations
176
+ - has_data
177
+ - delete_data
178
+ - clone_data
179
+ - data_size
180
+ - get_all_data
181
+ - get_data
182
+ - begin_data
183
+ - end_data
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'openbabel'
5
+ include OpenBabel
6
+
7
+ if ARGV.size == 0
8
+ puts "smiles and smart"
9
+ exit
10
+ end
11
+
12
+ (smiles_string, smart_search) = ARGV
13
+
14
+ smi_to_svg = OBConversion.new
15
+ smi_to_svg.set_in_and_out_formats("smi", "svg")
16
+
17
+ obmol = OBMol.new
18
+
19
+ smi_to_svg.read_string(obmol, smiles_string)
20
+ obmol.add_hydrogens
21
+
22
+ p obmol.get_formula
23
+ svg_string = smi_to_svg.write_string(obmol).rstrip
24
+ File.write("before.svg", svg_string)
25
+
26
+ bond_triplets = []
27
+ (1..obmol.num_bonds).each do |i|
28
+ bond = obmol.get_bond(i)
29
+ if bond
30
+ bond_triplets << [bond.get_begin_atom, bond.get_end_atom, bond]
31
+ end
32
+ end
33
+
34
+ (1..obmol.num_atoms).each do |i|
35
+ atom = obmol.get_atom(i)
36
+ if atom.matches_smarts("C(=O)CC")
37
+ bond_triplet = bond_triplets.find {|triplet| triplet.include?(atom) }
38
+ obmol.delete_bond(bond_triplet.last)
39
+ atom.begin_nbr_atom
40
+ atom.next_nbr_atom
41
+ break
42
+ end
43
+ end
44
+
45
+ molecules = obmol.separate
46
+ molecules.each_with_index do |mol,i|
47
+ puts "mol #{i}"
48
+ p mol.get_formula
49
+ p mol.add_hydrogens
50
+ p mol.get_formula
51
+ svg_string = smi_to_svg.write_string(mol).rstrip
52
+ File.write("after_#{i}.svg", svg_string)
53
+ end
54
+
55
+
56
+
57
+ #puts (obmol.methods - Object.new.methods).map(&:to_s).to_yaml
58
+ #p obmol.exact_mass
59
+
60
+
61
+
62
+
63
+ =begin
64
+ $obConversion->ReadFile($obMol, $filename);
65
+
66
+ for (1..$obMol->NumAtoms()) {
67
+ $atom = $obMol->GetAtom($_);
68
+ # look to see if this atom is a thiophene sulfur atom
69
+ if ($atom->MatchesSMARTS("[#16D2]([#6D3H1])[#6D3H1]")) {
70
+ $sulfurIdx = $atom->GetIdx();
71
+ # see if this atom is one of the carbon atoms bonded to a thiophene sulfur
72
+ } elsif ($atom->MatchesSMARTS("[#6D3H1]([#16D2][#6D3H1])[#6]") ) {
73
+ if ($c2Idx == 0) { $c2Idx = $atom->GetIdx(); }
74
+ else {$c5Idx = $atom->GetIdx(); }
75
+ }
76
+ }
77
+
78
+ # Get the actual atom objects -- indexing will change as atoms are added and deleted!
79
+ $sulfurAtom = $obMol->GetAtom($sulfurIdx);
80
+ $c2Atom = $obMol->GetAtom($c2Idx);
81
+ $c5Atom = $obMol->GetAtom($c5Idx);
82
+
83
+ $obMol->DeleteAtom($sulfurAtom);
84
+
85
+ $obMol->DeleteHydrogens($c2Atom);
86
+ $obMol->DeleteHydrogens($c5Atom);
87
+
88
+ $c2Atom->SetAtomicNum(1);
89
+ $c5Atom->SetAtomicNum(1);
90
+
91
+ $obConversion->WriteFile($obMol, "$filename.mol");
92
+
93
+ =end
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trollop'
4
+
5
+ require 'bsearch'
6
+
7
+ require 'mspire/lipid/ion'
8
+ require 'mspire/lipid/modification'
9
+ require 'mspire/lipid_maps'
10
+
11
+ parser = Trollop::Parser.new do
12
+ banner "usage: #{File.basename(__FILE__)} <lipidmaps.tsv> <m/z> ..."
13
+ banner ""
14
+ opt :top_n, "how many closest ions to print", :default => 3
15
+ banner ""
16
+ text "modifications: (at least 1 charged mod is required)"
17
+ text "will search for i down to 1 mod: "
18
+ #opt :newmod, "<name>:<formula>:<charge>:<L/G>:<#occurences> L/G=loss or gain", :type => :string, :multi => true
19
+ opt :lithium, "Li+ gain", :default => 0
20
+ opt :sodium, "Na+ gain", :default => 0
21
+ opt :ammonium, "", :default => 0
22
+ opt :ammonia_loss, "search for i down to 1 ammonia losses", :default => 0
23
+ opt :carbon_dioxide_loss, "search for i down to 1 CO2 losses", :default => 0
24
+ opt :proton_gain, "search for i down to 1 proton additions", :default => 0
25
+ opt :proton_loss, "search for i down to 1 proton losses", :default => 0
26
+ opt :water_loss, "if used, *all* mods are also considered with i down to 0 water losses", :default => 0
27
+ opt :acetate, "search for i down to 0 water losses", :default => 0
28
+ text ""
29
+ text "other:"
30
+ opt :textfile, "a text file with m/z values, one per line", :type => String
31
+ opt :lower_bound, "use lower bound searching (requires m/z's to be in sorted order)"
32
+ opt :sort, "sorts the m/z's"
33
+ end
34
+
35
+ opts = parser.parse(ARGV)
36
+
37
+ if ARGV.size == 0
38
+ parser.educate
39
+ exit
40
+ end
41
+
42
+ CHARGED_MODS = [:lithium, :sodium, :ammonium, :proton_gain, :proton_loss]
43
+ UNCHARGED_MODS = [:water_loss, :carbon_dioxide_loss, :ammonia_loss]
44
+
45
+ unless CHARGED_MODS.any? {|key| opts[key] > 0 }
46
+ puts "*" * 78
47
+ puts "ArgumentError: need at least one charged mod!"
48
+ puts "*" * 78
49
+ parser.educate
50
+ exit
51
+ end
52
+
53
+ (lipidmaps, *actual_mzs) = ARGV
54
+
55
+ if f=opts[:textfile]
56
+ actual_mzs = IO.readlines(f).map(&:chomp)
57
+ end
58
+
59
+ actual_mzs.map!(&:to_f)
60
+
61
+ unless actual_mzs.size > 0
62
+ STDERR.puts "NO m/z values given!!!"
63
+ parser.educate
64
+ exit
65
+ end
66
+
67
+ $VERBOSE = opts[:verbose]
68
+
69
+ LipidMod = Mspire::Lipid::Modification
70
+
71
+ mods = {
72
+ proton_gain: LipidMod.new(:proton),
73
+ water_loss: LipidMod.new(:water, :loss => true),
74
+ lithium: LipidMod.new(:lithium),
75
+ sodium: LipidMod.new(:sodium),
76
+ ammonium: LipidMod.new(:ammonium),
77
+ proton_loss: LipidMod.new(:proton, :loss => true),
78
+ ammonia_loss: LipidMod.new(:ammonium, :loss => true),
79
+ carbon_dioxide_loss: LipidMod.new(:carbon_dioxide, :loss => true),
80
+ }
81
+
82
+ lipids = Mspire::LipidMaps.parse_file(lipidmaps)
83
+
84
+ ions = []
85
+ lipids.each do |lipid|
86
+ CHARGED_MODS.each do |key|
87
+ if opts[key] > 0
88
+ opts[key].downto(1) do |num_charge_mod|
89
+ mods_to_use = [mods[key]] * num_charge_mod
90
+ UNCHARGED_MODS.each do |umod|
91
+ opts[umod].downto(0) do |i|
92
+ ions << Mspire::Lipid::Ion.new(lipid, mods_to_use + ([mods[umod]]*i))
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ ions.sort_by!(&:mz)
101
+
102
+ PPM = 1500
103
+
104
+ cats = %w(exp_mz rank ppm ppm_abs category lm_id common_name modifications)
105
+ puts cats.join("\t")
106
+
107
+ actual_mzs.sort! if opts[:sort]
108
+
109
+ starting_i = 0
110
+ len = ions.size
111
+
112
+ actual_mzs.each do |exp_mz|
113
+
114
+ range = ions.bsearch_range(starting_i...len) do |ion|
115
+ part_diff = ((exp_mz - ion.mz)/ion.mz)*1e6
116
+ if part_diff.abs <= PPM then 0
117
+ elsif part_diff < PPM then 1
118
+ else
119
+ -1
120
+ end
121
+ end
122
+
123
+ starting_i = range.begin if opts[:lower_bound]
124
+
125
+ closest = ions[range].sort_by {|ion| [(ion.mz - exp_mz).abs, ion.mz] }
126
+ row = [exp_mz]
127
+ closest[0,opts[:top_n]].each_with_index do |ion,i|
128
+ rank = i + 1
129
+ ppm = ((exp_mz - ion.mz) / ion.mz) * 1e6
130
+ lipid = ion.lipid
131
+ row.push( rank, ppm, ppm.abs, lipid.category, lipid.lm_id, lipid.common_name, ion.modifications.map(&:charged_formula_string).join(", ") )
132
+ end
133
+ puts row.join("\t")
134
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ require 'mspire/lipid'
4
+ require 'mspire/lipid/modification'
5
+ require 'mspire/lipid/ion'
6
+ require 'mspire/mass/element'
7
+ require 'mspire/mass/common'
8
+
9
+ module MSS
10
+ CO2 = ( %w(C O O).map {|e| Mspire::Mass::Element::MONO_STRING[e] }.reduce(:+) )
11
+ H2O = Mspire::Mass::Common::MONO_STRING['H2O']
12
+ PROTON_LOSS = Mspire::Lipid::Modification.new(:proton, :loss => true)
13
+ end
14
+
15
+
16
+ describe Mspire::Lipid::Ion do
17
+
18
+ before do
19
+ lipid = Mspire::Lipid.new("LMGP02010009", "PE(16:0/18:1(9Z))", "1-hexadecanoyl-2-(9Z-octadecenoyl)-sn-glycero-3-phosphoethanolamine", 'C39H76NO8P', 717.5308, 'Glycerophospholipids [GP]', 'Glycerophosphoethanolamines [GP02]', 'Diacylglycerophosphoethanolamines [GP0201]', '7850611', 'FHQVHHIBKUMWTI-OTMQOFQLSA-N')
20
+ proton = Mspire::Lipid::Modification.new(:proton)
21
+ proton_loss = Mspire::Lipid::Modification.new(:proton, :loss => true)
22
+ h2o_loss = Mspire::Lipid::Modification.new(:water, :loss => true)
23
+ @plus1_less_h20 = Mspire::Lipid::Ion.new(lipid, [proton, h2o_loss])
24
+ @plus2_less_h20 = Mspire::Lipid::Ion.new(lipid, [proton, proton, h2o_loss])
25
+ @minus1_less_h20 = Mspire::Lipid::Ion.new(lipid, [proton_loss, h2o_loss])
26
+ end
27
+
28
+ it 'calculates the correct m/z' do
29
+ @plus1_less_h20.mz.should be_within(1e-5).of(700.52751178307)
30
+ @plus2_less_h20.mz.should be_within(1e-5).of(350.76739412492003)
31
+ @minus1_less_h20.mz.should be_within(1e-5).of(698.5129588842301)
32
+ end
33
+
34
+ it 'calculates the correct formula' do
35
+ @plus1_less_h20.formula.to_s.should == "C39H75NO7P"
36
+ @plus1_less_h20.charge.should == 1
37
+
38
+ @plus2_less_h20.formula.to_s.should == "C39H76NO7P"
39
+ @plus2_less_h20.charge.should == 2
40
+ @minus1_less_h20.formula.to_s.should == "C39H73NO7P"
41
+ @minus1_less_h20.charge.should == -1
42
+ end
43
+
44
+ describe 'predicting ms/ms fragments' do
45
+ describe 'predicting simple fatty acyls' do
46
+ xit 'hexadecanoic acid' do
47
+ lipid = Mspire::Lipid.new('LMFA01010001', 'Palmitic acid', 'hexadecanoic acid', 'C16H32O2', 256.24, 'Fatty Acyls [FA]', 'Fatty Acids and Conjugates [FA01]', 'Straight chain fatty acids [FA0101]')
48
+
49
+ ion = Mspire::Lipid::Ion.new(lipid, [MSS::PROTON_LOSS])
50
+ frags = [ion.mz - MSS::H2O]
51
+ frags << ion.mz - MSS::CO2
52
+ frags << ion.mz - (MSS::H2O + MSS::CO2)
53
+
54
+ mzs = ion.predict_fragment_mzs
55
+ mzs.should be_an(Array)
56
+ mzs.sort.should == frags.sort
57
+ end
58
+
59
+ # WORKING THIS GUY OUT!!!!!!
60
+ xit '11-methyl-9S-hydroxy-13E-hexadecenoic acid' do
61
+ lipid = Mspire::Lipid.new(nil, 'Made Up', '11-methyl-9S-hydroxy-13E-hexadecenoic acid', 'C17H32O3', 284.23514488492003, 'Fatty Acyls [FA]', 'Fatty Acids and Conjugates [FA01]', 'Branched fatty acids [FA0102]')
62
+ ion = Mspire::Lipid::Ion.new(lipid, [MSS::PROTON_LOSS])
63
+
64
+ # one water loss
65
+ frags = [ion.mz - MSS::H2O]
66
+
67
+ # two water loss
68
+ frags << (ion.mz - (2*MSS::H2O))
69
+
70
+ # CO2 loss
71
+ frags << (ion.mz - MSS::CO2)
72
+
73
+ # CO2 + H20 loss
74
+ frags << ion.mz - (MSS::H2O + MSS::CO2)
75
+
76
+ oh_frag_mass = 140.12011513268
77
+ frag1 = (ion.mz - oh_frag_mass)
78
+
79
+ frags << frag1 - MSS::H2O
80
+
81
+ frags << frag1 - MSS::CO2
82
+
83
+ frags << frag1 - (MSS::H2O + MSS::CO2)
84
+
85
+ mzs = ion.predict_fragment_mzs
86
+ #mzs.sort.should == frags.sort
87
+ end
88
+
89
+ end
90
+
91
+ it 'predicts simple glycerophosopholipids' do
92
+ end
93
+
94
+ end
95
+
96
+ end