Source code for CADETProcess.performance
"""
=============================================
Performance (:mod:`CADETProcess.performance`)
=============================================
.. currentmodule:: CADETProcess.performance
Performance data
================
Classes for storing the performance parameters after fractionation.
.. autosummary::
:toctree: generated/
Performance
RankedPerformance
Performance Indicators
======================
Individual performance indicators (extracted from Performance).
Mostly convenince method.
.. autosummary::
:toctree: generated/
PerformanceIndicator
Mass
Recovery
Productivity
EluentConsumption
Purity
Concentration
PerformanceProduct
MassBalanceDifference
Notes
-----
Performance Indicators might be deprecated in future since with new evaluation chains
it's no longer required for setting up as optimization problem.
"""
import numpy as np
from CADETProcess import CADETProcessError
from CADETProcess.dataStructure import Structure
from CADETProcess.metric import MetricBase
from CADETProcess.dataStructure import SizedNdArray
from CADETProcess.processModel import ComponentSystem
[docs]
class Performance(Structure):
"""Class for storing the performance parameters after fractionation.
Attributes
----------
mass : np.ndarray
Mass of each component in the system after fractionation.
Size depends on number of components.
concentration : np.ndarray
Concentration of each component in the system after fractionation.
Size depends on number of components.
purity : np.ndarray
Purity of each component in the system after fractionation.
Size depends on number of components.
recovery : np.ndarray
Recovery of each component in the system after fractionation.
Size depends on number of components.
productivity : np.ndarray
Productivity of each component in the system after fractionation.
Size depends on number of components.
eluent_consumption : np.ndarray
Eluent consumption of each component in the system after fractionation.
Size depends on number of components.
mass_balance_difference : np.ndarray
Mass balance difference of each component.
Size depends on number of components.
component_system : ComponentSystem
The component system used for fractionation.
If not provided, a default component system is used.
See Also
--------
CADETProcess.fractionation
RankedPerformance
"""
_performance_keys = [
'mass', 'concentration', 'purity', 'recovery',
'productivity', 'eluent_consumption', 'mass_balance_difference'
]
mass = SizedNdArray(size=('n_comp'))
concentration = SizedNdArray(size=('n_comp'))
purity = SizedNdArray(size=('n_comp'))
recovery = SizedNdArray(size=('n_comp'))
productivity = SizedNdArray(size=('n_comp'))
eluent_consumption = SizedNdArray(size=('n_comp'))
mass_balance_difference = SizedNdArray(size=('n_comp'))
def __init__(
self, mass, concentration, purity, recovery,
productivity, eluent_consumption, mass_balance_difference, component_system=None):
"""Initialize Performance.
Parameters
----------
mass : ndarray
The mass of each component.
concentration : ndarray
The concentration of each component.
purity : ndarray
The purity of each component.
recovery : ndarray
The recovery of each component.
productivity : ndarray
The productivity of each component.
eluent_consumption : ndarray
The eluent consumption of each component.
mass_balance_difference : ndarray
The difference in mass balance of each component.
component_system : ComponentSystem
The ComponentSystem object that describes the system's components.
"""
if component_system is None:
component_system = ComponentSystem(mass.shape[0])
self.component_system = component_system
self.mass = mass
self.concentration = concentration
self.purity = purity
self.recovery = recovery
self.productivity = productivity
self.eluent_consumption = eluent_consumption
self.mass_balance_difference = mass_balance_difference
@property
def n_comp(self):
"""int: Number of components in the system."""
return self.component_system.n_comp
[docs]
def to_dict(self):
"""Return a dictionary representation of the object."""
return {key: getattr(self, key).tolist()
for key in self._performance_keys}
[docs]
def __getitem__(self, item):
"""Get an attribute of the object by its name."""
if item not in self._performance_keys:
raise AttributeError('Not a valid performance parameter')
return getattr(self, item)
def __repr__(self):
"""String representation of the object."""
return \
f'{self.__class__.__name__}(mass={np.array_repr(self.mass)}, '\
f'concentration={np.array_repr(self.concentration)}, '\
f'purity={np.array_repr(self.purity)}, '\
f'recovery={np.array_repr(self.recovery)}, '\
f'productivity={np.array_repr(self.productivity)}, '\
f'eluent_consumption={np.array_repr(self.eluent_consumption)} '\
f'mass_balance_difference={np.array_repr(self.mass_balance_difference)})'
[docs]
class RankedPerformance():
"""Class for calculating a weighted average of the Performance
See Also
--------
Performance
ranked_objective_decorator
"""
_performance_keys = Performance._performance_keys
def __init__(self, performance, ranking=1.0):
if not isinstance(performance, Performance):
raise TypeError('Expected Performance')
self._performance = performance
self.ranking = ranking
@property
def performance(self):
return self._performance
@property
def ranking(self):
return self._ranking
@ranking.setter
def ranking(self, ranking):
if isinstance(ranking, (float, int)):
ranking = self.performance.n_comp * [ranking]
elif len(ranking) != self.performance.n_comp:
raise CADETProcessError('Number of components does not match.')
self._ranking = ranking
[docs]
def to_dict(self):
return {
key: float(getattr(self, key)) for key in self._performance_keys
}
def __getattr__(self, item):
if item not in self._performance_keys:
raise AttributeError
return sum(self._performance[item]*self.ranking)/sum(self.ranking)
[docs]
def __getitem__(self, item):
if item not in self._performance_keys:
raise AttributeError('Not a valid performance parameter')
return getattr(self, item)
def __repr__(self):
return \
f'{self.__class__.__name__}(mass={np.array_repr(self.mass)}, '\
f'concentration={np.array_repr(self.concentration)}, '\
f'purity={np.array_repr(self.purity)}, '\
f'recovery={np.array_repr(self.recovery)}, '\
f'productivity={np.array_repr(self.productivity)}, '\
f'eluent_consumption={np.array_repr(self.eluent_consumption)} ' \
f'mass_balance_difference={np.array_repr(self.mass_balance_difference)})'
[docs]
class PerformanceIndicator(MetricBase):
"""Base class for performance indicators used in optimization and fractionation.
See Also
--------
RankedPerformance
"""
def __init__(self, ranking=None):
"""Initialize PerformanceIndicator.
Parameters
----------
ranking : list of floats, optional
Weights to rank individual compoments. If None, all compoments are ranke
"""
self.ranking = ranking
@property
def ranking(self):
return self._ranking
@ranking.setter
def ranking(self, ranking):
self._ranking = ranking
@property
def bad_metrics(self):
return 0
[docs]
def evaluate(self, performance):
"""Evaluate the performance indicator for the given performance data.
Parameters
----------
performance : Performance
Object containing performance data.
Returns
-------
list
List of performance indicator values.
"""
try:
performance = performance.performance
except AttributeError:
pass
if self.ranking is not None:
performance = RankedPerformance(performance, self.ranking)
value = self._evaluate(performance).tolist()
if self.ranking is not None:
metric = [value]
else:
metric = []
for i, comp in enumerate(performance.component_system):
metric.append(value[i])
return metric
__call__ = evaluate
def __str__(self):
"""String representation of the class."""
return self.__class__.__name__
[docs]
class Mass(PerformanceIndicator):
"""Performance indicator based on the mass of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.mass
[docs]
class Recovery(PerformanceIndicator):
"""Performance indicator based on the recovery of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.recovery
[docs]
class Productivity(PerformanceIndicator):
"""Performance indicator based on the productivity of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.productivity
[docs]
class EluentConsumption(PerformanceIndicator):
"""Performance indicator based on the specific eluent consumption of each component.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.eluent_consumption
[docs]
class Purity(PerformanceIndicator):
"""Performance indicator based on the purity of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.purity
[docs]
class Concentration(PerformanceIndicator):
"""Performance indicator based on the concentration of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return performance.concentration
[docs]
class PerformanceProduct(PerformanceIndicator):
"""Performance indicator based on the product of several performance indicators.
See Also
--------
Productivity
Recovery
EluentConsumption
PerformanceIndicator
"""
def _evaluate(self, performance):
return \
performance.productivity \
* performance.recovery \
* performance.eluent_consumption
[docs]
class MassBalanceDifference(PerformanceIndicator):
"""Performance indicator based on the mass balance of each component in the system.
See Also
--------
PerformanceIndicator
"""
def _evaluate(self, performance):
return np.abs(performance.mass_balance_difference)