Skip to content

Commit

Permalink
implemented componentsystem that inherits from
Browse files Browse the repository at this point in the history
cadet process and fixes the small bug with the
molecular weight, added molecular volume

first implementation of the def unit_operation
and residual equations still

both still need testing and unit_operation def
doesn't have rejection model yet
  • Loading branch information
daklauss committed Jul 31, 2024
1 parent 31d6447 commit 321bba7
Show file tree
Hide file tree
Showing 7 changed files with 394 additions and 72 deletions.
265 changes: 265 additions & 0 deletions CADETPythonSimulator/componentsystem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
from CADETProcess.processModel import ComponentSystem, Component, Species
from CADETProcess.dataStructure import UnsignedFloat, String, Integer
from CADETProcess.dataStructure import Structure

from CADETPythonSimulator.exception import CADETPythonSimError
from functools import wraps

class CPSSpecies(Structure):
"""Species class.
Represent a species in a chemical system.
Same as in cadet Process but with added
density and Volume
Attributes
----------
name : str
The name of the species.
charge : int, optional
The charge of the species. Default is 0.
molecular_weight : float
The molecular weight of the species.
density : float
Density of the species.
molecular_volume : float
The molecular volume of the species
"""
name = String()
charge = Integer(default=0)
molecular_weight = UnsignedFloat()
density = UnsignedFloat()
molecular_volume = UnsignedFloat()

class CPSComponent(Component):
"""Information about single component.
Inherits from CadetProcess Component
Same function but with fixed molecular weight and added densities and volume
A component can contain subspecies (e.g. differently charged variants).
Attributes
----------
name : String
Name of the component.
species : list
List of Subspecies.
n_species : int
Number of Subspecies.
label : list
Name of component (including species).
charge : list
Charge of component (including species).
molecular_weight : list
Molecular weight of component (including species).
density : list
density of component (including species).
molecular_volume : list
Molecular volume of component (including species).
See Also
--------
Species
ComponentSystem
"""
def __init__(self,
name=None,
species=None,
charge=None,
molecular_weight=None,
density=None,
molecular_volume=None):

self.name = name
self._species = []

if species is None:
self.add_species(name, charge, molecular_weight, density, molecular_volume)
elif isinstance(species, str):
self.add_species(species,
charge, molecular_weight, density, molecular_volume)
elif isinstance(species, list):
if charge is None:
charge = len(species) * [None]
if molecular_weight is None:
molecular_weight = len(species) * [None]
if density is None:
density = len(species) * [None]
if molecular_volume is None:
molecular_volume = len(species) * [None]
for i, spec in enumerate(species):
self.add_species(spec,
charge[i], molecular_weight[i], density[i], molecular_volume[i])
else:
raise CADETPythonSimError("Could not determine number of species")

def add_species(self, species, *args, **kwargs):
if not isinstance(species, CPSSpecies):
species = CPSSpecies(species, *args, **kwargs)
self._species.append(species)

@property
def molecular_volume(self):
"""list of float or None: The molecular volume of the subspecies."""
return [spec.molecular_volume for spec in self.species]

@property
def density(self):
"""list of float or None: The density of the subspecies."""
return [spec.density for spec in self.species]

@property
def molecular_weight(self):
"""list of float or None: The molecular weights of the subspecies."""
return [spec.molecular_weight for spec in self.species]

class CPSComponentSystem(ComponentSystem):
"""Information about components in system. Inherits from Component System. Adds
molecular Volume to the Component System.
A component can contain subspecies (e.g. differently charged variants).
Attributes
----------
name : String
Name of the component system.
components : list
List of individual components.
n_species : int
Number of Subspecies.
n_comp : int
Number of all component species.
n_components : int
Number of components.
indices : dict
Component indices.
names : list
Names of all components.
species : list
Names of all component species.
charge : list
Charges of all components species.
molecular_weight : list
Molecular weights of all component species.
molecular_volume : list
Molecular volume of all component species.
See Also
--------
Species
Component
"""

def __init__(
self,
components=None,
name=None,
charges=None,
molecular_weights=None,
densities=None,
molecular_volume=None
):
"""Initialize the ComponentSystem object.
Parameters
----------
components : int, list, None
The number of components or the list of components to be added.
If None, no components are added.
name : str, None
The name of the ComponentSystem.
charges : list, None
The charges of each component.
molecular_weights : list, None
The molecular weights of each component.
densities : list, None
Densities of each component
molecular_volume : list, None
The molecular volume of each component.
Raises
------
CADETProcessError
If the `components` argument is neither an int nor a list.
"""

self.name = name

self._components = []

if components is None:
return

if isinstance(components, int):
n_comp = components
components = [str(i) for i in range(n_comp)]
elif isinstance(components, list):
n_comp = len(components)
else:
raise CADETPythonSimError("Could not determine number of components")

if charges is None:
charges = n_comp * [None]
if molecular_weights is None:
molecular_weights = n_comp * [None]
if densities is None:
densities = n_comp * [None]
if molecular_volume is None:
molecular_volume = n_comp * [None]

for i, comp in enumerate(components):
self.add_component(
comp,
charge=charges[i],
molecular_weight=molecular_weights[i],
density=densities[i],
molecular_volume=molecular_volume[i]
)

@wraps(CPSComponent.__init__)
def add_component(self, component, *args, **kwargs):
"""
Add a component to the system.
Parameters
----------
component : {str, Component}
The class of the component to be added.
*args : list
The positional arguments to be passed to the component class's constructor.
**kwargs : dict
The keyword arguments to be passed to the component class's constructor.
"""
if not isinstance(component, CPSComponent):
component = CPSComponent(component, *args, **kwargs)

if component.name in self.names:
raise CADETPythonSimError(
f"Component '{component.name}' "
"already exists in ComponentSystem."
)

self._components.append(component)

@property
def molecular_volumes(self):
"""list: List of species molecular volumes."""
molecular_volumes = []
for comp in self.components:
molecular_volumes += comp.molecular_volume

return molecular_volumes

@property
def densities(self):
"""list: List of species densities."""
densities = []
for comp in self.components:
densities += comp.density

return densities
33 changes: 5 additions & 28 deletions CADETPythonSimulator/residual.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ def calculate_residual_volume_cstr(
Volume leaving the Unit
Returns
-------
float
float
Residual of the Flow equation of the CSTR with dimensions like the inpu
"""

if V < 0:
raise CADETPythonSimError("V can't be less then zero")

Expand All @@ -43,7 +43,7 @@ def calculate_residual_concentration_cstr(
) -> np.ndarray :
"""
Calculates the residual equations of the concentration of a cstr
Parameters
----------
c : np.ndarray
Expand Down Expand Up @@ -114,7 +114,7 @@ def calculate_residual_press_easy_def(
"""
Calculates the residual equations fo a dead end filtration equation for the pressure
in the easy model.
Parameters
----------
V_dot_P : np.ndarray
Expand All @@ -138,34 +138,11 @@ def calculate_residual_press_easy_def(
return -V_dot_P + deltap * A *hyd_resistance


def calculate_residual_perm_easy_def(
Q_in : float,
V_dot_C : float,
V_dot_P : float
) -> float:
"""
Calculates the residual equations fo a dead end filtration equation for the permeate Volume
in the easy model.
Parameters
----------
Q_in : float
Flow entering the unit operation
V_dot_P : float
FLow of the Permeate through the membrane and Cake
V_dot_C : float
Volume of the Retentate becoming the Cake
"""


return -Q_in + V_dot_C + V_dot_P


def calculate_residual_visc_def():

"""
Calculates the residual of the Viscosity equation of the CSTR
"""
warnings.warn("Viscosity of def not yet implemented")

return 0
return 0
1 change: 1 addition & 0 deletions CADETPythonSimulator/system_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ def couple_unit_operations(
origin_port = origin_info['port']

y_origin_unit = y_initial[self.unit_slices[origin_unit]]

s_unit = origin_unit.get_outlet_state(y_origin_unit, origin_port)

s_new += s_unit * Q_destination # Accumulate weighted states
Expand Down
Loading

0 comments on commit 321bba7

Please sign in to comment.