Skip to content

Commit

Permalink
add chemicals outline feature
Browse files Browse the repository at this point in the history
  • Loading branch information
yoelcortes committed Jan 4, 2025
1 parent b55ac78 commit 58c83cf
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 5 deletions.
7 changes: 4 additions & 3 deletions thermosteam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from .network import *
from ._chemical_data import ChemicalData
from ._chemical import Chemical
from ._chemicals import Chemicals, CompiledChemicals
from ._chemicals import Chemicals, CompiledChemicals, ChemicalDraft, ChemicalsOutline
from ._thermal_condition import ThermalCondition
from ._thermo import Thermo, IdealThermo
from ._settings import settings, ProcessSettings
Expand All @@ -71,8 +71,9 @@
from .mixture import *
from ._preferences import preferences

__all__ = ('Chemical', 'ChemicalData', 'Chemicals', 'CompiledChemicals', 'Thermo',
'IdealThermo', 'Stream', 'MultiStream', 'Heat', 'Power', 'ThermalCondition', 'ProcessSettings',
__all__ = ('Chemical', 'ChemicalData', 'Chemicals', 'CompiledChemicals',
'ChemicalDraft', 'ChemicalsOutline', 'Thermo', 'IdealThermo',
'Stream', 'MultiStream', 'Heat', 'Power', 'ThermalCondition', 'ProcessSettings',
'mixture', 'ThermoData', *reaction.__all__, *equilibrium.__all__, *mixture.__all__,
*network.__all__, 'preferences',
'indexer', 'settings', 'functor', 'functors', 'chemicals', 'base',
Expand Down
1 change: 1 addition & 0 deletions thermosteam/_chemical.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ def __new__(cls, ID, cache=None, *, search_ID=None,
metadata = pubchem_db.search(search_ID)
data['metadata'] = metadata
self = cls.new(ID, metadata.CASs, eos, phase_ref, phase, free_energies=False, **data)
if CAS is not None: self._CAS = CAS
else:
self = cls.blank(ID, CAS, phase_ref, phase=phase, free_energies=False, **data)
if phase:
Expand Down
114 changes: 113 additions & 1 deletion thermosteam/_chemicals.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import thermosteam as tmo
import numpy as np

__all__ = ('Chemicals', 'CompiledChemicals')
__all__ = ('Chemicals', 'CompiledChemicals', 'ChemicalDraft', 'ChemicalsOutline')
setattr = object.__setattr__

# %% Functions
Expand Down Expand Up @@ -46,6 +46,118 @@ def prepare(chemicals, skip_checks):
"all missing properties"
)

# %% Outline

class ChemicalDraft:
"""
Create a draft of a chemical without actually loading the chemical.
This allows for extending and modifying an outline of a property package
before loading all the chemicals.
"""
def __init__(self, ID, CAS=None, *args, **kwargs):
self.ID = ID
self.CAS = CAS
self.args = args
self.kwargs = kwargs

def copy(self, CAS=None, **data):
new = ChemicalDraft(self.ID, CAS=self.CAS)
for i, j in data.items(): setattr(new, i, j)

def to_chemical(self):
dct = self.__dict__.copy()
chemical = Chemical(
dct.pop('ID'), *dct.pop('args'), CAS=dct.pop('CAS'), **dct.pop('kwargs')
)
for i, j in dct.items(): setattr(chemical, i, j)
return chemical

def __repr__(self):
return f'{type(self).__name__}({self.ID})'


class ChemicalsOutline:
"""
Create an outline of chemicals without actually loading the chemicals.
This allows for extending and modifying an outline of a property package
before loading all the chemicals.
"""
def __new__(cls, chemicals, cache=None):
self = super().__new__(cls)
isa = isinstance
setfield = setattr
chemicals = [i if isa(i, ChemicalDraft) else ChemicalDraft(i, cache=cache) for i in chemicals]
for i in chemicals: setfield(self, i.ID, i)
return self

def __getnewargs__(self):
return (tuple(self),)

def __setattr__(self, ID, chemical):
raise TypeError("can't set attribute; use <ChemicalsOutline>.append instead")

def __setitem__(self, ID, chemical):
raise TypeError("can't set item; use <ChemicalsOutline>.append instead")

def __getitem__(self, key):
dct = self.__dict__
try:
if isinstance(key, str):
return dct[key]
else:
return [dct[i] for i in key]
except KeyError as key_error:
raise UndefinedChemicalAlias(key_error.args[0])

def copy(self):
copy = object.__new__(self.__class__)
for chem in self: setattr(copy, chem.ID, chem)
return copy

def append(self, chemical):
if isinstance(chemical, str):
chemical = ChemicalDraft(chemical)
elif not isinstance(chemical, ChemicalDraft):
raise TypeError("only 'ChemicalDraft' objects can be appended, "
f"not '{type(chemical).__name__}'")
ID = chemical.ID
if ID in self.__dict__:
raise ValueError(f"{ID} already defined in chemicals")
setattr(self, ID, chemical)

def extend(self, chemicals):
if isinstance(chemicals, ChemicalsOutline):
self.__dict__.update(chemicals.__dict__)
else:
for chemical in chemicals: self.append(chemical)

def to_chemicals(self):
return Chemicals([i.to_chemical() for i in self])

kwarray = array = index = indices = must_compile

def show(self):
print(self)
_ipython_display_ = show

def __len__(self):
return len(self.__dict__)

def __contains__(self, chemical):
if isinstance(chemical, str):
return chemical in self.__dict__
elif hasattr(chemical, 'ID'):
return chemical.ID in self.__dict__
else: # pragma: no cover
return False

def __iter__(self):
yield from self.__dict__.values()

def __repr__(self):
return f"{type(self).__name__}([{', '.join(self.__dict__)}])"


# %% Chemicals

class Chemicals:
Expand Down
2 changes: 1 addition & 1 deletion thermosteam/_heat_and_power.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def empty(self):

@classmethod
def sum(cls, streams, ID=None):
new = Power(ID)
new = Heat(ID)
new.mix_from(streams)
return new

Expand Down

0 comments on commit 58c83cf

Please sign in to comment.