class Eulim::Chemistry::Reaction

This class has functionality for reaction Ex: check for balanced rxn, validity of a rxn

Constants

STATES

Attributes

balanced_eqn[RW]
equation[RW]
is_valid[RW]
participants[RW]
rate_equation[RW]
species[RW]

Public Class Methods

new(args) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 14
def initialize(args)
  # rate_eqn should be of the form: 'r_{CaO} = k[CaO][CO2]'
  @equation = args[:equation]
  @species = build_species
  @is_valid = valid_rxn?
  participant_elements
  @balanced_eqn = balance_rxn
  @rate_equation = validify_rate_eqn args[:rate_equation]
end

Private Instance Methods

balance_rxn() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 139
def balance_rxn
  exp = ''
  i = 0
  bal_coeff = balanced_coeff_array
  @species.keys.each do |key|
    @species[key].keys.each do |comp|
      coeff = bal_coeff[i] == 1 ? ' ' : ' ' + bal_coeff[i].abs.to_s
      state = STATES.key(@species[key][comp][:state])
      exp = exp + coeff + comp + state + ' +'
      i += 1
    end
    exp = key == :reactants ? exp.chomp('+') + '>>' : exp.chomp('+')
  end
  exp.strip
end
balanced_coeff_array() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 132
def balanced_coeff_array
  write_matrix
  null_space_array = @matrix.nullspace_array
  lcm = null_space_array.collect(&:denominator).reduce(1, :lcm)
  null_space_array.collect { |x| (x * lcm).to_i }
end
balanced_rxn?() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 66
def balanced_rxn?
  bal = { reactants: {}, products: {} }
  @species.each do |type, type_species|
    type_species.each do |_specie, s_info|
      s_info[:compound].constituents.each do |sym, c_info|
        bal[type][sym] ||= 0
        bal[type][sym] += c_info[:atom_count] * s_info[:stoichiometry]
      end
    end
  end
  bal[:products] == bal[:reactants]
end
build_species() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 38
def build_species
  r = {}
  result = {}
  r[:reactants], r[:products] = @equation.split('>>')
  r.each do |type, _type_species|
    result[type] = {}
    r[type].split('+').each do |specie|
      result[type].merge!(get_specie_info(specie.strip))
    end
  end
  result
end
get_participant_row(parti) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 108
def get_participant_row(parti)
  row = []
  @species.keys.each do |key|
    i = key == :reactants ? 1 : -1
    @species[key].keys.each do |specie|
      if specie.include? parti
        row << @species[key][specie][:compound]
               .constituents[parti][:atom_count] * i
      else
        row << 0
      end
    end
  end
  row
end
get_specie_info(specie) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 51
def get_specie_info(specie)
  sc = get_stoichiometry specie
  st = get_state specie
  offset_sc = sc.zero? ? 0 : sc.to_s.length
  offset_st = st.empty? ? 0 : st.length
  specie_str = specie[offset_sc..(specie.length - offset_st - 1)]
  {
    specie_str => {
      compound: Compound.new(specie_str),
      stoichiometry: sc.zero? ? 1 : sc,
      state: STATES[st]
    }
  }
end
get_state(specie) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 96
def get_state(specie)
  specie.match(/\((s|l|g|aq)\)$/).to_s
end
get_stoichiometry(specie) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 92
def get_stoichiometry(specie)
  specie.match(/^\d*/).to_a.first.to_i
end
participant_elements() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 100
def participant_elements
  participants = []
  @species[:reactants].keys.each do |r|
    participants << @species[:reactants][r][:compound].constituents.keys
  end
  @participants = participants.flatten.uniq
end
valid_rxn?() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 79
def valid_rxn?
  valid = {}
  @species.each do |type, type_species|
    valid[type] = []
    type_species.each do |_specie, info|
      info[:compound].constituents.each do |symbol, _count|
        valid[type] << symbol
      end
    end
  end
  valid[:reactants].sort.uniq == valid[:products].sort.uniq
end
validify_rate_eqn(rate_eqn) click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 26
def validify_rate_eqn(rate_eqn)
  if rate_eqn
    rate_eqn.gsub('_{', '')
            .gsub('}', '')
            .gsub('[', ' * c')
            .gsub(']', '')
  else
    specie = @species[:reactants].keys.first
    'r' + specie + ' = k * c' + specie
  end
end
write_matrix() click to toggle source
# File lib/eulim/chemistry/reaction.rb, line 124
def write_matrix
  @matrix = Matrix[]
  @participants.each do |parti|
    @matrix = Matrix.rows(@matrix.to_a << get_participant_row(parti))
  end
  @matrix
end