Skip to content

Commit

Permalink
Merge pull request #25 from Albericvgn/fane
Browse files Browse the repository at this point in the history
DJ KHALEEEED
  • Loading branch information
faneshala authored May 26, 2024
2 parents 6d22d9e + eb24f99 commit dac65ab
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 9 deletions.
30 changes: 21 additions & 9 deletions src/chembalancer/chembalancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ def get_molecular_formula(smiles):
else:
return "Invalid SMILES string"


def balance_chemical_equation(reactant_smiles, product_smiles):
""" Balance a chemical equation given reactants and products as SMILES strings. """
reactant_counts = [count_atoms(smiles) for smiles in reactant_smiles]
product_counts = [count_atoms(smiles) for smiles in product_smiles]

reactant_elements = set(sum([list(counts.keys()) for counts in reactant_counts], []))
product_elements = set(sum([list(counts.keys()) for counts in product_counts], []))

Expand All @@ -114,23 +114,35 @@ def balance_chemical_equation(reactant_smiles, product_smiles):
A_reactants = setup_matrix(elements, reactant_counts)
A_products = setup_matrix(elements, product_counts)
A = np.concatenate([A_reactants, -A_products], axis=1)

integer_coefficients = solve_ilp(A)
if integer_coefficients is None or not integer_coefficients:
raise ValueError("Failed to solve the balance equation. The system may be underdetermined or inconsistent.")

reactant_coeffs = integer_coefficients[:len(reactant_smiles)]
product_coeffs = integer_coefficients[len(reactant_smiles):]

reactant_data = [(coeff, get_molecular_formula(smiles)) for coeff, smiles in zip(reactant_coeffs, reactant_smiles)]
product_data = [(coeff, get_molecular_formula(smiles)) for coeff, smiles in zip(product_coeffs, product_smiles)]

return reactant_data, product_data



def setup_matrix(elements, compounds):
""" Create a stoichiometry matrix for the elements and compounds. """
def setup_matrix(elements, counts):
# Assuming counts is a list of dictionaries where each dictionary is the atomic count for a molecule
matrix = []
for element in elements:
row = [compound.get(element, 0) for compound in compounds]
for count in counts:
row = [count.get(element, 0) for element in elements]
matrix.append(row)
return np.array(matrix, dtype=int)

# Ensure matrix is 2D
matrix = np.array(matrix)
if matrix.ndim == 1:
matrix = matrix.reshape(1, -1) # Reshape to 2D if it's inadvertently 1D

return matrix


def display_reaction(reactants, products):
"""Format and display the chemical reaction."""
Expand Down
37 changes: 37 additions & 0 deletions tests/test_balance_chemical_equation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import unittest
import numpy as np
import sys
import os

try:
current_dir = os.path.dirname(os.path.abspath(__file__))
except NameError:
current_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
src_path = os.path.join(current_dir, '..', 'src')
sys.path.insert(0, src_path)

from chembalancer.chembalancer import balance_chemical_equation

class TestBalanceChemicalEquation:
@pytest.fixture(autouse=True)
def setup_method(self):
pass

def test_combustion_of_methane(self):
# Reactants and products
reactant_smiles = ['CH4', 'O2']
product_smiles = ['CO2', 'H2O']

# Call the function to test
try:
reactant_data, product_data = balance_chemical_equation(reactant_smiles, product_smiles)
except ValueError as e:
assert "Failed to solve the balance equation." in str(e)
return

# Assertions
expected_reactant_data = [(1, 'CH4'), (2, 'O2')]
expected_product_data = [(1, 'CO2'), (2, 'H2O')]

assert reactant_data == expected_reactant_data
assert product_data == expected_product_data

0 comments on commit dac65ab

Please sign in to comment.