When I run the code
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# Initial conditions
def f_func(eta,y_in):
y_out = np.zeros(3)
y_out[0] = y_in[1]
y_out[1] = y_in[2]
y_out[2] = -y_in[0]*y_in[2]/2
return y_out
eta = np.linspace(0,8,100)
X0 = [0,0,0.33206]
X = odeint(f_func,X0,eta)
I get the error
'float' object has no attribute '__getitem__'
When I run the following MATLAB program, everything works OK. The MATLAB function ode45 is equivalent to Pythons' odeint.
main program:
clear
global beta
beta = 1;
initial_value = [0,0,1.2322];
eta = linspace(0,4,100)
[x_out, y_out] = ode45(#falkner_skan,eta,initial_value);
plot(x_out,y_out(:,2))
falkner_skan function:
function y_out = falkner_skan(x,y_in)
global beta
y_out(1,1) = y_in(2);
y_out(2,1) = y_in(3);
y_out(3,1) = -y_in(1)*y_in(3) - beta*(1-y_in(2)^2);
end
This and this and this thread does not seem to give me any guidance.
It seems as though y_in is not a list but a float value. The error rises because you're trying to get an item with obj[x] of an object which doesn't support it.
Looking at the documentation for odeint it says that the input function should take two arguments, the first being your data object and the second should be a float. Your implementation of f_func is therefore wrong.
NumPy has float 64 object which has item() function, np.float64(10.5).item()
I had the same issue. According to documentation for odeint, in f_func(eta,y_in), change the order of eta and y_in, i.e. write it as f_func(y_in, eta) or set the argument tfirst to be True.
Related
I'm a student learning ML with Python. I have the following code which generates a np.array, uses it as a parameter of the function and creates its plot:
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize as opt
def _y_(x):
return np.sin(x/5)*np.exp(x/10) + 5*np.exp(-x/2)
x = np.arange(1, 30.01, 0.01)
y = _y_(x)
plt.plot(x, y)
plt.show()
min1 = opt.minimize(y, x0=2)
print(res1)
print()
min2 = opt.minimize(y, x0=15)
print(min2)
print()
min3 = opt.minimize(y, x0=30)
print(min3)
print()
But when I try to find the minimum of the function for three different points, I get an error:
'numpy.ndarray' object is not callable
It occurs on this line:
min1 = opt.minimize(y, x0=2)
Please, help me fix it!
The minimize function of scipy.optimize expects a callable argument (a function) as its first argument, as per its documentation.
You are providing the array y as input argument. Instead, you should provide the function that calculates y from x, so you should provide _y_. The code min1 = opt.minimize(_y_, x0=2) works without issues.
help, please - I can't understand my own code! lol
I'm fairly new at python and after many trials and errors, I got my code to work, but there is one particular part of it I don't understand.
In the code below, I'm solving a fairly basic ODE through scipy's odeint-function. My goal is then to build on this blue-print for more complicated systems.
My question(s): How could I call the method .reaction_rate_simple without any arguments and without the closing parenthesis? What does this mean in python? Should I use a static method here somewhere?
If anyone has any feedback on this - maybe this is a crappy piece of code and there's a better way of solving it!
I am very thankful for any response and help!
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
class batch_reator:
def __init__(self, C_init, volume_reactor, time_init, time_end):
self.C_init = C_init
self.volume = volume_reactor
self.time_init = time_init
self.time_end = time_end
self.operation_time = (time_end - time_init)
def reaction_rate_simple(self, concentration_t, t, stoch_factor, order, rate_constant):
reaction_rate = stoch_factor * rate_constant * (concentration_t ** order)
return reaction_rate
def equations_system(self, kinetics):
dCdt = kinetics
return dCdt
C_init = 200
time_init, time_end = 0, 1000
rate_constant, volume_reactor, order, stoch_factor = 0.0001, 10, 1, -1
time_span = np.linspace(time_init, time_end, 100)
Batch_basic = batch_reator(C_init, volume_reactor, time_init, time_end)
kinetics = Batch_basic.reaction_rate_simple
sol = odeint(Batch_basic.equations_system(kinetics), Batch_basic.C_init, time_span, args=(stoch_factor, order, rate_constant))
plt.plot(time_span, sol)
plt.show()
I assume you are referring to the line
kinetics = Batch_basic.reaction_rate_simple
You are not calling it, you are saving the method as a variable and then passing that method to equations_system(...), which simply returns it. I am not familiar with odeint, but according to the documentation, it accepts a callable, which is what you are giving it.
In python functions, lambdas, classes are all callable and can be assigned to variable and passed to functions and called as needed.
In this particular case the callback definition from the odeint docs say
func callable(y, t, …) or callable(t, y, …)
Computes the derivative of y at t. If the signature is callable(t, y, ...), then the argument tfirst must be set True.
So the first two arguments are passed in by odeint, and the other three are coming from the arguments specified by you.
I am trying to create an curve fitting program using LMFIT on python (Anaconda) but I keep receiving the same error message: TypeError: only size-1 arrays can be converted to Python scalars. I was able to perform an optimization using just one function, but when I try to optimize a function that calls other user-defined functions, I get this error.
import numpy as np
from matplotlib import pyplot
import scipy.special as sp
from scipy import integrate
import lmfit as lm
#Defining the first function.
def function1(alpha,q,s,l):
Intensity = alpha**2 + q -s*alpha / (5*l)
return Intensity
#Defining a second function that will perform a integration over the first function.
def integrate_function(q,s,l):
func_parameters = {
'q':q,
's':s,
'l':l,
}
to_be_integrated = lambda alpha: function1(alpha, **func_parameters)
result, error = integrate.quad(to_be_integrated, 0, 10)
return result
#Setting up the LMFIT model. Here I also provide the initial guess for the parameters.
integrate_function_model = lm.Model(integrate_function, independent_vars=['q'])
integrate_function_model.set_param_hint('s', value=2, min=-10.0, max=20.0, vary=True)
integrate_function_model.set_param_hint('l', value=3, min=1.0, max=10.0, vary=True)
initial_params = integrate_function_model.make_params()
#Creating data to be fitted (I also add some noise)
#Here I set s=1.5 and l=5.0 and I want the optimization routine to be able to find out these numbers.
x_data = np.linspace(0, 10, 100)
y_data = np.zeros(len(x_data))
for i in range(len(x_data)):
y_data[i] = integrate_function(x_data[i],1.5,5.0) + 5.0*np.random.random()
#Fitting the data.
fitting = integrate_function_model.fit(y_data, initial_params, q=x_data, method='leastsq')
#Printing original data and fitted model.
pyplot.plot(x_data, y_data, color='green', lw=2)
pyplot.plot(x_data, fitting.best_fit, color='blue', lw=2)
pyplot.show()
The error occurs when your function integrate_function is called with a np.array as an argument for q:
>>> integrate_function(1,1,1)
333.33333333333337
>>> integrate_function(np.array([1,2]),1,1)
TypeError: only size-1 arrays can be converted to Python scalars
This happens during output.fit where integrate.quad is called. quad is not able to handle vectorized input, which is happening in your case.
One option to fix this would be to change integrate_function to handle the case where q is an array accordingly, for example by manually including a loop over all values in q:
def integrate_function(q,s,l):
# Make q iterable if it is only a float/int
if not hasattr(q, '__iter__'):
q = np.array([q])
result = []
for q0 in q:
func_parameters = {
'q':q0,
's':s,
'l':l,
}
to_be_integrated = lambda alpha: function1(alpha, **func_parameters)
result.append(integrate.quad(to_be_integrated, 0, 10)[0])
return np.array(result)
Executing your code with the modified integrate_function then yields the following plot:
When I run my code I receive the error "unsupported operand type(s) for ** or pow(): 'numpy.ufunc' and 'float'"
The code is:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sqrt,exp,log
from scipy import linalg
from scipy.optimize import curve_fit
data1 = np.loadtxt('decay1.txt', float,skiprows=1)
t = data1[:,0]
n = data1[:,1]
data2 = np.loadtxt('decay2.txt', float,skiprows=1)
T = data2[:,0]
N = data2[:,1]
def Radio(n,t,tao,b):
return (n*(exp**(-(t/tao)))) + b
guesses = (1,1,1)
guesses2 = (1,1,1)
(p0,p1,p2),cc = curve_fit(Radio,t,n,guesses)
(p02,p12,p22),cc2 = curve_fit(Radio,T,N,guesses2)
yfit = Radio(t,p0,p1,p2)
y2fit = Radio(T,p02,p12,p22)
I have to fit the function to the radioactive decay data, so tell me if I also messed up the code to fit a function to it. Thanks for any help!
numpy.exp is the exponential function and ** is the power operator, so you're trying to raise a function definition to the power (-(t/tao)). I think you wanted
def Radio(n,t,tao,b):
return (n*(exp(-(t/tao)))) + b
With respect to the use of the optimization function, there are a couple of issues. First, you are using n as both the parameter (inside the Radio method) and the dependent variable data (from the problem statement), which is confusing things. I would change that to something like a (as is used in the curve_fit doc. That's not really necessary, but helps readability.
Second, and more importantly, the function to be fit must have the independent variable (in this case, t) as the first argument. I think what is happening to cause a flat fit is that you are actually fitting the curve n->Radio(n) (with all those other variables as parameters) instead of t->Radio(t).
I am getting a "TypeError: 'float' object is not callable.
Here is my code:
from matplotlib.pylab import *
def f(x,t):
return (exp(-(x-3*t)**2) )*sin(3*pi(x-t))
x = linspace(-4, 4, 8)
y = zeros(len(x))
for i in xrange(len(x)):
y[i] = f(x[i],0)
plot(x, y)
show()
pi isn't a function, but since you didn't use * to indicate you want to multiply with it, it looks like you are using it as one.
float is a number type in Python. You cannot call this because it is not a function. I am not familiar with the mathplotlib.pylab package, but taking a quick look at your code, I would guess that the error is in this part of the code
from matplotlib.pylab import *
def f(x,t):
return (exp(-(x-3*t)**2) )*sin(3*pi(x-t)) #<---- pi is not a function, it can't be called
x = linspace(-4, 4, 8)
y = zeros(len(x))
for i in xrange(len(x)):
y[i] = f(x[i],0)
plot(x, y)
show()
If you have not defined a method called pi or mathplotlib.pylab contains no method called pi, then that would be where your error is. If py is a floating point variable equal to 3.1415 then calling pi(x-t) would be the same as calling 3.1415(x-t).
You most likely want to perform an operation with pi. If so, then use the desired operation. example, `pi+(x-t)
c=(1/((abs(r1-rmed)+1)(abs(r2-rmed)+1)))
when I type this line in my program, I get the error:
float object is not callable.
for removing the error I use * between the bracket.
c=(1/((abs(r1-rmed)+1)*(abs(r2-rmed)+1)))