Module: Rubabel::Molecule::Fragmentable
- Included in:
- Rubabel::Molecule
- Defined in:
- lib/rubabel/molecule/fragmentable.rb
Constant Summary collapse
- RULES =
:sp3c_oxygen_asymmetric_far_sp3, :sp3c_nitrogen_asymmetric_far_sp3,
Set[ :alcohol_to_aldehyde, :peroxy_to_carboxy, :co2_loss, :sp3c_oxygen_double_bond_far_side_sp3, :sp3c_oxygen_double_bond_far_side_sp2, :sp3c_oxygen_double_bond_water_loss, :sp3c_nitrogen_double_bond, ]
- CO_RULES =
ADDUCTS = [:lioh, :nh4cl, :nh4oh]
Set[:alcohol_to_aldehyde, :peroxy_to_carboxy, :co2_loss, :sp3c_oxygen_double_bond_water_loss, :sp3c_oxygen_double_bond_far_side_sp2, :sp3c_oxygen_double_bond_far_side_sp3, :sp3c_oxygen_asymmetric_far_sp3 ]
- DEFAULT_OPTIONS =
{ rules: RULES, #adduct: nil, ph: 7.4, # return only the set of unique fragments uniq: false, }
Instance Method Summary collapse
- #alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs) ⇒ Object
-
#allowable_fragment_sets!(fragment_sets) ⇒ Object
add_h! to self, then selects allowable fragments.
-
#allowable_fragmentation?(frags) ⇒ Boolean
molecules and fragments should all have hydrogens added (add_h!) before calling this method.
- #co2_loss(carbon, oxygen, c3_nbr) ⇒ Object
-
#electrophile_snatches_electrons(carbon, electrophile) ⇒ Object
warning, this method adds_h! to the calling molecule.
-
#feint_double_bond(bond, give_e_pair = nil, get_e_pair = nil, &block) ⇒ Object
will turn bond into a double bond, yield the changed molecule, then return the bond to the original state when the block is closed returns whatever the block returned.
- #feint_e_transfer(give_e_pair = nil, get_e_pair = nil, &block) ⇒ Object
-
#fragment(opts = {}) ⇒ Object
to ensure proper fragmentation, will add_h!(ph) first at the given ph an empty array is returned if there are no fragments generated.
- #near_side_double_bond_break(carbon, electrophile) ⇒ Object
- #peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr) ⇒ Object
Instance Method Details
#alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs) ⇒ Object
101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 101 def alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs) # alcohol becomes a ketone and one R group is released frag_sets = carbon_nbrs.select {|atom| atom.type == 'C3' }.map do |_atom| frags = feint_double_bond(carbon.get_bond(oxygen)) do |_mol| frags = _mol.split(carbon.get_bond(_atom)) frags.map(&:add_h!) end end allowable_fragment_sets!(frag_sets) end |
#allowable_fragment_sets!(fragment_sets) ⇒ Object
add_h! to self, then selects allowable fragments
38 39 40 41 42 43 44 45 46 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 38 def allowable_fragment_sets!(fragment_sets) self.add_h! fragment_sets.select do |_frags| putsv "ExMAIN:" putsv _frags.inspect putsv self.allowable_fragmentation?(_frags) self.allowable_fragmentation?(_frags) end end |
#allowable_fragmentation?(frags) ⇒ Boolean
molecules and fragments should all have hydrogens added (add_h!) before calling this method
For instance, water loss with double bond formation is not allowable for NCC(O)CC => CCC=C, presumably because of the lone pair and double bond resonance.
33 34 35 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 33 def allowable_fragmentation?(frags) self.num_atoms == frags.map(&:num_atoms).reduce(:+) end |
#co2_loss(carbon, oxygen, c3_nbr) ⇒ Object
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 112 def co2_loss(carbon, oxygen, c3_nbr) # carboxyl rules ... # neutral carbon dioxide loss with anion gain on attaching group # (if carbon) frags = feint_double_bond(carbon.get_bond(oxygen), oxygen, c3_nbr) do |_mol| frags = _mol.split(c3_nbr.get_bond(carbon)) frags.map(&:add_h!) end allowable_fragment_sets!([frags]) end |
#electrophile_snatches_electrons(carbon, electrophile) ⇒ Object
warning, this method adds_h! to the calling molecule
65 66 67 68 69 70 71 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 65 def electrophile_snatches_electrons(carbon, electrophile) self.add_h! frags = self.split(carbon.get_bond(electrophile)) raise NotImplementedError # don't check for allowable fragments because it #allowable_fragment_sets!([frag_set]) end |
#feint_double_bond(bond, give_e_pair = nil, get_e_pair = nil, &block) ⇒ Object
will turn bond into a double bond, yield the changed molecule, then return the bond to the original state when the block is closed returns whatever the block returned
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 51 def feint_double_bond(bond, give_e_pair=nil, get_e_pair=nil, &block) orig = bond.bond_order bond.bond_order = 2 reply = if give_e_pair || get_e_pair feint_e_transfer(give_e_pair, get_e_pair, &block) else block.call(self) end bond.bond_order = orig reply end |
#feint_e_transfer(give_e_pair = nil, get_e_pair = nil, &block) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 73 def feint_e_transfer(give_e_pair=nil, get_e_pair=nil, &block) if give_e_pair gc_orig = give_e_pair.charge give_e_pair.charge = gc_orig + 1 end if get_e_pair rc_orig = get_e_pair.charge get_e_pair.charge = rc_orig - 1 end reply = block.call(self) give_e_pair.charge = gc_orig if give_e_pair get_e_pair.charge = rc_orig if get_e_pair reply end |
#fragment(opts = {}) ⇒ Object
to ensure proper fragmentation, will add_h!(ph) first at the given ph an empty array is returned if there are no fragments generated.
:ph => 7.4
:uniq => false
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 150 def fragment(opts={}) opts = DEFAULT_OPTIONS.merge(opts) opts[:rules].each do |rule| raise ArgumentError, "bad rule: #{rule}" unless RULES.include?(rule) end had_hydrogens = self.h_added? self.correct_for_ph!(opts[:ph]) self.remove_h! rules = opts[:rules] fragment_sets = [] if rules.any? {|rule| CO_RULES.include?(rule) } putsv "matching C-O" self.each_match("CO").each do |_atoms| # note: this will *not* match C=O (carbon, oxygen) = _atoms carbon_nbrs = carbon.atoms.reject {|atom| atom == oxygen } c3_nbrs = carbon_nbrs.select {|atm| atm.type == 'C3' } # pulling this out here causes it to work incorrectly internally # (not sure why) #co_bond = carbon.get_bond(oxygen) case oxygen.bonds.size # non-hydrogen bonds when 1 # *must* be an alcohol or a carboxylic acid putsv "#{csmiles} oxygen has no other bonds besides C-O (alcohol or carboxylic acid)" if carbon.type == 'C3' if rules.include?(:sp3c_oxygen_double_bond_water_loss) putsv "rule :sp3c_oxygen_double_bond_water_loss" fragment_sets.push *near_side_double_bond_break(carbon, oxygen) end if rules.include?(:alcohol_to_aldehyde) putsv "rule :alcohol_to_aldehyde" fragment_sets.push *alcohol_to_aldehyde(carbon, oxygen, carbon_nbrs) end elsif carbon.carboxyl_carbon? if rules.include?(:co2_loss) putsv "rule :co2_loss" if c3_nbr = c3_nbrs.first fragment_sets.push *co2_loss(carbon, oxygen, c3_nbr) end end end when 2 putsv "#{csmiles} c-o & oxygen has 2 non-hydrogen bonds" oxygen_nbr = oxygen.atoms.reject {|atom| atom.idx == carbon.idx }.first if carbon.type == 'C3' if rules.include?(:peroxy_to_carboxy) fragment_sets.push *peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr) end # ester and ethers (look *only* on close side for places to make # double bond) if oxygen_nbr.type == 'C3' putsv "oxygen nbr is C3" if rules.include?(:sp3c_oxygen_double_bond_far_side_sp3) putsv "rule :sp3c_oxygen_double_bond_far_side_sp3" fragment_sets.push *near_side_double_bond_break(carbon, oxygen) end if rules.include?(:sp3c_oxygen_asymmetric_far_sp3) putsv "rule :sp3c_oxygen_asymmetric_far_sp3" # only returns a single frag set fragment_sets.push electrophile_snatches_electrons(carbon, oxygen) end end if oxygen_nbr.type == 'C2' if rules.include?(:sp3c_oxygen_double_bond_far_side_sp2) putsv "rule :sp3c_oxygen_double_bond_far_side_sp2" fragment_sets.push *near_side_double_bond_break(carbon, oxygen) end end # note: the case of a carboxy is found with CO search end end end end if rules.include?(:sp3c_nitrogen_double_bond) self.each_match("CN") do |_atoms| (carbon, nitrogen) = _atoms num_nitrogen_bonds = nitrogen.bonds.size case num_nitrogen_bonds when 2 if carbon.type == 'C3' fragment_sets.push *near_side_double_bond_break(carbon, nitrogen) end end end end unless had_hydrogens fragment_sets.each {|set| set.each(&:remove_h!) } self.remove_h! end if opts[:uniq] # TODO: impelent properly #fragment_sets = fragment_sets.uniq_by(&:csmiles) raise NotImplementedError end fragment_sets end |
#near_side_double_bond_break(carbon, electrophile) ⇒ Object
91 92 93 94 95 96 97 98 99 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 91 def near_side_double_bond_break(carbon, electrophile) frag_sets = carbon.atoms.select {|atom| atom.type == "C3" }.map do |near_c3| frags = feint_double_bond(carbon.get_bond(near_c3)) do |_mol| frags = _mol.split(electrophile.get_bond(carbon)) frags.map(&:add_h!) end end allowable_fragment_sets!(frag_sets) end |
#peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/rubabel/molecule/fragmentable.rb', line 123 def peroxy_to_carboxy(carbon, oxygen, carbon_nbrs, oxygen_nbr) if oxygen_nbr.el == :o # has a neighbor oxygen distal_o = oxygen_nbr if distal_o.bonds.size == 1 # this is a peroxy frag_sets = carbon_nbrs.select {|atom| atom.type == 'C3' }.map do |_atom| self.swap!(carbon, _atom, oxygen, distal_o) frags = feint_double_bond(carbon.get_bond(oxygen)) do |_mol| # we swapped the atoms so the bond to split off is now # attached to the oxygen frags = _mol.split(oxygen.get_bond(_atom)) frags.map(&:add_h!) end self.swap!(carbon, distal_o, oxygen, _atom) frags end allowable_fragment_sets!(frag_sets) end end end |