rubabel 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e50e4f083ed06992600b2b86767d0d3a2b00fcf
4
- data.tar.gz: e2b4f65a73450c8336b31d650c3c4bfff6981942
3
+ metadata.gz: 8c407acb50267d5d801e3b17c7ca6c9090f09935
4
+ data.tar.gz: dc4f917d5688fd3be0b593bb34d3f25edce5b362
5
5
  SHA512:
6
- metadata.gz: a1e131cbc6b178f52ea340acc11ca1b48b606846cdfe3f21609e9578c7b7ecbd9f5590655c988a1098bc7356e9089a930c5570dc359df09f6384f4349d69c65f
7
- data.tar.gz: e626626e6f236810a4e46e41bdcf63da8927e8bfe0bc2d8b271c915ba2fc48dc898012eccf0c535f2b5c95dd1281e3be2c1d99c27c53f9779811613da191629b
6
+ metadata.gz: 618fb4a2d529cdbf7c3ec1ae1fc85088a92cd4b554d43f95bfa527bb15c1cae946a45474c1553db0a4ab456cf70a7cd5c6566a47856a0a4f4656c251378ff067
7
+ data.tar.gz: eeb366cb6d73da968fd54dae44e6f64d3edc485a0913742713846ed7b28dabdb89708533d145dfc6ad6bf6b164a6584f8288120e45dc19e82c7af9e9410fa8a2
@@ -2,7 +2,6 @@ require 'openbabel'
2
2
  require 'rubabel'
3
3
  require 'rubabel/atom'
4
4
  require 'rubabel/bond'
5
- require 'rubabel/molecule/fragmentable'
6
5
  require 'stringio'
7
6
  require 'mini_magick'
8
7
 
@@ -1,3 +1,3 @@
1
1
  module Rubabel
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubabel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John T. Prince
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-07 00:00:00.000000000 Z
11
+ date: 2013-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openbabel
@@ -139,8 +139,7 @@ dependencies:
139
139
  description: Ruby interface to the OpenBabel ruby bindings similar to pybel
140
140
  email:
141
141
  - jtprince@gmail.com
142
- executables:
143
- - fragmenter.rb
142
+ executables: []
144
143
  extensions: []
145
144
  extra_rdoc_files: []
146
145
  files:
@@ -152,7 +151,6 @@ files:
152
151
  - README.md
153
152
  - Rakefile
154
153
  - VERSION
155
- - bin/fragmenter.rb
156
154
  - lib/rubabel.rb
157
155
  - lib/rubabel/atom.rb
158
156
  - lib/rubabel/bond.rb
@@ -160,7 +158,6 @@ files:
160
158
  - lib/rubabel/core_ext/putsv.rb
161
159
  - lib/rubabel/fingerprint.rb
162
160
  - lib/rubabel/molecule.rb
163
- - lib/rubabel/molecule/fragmentable.rb
164
161
  - lib/rubabel/molecule_data.rb
165
162
  - lib/rubabel/pm.rb
166
163
  - lib/rubabel/smarts.rb
@@ -186,7 +183,6 @@ files:
186
183
  - spec/chemistry_toolkit_rosetta/tpsa.tab
187
184
  - spec/rubabel/atom_spec.rb
188
185
  - spec/rubabel/bond_spec.rb
189
- - spec/rubabel/molecule/fragmentable_spec.rb
190
186
  - spec/rubabel/molecule_data_spec.rb
191
187
  - spec/rubabel/molecule_spec.rb
192
188
  - spec/rubabel_spec.rb
@@ -236,7 +232,6 @@ test_files:
236
232
  - spec/chemistry_toolkit_rosetta/tpsa.tab
237
233
  - spec/rubabel/atom_spec.rb
238
234
  - spec/rubabel/bond_spec.rb
239
- - spec/rubabel/molecule/fragmentable_spec.rb
240
235
  - spec/rubabel/molecule_data_spec.rb
241
236
  - spec/rubabel/molecule_spec.rb
242
237
  - spec/rubabel_spec.rb
@@ -1,67 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'trollop'
4
- require 'rubabel'
5
- require 'rubabel/molecule/fragmentable'
6
-
7
- default_ph = 2.5
8
-
9
- Fragment = Struct.new(:frag, :id, :title, :mz, :mass, :charge, :smiles, :pairing)
10
-
11
- parser = Trollop::Parser.new do
12
- banner "usage: #{File.basename($0)} [OPTIONS|RULES] <SMARTS> ..."
13
- text "\noptions:"
14
- opt :ph, "the pH to use (experimental option)", :default => default_ph
15
- opt :images, "print out svg images of fragments"
16
- opt :format, "format of the molecules", :default => 'smiles'
17
- #opt :uniq, "no repeated fragments", :default => false
18
- text "\nrules:"
19
- Rubabel::Molecule::Fragmentable::RULES.each do |rule|
20
- opt rule, rule.to_s.gsub("_",' ')
21
- end
22
- text "\nexample:"
23
- text "fragmenter.rb -xeh 'CCC(=O)OCCC' 'CCC(=O)OCCC(=O)O'"
24
- end
25
-
26
- options = parser.parse(ARGV)
27
- opts = {rules: []}
28
- opts[:uniq] = options.delete(:uniq)
29
- ph = options.delete(:ph)
30
- opts[:rules] = Rubabel::Molecule::Fragmentable::RULES.map do |rule|
31
- rule if options["#{rule}_given".to_sym]
32
- end.compact
33
-
34
- if ARGV.size == 0
35
- parser.educate && exit
36
- end
37
-
38
- ARGV.each do |smiles|
39
- mol = Rubabel[smiles, options[:format].to_sym]
40
- puts "\nmolecule: #{mol.csmiles}"
41
- mol.correct_for_ph!(ph)
42
- puts "at ph #{ph}: #{mol.csmiles}"
43
- fragment_sets = mol.fragment(opts)
44
- puts %w(mz mass charge title smiles pairing).join("\t")
45
- frags = []
46
- fragment_sets.each_with_index do |frag_set,i|
47
- frag_set.each_with_index do |frag,j|
48
- unless frag.charge == 0
49
- mz = (frag.mass / frag.charge).round(5)
50
- end
51
-
52
- frag.title = "#{i}-#{j}pair_" + (mz ? "#{mz}_mz" : "#{frag.mass.round(3)}_Mass")
53
- frag_obj = Fragment.new(frag, frag.title, frag.title, mz, frag.exact_mass, frag.charge, frag.csmiles, i)
54
- frags << frag_obj
55
- end
56
- end
57
- frags = frags.sort_by {|frag| [-frag.charge, frag.mz] }
58
- if options[:images]
59
- frags.each do |frag|
60
- fn = "#{frag.title}.png"
61
- frag.frag.write(fn)
62
- end
63
- end
64
- frags.each do |frag|
65
- puts [:mz, :mass, :charge, :title, :smiles, :pairing].map {|cat| frag.send(cat) }.join("\t")
66
- end
67
- end
@@ -1,162 +0,0 @@
1
- require 'set'
2
- require 'rubabel/core_ext/putsv'
3
- require 'rubabel/core_ext/enumerable'
4
-
5
- module Rubabel
6
- class Molecule
7
- module Fragmentable
8
-
9
- #RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh]
10
- RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh, :oxhpd]
11
-
12
- DEFAULT_OPTIONS = {
13
- rules: RULES,
14
- errors: :remove,
15
- # return only the set of unique fragments
16
- uniq: false,
17
- }
18
-
19
- # molecules and fragments should all have hydrogens added (add_h!)
20
- # before calling this method
21
- #
22
- # For instance, water loss with double bond formation is not allowable
23
- # for NCC(O)CC => CCC=C[NH2+], presumably because of the lone pair and
24
- # double bond resonance.
25
- def allowable_fragmentation?(frags)
26
- self.num_atoms(true) == frags.reduce(0) {|cnt,fr| cnt + fr.num_atoms(true) }
27
- end
28
-
29
- # splits the molecule between the carbon and carbon_nbr, adds a double
30
- # bond between the carbon and oxygen, and moves whatever was on the
31
- # oxygen (e.g., an OH or a charge) to the carbon_nbr. Returns two new
32
- # molecules.
33
- def carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
34
- appendage = oxygen.atoms.find {|a| a.el != :C }
35
- if oxygen.charge != 0
36
- ocharge = oxygen.charge
37
- end
38
- nmol = self.dup
39
- new_oxygen = nmol.atom(oxygen.id)
40
- new_carbon = nmol.atom(carbon.id)
41
- new_carbon_nbr = nmol.atom(carbon_nbr.id)
42
- new_appendage = nmol.atom(appendage.id) if appendage
43
- nmol.delete_bond(new_carbon.get_bond(new_carbon_nbr))
44
- if new_appendage
45
- nmol.delete_bond(new_oxygen.get_bond(new_appendage))
46
- nmol.add_bond!(new_carbon_nbr, new_appendage)
47
- end
48
- if ocharge
49
- new_carbon_nbr.charge += ocharge
50
- new_oxygen.charge -= ocharge
51
- end
52
- new_carbon.get_bond(new_oxygen).bond_order = 2
53
- nmol.split
54
- end
55
-
56
- # breaks the bond and gives the electrons to the oxygen
57
- def carbon_oxygen_esteal(carbon, oxygen)
58
- nmol = self.dup
59
- ncarbon = nmol.atom(carbon.id)
60
- noxygen = nmol.atom(oxygen.id)
61
-
62
- is_carboxyl = noxygen.carboxyl_oxygen?
63
-
64
- nmol.delete_bond(ncarbon, noxygen)
65
- ncarbon.remove_a_hydride!
66
- noxygen.remove_a_proton!
67
- nmol.split
68
- end
69
-
70
- # returns the duplicated molecule and the equivalent atoms
71
- def dup_molecule(atoms=[])
72
- nmol = self.dup
73
- [nmol, atoms.map {|old_atom| nmol.atom(old_atom.id) }]
74
- end
75
-
76
- # returns molecules created from splitting between the electrophile and
77
- # the center and where the bond order is increased between the center
78
- # and center_nbr
79
- def break_with_double_bond(electrophile, center, center_nbr)
80
- (nmol, (nele, ncarb, ncarb_nbr)) = self.dup_molecule([electrophile, center, center_nbr])
81
- nmol.delete_bond(nele, ncarb)
82
- ncarb_nbr.get_bond(ncarb) + 1
83
- nmol.split
84
- end
85
-
86
- # an empty array is returned if there are no fragments generated.
87
- # Hydrogens are added at a pH of 7.4, unless they have already been
88
- # added.
89
- #
90
- # :rules => queryable by :include? set of rules
91
- # :uniq => false
92
- # :errors => :remove | :fix | :ignore (default is :remove)
93
- def fragment(opts={})
94
- only_uniqs = true
95
- opts = DEFAULT_OPTIONS.merge(opts)
96
- opts[:rules].each do |rule|
97
- raise ArgumentError, "bad rule: #{rule}" unless RULES.include?(rule)
98
- end
99
-
100
- had_hydrogens = self.h_added?
101
- self.correct_for_ph!(7.4) unless had_hydrogens
102
- self.remove_h!
103
-
104
- fragment_sets = []
105
-
106
- if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
107
- self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
108
- carbon.atoms.select {|a| a.el == :C }.each do |carbon_nbr|
109
- fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
110
- end
111
- end
112
- end
113
- if opts[:rules].any? {|r| [:oxe].include?(r) }
114
- self.each_match("C-O", only_uniqs) do |carbon, oxygen|
115
- fragment_sets << carbon_oxygen_esteal(carbon, oxygen)
116
- end
117
- end
118
- # right now implemented so that a beta hydrogen has to be availabe for
119
- # extraction
120
- if opts[:rules].any? {|r| [:oxh].include?(r) }
121
- self.each_match("C[C,O]-O", only_uniqs) do |beta_c, center, oxygen|
122
- next unless beta_c.hydrogen_count > 0
123
- fragment_sets << break_with_double_bond(oxygen, center, beta_c)
124
- end
125
- end
126
- if opts[:rules].any? {|r| [:oxhpd].include?(r) }
127
- self.each_match("C-O-P-O", only_uniqs) do |carbon, alc_oxy, phosphate, beta_carb_oxy|
128
- next unless beta_carb_oxy.hydrogen_count > 0
129
- frag_set = break_with_double_bond(alc_oxy, phosphate, beta_carb_oxy)
130
- frag_set.map! &:convert_dative_bonds!
131
- fragment_sets << frag_set
132
- end
133
- end
134
- if opts[:rules].any? {|r| [:oxepd].include?(r) }
135
- self.each_match("P-O-C", only_uniqs) do |phosphate, oxygen, carbon|
136
- frag_set = carbon_oxygen_esteal(phosphate, oxygen)
137
- frag_set.map! &:convert_dative_bonds!
138
- fragment_sets << frag_set
139
- end
140
- end
141
-
142
- case opts[:errors]
143
- when :remove
144
- fragment_sets.select! {|set| allowable_fragmentation?(set) }
145
- when :fix
146
- raise NotImplementedError
147
- when :ignore # do nothing
148
- end
149
-
150
- self.remove_h!
151
- if opts[:uniq]
152
- # TODO: impelent properly
153
- raise NotImplementedError
154
- #fragment_sets = fragment_sets.uniq_by(&:csmiles)
155
- end
156
-
157
- fragment_sets
158
- end
159
- end
160
- include Fragmentable
161
- end
162
- end # Rubabel
@@ -1,199 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'rubabel'
4
-
5
- $VERBOSE = nil
6
-
7
- describe Rubabel::Molecule::Fragmentable do
8
-
9
- # :peroxy_to_carboxy
10
- # :oxygen_asymmetric_sp3, :nitrogen_asymmetric_sp3,
11
- # :internal_phosphoester
12
-
13
- describe 'fragmentation rules' do
14
- # coenzyme: CC1=CC(=O)C=CC1=O
15
- # 2-methylcyclohexa-2,5-diene-1,4-dione
16
-
17
- #let(:test_mol) { "COP(=O)(O)OCNCOCC(OO)C(=O)O" }
18
-
19
- it 'raises an error for a bad rule' do
20
- mol = Rubabel["CCNC"]
21
- expect { mol.fragment(rules: [:wackiness]) }.to raise_error
22
- end
23
-
24
- describe 'cod: carbonyl appendage dump' do
25
- # a primary oxygen or peroxide => C=O appendage dump
26
-
27
- specify 'cod: primary alcohol' do
28
- mol = Rubabel["NCC(O)CC"]
29
- frags = mol.fragment(rules: [:cod])
30
- frags.flatten(1).map(&:csmiles).should == ["C[NH3+]", "CCC=O", "C([NH3+])C=O", "CC"]
31
- end
32
-
33
- specify 'peroxide' do
34
- mol = Rubabel["NCC(OO)CC"]
35
- frags = mol.fragment(rules: [:codoo])
36
- frags.flatten(1).map(&:csmiles).should == ["OC[NH3+]", "CCC=O", "C([NH3+])C=O", "CCO"]
37
- end
38
-
39
- specify 'cod: carboxylate' do
40
- mol = Rubabel["CCC(=O)O"]
41
- pieces = mol.fragment(rules: [:cod])
42
- pieces.flatten(1).map(&:csmiles).should == ["[CH2-]C", "O=C=O"]
43
- end
44
-
45
- specify 'cod: carboxylic acid' do
46
- mol = Rubabel["CCC(=O)O"]
47
- mol.add_h!(1.5)
48
- pieces = mol.fragment(rules: [:cod])
49
- pieces.flatten(1).map(&:csmiles).should == ["CC", "O=C=O"]
50
- end
51
- end
52
-
53
- describe 'oxe: oxygen electron stealing' do
54
- # oxygen just steals the electron pair it is attached to. This
55
- # typically results in a negatively charged oxygen and a positively
56
- # charged carbo-cation.
57
- specify 'ether to ions' do
58
- mol = Rubabel["CCOCCN"]
59
- frag_set = mol.fragment(rules: [:oxe])
60
- frags = frag_set.first
61
- frags.first.csmiles.should == "C[CH2+]"
62
- frags.last.csmiles.should == '[O-]CC[NH3+]'
63
- frags.first.formula.should == 'C2H5+'
64
- frags.last.formula.should == 'C2H7NO'
65
- frags.first.exact_mass.should be_within(1e-6).of(29.03912516)
66
- frags.last.exact_mass.should be_within(1e-6).of(61.052763849)
67
- end
68
-
69
- specify 'ester to ions' do
70
- mol = Rubabel["CCOC(=O)CCN"]
71
- frag_set = mol.fragment(rules: [:oxe])
72
- ff = frag_set.first
73
- ff.first.csmiles.should == 'C[CH2+]'
74
- ff.last.csmiles.should == '[O-]C(=O)CC[NH3+]'
75
- ff.first.formula.should == "C2H5+"
76
-
77
- ff.last.formula.should == "C3H7NO2"
78
- ff.first.exact_mass.should be_within(1e-6).of(29.03912516035)
79
- ff.last.exact_mass.should be_within(1e-6).of(89.04767846841)
80
- end
81
-
82
- specify 'carboxyl group' do
83
- mol = Rubabel["CCC(=O)O"]
84
- frag_set = mol.fragment(rules: [:oxe])
85
- ff = frag_set.first
86
- ff.first.csmiles.should == 'CC[C+]=O'
87
- # this is a carboxylate oxygen that falls off
88
- ff.last.csmiles.should == '[O-2]'
89
- #ff.first.formula.should == "C3H5O"
90
- ff.first.formula.should == "C3H5O+"
91
- ff.first.exact_mass.should be_within(1e-6).of(57.034039779909996)
92
- #ff.last.formula.should == "O"
93
- ff.last.formula.should == "O--"
94
- end
95
-
96
- specify 'phosphodiester' do
97
- mol = Rubabel["CC(COP(=O)([O-])OCCN"]
98
- frag_set = mol.fragment(rules: [:oxepd])
99
- ff = frag_set.first
100
- ff.first.csmiles.should == '[O-]CCC'
101
- #ff.last.csmiles.should == '[NH3+]CCO[P](=O)=O'
102
- ff.last.csmiles.should == "[NH3+]CCOP(=O)=O"
103
- #ff.first.formula.should == 'C3H7O'
104
- ff.first.formula.should == 'C3H7O-'
105
- ff.first.exact_mass.should be_within(1e-6).of(59.049689844)
106
- #ff.last.formula.should == 'C2H7NO3P'
107
- ff.last.formula.should == 'C2H7NO3P+'
108
- ff.last.exact_mass.should be_within(1e-6).of(124.016354719)
109
-
110
- mol = Rubabel["CCCOP(=O)(OCC[N+](C)(C)C)[O-]"]
111
- frag_set = mol.fragment(rules: [:oxepd, :oxe])
112
- # some of these don't like right on first inspection, but that is
113
- # because we 'converted dative bonds' meaning + and - next to each
114
- # other are allowed to cancel one another out!
115
- frag_set.size.should == 4
116
- mols = frag_set.flatten
117
- mols.map(&:csmiles).should == ["CC[CH2+]", "[O-]P(=O)(OCC[N+](C)(C)C)[O-]", "CCCOP(=O)([O-])[O-]", "[CH2+]C[N+](C)(C)C", "[O-]CCC", "O=P(=O)OCC[N+](C)(C)C", "CCCOP(=O)=O", "[O-]CC[N+](C)(C)C"]
118
- mols.map(&:formula).should == ["C3H7+", "C5H13NO4P-", "C3H7O4P--", "C5H13N++", "C3H7O-", "C5H13NO3P+", "C3H7O3P", "C5H13NO"]
119
- mols.map(&:exact_mass).zip([43.05477522449, 182.05821952995, 138.00819533273, 87.10479942171, 59.04968984405, 166.06330491039, 122.01328071317, 103.09971404127]) do |act, exp|
120
- act.should be_within(1e-6).of(exp)
121
- end
122
-
123
- end
124
- end
125
-
126
- # this is really a subset of oxygen bond stealing: if the negatively
127
- # charged oxygen can rip off a nearby proton, it will.
128
- describe 'oxh: oxygen alpha/beta/gamma hydrogen stealing' do
129
- specify 'primary alcohol giving water loss' do
130
- mol = Rubabel["CC(O)CCN"]
131
- frags = mol.fragment(rules: [:oxh])
132
- ff = frags.first
133
- ff.first.csmiles.should == 'C=CCC[NH3+]'
134
- ff.last.csmiles.should == 'O'
135
- ll = frags.last
136
- ll.first.csmiles.should == 'CC=CC[NH3+]'
137
- ll.last.csmiles.should == 'O'
138
- #ff.first.formula.should == 'C4H10N'
139
- ff.first.formula.should == 'C4H10N+'
140
- ff.first.exact_mass.should be_within(1e-6).of(72.0813243255)
141
- end
142
-
143
- specify 'peroxide carbonyl formation (or peroxide formation [that what we want??])' do
144
- # do we really see peroxide formation? Tamil didn't include this in
145
- # the rules but it follows from the broad way for creating these
146
- # rules. Can prohibit peroxide formation in future if necessary...
147
- mol = Rubabel["CC(OO)CCN"]
148
- frags = mol.fragment(rules: [:oxh])
149
- mols = frags.flatten
150
- mols.map(&:csmiles).should == ["C=CCC[NH3+]", "OO", "CC(=O)CC[NH3+]", "O", "CC=CC[NH3+]", "OO"]
151
- mols.map(&:formula).should == ["C4H10N+", "H2O2", "C4H10NO+", "H2O", "C4H10N+", "H2O2"]
152
- #mols.map(&:formula).should == ["C4H10N", "H2O2", "C4H10NO", "H2O", "C4H10N", "H2O2"]
153
- mols.map(&:exact_mass).zip([72.081324325, 34.005479304, 88.076238945, 18.010564684, 72.081324325, 34.005479304]) do |act, exp|
154
- act.should be_within(1e-6).of(exp)
155
- end
156
- end
157
-
158
- specify 'ether to alcohol, ignoring errors' do
159
- # this is a good example of a 'disallowed structure' where the
160
- # formula's do not match up to the original formulas
161
- mol = Rubabel["CCOCCN"]
162
- frags = mol.fragment(rules: [:oxh], errors: :ignore)
163
- mols = frags.flatten
164
- mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]", "CCO", "C=C[NH2+]"]
165
- end
166
-
167
- specify 'ether to alcohol, removing errors' do
168
- mol = Rubabel["CCOCCN"]
169
- frags = mol.fragment(rules: [:oxh])
170
- mols = frags.flatten
171
- mols.map(&:csmiles).should == ["C=C", "OCC[NH3+]"]
172
- end
173
-
174
- specify 'ester to alcohol' do
175
- mol = Rubabel["CC(=O)OCCCN"]
176
- frags = mol.fragment(rules: [:oxh])
177
- mols = frags.flatten
178
- mols.map(&:csmiles).should == ["C=C=O", "OCCC[NH3+]", "CC(=O)O", "C=CC[NH3+]"]
179
- #mols.map(&:formula).should == ["C2H2O", "C3H10NO", "C2H4O2", "C3H8N"]
180
- mols.map(&:formula).should == ["C2H2O", "C3H10NO+", "C2H4O2", "C3H8N+"]
181
- mols.map(&:exact_mass).zip([42.010564684, 76.076238945, 60.021129368000004, 58.065674261]) do |act,exp|
182
- act.should be_within(1e-6).of(exp)
183
- end
184
- end
185
-
186
- specify 'phosphodiester (right now needs very low pH and NOT SURE WORKING PROPERLY)' do
187
- mol = Rubabel["CC(COP(=O)(O)OCCCN"]
188
- mol.add_h!(1.0)
189
- frags = mol.fragment(rules: [:oxhpd])
190
- frags = frags.flatten
191
- frags.map(&:csmiles).should == ["CCCO", "[NH3+]CCCOP(=O)=O", "CCCOP(=O)=O", "OCCC[NH3+]"]
192
- end
193
- end
194
-
195
- end
196
- end
197
-
198
-
199
-