class Mspire::MolecularFormula

Attributes

charge[RW]

integer desribing the charge state mass calculations will add/remove electron mass from this

Public Class Methods

[](arg, charge=0)
Alias for: from_any
from_aaseq(aaseq, formula_hash=Mspire::Isotope::AA::FORMULAS) click to toggle source
# File lib/mspire/molecular_formula.rb, line 8
def from_aaseq(aaseq, formula_hash=Mspire::Isotope::AA::FORMULAS)
  hash = aaseq.each_char.inject({}) do |hash,aa| 
    hash.merge(formula_hash[aa]) {|hash,old,new| (old ? old : 0) + new }
  end
  hash[:H] += 2
  hash[:O] += 1
  self.new(hash)
end
from_any(arg, charge=0) click to toggle source

arg may be a String, Hash, or MolecularFormula object.

# File lib/mspire/molecular_formula.rb, line 28
def from_any(arg, charge=0)
  if arg.is_a?(String)
    from_string(arg, charge)
  else
    self.new(arg, arg.respond_to?(:charge) ? arg.charge : 0)
  end
end
Also aliased as: []
from_string(mol_form_str, charge=0) click to toggle source

takes a string, with properly capitalized elements making up the formula. The elements may be in any order.

# File lib/mspire/molecular_formula.rb, line 19
def from_string(mol_form_str, charge=0)
  mf = self.new({}, charge)
  mol_form_str.scan(/([A-Z][a-z]?)(\d*)/).each do |k,v| 
    mf[k.to_sym] = (v == '' ? 1 : v.to_i)
  end
  mf
end
new(hash={}, charge=0) click to toggle source

Takes a hash and an optional Integer expressing the charge

{H: 22, C: 12, N: 1, O: 3, S: 2}  # case and string/sym doesn't matter
# File lib/mspire/molecular_formula.rb, line 45
def initialize(hash={}, charge=0)
  @charge = charge
  self.merge!(hash)
end

Public Instance Methods

*(int) click to toggle source
# File lib/mspire/molecular_formula.rb, line 86
def *(int)
  self.dup.mul!(int)
end
+(*others) click to toggle source

returns a new formula object where all the atoms have been added up

# File lib/mspire/molecular_formula.rb, line 51
def +(*others)
  self.dup.add!(*others)
end
-(*others) click to toggle source

returns a new formula object where all the formulas have been subtracted from the caller

# File lib/mspire/molecular_formula.rb, line 66
def -(*others)
  self.dup.sub!(*others)
end
/(int) click to toggle source
# File lib/mspire/molecular_formula.rb, line 99
def /(int)
  self.dup.div!(int)
end
==(other) click to toggle source
# File lib/mspire/molecular_formula.rb, line 159
def ==(other)
  old_equal(other) && self.charge == other.charge
end
Also aliased as: old_equal
add!(*others) click to toggle source

returns self

# File lib/mspire/molecular_formula.rb, line 56
def add!(*others)
  others.each do |other|
    self.merge!(other) {|key, oldval, newval| self[key] = oldval + newval }
    self.charge += other.charge
  end
  self
end
avg_mass() click to toggle source
# File lib/mspire/molecular_formula.rb, line 128
def avg_mass
  inject(0.0) {|sum,(el,cnt)| sum + (Mspire::Mass::Element::AVG[el]*cnt) }
end
div!(int, also_do_charge=true) click to toggle source
# File lib/mspire/molecular_formula.rb, line 103
def div!(int, also_do_charge=true)
  raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
  self.each do |k,v|
    quotient, modulus = v.divmod(int)
    raise ArgumentError "all numbers must be divisible by int" unless modulus == 0
    self[k] = quotient
  end
  if also_do_charge
    quotient, modulus = self.charge.divmod(int) 
    raise ArgumentError "charge must be divisible by int" unless modulus == 0
    self.charge = quotient
  end
  self
end
isotope_distribution(normalize: Mspire::Isotope::Distribution::NORMALIZE, peak_cutoff: nil, percent_cutoff: nil, prefer_lowest_index: true, isotope_table: Mspire::Isotope::BY_ELEMENT) click to toggle source

Returns isotopic distribution beginning with the lightest possible peak. (for most molecules this will also be the monoisotopic peak)

Two cutoff protocols may be specified, percent_cutoff or peak_cutoff. Normalization is performed after cutoff.

percent_cutoff: cuts off when no more peaks contribute more than percent_cutoff 
                    to the total distribution.  
peak_cutoff:    cuts off after that many peaks.

prefer_lowest_index controls the behavior if both percent_cutoff and peak_cutoff are specified. If true, then the lowest index found between the two methods will be used, otherwise the highest index.

all values will be fractional. normalize may be one of:

:total   normalize to the total intensity
:max     normalize to the highest peak intensity
:first   normalize to the intensity of the first peak 
        (this is typically the monoisotopic peak)
# File lib/mspire/isotope/distribution.rb, line 40
def isotope_distribution(normalize: Mspire::Isotope::Distribution::NORMALIZE, peak_cutoff: nil, percent_cutoff: nil, prefer_lowest_index: true, isotope_table: Mspire::Isotope::BY_ELEMENT)
  mono_dist = raw_isotope_distribution(isotope_table: isotope_table)

  cutoff_index = [ 
    if percent_cutoff
      total_signal = mono_dist.reduce(:+)
      cutoff_index_less1 = (mono_dist.size-1).downto(0).find do |i|
        # finds the index
        (mono_dist[i] / total_signal) >= (percent_cutoff/100.0)
      end
      cutoff_index = cutoff_index_less1 ? (cutoff_index_less1 + 1) : 0
    end,
    peak_cutoff
  ].compact.send( prefer_lowest_index ? :min : :max ) || mono_dist.size

  # mono_dist.size will result in nothing sliced off (i.e., for no cutoff)

  mono_dist.slice!(cutoff_index..-1)

  # normalization
  norm_by =
    case normalize
    when :total
      total_signal || mono_dist.reduce(:+)
    when :max
      mono_dist.max
    when :first
      mono_dist.first
    end
  mono_dist.map do |i| 
    v = i / norm_by
    (v > 0) ? v : 0
  end
end
isotope_distribution_spectrum(*args) click to toggle source

returns a spectrum object with mass values and intensity values. Arguments are passed directly to isotope_distribution. the molecule has a charge, this will be used to adjust the m/z values (by removing or adding electrons to the m/z and as the z)

# File lib/mspire/isotope/distribution.rb, line 79
def isotope_distribution_spectrum(*args)
  intensities = isotope_distribution(*args)
  mono = self.map {|el,cnt| Mspire::Mass::Element::MONO[el]*cnt }.reduce(:+)
  masses = Array.new(intensities.size)
  neutron = Mspire::Mass::NEUTRON
  masses[0] = mono
  (1...masses.size).each {|i| masses[i] = masses[i-1] + neutron }
  if self.charge && self.charge != 0
    masses.map! do |mass| 
      (mass - (self.charge * Mspire::Mass::ELECTRON)) / self.charge 
    end
  end
  Mspire::Spectrum.new [masses, intensities]
end
mass(consider_electron_masses = true) click to toggle source

gives the monoisotopic mass adjusted by the current charge (i.e., adds/subtracts electron masses for the charges)

# File lib/mspire/molecular_formula.rb, line 120
def mass(consider_electron_masses = true)
  mss = inject(0.0) do |sum,(el,cnt)| 
    sum + (Mspire::Mass::Element::MONO[el]*cnt)
  end
  mss -= (Mspire::Mass::ELECTRON * charge) if consider_electron_masses
  mss
end
mul!(int, also_do_charge=true) click to toggle source
# File lib/mspire/molecular_formula.rb, line 90
def mul!(int, also_do_charge=true)
  raise ArgumentError, "must be an integer" unless int.is_a?(Integer)
  self.each do |k,v|
    self[k] = v * int
  end
  self.charge *= int if also_do_charge
  self
end
mz(consider_electron_masses = true) click to toggle source

returns nil if the charge == 0

# File lib/mspire/molecular_formula.rb, line 133
def mz(consider_electron_masses = true)
  if charge == 0
    nil
  else
    mass(consider_electron_masses) / charge
  end
end
old_equal(other)
Alias for: ==
raw_isotope_distribution(isotope_table: Mspire::Isotope::BY_ELEMENT) click to toggle source

returns relative ratios from low nominal mass to high nominal mass. These are not normalized at all.

# File lib/mspire/isotope/distribution.rb, line 96
def raw_isotope_distribution(isotope_table: Mspire::Isotope::BY_ELEMENT)
  low_nominal = 0
  high_nominal = 0
  self.each do |el,cnt|
    isotopes = isotope_table[el]
    low_nominal += (isotopes.first.mass_number * cnt)
    high_nominal += (isotopes.last.mass_number * cnt)
  end

  ffts = self.map do |el, cnt|
    isotope_el_ar = NArray.float(high_nominal+1)
    isotope_table[el].each do |isotope|
      isotope_el_ar[isotope.mass_number] = isotope.relative_abundance
    end
    FFTW3.fft(isotope_el_ar)**cnt
  end
  FFTW3.ifft(ffts.reduce(:*)).real.to_a[low_nominal..high_nominal]
end
sub!(*others) click to toggle source
# File lib/mspire/molecular_formula.rb, line 70
def sub!(*others)
  others.each do |other|
    oth = other.dup
    self.each do |k,v|
      if oth.key?(k)
        self[k] -= oth.delete(k)
      end
    end
    oth.each do |k,v|
      self[k] = -v
    end
    self.charge -= other.charge
  end
  self
end
to_hash() click to toggle source
# File lib/mspire/molecular_formula.rb, line 153
def to_hash
  Hash[ self ]
end
to_s(alphabetize=true) click to toggle source
# File lib/mspire/molecular_formula.rb, line 141
def to_s(alphabetize=true)
  h = alphabetize ? self.sort : self
  st = ''
  h.each do |k,v|
    if v > 0
      st << k.to_s.capitalize
      st << v.to_s if v > 1
    end
  end 
  st
end