How to use a previous list in another expression - python

I am trying to use the list created for Mf_values to be used in the expression for P0 in my code. I have tried it in the following way:
Mf_values=[0.8, 0.9, 1.2, 1.5]
Vinf_values=[Mf_value*(gamma*R*tatm)**0.5 for Mf_value in Mf_values]
print(Vinf_values)
P0=[(1+((gamma-1)/2)*(Mf_values**2)**(gamma/(gamma-1))]
T0=(1+((gamma-1)/2)*(Mf_values**2))*tatm
I want to use the 4 different Mf_values for solving the expression for P0 and T0 and save the results in a list in a similar fashion to Vinf_values. However, python gives me the following error:
P0=[(1+((gamma-1)/2)*(Mf_values**2)**(gamma/(gamma-1))]
^
SyntaxError: invalid syntax
How could I solve this issue?

It is easier to do what you want using numpy:
import numpy as np
# Change the below values to the correct ones
gamma = 0.5
R = 1.0
tatm = 1.0
Mf_values = np.array([0.8, 0.9, 1.2, 1.5])
Vinf_values = Mf_values * (gamma * R * tatm)**0.5
print(Vinf_values)
P0 = (1 + ((gamma - 1) / 2) * (Mf_values**2))**(gamma/(gamma - 1))
T0 = (1 + ((gamma - 1) / 2) * (Mf_values**2)) * tatm
If really need lists, you can simply convert to lists by doing this:
P0 = list(P0)
T0 = list(T0)

you cannot do pow operation and other operations that you're trying to do with a normal python list, you can either use numpy or you can do the following :
Mf_values = [0.8, 0.9, 1.2, 1.5]
Vinf_values = [ Mf_value * ( gamma * R * tatm ) ** 0.5 for Mf_value in Mf_values ]
Mf_values_2 = [v ** 2 for v in Mf_values ]
tmp = [ v ** ( gamma / (gamma - 1) ) for v in Mf_values_2 ]
P0=[ v * (1 + ( ( gamma - 1 ) / 2)) for v in tmp]
tmp2 = [ v * (1 + ( (gamma - 1) / 2 )) for v in Mf_values_2 ]
T0 = [tatm * v for v in tmp2 ]
to do an add operation between a value and a list, do :
# lst is a list and val is an number
result = [val * elem for elem in lst]
to do an add operation between the elements of 2 lists, do :
# lst1 and lst2 are lists
result = [a + b for a, b in zip(lst1, lst2)]

Related

Finding roots of an equation involving a summation using sympy

I am currently to new to sympy and I am trying to reproduce the Mathematica example in the attached image in Python. My attempt is written below but it returns an empty list
import sympy
m , n, D_star, a, j = sympy.symbols('m , n, D_star, a, j')
s1 = sympy.Sum(a**(j-1),(j, 1, m-1))
rhs = 6 * sympy.sqrt((D_star * (1 + a)*(n - 1))/2)
expand_expr = sympy.solve(s1 - rhs, m)
temp = sympy.lambdify((a, n, D_star), expand_expr, 'numpy')
n = 100
a = 1.2
D_star = 2.0
ms = temp(1.2, 100, 2.0)
ms
# what I get is an empty list []
# expected answer using Mma FindRoot function is 17.0652
Adding .doit() to expand the sum seems to help. It gives Piecewise((m - 1, Eq(a, 1)), ((a - a**m)/(1 - a), True))/a for the sum in s1.
from sympy import symbols, Eq, Sum, sqrt, solve, lambdify
m, n, j, a, D_star = symbols('m n j a D_star')
s1 = Sum(a**(j - 1), (j, 1, m - 1)).doit()
rhs = 6 * sqrt((D_star * (1 + a) * (n - 1)) / 2)
expand_expr = solve(Eq(s1, rhs), m)
temp = lambdify((a, n, D_star), expand_expr, 'numpy')
n = 100
a = 1.2
D_star = 2.0
ms = temp(1.2, 100, 2.0)
This gives for expand_expr:
[Piecewise((log(a*(3*sqrt(2)*a*sqrt(D_star*(a*n - a + n - 1)) - 3*sqrt(2)*sqrt(D_star*(a*n - a + n - 1)) + 1))/log(a), Ne(a, 1)), (nan, True)),
Piecewise((3*sqrt(2)*a*sqrt(D_star*(a*n - a + n - 1)) + 1, Eq(a, 1)), (nan, True))]
which separates into a != 1 and a == 1.
The result of ms gives [array(17.06524172), array(nan)], again in a bit awkward way to separate a hypothetical a == 1.

Python calculate percentage of list values one by others

I have a list of values and I want to get difference percentage of the each element with others.
x[1] with x[2],x[3],x[4]
x[2] with x[1],x[3],x[4] and so on.
x =["3150000", "3156000", "3150000","3250000"]
Here is what I want using python:
((3150000 - 3156000) / 3150000) * 100
Desired output:
[-0.19, 0, 3.17, 0.19, 0.19 ..., 3.08]
What's the most efficient way to do this?
is this what you want?
x =["3150000", "3156000", "3150000","3250000"]
x = list(map(int, x))
for x1 in x:
for x2 in x:
if x1 == x2:
continue
diff_per = abs(x1 - x2) / x1 * 100
print("abs({x1} - {x2}) / {x1} * 100 == {:.2f}%".format(diff_per, x1=x1, x2=x2))
output:
abs(3150000 - 3156000) / 3150000 * 100 == 0.19%
abs(3150000 - 3250000) / 3150000 * 100 == 3.17%
abs(3156000 - 3150000) / 3156000 * 100 == 0.19%
abs(3156000 - 3150000) / 3156000 * 100 == 0.19%
abs(3156000 - 3250000) / 3156000 * 100 == 2.98%
abs(3150000 - 3156000) / 3150000 * 100 == 0.19%
abs(3150000 - 3250000) / 3150000 * 100 == 3.17%
abs(3250000 - 3150000) / 3250000 * 100 == 3.08%
abs(3250000 - 3156000) / 3250000 * 100 == 2.89%
abs(3250000 - 3150000) / 3250000 * 100 == 3.08%
Assuming you are looking for all possible difference pairs.
You can compute the matrix of differences with broadcasting, then divide back and normalize to a percentage:
>>> (x - x[:, None])/x*100
array([[ 0. , 0.19011407, 0. , 3.07692308],
[-0.19047619, 0. , -0.19047619, 2.89230769],
[ 0. , 0.19011407, 0. , 3.07692308],
[-3.17460317, -2.97845374, -3.17460317, 0. ]])
Where component at position i, j corresponds to (x[i] - x[j]) / x[i] * 100.
I did preprocess x with:
>>> x = np.array([int(i) for i in x])
array([3150000, 3156000, 3150000, 3250000])
Similarly you could use np.array(x).astype(float).
You can use itertools.permutations:
import itertools
def func(l):
return round(((l[0] - l[1]) / l[0]) * 100)
lst = ["3150000", "3156000", "3150000","3250000"]
# map the string values in list to their integer counterpart
lst = map(int, lst)
# create permutations of length 2 from list
permutations = list(itertools.permutations(lst, 2))
# apply function to the permutations
results = {l: func(l) for l in permutations}
# print results
print(*results.items(), sep='\n')
((3150000, 3156000), -0.19)
((3150000, 3150000), 0.0)
((3150000, 3250000), -3.17)
((3156000, 3150000), 0.19)
((3156000, 3250000), -2.98)
((3250000, 3150000), 3.08)
((3250000, 3156000), 2.89)
As one-liner:
results = {l: func(l) for l in list(itertools.permutations(map(int, lst), 2))}

Lyapunov Spectrum for known ODEs - Python 3 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I want to numerically compute the Lyapunov Spectrum of the Lorenz System by using the standard method which is described in this Paper, p.81.
One basically need integrate the Lorenz system and the tangential vectors (i used the Runge-Kutta method for this). The evolution equation of the tangential vectors are given by the Jacobi matrix of the Lorenz system. After each iterations one needs to apply the Gram-Schmidt scheme on the vectors and store its lengths. The three Lyapunov exponents are then given by the averages of the stored lengths.
I implemented the above explained scheme in python (used version 3.7.4), but I don't get the correct results.
I thing the bug lies in the Rk4-Method for der vectors, but i cannot find any error...The RK4-method for the trajectories x,y,z works correctly (indicated by the plot) and the implemented Gram-Schmidt scheme is also correctly implemented.
I hope that someone could look through my short code and maybe find my error
Edit: Updated Code
from numpy import array, arange, zeros, dot, log
import matplotlib.pyplot as plt
from numpy.linalg import norm
# Evolution equation of tracjectories and tangential vectors
def f(r):
x = r[0]
y = r[1]
z = r[2]
fx = sigma * (y - x)
fy = x * (rho - z) - y
fz = x * y - beta * z
return array([fx,fy,fz], float)
def jacobian(r):
M = zeros([3,3])
M[0,:] = [- sigma, sigma, 0]
M[1,:] = [rho - r[2], -1, - r[0] ]
M[2,:] = [r[1], r[0], -beta]
return M
def g(d, r):
dx = d[0]
dy = d[1]
dz = d[2]
M = jacobian(r)
dfx = dot(M, dx)
dfy = dot(M, dy)
dfz = dot(M, dz)
return array([dfx, dfy, dfz], float)
# Initial conditions
d = array([[1,0,0], [0,1,0], [0,0,1]], float)
r = array([19.0, 20.0, 50.0], float)
sigma, rho, beta = 10, 45.92, 4.0
T = 10**5 # time steps
dt = 0.01 # time increment
Teq = 10**4 # Transient time
l1, l2, l3 = 0, 0, 0 # Lengths
xpoints, ypoints, zpoints = [], [], []
# Transient
for t in range(Teq):
# RK4 - Method
k1 = dt * f(r)
k11 = dt * g(d, r)
k2 = dt * f(r + 0.5 * k1)
k22 = dt * g(d + 0.5 * k11, r + 0.5 * k1)
k3 = dt * f(r + 0.5 * k2)
k33 = dt * g(d + 0.5 * k22, r + 0.5 * k2)
k4 = dt * f(r + k3)
k44 = dt * g(d + k33, r + k3)
r += (k1 + 2 * k2 + 2 * k3 + k4) / 6
d += (k11 + 2 * k22 + 2 * k33 + k44) / 6
# Gram-Schmidt-Scheme
orth_1 = d[0]
d[0] = orth_1 / norm(orth_1)
orth_2 = d[1] - dot(d[1], d[0]) * d[0]
d[1] = orth_2 / norm(orth_2)
orth_3 = d[2] - (dot(d[2], d[1]) * d[1]) - (dot(d[2], d[0]) * d[0])
d[2] = orth_3 / norm(orth_3)
for t in range(T):
k1 = dt * f(r)
k11 = dt * g(d, r)
k2 = dt * f(r + 0.5 * k1)
k22 = dt * g(d + 0.5 * k11, r + 0.5 * k1)
k3 = dt * f(r + 0.5 * k2)
k33 = dt * g(d + 0.5 * k22, r + 0.5 * k2)
k4 = dt * f(r + k3)
k44 = dt * g(d + k33, r + k3)
r += (k1 + 2 * k2 + 2 * k3 + k4) / 6
d += (k11 + 2 * k22 + 2 * k33 + k44) / 6
orth_1 = d[0] # Gram-Schmidt-Scheme
l1 += log(norm(orth_1))
d[0] = orth_1 / norm(orth_1)
orth_2 = d[1] - dot(d[1], d[0]) * d[0]
l2 += log(norm(orth_2))
d[1] = orth_2 / norm(orth_2)
orth_3 = d[2] - (dot(d[2], d[1]) * d[1]) - (dot(d[2], d[0]) * d[0])
l3 += log(norm(orth_3))
d[2] = orth_3 / norm(orth_3)
# Correct Solution (2.16, 0.0, -32.4)
lya1 = l1 / (dt * T)
lya2 = l2 / (dt * T) - lya1
lya3 = l3 / (dt * T) - lya1 - lya2
lya1, lya2, lya3
# my solution T = 10^5 : (1.3540301507934012, -0.0021967491623752448, -16.351653561383387)
The above code is updated according to Lutz suggestions.
The results look much better but they are still not 100% accurate.
Correct Solution (2.16, 0.0, -32.4)
My solution (1.3540301507934012, -0.0021967491623752448, -16.351653561383387)
The correct solutions are from Wolf's Paper, p.289. On page 290-291 he describes his method, which looks exactly the same as in the paper that i mentioned in the beginning of this post (Paper, p.81).
So there must be another error in my code...
You need to solve the system of point and Jacobian as the (forward) coupled system that it is. In the original source exactly that is done, everything is updated in one RK4 call for the combined system.
So for instance in the second stage, you would mix the operations to have a combined second stage
k2 = dt * f(r + 0.5 * k1)
M = jacobian(r + 0.5 * k1)
k22 = dt * g(d + 0.5 * k11, r + 0.5 * k1)
You could also delegate the computation of M inside the g function, as this is the only place where it is needed, and you increase locality in the scope of variables.
Note that I changed the update of d from k1 to k11, which should be the main source of the error in the numerical result.
Additional remarks on the last code version (2/28/2021):
As said in the comments, the code looks like it will do what the mathematics of the algorithm prescribes. There are two misreadings that prevent the code from returning a result close to the reference:
The parameter in the paper is sigma=16.
The paper uses not the natural logarithm, but the binary one, that is, the magnitude evolution is given as 2^(L_it). So you have to divide the computed exponents by log(2).
Using the method derived in https://scicomp.stackexchange.com/questions/36013/numerical-computation-of-lyapunov-exponent I get the exponents
[2.1531855610566595, -0.00847304754613621, -32.441308372177566]
which is sufficiently close to the reference (2.16, 0.0, -32.4).

Integrate Over Multiple Columns in 1 List to Fill Additional List With Same Number Of Columns

I am intending to take a list of random variables and alter a previous list in each column by said random variables. However, for the purpose of my function, each variable must be used in a Gamma function as well as integrated.
x[t] = c * (1 / (2 ** (v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
x[ t ] is an np.zeros((x , y)) list, and test[t - 1] is an np.zeros((x - 1, y)) list
I have filled test[ ] with the appropriate random variables, but I am unable to pass them through this equation to complete the columns of row [ t ] in x
When I try to run my current code, I receive:
File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_64\lib\site-packages\scipy\integrate\quadpack.py", line 450, in _quad
return _quadpack._qagie(func,bound,infbounds,args,full_output,epsabs,epsrel,limit)
TypeError: only size-1 arrays can be converted to Python scalars
Is there a different special function which allows me to use each column's variable to solve for my desired x[ t ]?
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import stats
import mpmath as mp
import scipy.integrate as integrate
from scipy.special import gamma
T = 1
beta = 0.5
x0 = 0.05
q = 0
mu = x0 - q
alpha = - (2 - beta) * mu
sigma0 = 0.1
sigma = (2 - beta) * sigma0
b = - ((1 - beta) / (2 * mu) * (sigma0 ** 2))
simulations = 100
M = 50
dt = T / M
def srd_sampled_nxc2():
x = np.zeros((M + 1, simulations))
x[0] = x0
test = np.zeros((M, simulations))
for t in range(1, M + 1):
v = 4 * b * alpha / sigma ** 2
c = (sigma ** 2 * (1 - np.exp(-alpha * dt))) / (4 * alpha)
nc = np.exp(-alpha * dt) / c * x[t - 1]
if v > 1:
x[t] = c * ((np.random.standard_normal(simulations) + nc ** 0.5) ** 2 + mp.nsum(
lambda i: np.random.standard_normal(simulations) ** 2, [0, v - 1]))
else:
max_array = []
nc_over_2 = [l / 2 for l in nc]
for p in range(simulations):
sump = []
poisson_start = 0
while poisson_start <= 1:
x_i = sum(-np.log(np.random.uniform(0, 1, simulations)) / nc_over_2)
sump.append(
x_i
)
poisson_start += x_i
x_n = max(sump)
max_array.append(
x_n
)
sump = []
test[t - 1] = max_array
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1])) * (gamma((v / 2) + test[t - 1]))) * integrate.\
quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + test[t - 1] - 1), 0, np.inf)
max_array = []
return x
Ultimately ended up finding a workaround which is simple to implement:
else:
max_array = []
for p in range(simulations):
k = nc[t - 1, p]
lam = k / 2
poisson_samp = 0
while poisson_samp <= 1:
x_i = -math.log(np.random.uniform(0, 1)) / lam
max_array.append(
x_i
)
poisson_samp += x_i
test[t - 1, p] = len(max_array) - 1
max_array.clear()
for f in range(simulations):
n = test[t - 1, f]
z = integrate.quad(lambda h: np.exp(-h / 2) * h ** ((v / 2) + n - 1), 0, 1)
new[t - 1, f] = z[0]
x[t] = c * (1 / (2 ** ((v / 2) + test[t - 1]) * (gamma((v / 2) + test[t - 1]))) * new[0])
The only real problem is the shrinkage of x[t] which leads to dividing by zero--just a formula problem.

scipy.signal.fftconvolve doesn't give the required results

I have a question regarding python's fftconvolve. In my current research I've been required to calculate some convolution between two functions. To do so I'm calculating it using fourier transform (which I used numpy.fft and normalize it) . The thing is that if I want to compare it using fftconvolve package, it fails to give the correct results. Here is my code:
#!/usr/bin/python
import numpy as np
from scipy.signal import fftconvolve , convolve
def FFT(array , sign):
if sign==1:
return np.fft.fftshift(np.fft.fft(np.fft.fftshift(array))) * dw / (2.0 * np.pi)
elif sign==-1:
return np.fft.fftshift(np.fft.ifft(np.fft.fftshift(array))) * dt * len(array)
def convolve_arrays(array1,array2,sign):
sign = int(sign)
temp1 = FFT(array1 , sign,)
temp2 = FFT(array2 , sign,)
temp3 = np.multiply(temp1 , temp2)
return FFT(temp3 , -1 * sign) / (2. * np.pi)
""" EXAMPLE """
dt = .1
N = 2**17
t_max = N * dt / 2
time = dt * np.arange(-N / 2 , N / 2 , 1)
dw = 2. * np.pi / (N * dt)
w_max = N * dw / 2.
w = dw * np.arange(-N / 2 , N / 2 , 1)
eta_fourier = 1e-10
Gamma = 1.
epsilon = .5
omega = .5
G = zeros(N , complex)
G[:] = 1. / (w[:] - epsilon + 1j * eta_fourier)
D = zeros(N , complex)
D[:] = 1. / (w[:] - omega + 1j * eta_fourier) - 1. / (w[:] + omega + 1j * eta_fourier)
H = convolve_arrays(D , G , 1)
J = fftconvolve(D , G , mode = 'same') * np.pi / (2. * N)
If you plot the real/imaginary part of H, J you'll see a shift in the w axes and also I had to multiply the J's results in order to get somehow close (but still not) to the correct results.
Any suggestions?
Thanks!
Boundary conditions are important when you compute convolutions.
When you convolve two signals, the edges of the result depend on what values you assume outside the edges of the inputs. fftconvolve computes convolution assuming zero-padded boundaries.
Take a look at the source code of fftconvolve. Notice the shenanigans they go through to achieve zero-padded boundary conditions, in particular, these lines:
size = s1 + s2 - 1
...
fsize = 2 ** np.ceil(np.log2(size)).astype(int) #For speed; often suboptimal!
fslice = tuple([slice(0, int(sz)) for sz in size])
...
ret = ifftn(fftn(in1, fsize) * fftn(in2, fsize))[fslice].copy()
...
return _centered(ret, s1) #strips off padding
This is good stuff! It's probably worth reading fftconvolve's code carefully, and a good education if you want to understand Fourier-based convolution.
Brief sketch
The forward FFT zero-pads each signal to prevent periodic boundary conditions:
a = np.array([3, 4, 5])
b = np.fft.ifftn(np.fft.fftn(a, (5,))).real
print b #[ 3. 4. 5. 0. 0.]
the inverse FFT of the product of the forward FFTs gives a padded result:
a = np.array([3, 4, 5])
b = np.array([0., 0.9, 0.1])
b = np.fft.ifftn(np.fft.fftn(a, (5,))*
np.fft.fftn(b, (5,))
).real
print b #[ 0. 2.7 3.9 4.9 0.5]
and the _centered function strips off the extra padding pixels at the end (assuming you use the mode='same' option).

Categories

Resources