-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separated stoichiometric functions from Compound class and placed in …
…the stoich module
- Loading branch information
Showing
5 changed files
with
145 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from typing import List, Union | ||
|
||
from pychemkit.foundations.element import Element | ||
from pychemkit.foundations.compound import Compound | ||
from pychemkit.exceptions.invalids import NotAValidCompoundException, NotAValidElementException | ||
from pychemkit.utils.utils import is_number | ||
|
||
|
||
def entity_handler(entity: Union[str, Element, Compound]) -> Union[str, Element, Compound]: | ||
""" | ||
Handler for string inputs (not an instance of element, or a compound) | ||
:param entity: string input of an element or a compound | ||
:return: if valid, an instance of element of a compound, raises an exception if not | ||
""" | ||
if isinstance(entity, str): | ||
try: | ||
entity = Element(entity) | ||
except NotAValidElementException: | ||
try: | ||
entity = Compound(entity) | ||
except NotAValidCompoundException: | ||
raise ValueError( | ||
f'{entity} is not a valid Element of Compound' | ||
) | ||
|
||
return (entity, type(entity)) | ||
|
||
|
||
def amount_handler(amount: float) -> float: | ||
""" | ||
Handler for amount inputs | ||
:param amount: float or int input representing valid amounts in grams, moles, etc | ||
:return: raises a TypeError if not a valid amount | ||
""" | ||
if is_number(amount): | ||
return amount | ||
else: | ||
raise TypeError('Enter a valid amount') | ||
|
||
|
||
def selection_handler(input: str, selection: List[str]): | ||
""" | ||
Handler for selections | ||
:param input: input string | ||
:param selection: list of valid selections | ||
:return: raises a ValueError if the selection is not in the list | ||
""" | ||
if input not in selection: | ||
raise ValueError( | ||
f'Invalid input: {input}. Valud options are {selection}' | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from typing import Union, List | ||
|
||
import numpy as np | ||
from pychemkit.exceptions.invalids import NotAValidCompoundException, NotAValidElementException | ||
from pychemkit.foundations.element import Element | ||
from pychemkit.foundations.compound import Compound | ||
from pychemkit.foundations.constants import AVOGADRO_NUM | ||
from pychemkit.utils.utils import is_number | ||
from pychemkit.exceptions.handlers import entity_handler, amount_handler, selection_handler | ||
|
||
|
||
class StoichConverter: | ||
|
||
def convert_mass(self, entity: Union[str, Element, Compound], mass: float, to: str) -> float: | ||
""" | ||
Converts mass in grams to mole, given a compound | ||
:param Compound: An instance of a compound | ||
:param mass: mass in grams | ||
""" | ||
|
||
selection_handler(to, ['moles', 'atoms']) | ||
entity, ent_type = entity_handler(entity) | ||
|
||
mass = amount_handler(mass) | ||
|
||
if ent_type == Element: | ||
ent_mass = entity.atomic_mass | ||
elif ent_type == Compound: | ||
ent_mass = entity.molecular_mass | ||
|
||
moles = mass / ent_mass | ||
|
||
if to == 'moles': | ||
return moles | ||
elif to == 'atoms': | ||
return np.round(moles * AVOGADRO_NUM, 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import unittest | ||
|
||
from pychemkit.foundations.element import Element | ||
from pychemkit.foundations.compound import Compound | ||
from pychemkit.foundations.constants import AVOGADRO_NUM | ||
from pychemkit.stoich.converter import StoichConverter | ||
|
||
|
||
class TestStoich(unittest.TestCase): | ||
|
||
def setUp(self) -> None: | ||
|
||
el1 = Element('C') | ||
el2 = Element('Hg') | ||
el3 = 'Po' | ||
|
||
cpd1 = Compound('CH3COOH') | ||
cpd2 = Compound('NaCl') | ||
cpd3 = 'MgSO4' | ||
|
||
self.test_elements = [el1, el2, el3] | ||
self.test_compounds = [cpd1, cpd2, cpd3] | ||
|
||
self.test_elem_masses = [12.01, 200.59, 208.98243] | ||
self.test_cpd_masses = [60.025, 58.44, 120.366] | ||
|
||
self.converter = StoichConverter() | ||
|
||
def test_mass_to_moles(self): | ||
|
||
convert_to_list = ['moles'] | ||
|
||
expected_moles = { | ||
'moles': [1, 1, 1], | ||
'atoms': [AVOGADRO_NUM] * 3 | ||
} | ||
|
||
for to in convert_to_list: | ||
for i, (el, cpd) in enumerate(zip(self.test_elements, self.test_compounds)): | ||
expected = expected_moles.get(to)[i] | ||
actual_el = self.converter.convert_mass( | ||
entity=el, | ||
mass=self.test_elem_masses[i], | ||
to=to | ||
) | ||
|
||
actual_cpd = self.converter.convert_mass( | ||
entity=cpd, | ||
mass=self.test_cpd_masses[i], | ||
to=to | ||
) | ||
|
||
self.assertAlmostEqual(actual_el, expected, 1) | ||
self.assertAlmostEqual(actual_cpd, expected, 1) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |