Steric mass action isotherm model parameters setting

Hi Team,
I am new to CADET and trying to implement GRM model Steric Mass isotherm, but I am not getting expected result. I think some error in parameter setting. The details is given below. Please help me how to set up the model. I have taken code from CADET Tutorial Master/05_Simple_chromatographic_process.

Column Volume (mL) = 0.353
Total void =0.592
flow rate (ml/min)= 0.170
col height (m)= 0.050
col radius (cm) = 0.150
Column cross sec area (cm2) = 0.071
velocity (m/s) = 4.01E-04
Particle radius (m)= 3.25E-05
Start IS (mM) = 60.842
Gradient end IS (mM)=288.580
Column Porosity = 0.470
Pore Porosity=0.230
Protein load conc. (mM)= 0.029
Gradient CV = 20.000
Load time (s) = 4232.598
Elution start (s) =7407.137
Gradient end (s)= 9898.902
End time (s)= 9998.902
Gradient slope = 0.091
Isotherm parameters
ka= 4.35E-31
nu = 14.000
kd = 1.00E-22
lambda =710.000
sigma= 261.000
Transport parameters
Column dispersion (m2/s) =3.90E-07
film diffusion (m/s)=1.00E-05
particle diffusion (m2/s) = 5.50E-12
surface diffusion Dsf (m2/s) = 1.38E-15

My Code here:

wash_start = 2009.2
grad_start = 8115.0
t_cycle = 10707.4

lwe_model = get_cadet_template(n_units=3)

# Sections and Switches
lwe_model.root.input.solver.sections.nsec = 3
lwe_model.root.input.solver.sections.section_times = [0.0, wash_start, grad_start, t_cycle]

lwe_model.root.input.model.unit_000.sec_000.const_coeff = [84.105,0.029]
lwe_model.root.input.model.unit_000.sec_001.const_coeff = [84.105,0.0]
lwe_model.root.input.model.unit_000.sec_002.const_coeff = [84.105,0.0]
lwe_model.root.input.model.unit_000.sec_002.lin_coeff = [0.082,0.0]

#set the times that the simulator writes out data for
lwe_model.root.input.solver.user_solution_times = np.linspace(0, t_cycle, int(t_cycle) + 1)

n_comp = 2

lwe_model.root.input.model.unit_000.unit_type = 'INLET'
lwe_model.root.input.model.unit_000.ncomp = n_comp
lwe_model.root.input.model.unit_000.inlet_type = 'PIECEWISE_CUBIC_POLY'

lwe_model.root.input.model.unit_001.unit_type = 'GENERAL_RATE_MODEL'
lwe_model.root.input.model.unit_001.ncomp = n_comp

lwe_model.root.input.model.unit_001.col_length = 0.05
lwe_model.root.input.model.unit_001.cross_section_area = 7.1e-6
lwe_model.root.input.model.unit_001.col_porosity = 0.47
lwe_model.root.input.model.unit_001.par_porosity = 0.23
lwe_model.root.input.model.unit_001.par_radius = 3.25e-5
lwe_model.root.input.model.unit_001.col_dispersion = 3.9e-7

lwe_model.root.input.model.unit_001.film_diffusion = [1.0E-5, 1.0E-7]
lwe_model.root.input.model.unit_001.par_diffusion = [5.5e-12, 5.5e-12]
lwe_model.root.input.model.unit_001.par_surfdiffusion = [1.38e-15, 1.38e-15]

lwe_model.root.input.model.unit_002.unit_type = 'OUTLET'
lwe_model.root.input.model.unit_002.ncomp = n_comp

## Discretization
set_discretization(lwe_model, n_bound=[1,1])

# Connections
lwe_model.root.input.model.connections.nswitches = 1
lwe_model.root.input.model.connections.switch_000.section = 0
lwe_model.root.input.model.connections.switch_000.connections = [
    0, 1, -1, -1, 2.83e-9,
    1, 2, -1, -1, 2.83e-9

sma_refc0 = lwe_model.root.input.model.unit_000.sec_002.lin_coeff[0] * (t_cycle - grad_start)
lambda_ = 710.0

lwe_model.root.input.model.unit_001.adsorption_model = 'STERIC_MASS_ACTION'
lwe_model.root.input.model.unit_001.adsorption.is_kinetic = 1
lwe_model.root.input.model.unit_001.adsorption.sma_ka = [4.35e-31, 1.0]
lwe_model.root.input.model.unit_001.adsorption.sma_kd = [1.0e-22, 1.0]
lwe_model.root.input.model.unit_001.adsorption.sma_lambda = lambda_
lwe_model.root.input.model.unit_001.adsorption.sma_nu = [0.0, 14.0]
lwe_model.root.input.model.unit_001.adsorption.sma_sigma = [0.0, 261.0]

lwe_model.root.input.model.unit_001.adsorption.sma_refc0 = sma_refc0
lwe_model.root.input.model.unit_001.adsorption.sma_refq = lambda_
lwe_model.root.input.model.unit_001.init_c = [84.105, 0.0]
lwe_model.root.input.model.unit_001.init_q = [lambda_, 0.0]

Hey Shyama,

welcome to CADET and the community :slight_smile:

I used your provided parameters from above and this is the result I am getting.

Could you please give some more detail about your expected results and why you think there is an error in the parameter setting?

Since you are new to CADET I would like to recommend CADET-Process. From my point of view, it is more user-friendly for beginners. If you want to have a look at CADET-Process check out the documentation. There is also the installation described.

The results above are also generated with CADET-Process. Here is the code used for your problem:

import numpy as np

from CADETProcess.processModel import ComponentSystem
from CADETProcess.processModel import StericMassAction
from CADETProcess.processModel import Source, GeneralRateModel, Sink
from CADETProcess.processModel import FlowSheet
from CADETProcess.processModel import Process

# Input Model
c_salt_low = 84.105
c_salt_high = 288.58
c_protein = 0.029

# Component System
component_system = ComponentSystem()

# Binding Model
binding_model = StericMassAction(component_system, name='SMA')
binding_model.is_kinetic = True
binding_model.adsorption_rate = [0.0, 4.35E-31]
binding_model.desorption_rate = [0.0, 1.00E-22]
binding_model.characteristic_charge = [0.0, 14.000]
binding_model.steric_factor = [0.0, 261.000]
binding_model.capacity = 710

# Unit Operations
inlet = Source(component_system, name='inlet')
inlet.flow_rate = 2.83e-9

column = GeneralRateModel(component_system, name='column')
column.binding_model = binding_model

column.length = 0.05
column.diameter = 0.15e-2*2
column.bed_porosity = 0.47
column.particle_radius = 3.25E-05
column.particle_porosity = 0.23
column.axial_dispersion = 3.9e-7
column.film_diffusion = [2.0e-5, 1.0e-5]
column.pore_diffusion = [7e-5, 5.5e-12]
column.surface_diffusion = [0.0, 1.38E-15]

column.c = [c_salt_low, 0]
column.q = [binding_model.capacity, 0]

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

# flow sheet
flow_sheet = FlowSheet(component_system)

flow_sheet.add_unit(outlet, chromatogram_sink=True)

flow_sheet.add_connection(inlet, column)
flow_sheet.add_connection(column, outlet)

# Process
process = Process(flow_sheet, 'lwe')
process.cycle_time = 9898.902

## Create Events and Durations
wash_start = 4232.598
gradient_start = 7407.137
concentration_difference = np.array([c_salt_high, 0.0]) - np.array([c_salt_low, 0.0])
gradient_duration = process.cycle_time - gradient_start
gradient_slope = concentration_difference/gradient_duration

process.add_event('load', 'flow_sheet.inlet.c', [c_salt_low, c_protein])
process.add_event('wash', 'flow_sheet.inlet.c', [c_salt_low, 0.0], wash_start)
    [[c_salt_low, gradient_slope[0]], [0, gradient_slope[1]]],


from CADETProcess.simulator import Cadet
process_simulator = Cadet()

simulation_results = process_simulator.simulate(process)

from CADETProcess.plotting import SecondaryAxis
sec = SecondaryAxis()
sec.component_indices = [0]
sec.y_label = '$c_{salt}$'


1 Like

Hi Lukas,
Thanks for the response.
The out would be like that image given below. This data taken from @vijesh paper, “Robust mechanistic modeling of protein ion-exchange chromatography”. Here given actual result by experiment and simulation by @vijesh.

Thanks and Regards

Hey Shyama,

for now, I can not tell you where the difference arises from.

But first of all, is the model running on your system, or do you need any assistance doing that?

If you are able to run the model I would recheck the values you posted above. Maybe there are differences in concentration or loading times or something else.

If you need further help please feel free to reach out.


HI Shyama, You have to use salt dependent exponential surface diffusion model

1 Like

Hi Vijesh,
Thanks for the response.
I am not able to find any salt dependent exponential surface diffusion sample model in the CADET tutorial. As I am new in this domain, I am not able create this at this time. Please share the link, if you know this model exist in the CADET website.

Thanks and Regards

The hindered surface diffusion model is included in the main branch of the CADET code but not yet described in the public documentation. Hang on, we are working on it.

I now added the documentation. Please note that the implementation differs from the Vijesh’s version in multiple aspects:

  • The correct value of the coefficient is used in the boundary condition (requires updating the respective sparse Jacobian blocks).
  • The coefficient value at the cell interfaces in the finite volume method is obtained by a weighted arithmetic average of the coefficients in the adjacent cells. This should work for smooth dependencies of the surface diffusion coefficient with respect to salt concentration, which do not change rapidly. The non-averaged version Vijesh already had can exhibit problems with mass conservation.
  • The code implements an interface for arbitrary dependencies. I’ve added three particular ones, which modify the surface diffusion coefficient based on the salt mobile phase concentration: LIQUID_SALT_EXPONENTIAL (exponential law), LIQUID_SALT_POWER (power law), LIQUID_SALT_COLLOIDAL_AFFINITY (based on log(k_{eq}) of colloidal model).

In order to use salt dependent surface diffusion, set PAR_SURFDIFFUSION_DEP to one of the three choices mentioned above and provide the respective fields (see documentation). This feature is only available for the 1D General Rate Model.

Please let us know if you have issues with the implementation.

@alters Could this also be interesting for your case?

Hi guys,

I have used the variable surface diffusion model for fitting BT curves in ion exchange and also affinity chrom. Haven’t tried it for multimodal yet, but that is something I will hopefully get around to.

The way I use it is with the salt dependent terms since this is flexible for any isotherm model vs colloidal affinity which would just be for colloidal with power law salt dependence (unless I am mistaken). On that note, if logKeq has an exponential dependence on salt and you use the the colloidal affinity surface diff setting, does it still assume a power law relationship or is the dependence strictly on whatever logKeq is?

I believe the version I have is from the branch that Vijesh had - this is the one I am still using but I’d be happy to try this update to it and confirm that it is working correctly.


Hi Lukas,

Thanks for your interest. Initially I was stuck to implement CADET Process. Now, I am able to implemented CADET Process. I got same results like you. Thanks for sharing the code. I was working with it, that’s why late reply.

Thanks and Regards