Fractionator print all components

Hey everyone,

Does anyone know how, when using the fractionator, I can print the information for all the different components, rather than for just one? This is what I’m using now:

frac = Fractionator(results, components=['EAV','MP','fBV','cAV','cBV'])

frac.add_fractionation_event('elute_on', 'MP', t_elution_start)
frac.add_fractionation_event('elute_off', -1, 315*60)

perf = frac.performance

print(perf)

And it print the information about the MP (Main Peak), however I would like to know the composition of the Elution Pool for all different components. Thanks!

Hi Sasha,

Thanks for your post.

Could you share a minimal working example of your code, along with:

  1. The exact output you see
  2. The output you expect
  3. Your environment and pacakge details

This will help us determine whether the behaviour is due to your configuration or a bug.

Thanks and all the best,
Hannah

Hey, so my code is this:

import matplotlib.pyplot as plt; plt.show()
import numpy as np
from CADETProcess.processModel import (
    ComponentSystem, MultiComponentColloidal, Inlet, GeneralRateModel, Outlet, FlowSheet, Process
)
from CADETProcess.simulator import Cadet

# =============== Components (Salt, pH, A, B, C) ===============
component_system = ComponentSystem()
component_system.add_component('Salt')   # 0
component_system.add_component('pH')     # 1
component_system.add_component('EAV')      # 2
component_system.add_component('MP')      # 3
component_system.add_component('fBV')      # 4
component_system.add_component('cAV') 
component_system.add_component('cBV') 

# =============== Binding model (your params) ==================
binding_model = MultiComponentColloidal(component_system, name='MultiComponentColloidal')
binding_model.is_kinetic = 1

binding_model.kinetic_rate_constant = [0.0, 0.0, 1e+10, 1e+10, 1e+10, 1e+10, 1e+10]
binding_model.protein_radius        = [1e-10, 1e-10, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7]
binding_model.kappa_constant        = 1e-2
binding_model.kappa_exponential     = 0.0
binding_model.kappa_factor          = 0.0

binding_model.logkeq_ph_exponent       = [0.0, 0, 1.14, 1.07, 1.20, 1.14, 1.15]
binding_model.logkeq_power_exponent    = [0.0]*7
binding_model.logkeq_power_factor      = [0.0]*7
binding_model.logkeq_exponent_factor   = [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0]
binding_model.logkeq_exponent_multiplier = [0.0]*7

binding_model.bpp_ph_exponent        = [0.0]*7
binding_model.bpp_power_exponent     = [0.0]*7
binding_model.bpp_power_factor       = [0.0]*7
binding_model.bpp_exponent_multiplier = [0.0]*7
binding_model.bpp_exponent_factor    = [1e-12]*7

binding_model.use_ph = True
binding_model.linear_threshold = 1e-12
binding_model.phase_ratio = 5.0e7
binding_model.coordination_number = 5
binding_model.bound_states = [0, 0, 1, 1, 1, 1, 1]  # 5 variants bound

print("Binding model OK?:", binding_model.check_required_parameters())

# =============== Units =======================================
inlet = Inlet(component_system, name='inlet')
inlet.flow_rate = 2.3e-8   # m^3/s

column = GeneralRateModel(component_system, name='column')
column.binding_model = binding_model
column.length = 0.204
column.diameter = 0.0066
column.bed_porosity = 0.44
column.particle_radius = 5e-5
column.particle_porosity = 0.902
column.axial_dispersion = 2.43e-07

# transport coeffs per component (len=7); keep >0
column.film_diffusion = [1e-04, 1e-04, 2.83e-05, 9.27e-05, 1.48e-05, 9.42e-05, 2.67e-05]
column.pore_diffusion = [5e-10, 5e-10, 4.89e-12, 1.70e-11, 1.75e-11, 7.61e-12, 4.90e-12]
column.surface_diffusion = [1e-5, 1E-5, 1e-5, 1e-5, 1e-5]

# Initial mobile/intraparticle concentrations (len=7)
column.c  = [0.1, 1e-7, 0.0, 0.0, 0.0, 0.0, 0.0]
column.cp = [0.1, 1e-7, 0.0, 0.0, 0.0, 0.0, 0.0]

outlet = Outlet(component_system, name='outlet')

# =============== Flow sheet ==================================
flow_sheet = FlowSheet(component_system)
flow_sheet.add_unit(inlet)
flow_sheet.add_unit(column)
flow_sheet.add_unit(outlet, product_outlet=True)
flow_sheet.add_connection(inlet, column)
flow_sheet.add_connection(column, outlet)

# =============== Process & events =============================
process = Process(flow_sheet, 'lwe')
process.cycle_time = 240.0 * 60.0  # seconds

t_wash_start    = 50 * 60
t_elution_start  = 150 * 60
t_strip_start  = 200 * 60

EA_load = (2.64 * 0.198 / 100615.0) * 1e3
MP_load = (2.64 * 0.499 / 100615.0) * 1e3
FB_load = (2.64 * 0.138 / 100615.0) * 1e3
CA_load = (2.64 * 0.102 / 100615.0) * 1e3  
CB_load = (2.64 * 0.064 / 100615.0) * 1e3  

#            [Salt,   pH,     EA,      MP,      FB,      CA,      CB]
c_load  = np.array([0.1,   7,   EA_load, MP_load, FB_load, CA_load, CB_load])
c_wash  = np.array([0.1, 7,  0.0,     0.0,     0.0,     0.0,     0.0])
c_elute = np.array([0.1, 4.02  , 0.0,     0.0,     0.0,     0.0,     0.0])
c_strip = np.array([0.1, 3 ,  0.0,     0.0,     0.0,     0.0,     0.0])

process.add_event('load',       'flow_sheet.inlet.c', c_load)
process.add_event('wash',       'flow_sheet.inlet.c', c_wash, t_wash_start)
process.add_event('elute', 'flow_sheet.inlet.c', c_elute, t_elution_start)
process.add_event('strip', 'flow_sheet.inlet.c', c_strip, t_strip_start)

# =============== Simulate ====================================
simulator = Cadet()
results = simulator.simulate(process)

from CADETProcess.fractionation import Fractionator
import numpy as np

frac = Fractionator(results, components=['EAV','MP','fBV','cAV','cBV'])

frac.add_fractionation_event('elute_on', 'MP', 160*60)
frac.add_fractionation_event('elute_off', -1, 185*60)

perf = frac.performance

print(perf)

_ = frac.plot_fraction_signal()

I get this output:

Performance(mass=array([0.00000000e+00, 8.34115553e-07, 0.00000000e+00, 0.00000000e+00,
       0.00000000e+00]), concentration=array([0.        , 0.02417726, 0.        , 0.        , 0.        ]), purity=array([0.        , 0.75128976, 0.        , 0.        , 0.        ]), recovery=array([0.00000000e+000, 1.79769313e+308, 0.00000000e+000, 0.00000000e+000,
       0.00000000e+000]), productivity=array([0.        , 0.00015123, 0.        , 0.        , 0.        ]), eluent_consumption=array([nan, inf, nan, nan, nan]) mass_balance_difference=array([3.58611698e-07, 9.03400389e-07, 2.50188963e-07, 1.84739365e-07,
       1.15922674e-07]))

I’m interested in the purity array. But as you can see it only gives me the purities for one component, and I would like to know for all.

My environment is this:

cadet_env.yml (5.0 KB)

Actually also if you could take a look at whats happening to the recovery array, would be helpful. Thanks a lot

Hi Sasha,

Thanks for providing a running code example.

I think what you are seeing lies in the nature of the Fractionator.

With these lines

frac.add_fractionation_event('elute_on', 'MP', t_elution_start)
frac.add_fractionation_event('elute_off', -1, 315*60)

you declare that MP is the online product pool you are interested in, and the rest is treated as waste, which is why it is not considered in the fractionation.

If you are not interested in capturing any of your other components, but still want them to appear in your KPI vector, you can work around this by adding fractionation events at times where no component is present, e.g.:

frac.add_fractionation_event('MP', 'MP', 160*60)
frac.add_fractionation_event('EAV', 'fBV', 0*60)
frac.add_fractionation_event('fBV', 'EAV', 1*60)
frac.add_fractionation_event('cAV', 'cAV', 2*60)
frac.add_fractionation_event('cBV', 'cBV', 3*60)
frac.add_fractionation_event('waste', -1, 4*60)
frac.add_fractionation_event('elute_off', -1, 200*60)

Hope that helps! :slight_smile:

All the best,
Hannah