Module: Rubabel::Molecule::Fragmentable

Included in:
Rubabel::Molecule
Defined in:
lib/rubabel/molecule/fragmentable.rb

Constant Summary collapse

RULES =

RULES = Set[:cod, :codoo, :oxe, :oxepd, :oxh]

Set[:cod, :codoo, :oxe, :oxepd, :oxh, :oxhpd]
DEFAULT_OPTIONS =
{
  rules: RULES,
  errors: :remove,
  # return only the set of unique fragments
  uniq: false, 
}

Instance Method Summary collapse

Instance Method Details

#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.

Returns:

  • (Boolean)


25
26
27
# File 'lib/rubabel/molecule/fragmentable.rb', line 25

def allowable_fragmentation?(frags)
  self.num_atoms(true) == frags.reduce(0) {|cnt,fr| cnt + fr.num_atoms(true) }
end

#break_with_double_bond(electrophile, center, center_nbr) ⇒ Object

returns molecules created from splitting between the electrophile and the center and where the bond order is increased between the center and center_nbr



79
80
81
82
83
84
# File 'lib/rubabel/molecule/fragmentable.rb', line 79

def break_with_double_bond(electrophile, center, center_nbr)
  (nmol, (nele, ncarb, ncarb_nbr)) = self.dup_molecule([electrophile, center, center_nbr])
  nmol.delete_bond(nele, ncarb)
  ncarb_nbr.get_bond(ncarb) + 1
  nmol.split
end

#carbon_oxygen_esteal(carbon, oxygen) ⇒ Object

breaks the bond and gives the electrons to the oxygen



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rubabel/molecule/fragmentable.rb', line 57

def carbon_oxygen_esteal(carbon, oxygen)
  nmol = self.dup
  ncarbon = nmol.atom(carbon.id)
  noxygen = nmol.atom(oxygen.id)

  is_carboxyl = noxygen.carboxyl_oxygen?
  
  nmol.delete_bond(ncarbon, noxygen)
  ncarbon.remove_a_hydride!
  noxygen.remove_a_proton! 
  nmol.split
end

#carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr) ⇒ Object

splits the molecule between the carbon and carbon_nbr, adds a double bond between the carbon and oxygen, and moves whatever was on the oxygen (e.g., an OH or a charge) to the carbon_nbr. Returns two new molecules.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rubabel/molecule/fragmentable.rb', line 33

def carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
  appendage = oxygen.atoms.find {|a| a.el != :C }
  if oxygen.charge != 0
    ocharge = oxygen.charge
  end
  nmol = self.dup
  new_oxygen = nmol.atom(oxygen.id)
  new_carbon = nmol.atom(carbon.id)
  new_carbon_nbr = nmol.atom(carbon_nbr.id)
  new_appendage = nmol.atom(appendage.id) if appendage
  nmol.delete_bond(new_carbon.get_bond(new_carbon_nbr))
  if new_appendage
    nmol.delete_bond(new_oxygen.get_bond(new_appendage)) 
    nmol.add_bond!(new_carbon_nbr, new_appendage)
  end
  if ocharge
    new_carbon_nbr.charge += ocharge
    new_oxygen.charge -= ocharge
  end
  new_carbon.get_bond(new_oxygen).bond_order = 2
  nmol.split
end

#dup_molecule(atoms = []) ⇒ Object

returns the duplicated molecule and the equivalent atoms



71
72
73
74
# File 'lib/rubabel/molecule/fragmentable.rb', line 71

def dup_molecule(atoms=[])
  nmol = self.dup
  [nmol, atoms.map {|old_atom| nmol.atom(old_atom.id) }]
end

#fragment(opts = {}) ⇒ Object

an empty array is returned if there are no fragments generated. Hydrogens are added at a pH of 7.4, unless they have already been added.

:rules => queryable by :include? set of rules
:uniq => false
:errors => :remove | :fix | :ignore  (default is :remove)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rubabel/molecule/fragmentable.rb', line 93

def fragment(opts={})
  only_uniqs = true
  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!(7.4) unless had_hydrogens
  self.remove_h!

  fragment_sets = []

  if opts[:rules].any? {|r| [:cod, :codoo].include?(r) }
    self.each_match("C[O;h1,O]", only_uniqs) do |carbon, oxygen|
      carbon.atoms.select {|a| a.el == :C }.each do |carbon_nbr|
        fragment_sets << carbonyl_oxygen_dump(carbon, oxygen, carbon_nbr)
      end
    end
  end
  if opts[:rules].any? {|r| [:oxe].include?(r) }
    self.each_match("C-O", only_uniqs) do |carbon, oxygen|
      fragment_sets << carbon_oxygen_esteal(carbon, oxygen)
    end
  end
  # right now implemented so that a beta hydrogen has to be availabe for
  # extraction
  if opts[:rules].any? {|r| [:oxh].include?(r) }
    self.each_match("C[C,O]-O", only_uniqs) do |beta_c, center, oxygen|
      next unless beta_c.hydrogen_count > 0
      fragment_sets << break_with_double_bond(oxygen, center, beta_c)
    end
  end
  if opts[:rules].any? {|r| [:oxhpd].include?(r) }
    self.each_match("C-O-P-O", only_uniqs) do |carbon, alc_oxy, phosphate, beta_carb_oxy|
      next unless beta_carb_oxy.hydrogen_count > 0
      frag_set = break_with_double_bond(alc_oxy, phosphate, beta_carb_oxy)
      frag_set.map! &:convert_dative_bonds!
      fragment_sets << frag_set
    end
  end
  if opts[:rules].any? {|r| [:oxepd].include?(r) }
    self.each_match("P-O-C", only_uniqs) do |phosphate, oxygen, carbon|
      frag_set = carbon_oxygen_esteal(phosphate, oxygen)
      frag_set.map! &:convert_dative_bonds!
      fragment_sets << frag_set
    end
  end

  case opts[:errors]
  when :remove
    fragment_sets.select! {|set| allowable_fragmentation?(set) }
  when :fix
    raise NotImplementedError
  when :ignore  # do nothing
  end

  self.remove_h!
  if opts[:uniq]
    # TODO: impelent properly
    raise NotImplementedError
    #fragment_sets = fragment_sets.uniq_by(&:csmiles)
  end

  fragment_sets
end