Question about parameter sensitivity

Hi Cadet community,

I would like to use CADET to calculate parameter sensitivities for SMA isotherms, I have followed the tutorial (parameter-sensitivities) and set it up, but the calculation returns sensitivities all of which are 0. Is this Is it possible that there is an error in my settings? I would be grateful if someone could give me some advice!

The code is as follows:

model = Cadet()

model.root.input.model.nunits = 7
init_c = [70, 0.0, 0.0]
init_q = [0, 0.0, 0.0]

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

# parameter sensitivity
model.root.input.sensitivity.nsens = 1
model.root.input.sensitivity.sens_method = 'ad1'
model.root.input.sensitivity.param_000.sens_unit = 2
model.root.input.sensitivity.param_000.sens_name = 'sma_nu'
model.root.input.sensitivity.param_000.sens_comp = 0
model.root.input.sensitivity.param_000.sens_partype = -1
model.root.input.sensitivity.param_000.sens_reaction = -1
model.root.input.sensitivity.param_000.sens_boundphase = -1
model.root.input.sensitivity.param_000.sens_section = -1

# CSTR
model.root.input.model.unit_001.unit_type = 'CSTR'
model.root.input.model.unit_001.ncomp = n_comp
model.root.input.model.unit_001.init_volume = 1888.7e-9
model.root.input.model.unit_001.porosity = 1
model.root.input.model.unit_001.init_c = init_c
model.root.input.model.unit_001.init_q = init_q

# Column
model.root.input.model.unit_002.unit_type = 'LUMPED_RATE_MODEL_WITHOUT_PORES'
model.root.input.model.unit_002.ncomp = n_comp
model.root.input.model.unit_002.col_length = 0.1
model.root.input.model.unit_002.cross_section_area = 0.42e-4
model.root.input.model.unit_002.total_porosity = 0.9
model.root.input.model.unit_002.col_dispersion = 0.0406748e-6


model.root.input.model.unit_002.adsorption_model = 'STERIC_MASS_ACTION'
model.root.input.model.unit_002.adsorption.is_kinetic = True  # Kinetic binding
model.root.input.model.unit_002.adsorption.sma_ka = [0, 0.061045984, 0.242009462]
model.root.input.model.unit_002.adsorption.sma_kd = [0, 12483346166, 56253425.06]
model.root.input.model.unit_002.adsorption.sma_nu = [0, 5.874415, 5.812779]
model.root.input.model.unit_002.adsorption.sma_sigma = [0, 56.949595, 25.498036]
model.root.input.model.unit_002.adsorption.sma_lambda = [1010, 0.0, 0.0]

### Bound states
model.root.input.model.unit_001.discretization.nbound = [1, 1, 1]

# CSTR
model.root.input.model.unit_003.unit_type = 'CSTR'
model.root.input.model.unit_003.ncomp = n_comp
model.root.input.model.unit_003.init_volume = 223.24e-9
model.root.input.model.unit_003.porosity = 1
model.root.input.model.unit_003.init_c = init_c
model.root.input.model.unit_003.init_q = init_q

# CSTR
model.root.input.model.unit_004.unit_type = 'CSTR'
model.root.input.model.unit_004.ncomp = n_comp
model.root.input.model.unit_004.init_volume = 52e-9
model.root.input.model.unit_004.porosity = 1
model.root.input.model.unit_004.init_c = init_c
model.root.input.model.unit_004.init_q = init_q

# CSTR
model.root.input.model.unit_005.unit_type = 'CSTR'
model.root.input.model.unit_005.ncomp = n_comp
model.root.input.model.unit_005.init_volume = 212e-9
model.root.input.model.unit_005.porosity = 1
model.root.input.model.unit_005.init_c = init_c
model.root.input.model.unit_005.init_q = init_q


model.root.input.model.unit_006.unit_type = 'OUTLET'
model.root.input.model.unit_006.ncomp = n_comp


model.root.input.model.unit_002.init_c = [70, 0.0, 0.0]
model.root.input.model.unit_002.init_q = [1010, 0.0, 0.0]


# sections
model.root.input.solver.sections.nsec = 3
model.root.input.solver.sections.section_times = [0.0, 196, 958, 3478]   # s 10
model.root.input.model.unit_000.sec_000.const_coeff = [70, 8.806262230919765e-4, 2.974559686888454e-2]
model.root.input.model.unit_000.sec_001.const_coeff = [70, 0.0, 0.0]
model.root.input.model.unit_000.sec_002.const_coeff = [70, 0.0, 0.0]
model.root.input.model.unit_000.sec_002.lin_coeff = [300/(3478-958), 0.0, 0.0]


model.root.input.model.connections.nswitches = 1
model.root.input.model.connections.switch_000.section = 0
model.root.input.model.connections.switch_000.connections = [
    0, 1, -1, -1, 0.016666667e-6,  # [unit_000, unit_001, all components, all components, Q/ m^3*s^-1
    1, 2, -1, -1, 0.016666667e-6,
    2, 3, -1, -1, 0.016666667e-6,
    3, 4, -1, -1, 0.016666667e-6,
    4, 5, -1, -1, 0.016666667e-6,
    5, 6, -1, -1, 0.016666667e-6,
    ]

model.root.input.model.solver.gs_type = 1
model.root.input.model.solver.max_krylov = 0
model.root.input.model.solver.max_restarts = 10
model.root.input.model.solver.schur_safety = 1e-8

### Grid cells
model.root.input.model.unit_001.discretization.ncol = 100
model.root.input.model.unit_001.discretization.npar = 5

### Other options
model.root.input.model.unit_001.discretization.par_disc_type = 'EQUIDISTANT_PAR'
model.root.input.model.unit_001.discretization.use_analytic_jacobian = 1
model.root.input.model.unit_001.discretization.reconstruction = 'WENO'
model.root.input.model.unit_001.discretization.gs_type = 1
model.root.input.model.unit_001.discretization.max_krylov = 0
model.root.input.model.unit_001.discretization.max_restarts = 10
model.root.input.model.unit_001.discretization.schur_safety = 1.0e-8
model.root.input.model.unit_001.discretization.weno.boundary_model = 0
model.root.input.model.unit_001.discretization.weno.weno_eps = 1e-10
model.root.input.model.unit_001.discretization.weno.weno_order = 3

model.root.input.model.unit_002.discretization = model.root.input.model.unit_001.discretization
model.root.input.model.unit_003.discretization = model.root.input.model.unit_001.discretization
model.root.input.model.unit_004.discretization = model.root.input.model.unit_001.discretization
model.root.input.model.unit_005.discretization = model.root.input.model.unit_001.discretization
model.root.input.model.unit_006.discretization = model.root.input.model.unit_001.discretization

# Number of cores for parallel simulation
model.root.input.solver.nthreads = 6

# Tolerances for the time integrator
model.root.input.solver.time_integrator.abstol = 1e-6
model.root.input.solver.time_integrator.algtol = 1e-10
model.root.input.solver.time_integrator.reltol = 1e-6
model.root.input.solver.time_integrator.init_step_size = 1e-6
model.root.input.solver.time_integrator.max_steps = 1000000

# Return data
model.root.input['return'].split_components_data = 0
model.root.input['return'].split_ports_data = 0
model.root.input['return'].unit_000.write_solution_bulk = 1
model.root.input['return'].unit_000.write_solution_inlet = 1
model.root.input['return'].unit_000.write_solution_outlet = 1

model.root.input['return'].unit_000.write_sens_outlet = 1
model.root.input['return'].unit_000.write_sens_intlet = 1
model.root.input['return'].unit_000.write_sensdot_intlet = 1
model.root.input['return'].unit_000.write_sensdot_outlet = 1
model.root.input['return'].unit_000.write_sens_solid = 1

# Copy settings to the other unit operations
model.root.input['return'].unit_001 = model.root.input['return'].unit_000
model.root.input['return'].unit_002 = model.root.input['return'].unit_000
model.root.input['return'].unit_003 = model.root.input['return'].unit_000
model.root.input['return'].unit_004 = model.root.input['return'].unit_000
model.root.input['return'].unit_005 = model.root.input['return'].unit_000
model.root.input['return'].unit_006 = model.root.input['return'].unit_000

# Solution times
model.root.input.solver.user_solution_times = np.linspace(0, 3478, 3479)

model.filename = 'model.h5'
model.save()

data = model.run()
model.load()
time = model.root.output.solution.solution_times
c = model.root.output.solution.unit_006.solution_outlet
sensitivity_nu = model.root.output.sensitivity.param_000.unit_002.sens_outlet

Hi Yang,

here’s the corrected code:


# parameter sensitivity
model.root.input.sensitivity.nsens = 1
model.root.input.sensitivity.sens_method = 'ad1'
model.root.input.sensitivity.param_000.sens_unit = 2
model.root.input.sensitivity.param_000.sens_name = 'SMA_NU'  # not "sma_nu"
model.root.input.sensitivity.param_000.sens_comp = 0  # could be 1 if you want sensitivity for protein, or 0 if you want sensitivity for salt, I think
model.root.input.sensitivity.param_000.sens_partype = -1
model.root.input.sensitivity.param_000.sens_reaction = -1
model.root.input.sensitivity.param_000.sens_boundphase = 0  # not -1
model.root.input.sensitivity.param_000.sens_section = -1
1 Like

Thanks for the correction, it’s running successfully now!