Search code examples
lmfit

How do I set a max value for a parameter to be dependent on the value of another parameter in lmfit?


I am currently trying to estimate a Voigt profile on a measurement. I want to set an upper limit for the parameter 'amplitude', where the value of the upper limit is decided by another parameter, gamma:

    Voigt_dBm = Model(V_dBm) #V_dBm is defined as a Voigt profile
    params = Voigt_dBm.make_params(gamma=5, alpha=720, ...
          amplitude=2e-8, offset=1e-9, max_lin=max(y_lin)) #Values for parameters are appropriate for the data
    params.add('max_lin', vary=False)             #This value comes from the data and should be kept static
    params.add('amplitude',max=max_lin**(gamma*2)**2) <--- This is where I want to add the gamma-dependt limit
    
    result = Voigt_dBm.fit(y,params,x=f,nan_policy='propagate')

Solution

  • lmfit does not allow using expressions for bounds - the bounds need to have values known before the fit begins and cannot change during the fit.

    You could do something like this:

    params = Voigt_dBm.make_params(gamma=5, alpha=720, offset=1e-9, ...)
    
    params.add('max_lin', value=maxy(y_lin), vary=False)    
    params.add('amp_offset', value=max(y_lin)**(gamma*2)**2/4.0, min=0)
    params.add('amplitude',  expr='max_lin**(gamma*2)**2 - amp_offset')
    

    This will constrain amplitude to be max_lin**(gamma*2)**2 minus some variable amount. By putting a limit on that amplitude offset that it must be positive, the resulting amplitude cannot exceed your max_lin**(gamma*2)**2, even if gamma changes during the fit. I guessed an initial value of 1/4 of that amount, but maybe you would have a better idea of what a reasonable initial value should be.

    You can put bounds on parameters constrained by a mathematical expression, so if you wanted to ensure amplitude was positive, you could add min=0 to params.add('amplitude', ....).