lib/eulim/chemistry/reaction.rb in eulim-0.0.13 vs lib/eulim/chemistry/reaction.rb in eulim-0.0.14

- old
+ new

@@ -1,27 +1,44 @@ +require 'matrix' + module Eulim module Chemistry # This class has functionality for reaction # Ex: check for balanced rxn, validity of a rxn class Reaction - attr_accessor :equation, :is_valid, :is_balanced, :species + attr_accessor :equation, :is_valid, :species, :participants, :balanced_eqn, :rate_equation STATES = { '(s)' => 'solid', '(l)' => 'liquid', '(g)' => 'gaseous', '(aq)' => 'aqueous', - '' => 'liquid' + '' => '' }.freeze - def initialize(arg) - @equation = arg + 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? - @is_balanced = balanced_rxn? + p participant_elements + # @balanced_eqn = balance_rxn + @rate_equation = validify_rate_eqn args[:rate_equation] end private + 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 + def build_species r = {} result = {} r[:reactants], r[:products] = @equation.split('>>') r.each do |type, _type_species| @@ -78,9 +95,64 @@ specie.match(/^\d*/).to_a.first.to_i end def get_state(specie) specie.match(/\((s|l|g|aq)\)$/).to_s + end + + def participant_elements + participants = [] + @species[:reactants].keys.each do |r| + participants << @species[:reactants][r][:compound].constituents.keys + end + @participants = participants.flatten.uniq + end + + 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 + + def write_matrix + @matrix = Matrix[] + @participants.each do |parti| + @matrix = Matrix.rows(@matrix.to_a << get_participant_row(parti)) + end + @matrix + end + + 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 + + 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 end end end