Fitting reaction parameters to a set of experimental data

Hi everyone,

I am currently trying to simulate a reactive chromatographic process. In this a reaction should occur in the solid phase. For this I would like to fit parameters of the reaction system (k_fwd, k_bwd) to a set of experimental data.

The reaction system is of the type:
A + B <=> C + D
A + C <=> E + D

However, I have an issue when trying to add these variables to the optimization problem.
I receive an error stating the variable is “Not a valid Optimization variable”. Possibly my provided parameter path “flow_sheet.column.particle_reaction_model.k_fwd” is not correct? I am using cadet version 5.0.4.

Here I provide the reaction_system:

reaction_system = MassActionLaw(component_system)
    reaction_system.add_reaction(
        indices=[0, 1 , 2, 3, 4],
        coefficients=[-1, -1, 1, 1, 0],
        k_fwd=0.09,
        k_bwd=0.05
    )
    reaction_system.add_reaction(
        indices=[0, 1 , 2, 3, 4],
        coefficients=[0, -1, -1, 1, 1],
        k_fwd=0.01,
        k_bwd=0.005
    )

I use the particle reaction model:

column.particle_reaction_model = reaction_system

Providing the variable to the optimization problem:

optimization_problem.add_variable(
    name='k_fwd',parameter_path= "flow_sheet.column.particle_reaction_model.k_fwd",
    indices=(0,1),
    lb=1e-9, ub=1e-6,
    transform='auto'
    )

The simulation itself works without trouble, also with the reaction. Also I don’t have an issue with providing other parameters like axial dispersion, which works just fine.

Thanks in advance!
Best regards,
Adrian

1 Like

Hi Adrian,

thanks for reaching out. The issue you’re experiencing comes from the fact that under the hood, CADET currently has two different implementations for reactions. One for the bulk phase, and one for particles. The MassActionLaw instance is actually meant for the bulk phase, and MassActionLawParticle for particles. CADET-Process can automatically convert the former to the latter and it should show the following warning:

"Detected Bulk Reaction Model. "
"Attempt casting to Particle Reaction Model."

While this works fine for setting up the process, when configuring your optimization problem, you still need to refer to the converted particle parameter, i.e. k_fwd_liquid, so the following should work:

optimization_problem.add_variable(
    name='k_fwd',parameter_path= "flow_sheet.column.particle_reaction_model.k_fwd_liquid",
    indices=0,
    lb=1e-9, ub=1e-6,
    transform='auto'
)

Note, you only need a scalar index since it’s a “list” of reactions where each reaction has one forward rate.

Just to give some insight in how I approached solving your issue: to check whether something is a valid parameter, the first thing I do, is to inspect the parameters attribute of the given object. Here, I saw that k_fwd was not present, but k_fwd_liquid was. Then it clicked and I realized that the MassActionLaw had been casted to MassActionLawParticle. Hope that helps.


That being said, we’re currently in the process of overhauling our entire parameter structure, especially regarding particles and reactions. So expect this to change in the future, with a more consistent, robust, and flexible interface.

1 Like

Hi Johannes,

thanks for your kind reply. This solved my issue and I am able to add k_fwd_liquid and k_bwd_liquid to the correct path. I also tried using the MassActionLawParticle which works aswell for k_fwd_solid and k_bwd_solid.

However, now I receive an error in the optimization itself: “TypeError: ProxyList.init() missing 1 required positional argument: ‘instance’”.

I tried to implement k_fwd_liquid and k_bwd_liquid like this:

for reactions in range(1):
    optimization_problem.add_variable(
    name= f"k_fwd_liquid{reactions}", 
    parameter_path='flow_sheet.column.particle_reaction_model.k_fwd_liquid',
    lb=1e-2, ub=10,
    transform='auto',
    indices = [reactions]
    )
    optimization_problem.add_variable(
    name= f"k_bwd_liquid{reactions}", 
    parameter_path='flow_sheet.column.particle_reaction_model.k_bwd_liquid',
    lb=1e-2, ub=10,
    transform='auto',
    indices = [reactions]
    )

Using your suggestion the same error occurs:

optimization_problem.add_variable(
    name='k_fwd',parameter_path= "flow_sheet.column.particle_reaction_model.k_fwd_liquid",
    indices=0,
    lb=1e-9, ub=1e-6,
    transform='auto'
    )

optimization_problem.add_variable(
    name='k_bwd',parameter_path= "flow_sheet.column.particle_reaction_model.k_bwd_liquid",
    indices=0,
    lb=1e-9, ub=1e-6,
    transform='auto'
    )

"ProxyList.__init__() missing 1 required positional argument: 'instance'"

The way I understand it, for each reaction and indidual variable needs to be added to the optimization problem with an unique index? Maybe there is still a missunderstanding from my side.

I am looking forward to new additions to Cadet. :slight_smile:

Hi,

without the full code I could not reproduce your issue.

Hi, here is the jupyter notebook of the current code with some example data:

example_data_1.xlsx (23.8 KB)
example_data_2.xlsx (23.8 KB)
reactive_chrom_example.ipynb (1.4 MB)

This is the error I get:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[33], line 1 ----> 1 optimization_results = optimizer.optimize( 2 optimization_problem, 3 use_checkpoint=False 4 ) File c:\Users\adfa01.conda\envs\cadet_workshop\Lib\site-packages\CADETProcess\optimization\optimizer.py:277, in OptimizerBase.optimize(self, optimization_problem, x0, save_results, results_directory, use_checkpoint, overwrite_results_directory, exist_ok, log_level, reinit_cache, delete_cache, *args, **kwargs) 274 plt.switch_backend(“agg”) 276 start = time.time() → 277 self._run(self.optimization_problem, x0, *args, **kwargs) 278 time_elapsed = time.time() - start 280 self.results.time_elapsed = time_elapsed File c:\Users\adfa01.conda\envs\cadet_workshop\Lib\site-packages\CADETProcess\optimization\pymooAdapter.py:88, in PymooInterface._run(self, optimization_problem, x0) 86 pop = x0 87 else: —> 88 pop = optimization_problem.create_initial_values( 89 pop_size, seed=self.seed, include_dependent_variables=False 90 ) 92 pop = np.array(pop, ndmin=2) 94 if len(pop) < pop_size: File c:\Users\adfa01.conda\envs\cadet_workshop\Lib\site-packages\CADETProcess\optimization\optimizationProblem.py:3212, in OptimizationProblem.create_initial_values(self, n_samples, seed, burn_in, include_dependent_variables)

→ 4051 new_value = parameter_type(new_value.tolist()) 4053 # Set the value: 4054 self._set_value_in_evaluation_object(eval_obj, new_value) TypeError: ProxyList.init() missing 1 required positional argument: ‘instance’

Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings

Hi Adrian,

thanks for coming back. To facilitate the investigation of the root cause, it’s good practice - and great help for us - to simplify your code to an MRE I.e. remove everything that does not contribute to the issue itself:

  • Superfluous unit operations / Events
  • External data (use synthetic if required)
  • pre-/post-processing routines or other methods

This helps us to quicker pinpoint the issue. Otherwise it’s very time consuming for us to set everything up.

Also, this itself is already an excellent step towards finding the bug, in case you want to contribute to improving CADET yourself. :nerd_face:

2 Likes

Hi Johannes,

thank you for your feedback. I tried creating a minimal reproducible example, for this I removed the Langmuir isotherm, additional reactions and experimental data. However, I was not able to find the bug.

example_data_1.xlsx (9.0 KB)

minimal_working_example.ipynb (25.7 KB)

1 Like

No worries. I appreciate your effort! :nerd_face:

I’ll have a look and come back to you once I have a solution.