Explanation of Scipy fmin Warning - python

What does "Desired error not necessarily achieved due to precision loss" mean in the context of the scipy_fmin methods? I can't seem to find an explanation anywhere.
Here is my code:
import math
import numpy
import random
import scipy.optimize as opt
import matplotlib.pyplot as plt
from numpy import array
from numpy import dot
from random import randint
from numpy import matrix
import sys
ns = []
st = []
lam_funtrix = []
time_steps = 1000
delta_t = 0.1
mu = -0.7
def gen_st():
global st
st = []
for i in range(0, time_steps):
st.append(random.normalvariate(0,1) * math.sqrt(delta_t))
def f(val):
return math.exp(val)
def get_lam(t):
rate = mu
return pow(delta_t, -1) * f(rate)
def white_noise():
global ns
for i in range(0, time_steps):
lam = get_lam(i) * delta_t
spike_at_bin = numpy.random.poisson(lam)
ns.append(spike_at_bin)
def gen_lam_log(i, mu):
rate = mu
return pow(delta_t, -1) * f(rate)
def gen_lam_fun(mu):
global lam_funtrix
lam_funtrix = []
for i in range(0, time_steps):
lam_funtrix.append(gen_lam_log(i, mu))
def log_like(t):
mu = t
gen_lam_fun(mu)
sum = 0
for i in range(0,time_steps):
val = lam_funtrix[i]
sum = sum - ((ns[i] * math.log(val*delta_t)) - (val*delta_t))
return sum
def der_mu():
sum = 0.0
for i in range(0, time_steps):
sum -= (ns[i] - lam_funtrix[i] * delta_t)
return sum
def first_der(t):
mu = t
gen_lam_fun(mu)
dm = der_mu()
return dm
gen_st()
white_noise()
init_guess = array([0])
vals = opt.fmin_cg(log_like, init_guess, fprime=first_der)
print vals
The code is a little off since I pared it down a bit.
Warning: Desired error not necessarily achieved due to precision loss.
Current function value: 822.835581
Iterations: 1
Function evaluations: 18
Gradient evaluations: 6
[-0.7943019]

Related

Is there a way to speed up odeint in python

currently I am trying to think about how to speedup odeint for a simulation I am running. Actually its only a primitive second order ode with a friction term and a discontinuous force. The model I am using to describe the dynamics is defined in a seperate function. Trying to solve the ode results in an error or extremely high computation times (talking about days).
Here is my code mostly hardcoded:
import numpy as np
import pandas as pd
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def create_ref(tspan):
if tspan>2 and tspan<8:
output = np.sin(tspan)
elif tspan>=20:
output = np.sin(tspan*10)
else:
output = 0.5
return output
def model(state,t):
def Fs(x):
pT = 0
pB = 150
p0 = 200
pA = 50
kein = 0.25
kaus = 0.25
if x<0:
pA = pT
Fsres = -kaus*x*pA-kein*x*(p0-pB)
else:
pB = pT
Fsres = -kaus*x*pB-kein*x*(p0-pA)
return Fsres
x,dx = state
refnow = np.interp(t,xref.index.values,xref.values.squeeze())
refprev = np.interp(t-dt,xref.index.values,xref.values.squeeze())
drefnow = (refnow-refprev)/dt
x_meas = x
dx_meas = dx
errnow = refnow-x_meas
errprev = refprev-(x_meas-dx_meas*dt)
intrefnow = dt*(errnow-errprev)
kp = 10
kd = 0.1
ki = 100
sigma = kp*(refnow-x_meas)+kd*(drefnow-dx_meas)+ki*intrefnow
tr0 = 5
FricRed = (1.5-0.5*np.tanh(0.1*(t-tr0)))
kpu = 300
fr = 0.1
m = 0.01
d = 0.01
k = 10
u = float(kpu*np.sqrt(np.abs(sigma))*np.sign(sigma))
ddx = 1/m*(Fs(x)+FricRed*fr*np.sign(dx)-d*dx-k*x + u )
return [dx,ddx]
dt = 1e-3
tspan = np.arange(start=0, stop=50, step=dt)
steplim = tspan[-1]*0.1
reffunc = np.vectorize(create_ref)
xrefvals = reffunc(tspan)
xref = pd.DataFrame(data=xrefvals,index=tspan,columns=['xref'])
x0 = [-0.5,0]
simresult = odeint(model, x0, tspan)
plt.figure(num=1)
plt.plot(tspan,simresult[:,0],label='ispos')
plt.plot(tspan,xref['xref'].values,label='despos')
plt.legend()
plt.show()
I change the code according to Pranav Hosangadi s comments. Thanks for the hints. I didn't know that and learned something new and didn't expect dictionaries to have such a high impact on computation time. But now its much faster.

Floating RMS in Python

I'm trying to implement a floating window RMS in python. I'm simulating an incoming stream of measurement data by simpling iterating over time and calculating the sine wave. Since it's a perfect sine wave, its easy to compare the results using math. I also added a numpy calculation to confirm my arrays are populated correctly.
However my floating RMS is not returning the right values, unrelated to my sample size.
Code:
import matplotlib.pyplot as plot
import numpy as np
import math
if __name__ == '__main__':
# sine generation
time_array = []
value_array = []
start = 0
end = 6*math.pi
steps = 100000
amplitude = 10
#rms calc
acc_load_current = 0
sample_size = 1000
for time in np.linspace(0, end, steps):
time_array.append(time)
actual_value = amplitude * math.sin(time)
value_array.append(actual_value)
# rms calc
acc_load_current -= (acc_load_current/sample_size)
# square here
sq_value = actual_value * actual_value
acc_load_current += sq_value
# mean and then root here
floating_rms = np.sqrt(acc_load_current/sample_size)
fixed_rms = np.sqrt(np.mean(np.array(value_array)**2))
math_rms = 1/math.sqrt(2) * amplitude
print(floating_rms)
print(fixed_rms)
print(math_rms)
plot.plot(time_array, value_array)
plot.show()
Result:
2.492669969708522
7.071032456438027
7.071067811865475
I solved the issue by usin a recursive average with zero crossing detection:
import matplotlib.pyplot as plot
import numpy as np
import math
def getAvg(prev_avg, x, n):
return (prev_avg * n + x) / (n+1)
if __name__ == '__main__':
# sine generation
time_array = []
value_array = []
used_value_array = []
start = 0
end = 6*math.pi + 0.5
steps = 10000
amplitude = 325
#rms calc
rms_stream = 0
stream_counter = 0
#zero crossing
in_crossing = 0
crossing_counter = 0
crossing_limits = [-5,5]
left_crossing = 0
for time in np.linspace(0, end, steps):
time_array.append(time)
actual_value = amplitude * math.sin(time) + 4 * np.random.rand()
value_array.append(actual_value)
# detect zero crossing, by checking the first time we reach the limits
# and then not counting until we left it again
is_crossing = crossing_limits[0] < actual_value < crossing_limits[1]
# when we are at amp/2 we can be sure the noise is not causing zero crossing
left_crossing = abs(actual_value) > amplitude/2
if is_crossing and not in_crossing:
in_crossing = 1
crossing_counter += 1
elif not is_crossing and in_crossing and left_crossing:
in_crossing = 0
# rms calc
# square here
if 2 <= crossing_counter <= 3:
sq_value = actual_value * actual_value
rms_stream = getAvg(rms_stream, sq_value, stream_counter)
stream_counter += 1
# debugging by recording the used values
used_value_array.append(actual_value)
else:
used_value_array.append(0)
# mean and then root here
stream_rms_sqrt = np.sqrt(rms_stream)
fixed_rms_sqrt = np.sqrt(np.mean(np.array(value_array)**2))
math_rms_sqrt = 1/math.sqrt(2) * amplitude
print(stream_rms_sqrt)
print(fixed_rms_sqrt)
print(math_rms_sqrt)
plot.plot(time_array, value_array, time_array, used_value_array)
plot.show()

Distribution plot with wrong total value

To create
I have made a distribution plot with code below:
from numpy import *
import numpy as np
import matplotlib.pyplot as plt
sigma = 4.1
x = np.linspace(-6*sigma, 6*sigma, 200)
def distr(n):
def g(x):
return (1/(sigma*sqrt(2*pi)))*exp(-0.5*(x/sigma)**2)
FxSum = 0
a = list()
for i in range(n):
# divide into 200 parts and sum one by one
numb = g(-6*sigma + (12*sigma*i)/n)
FxSum += numb
a.append(FxSum)
return a
plt.plot(x, distr(len(x)))
plt.show()
This is, of course, a way of getting the result without using hist(), cdf() or any other options from Python libraries.
Why the total sum is not 1? It shouldn't depend from (for example) sigma.
Almost right, but in order to integrate you have to multiply the function value g(x) times your tiny interval dx (12*sigma/200). That's the area you sum up:
from numpy import *
import numpy as np
import matplotlib.pyplot as plt
sigma = 4.1
x = np.linspace(-6*sigma, 6*sigma, 200)
def distr(n):
def g(x):
return (1/(sigma*sqrt(2*pi)))*exp(-0.5*(x/sigma)**2)
FxSum = 0
a = list()
for i in range(n):
# divide into 200 parts and sum one by one
numb = g(-6*sigma + (12*sigma*i)/n) * (12*sigma/200)
FxSum += numb
a.append(FxSum)
return a
plt.plot(x, distr(len(x)))
plt.show()

calling args in a loop-function

for MCMC I use emcee package this tutorial. Instead of the equation of thispart which is fractional and so easy I use this form, I mean I use matrix form(not its code) and wrote the following code.
for more explanation of my code:
def new_calculation(n) is the equation for each component of matrix and def log_likelihood(theta,hh): is the mentioned matrix.
the problem is, I need args to use in soln = minimize(nll, initial, args=(hh)) and def log_probability(theta,hh):
I use hh as args but the Python says the hh is not defined. the problem may be for definition of arguments and function. I do not know how to fix it.
import numpy as np
import emcee
import matplotlib.pyplot as plt
from math import *
import numpy as np
from scipy.integrate import quad
from scipy.integrate import odeint
xx=np.array([0.01,0.012,0.014,0.016])
yy=np.array([32.95388698,33.87900347,33.84214074,34.11856704])
Cov=[[137,168],[28155,-2217]]
rc=0.09
c=0.7
H01 = 70
O_m1 = 0.28
z0=0
M1=10
np.random.seed(123)
def ant(z,O_m,O_D):
return 1/sqrt(((1+z)**2)*(1+O_m*z))
def new_calculation(n):
O_D=1-O_m-(1/(2*rc*yyn))
q=quad(ant,0,xx[n],args=(O_m,O_D))[0]
h=log10((1+xx[n])*q)
fn=(yy[n]-M-h)
return fn
def log_likelihood(theta,hh):
H0, O_m,M= theta
f_list = []
for i in range(2): # the value '2' reflects matrix size
f_list.append(new_calculation(i))
rdag=[f_list]
rmat=[[f] for f in f_list]
hh=np.linalg.det(np.dot(rdag,Cov),rmat)*0.000001
return hh
from scipy.optimize import minimize
np.random.seed(42)
nll = lambda *args: -log_likelihood(*args)
initial = np.array([H01, O_m1,M1]) + 0.1*np.random.randn(3)
soln = minimize(nll, initial, args=(hh))
H0_ml, O_m0_ml = soln.x
def log_prior(theta):
H0, O_D = theta
if 65 < H0 < 75 and 0.22 < O_m < 0.32 and 0 < M < 12:
return 0.0
return -np.inf
def log_probability(theta, mm,zz,hh):
lp = log_prior(theta)
if not np.isfinite(lp):
return -np.inf
return lp + log_likelihood(theta, mm,zz,hh)
y0=H0
pos = soln.x + 1e-4*np.random.randn(200, 3)
nwalkers, ndim = pos.shape
sampler = emcee.EnsembleSampler(nwalkers, ndim, log_probability, args=(rdag, rmat))
sampler.run_mcmc(pos, 500);
fig = plt.figure(2,figsize=(10, 10))
fig.clf()
for j in range(ndim):
ax = fig.add_subplot(ndim,1,j+1)
ax.plot(np.array([sampler.chain[:,i,j] for i in range(nwalkers)]),"k", alpha = 0.3)
ax.set_ylabel(("H0", "O_m")[j], fontsize = 15)
plt.xlabel('Steps', fontsize = 15)
fig.show()
I appreciate your help and your attention.

Why does scipy.optimize.curve_fit give an error?

I have been trying to make a function that solves a set of ordinary differential equations and then fit it to experimental data using the the scipy.optimize.curve_fit function, but I get an error message containing:
"ValueError: object too deep for desired array
odepack.error: Result from function call is not a proper array of floats."
Any help would be much appreciated.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from pylab import *
from scipy.optimize import curve_fit
kB = 8.6173324e-5 #eV/K
P_H2O = 0.05 # bar
H_H2O = -0.8 #eV
S_H2O = -0.0016
def K_H2O(T):
return np.exp(-H_H2O/(kB*T))*np.exp(S_H2O/(kB))
def FracA(T):
return K_H2O(T)*P_H2O / (1+K_H2O(T)*P_H2O)
def FracB(T):
return 1-FracA(T)
EA1_A = 0.725 # eV (from experimental data)
def k1_A(A1_A,T):
return A1_A*np.exp(-EA1_A/(kB*T))
A1_B = 5.e3 #
EA1_B = 0.8 #eV
def k1_B(T):
return A1_B*np.exp(-EA1_B/(kB*T))
A2_B = 8.e3 #
EA2_B = 1.0 #eV
def k2_B(T):
return A2_B*np.exp(-EA2_B/(kB*T))
# initial conditions
P_NO0 = 500.e-6 # initial NO
P_NH30 = 530.e-6 # initial NH3
y0 = [P_NO0, P_NH30] # initial condition vector
t = np.linspace(0, 30., 1000) # time grid
def conv(T,A1_A):
def f(y, t):
P_NOi = y[0]
P_NH3i = y[1]
# the differential equations
if y[0] and y[1] > 0:
f0 = -k1_A(A1_A,T)*FracA(T)*P_NOi -k1_B(T)*FracB(T)*P_NOi*P_NH3i**(-0.25)
else:
f0 = 0
if y[0] and y[1] > 0:
f1 = -k1_A(A1_A,T)*FracA(T)*P_NOi -k1_B(T)*FracB(T)*P_NOi*P_NH3i**(-0.25)-k2_B(T)*P_NH3i
else:
f1 = 0
return [f0, f1]
# solve the DEs
soln = odeint(f, y0, t)
P_NO = soln[:, 0]
P_NH3 = soln[:, 1]
NO_conv = 1-P_NO[-1]/P_NO0
return NO_conv
x_real = np.array([433.1,443.1,453.2,463.1,473.1,483.7,494.2,503.5,523.9,553.7,573.6,623.4,673.4,723.3,773.4,823.2])
y_real =np.array([0.064305859, 0.098333053, 0.151494329, 0.217225336, 0.296164608, 0.397472394, 0.508515308, 0.612339428, 0.793549257, 0.892454094, 0.895511489, 0.861625527, 0.949118344, 0.940025727, 0.852439418, 0.727332885])
popt, pcov = curve_fit(conv, x_real, y_real)

Categories