# Using callbacks

When using basico, usually there is no feedback given when running tasks. That is fine when tasks dont take a long time, but for optimizations or parameter estimation runs, it would be nice to know how long things could go. Setting a callback also allows for interrupting a running task through interrupting by pressing Ctrl+C. Lets see how this works. We start as always by import basico. Additionally we also import the callbacks module (since i consider it an experimental module at the time of writing this, it is not done automatically):

[1]:

from basico import *
from basico.callbacks import create_default_handler


For now i have wrapped the tqdm library, others could easily be added later on let me know if you have a preference! The create_default_handler function sets up a tdqm handler, that will be used for all longer running operations. It takes the following arguments:

• delay: delay in seconds before showing the first message (defaults to 1)

• leave: boolean flag, that indicates whether messages should remain on screen after being completed (defaults to False)

• unit: a string to display as unit for the iterations (by default tqdm will use it/s)

additional key value pairs will be passed on to tqdm. So let us just create a handler, and run some tasks:

[2]:

create_default_handler()


[3]:

load_example('LM');


it uses a local method and runs for 500 iterations, or until the tolerance of 1e-16 is reached:

[4]:

get_task_settings(T.PARAMETER_ESTIMATION)['method']

[4]:

{'Iteration Limit': 500,
'Tolerance': 1e-16,
'Stop after # Stalled Iterations': 0,
'#LogVerbosity': 0,
'name': 'Levenberg - Marquardt'}

[5]:

run_parameter_estimation()

[5]:

lower upper sol affected
name
(R1).k2 1e-6 1e6 0.000002 []
(R2).k1 1e-6 1e6 44.661715 []
Values[offset] -0.2 0.4 0.043018 [Experiment_1]
Values[offset] -0.2 0.4 0.054167 [Experiment_3]
Values[offset] -0.2 0.4 -0.050941 [Experiment]
Values[offset] -0.2 0.4 0.045922 [Experiment_4]
Values[offset] -0.2 0.4 0.048025 [Experiment_2]

lets choose just random search, which will take much longer, this will make the callbacks show up, and we will see the #function evaluations, as well as the best value reached. At any point we can interrup the execution of the cell (by presing the stop button on the notebook), this will cause the parameter estimation to stop after the next iteration, with partial results being returned:

[6]:

run_parameter_estimation(method=PE.RANDOM_SEARCH)

[6]:

lower upper sol affected
name
(R1).k2 1e-6 1e6 0.000123 []
(R2).k1 1e-6 1e6 40.864396 []
Values[offset] -0.2 0.4 0.108320 [Experiment_1]
Values[offset] -0.2 0.4 0.216139 [Experiment_3]
Values[offset] -0.2 0.4 0.010154 [Experiment]
Values[offset] -0.2 0.4 0.368608 [Experiment_4]
Values[offset] -0.2 0.4 -0.057231 [Experiment_2]

to remove the default handler again, the reset_default_handler function can be used. As it turns out, the output of the handler could not be seen on the html version of the notebook. So here a screenshot of the operation in action.

## Timeouts

callbacks can also be used, to ensure that tasks are automatically interrupted after a certain number of seconds. So if we repeat the example from above, and stop the parameter estimation automatically after 10seconds, we could use:

[7]:

create_default_handler(max_time=10)

[8]:

run_parameter_estimation(method=PE.RANDOM_SEARCH)

[8]:

lower upper sol affected
name
(R1).k2 1e-6 1e6 0.000002 []
(R2).k1 1e-6 1e6 43.882694 []
Values[offset] -0.2 0.4 -0.061506 [Experiment_1]
Values[offset] -0.2 0.4 0.062814 [Experiment_3]
Values[offset] -0.2 0.4 -0.016544 [Experiment]
Values[offset] -0.2 0.4 0.001578 [Experiment_4]
Values[offset] -0.2 0.4 0.096818 [Experiment_2]