I have a function for fitting:
import cvxpy as cp
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from lmfit import Model, Parameters
def f(wdata, pr, pi, cr, ci):
return ( np.arctan2(-2*ci*pi - 2*cr*pr, 2*cr*wdata) - np.arctan2((pi)**2 + (pr)**2 - (wdata)**2, -2*pr*wdata) )
wdata = (500000000.0, 520000000.0, 540000000.0, 560000000.0, 580000000.0, 600000000.0, 620000000.0, 640000000.0, 660000000.0, 680000000.0, 700000000.0, 720000000.0, 740000000.0, 760000000.0])
wdata= np.asarray(wdata)
ydata = f(wdata, -355574682.231318, -9040912422.93189, 31570159.4732856, -6238484.15663787)
fmodel = Model(f)
params = Parameters()
params.add('pr', value=-355574682.231318, vary=True)
params.add('pi', value=-9040912422.93189, vary=True)
params.add('pi', value=-9040912422.93189, vary=True)
params.add('cr', value=31570159.4732856, vary=True)
params.add('ci', expr='-((cr*pr)/pi) < ci < (cr*pr)/pi if pi<0 else ((cr*pr)/pi) < ci < -(cr*pr)/pi ', vary=True)
result = fmodel.fit(ydata, params, wdata=wdata)
print(result.fit_report())
plt.plot(wdata, ydata, 'bo')
plt.plot(wdata, result.init_fit, 'k--')
plt.plot(wdata, result.best_fit, 'r-')
plt.show()
As you can see, the parameter "ci" has to be bounded between other parameters. I put my constraints in an if statement; however, I got an error that name 'ci' is not defined. I think the reason is that I put the ci in two inequalities with other parameters. How can I tell my code that I want "ci" to be bounded? (with the bound that I've shown now in my code)
There are a number of odd things happening here that set off alarm bells and that you should probably fix:
Zeroth, don't name a parameter 'pi'. Code is meant to be read and that's just going to mess with people's minds. Below, I will call this 'phi'.
First, the initial values for your parameters do not need 15 significant digits.
Second, be careful to avoid variables with values that differ in scale by many orders of magnitude. if 'pr' is expected to be ~3e8 and 'phi' is expected to be ~9e9, consider "changing units" by 1e6 or 1e9 so that variable values are closer to unity.
OK, on to the actual question. I would try this:
params.add('pr', value=-3.6e8, vary=True)
params.add('phi', value=-9.0e9, vary=True)
params.add('cr', value=3.2e7, vary=True)
# add a new *internal* variable that is bound on [-pi/2, pi/2]
params.add('xangle', value=0.05, vary=True, min=-np.pi/2, max=np.pi/2)
# constrain 'ci' to be '(cr*pr/phi)*sin(xangle)'
params.add('ci', expr='(cr*pr/phi)*sin(xangle)')
Now, as xangle
varies between -pi/2
and +pi/2
, ci
will be able to take any value that is between -cr*pr/phi
and +cr*pr/phi
.