Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Overhaul Fractionator #219

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CADETProcess/fractionation/fractionationOptimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def _setup_fractionator(
CADETProcessError
If no areas with sufficient purity were found and `ignore_failed` is False.
"""
frac = Fractionator(
frac = Fractionator.from_simulation_results(
simulation_results,
components=components,
use_total_concentration_components=use_total_concentration_components,
Expand Down
107 changes: 43 additions & 64 deletions CADETProcess/fractionation/fractionator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from CADETProcess import plotting
from CADETProcess.performance import Performance
from CADETProcess.solution import slice_solution, SolutionIO
from CADETProcess import SimulationResults
from CADETProcess.processModel import ProcessInformation

from CADETProcess.fractionation.fractions import Fraction, FractionPool

Expand All @@ -22,7 +22,8 @@


class Fractionator(EventHandler):
"""Class for Chromatogram Fractionation.
"""
Class for fractionation of Chromatograms.

This class is responsible for setting events for starting and ending fractionation,
handling multiple chromatograms, and calculating various performance metrics.
Expand All @@ -45,78 +46,64 @@ class Fractionator(EventHandler):

def __init__(
self,
simulation_results,
chromatograms,
process_information,
components=None,
use_total_concentration_components=True,
*args, **kwargs):
"""Initialize the Fractionator.

Parameters
----------
simulation_results : SimulationResults
Simulation results containing chromatograms.
chromatograms : SolutionIO or list of SolutionIO
Chromatograms to be fractionated.
components : list, optional
List of components to be fractionated. Default is None.
List of components to be fractionated. If None, all components are
considered. The default is None.
use_total_concentration_components : bool, optional
Use total concentration components. Default is True.
If True, use the total concentration of components, i.e. the sum of all
subspecies of each component. The default is True.
*args
Variable length argument list.
**kwargs
Arbitrary keyword arguments.

"""
self.components = components
self.use_total_concentration_components = use_total_concentration_components
self.simulation_results = simulation_results

super().__init__(*args, **kwargs)

@property
def simulation_results(self):
"""SimulationResults: The simulation results containing the chromatograms."""
return self._simulation_results
if not isinstance(chromatograms, list):
chromatograms = [chromatograms]

@simulation_results.setter
def simulation_results(self, simulation_results):
"""Set the simulation results.
self.process_information = process_information

Parameters
----------
simulation_results : SimulationResults
Simulation results containing chromatograms.
for chrom in chromatograms:
if chrom.component_system is not self.component_system:
raise CADETProcessError("Component systems do not match.")

Raises
------
TypeError
If simulation_results is not of type SimulationResults.
CADETProcessError
If the simulation results do not contain any chromatograms.

"""
if not isinstance(simulation_results, SimulationResults):
raise TypeError('Expected SimulationResults')
component_system = chromatograms[0].component_system

if len(simulation_results.chromatograms) == 0:
raise CADETProcessError(
'Simulation results do not contain chromatogram'
)
if components is not None:
for comp in components:
if comp not in component_system:
raise CADETProcessError(
f"Could not find component {comp} in component system."
)

self._simulation_results = simulation_results
self.components = components
self.use_total_concentration_components = use_total_concentration_components

self._chromatograms = [
slice_solution(
chrom,
components=self.components,
use_total_concentration_components=self.use_total_concentration_components
)
for chrom in simulation_results.chromatograms
for chrom in chromatograms
]

m_feed = np.zeros((self.component_system.n_comp, ))
counter = 0
for comp, indices in simulation_results.component_system.indices.items():
for comp, indices in self.component_system.indices.items():
if comp in self.component_system.names:
m_feed_comp = simulation_results.process.m_feed[indices]
m_feed_comp = process_information.m_feed[indices]
if self.use_total_concentration_components:
m_feed[counter] = np.sum(m_feed_comp)
counter += 1
Expand All @@ -135,10 +122,12 @@ def simulation_results(self, simulation_results):
for chrom in self.chromatograms
})

self._cycle_time = self.process.cycle_time
self._cycle_time = self.process_information.cycle_time

self.reset()

super().__init__(*args, **kwargs)

@property
def component_system(self):
"""ComponentSystem: The component system of the chromatograms."""
Expand Down Expand Up @@ -195,9 +184,16 @@ def chromatogram_events(self):
return chrom_events

@property
def process(self):
def process_information(self):
"""Process: The process from the simulation results."""
return self.simulation_results.process
return self._process_information

@process_information.setter
def process_information(self, process_information):
if not isinstance(process_information, ProcessInformation):
raise TypeError("Expected ProcessInformation.")

self._process_information = process_information

@property
def n_comp(self):
Expand Down Expand Up @@ -539,7 +535,7 @@ def mass_balance_difference(self):
def productivity(self):
"""ndarray: Specific productivity in corresponding fraction pool."""
return self.mass / (
self.process.cycle_time * self.process.V_solid
self.process_information.cycle_time * self.process_information.V_solid
)

@property
Expand All @@ -552,7 +548,7 @@ def eluent_consumption(self):
consumption. It is preferred here in order to avoid numeric issues
if the collected mass is 0.
"""
return self.mass / self.process.V_eluent
return self.mass / self.process_information.V_eluent

@property
def performance(self):
Expand Down Expand Up @@ -725,22 +721,5 @@ def parameters(self, parameters):
def section_dependent_parameters(self):
return self.parameters

def save(self, case_dir, start=0, end=None):
path = os.path.join(settings.working_directory, case_dir)

for index, chrom in enumerate(self.chromatograms):
chrom.plot(save_path=path + f'/chrom_{index}.png')
chrom.plot_purity(
start=start, end=end, save_path=path + '/chrom_purity.png'
)

for chrom in enumerate(self.chromatograms):
self.plot_fraction_signal(
chromatogram=chrom,
start=start, end=end,
save_path=path + f'/fractionation_signal_{index}.png',
index=index
)

def __str__(self):
return self.__class__.__name__
28 changes: 28 additions & 0 deletions tests/fractionation/test_fractionator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import unittest

import numpy as np
from CADETProcess.processModel import ComponentSystem
from CADETProcess.fractionation import Fractionator
from CADETProcess.fractionation import FractionationOptimizer
from CADETProcess.fractionation import SimulationResults


from solution_fixtures import TestSolutionIOConstant, TestSolutionIOGaussian

component_system = ComponentSystem(['A', 'B'])

test_solution_const = TestSolutionIOConstant(component_system)
test_solution_gauss = TestSolutionIOGaussian(component_system)


frac = Fractionator():

class Test

class Test_Fractionator(unittest.TestCase):

def __init__(self, methodName='runTest'):
super().__init__(methodName)

if __name__ == '__main__':
unittest.main()
File renamed without changes.
Loading