Python array manipulation, pi*[n+1]^2 - pi*[n]^2 - python

I'm writing a script to subtract the inside cylinder from the outside cylinder for multiple cylinders.
for example: x = pi*[n+1]**2 - pi*[n]**2
However I'm not sure how to get n to change each time from for example 1 - 4, i want to be able to change n and have the code run through the new values without having to change everything.
x = pi*[1]**2 - pi*[0]**2
x = pi*[2]**2 - pi*[1]**2
x = pi*[3]**2 - pi*[2]**2
x = pi*[4]**2 - pi*[3]**2
I was trying to get a while loop to work but i cant figure out how to reference n without specifically stating which number in the array i want to reference.
Any help would be greatly appreciated.
rs = 0.2 # Radius of first cylinder
rc = 0.4 # Radius of each cylinder (concrete)
rg = 1 # Radius of each cylinder (soil)
BW = 3 # No. cylinders (concrete)
BG = 2 # No. cylinders (soil)
v1 = np.linspace(rs, rc, num=BW) # Cylinders (concrete)
v2 = np.linspace(rc * 1.5, rg, num=BG) # Cylinders (soil)
n = np.concatenate((v1, v2)) # Combined cylinders
for i in range(BW + BG):
x = np.pi * (n[i + 1] ** 2) - np.pi * (n[i] ** 2)

Try this:
for n in range(4): # 0 to 3
x = pi*[n+1]**2 - pi*[n]**2 #[1] - [0], [2] - [1] and so on...
# doSomething
If [n] is an index of an array with name num, replace [n] with
num[n] like so:
for n in range(4): # 0 to 3
x = pi*(num[n+1]**2) - pi*(num[n]**2) #[1] - [0], [2] - [1] and so on...
# doSomething
If instead it was simply n, replace [n] with n like so:
for n in range(4): # 0 to 3
x = pi*((n+1)**2) - pi*(n**2) #[1] - [0], [2] - [1] and so on...
# doSomething

Since your numbers are in a numpy array, it's much more efficient to use broadcast operations across the array (or slices of it), rather than writing a explicit loop and operating on individual items. This is the main reason to use numpy!
Try something like this:
# compute your `n` array as before
areas = pi * n**2 # this will be a new array with the area of each cylinder
area_differences = areas[1:] - areas[:-1] # differences in area between adjacent cylinders

How about this:
for i, value in enumerate(n[:-1]):
print(np.pi * (n[i + 1] ** 2) - np.pi * (value ** 2))
For me it prints:
0.157079632679
0.219911485751
0.628318530718
2.0106192983
Perhaps you want this:
>>> values = [np.pi * (n[i + 1] ** 2) - np.pi * (value ** 2)
for i, value in enumerate(n[:-1])]
>>> values
[0.15707963267948971, 0.2199114857512855, 0.62831853071795885, 2.0106192982974673]
Lets explain it:
we must get all elements in the list but the last, because n[i + 1] fails for the last item, so we use n[0:-1] (we are allowed omit the start of the slice if it is 0 or the end if it is equal or greater than len(n)).
enumerate(a_list) returns something resembling a list of pairs in the form
[(0, a_list[0]), (1, a_list[1]), ..., (n, a_list[n)]
for i, value in ... unpacks each pair into variables named i and value
[something for something in a_list] returns a new list. You may do calculations, and filter the values. For example, if you want a list of the square of the even integers bellow 10:
>>> [x * x for x in range(10) if x % 2 == 1]
[1, 9, 25, 49, 81]

I think this should provide the results you are looking for:
rs = 0.2 # Radius of first cylinder
rc = 0.4 # Radius of each cylinder (concrete)
rg = 1 # Radius of each cylinder (soil)
BW = 3 # No. cylinders (concrete)
BG = 2 # No. cylinders (soil)
v1 = np.linspace(rs, rc, num=BW) # Cylinders (concrete)
v2 = np.linspace(rc * 1.5, rg, num=BG) # Cylinders (soil)
n = np.concatenate((v1, v2))
results = []
for i, v in enumerate(n):
if i+1 < len(n):
results.append(pi * n[i+1] ** 2 - pi * v ** 2)
else:
break

Related

Python - Linear to Logarthmic Scale Conversion

Is there a way to convert number ranges?
I need to convert a linear range (0-1) to a logarithmic one (100*10^-12 - 1) so I can put a put a moveable horizontal line on a plotly plot (https://plotly.com/python/horizontal-vertical-shapes/#horizontal-and-vertical-lines-in-dash).
As far as I’m aware I can’t make my slider logarithmic to begin with (https://dash.plotly.com/dash-core-components/slider#non-linear-slider-and-updatemode).
I’ve tried normalizing. I’m not sure if that’s the right word, but basically putting my value into:
f(x) = log10(x * (max-min) + min)
Where:
x is the linear value being converted
max is the max of the log scale (1)
min is the min of the log scale (100*10^-12)
But f(.2) = .447 when I’m expecting 10*10^-9.
Is there a way accomplish this (or a better way to put a moveable horizontal line on the plot)?
BTW, 100*10^-12== 10^-10.
Seems you want to take logarithm of values at 10^-10..1 range to map them into 0..1 range and vice versa?
Y = A * log10(B * X)
substituting end values:
0 = A * log10(B * 10^-10) = A * (log10(B) - 10)
log10(B) = 10
B = 10^10
1 = A * log10(10^10 * 1) = A * 10
A = 0.1
So formula is
Y = 0.1 * log10(10^10 * X) =
1 + 0.1 * log10(X)
Reverse formula
10*Y = log10(10^10 * X)
10^(10*Y) = 10^10 * X
X = 10^(10*Y) * 10^-10 =
10^(10*Y-10)
using your example Y=0.2, we get X = 10^-8 as expected
from math import log10
for i in range(-10, 1):
X = 10**i
Y = 1 + 0.1 * log10(X)
print(Y)
print()
for i in range(0, 11):
Y = i / 10
X = 10**(10*Y-10)
print(X)

Error in implementation of Crank-Nicolson method applied to 1D TDSE?

This is more of a computational physics problem, and I've asked it on physics stack exchange, but no answers on there. This is, I suppose, a mix of the disciplines on here and there (and maybe even mathematics stack exchange), so finding the right place to post is a task in of itself apparently...
I'm attempting to use Crank-Nicolson scheme to solve the TDSE in 1D. The initial wave is a real Gaussian that has been normalised wrt its probability density. As the solution evolves, a depression grows in the central peak of the real part of the wave, and the imaginary part's central trough is perhaps a bit higher than I expect (image below).
Does this behaviour seem reasonable? I have searched around and not seen questions/figures that are similar. I've tested another person's code from Github and it exhibits the same behaviour, which makes me feel a bit better. But I still think the center peak should just decrease in height and increase in width. The likelihood of me getting a physics-based explanation is relatively low here I'd assume, but a computational-based explanation on errors I may have made is more likely.
I'm happy to give more information, for example my code, or the matrices used in the scheme, etc. Thanks in advance!
Here's a link to GIF of time evolution:
And the part of my code relevant to solving the 1D TDSE:
(pretty much the entire thing except the plotting)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Define function for norm.
def normf(dxc, uc, ic):
return sum(dxc * np.square(np.abs(uc[ic, :])))
# Define function for expectation value of position.
def xexpf(dxc, xc, uc, ic):
return sum(dxc * xc * np.square(np.abs(uc[ic, :])))
# Define function for expectation value of squared position.
def xexpsf(dxc, xc, uc, ic):
return sum(dxc * np.square(xc) * np.square(np.abs(uc[ic, :])))
# Define function for standard deviation.
def sdaf(xexpc, xexpsc, ic):
return np.sqrt(xexpsc[ic] - np.square(xexpc[ic]))
# Time t: t0 =< t =< tf. Have N steps at which to evaluate the CN scheme. The
# time interval is dt. decp: variable for plotting to certain number of decimal
# places.
t0 = 0
tf = 20
N = 200
dt = tf / N
t = np.linspace(t0, tf, num = N + 1, endpoint = True)
decp = str(dt)[::-1].find('.')
# Initialise array for filling with norm values at each time step.
norm = np.zeros(len(t))
# Initialise array for expectation value of position.
xexp = np.zeros(len(t))
# Initialise array for expectation value of squared position.
xexps = np.zeros(len(t))
# Initialise array for alternate standard deviation.
sda = np.zeros(len(t))
# Position x: -a =< x =< a. M is an even number. There are M + 1 total discrete
# positions, for the points to be symmetric and centred at x = 0.
a = 100
M = 1200
dx = (2 * a) / M
x = np.linspace(-a, a, num = M + 1, endpoint = True)
# The gaussian function u diffuses over time. sd sets the width of gaussian. u0
# is the initial gaussian at t0.
sd = 1
var = np.power(sd, 2)
mu = 0
u0 = np.sqrt(1 / np.sqrt(np.pi * var)) * np.exp(-np.power(x - mu, 2) / (2 * \
var))
u = np.zeros([len(t), len(x)], dtype = 'complex_')
u[0, :] = u0
# Normalise u.
u[0, :] = u[0, :] / np.sqrt(normf(dx, u, 0))
# Set coefficients of CN scheme.
alpha = dt * -1j / (4 * np.power(dx, 2))
beta = dt * 1j / (4 * np.power(dx, 2))
# Tridiagonal matrices Al and AR. Al to be solved using Thomas algorithm.
Al = np.zeros([len(x), len(x)], dtype = 'complex_')
for i in range (0, M):
Al[i + 1, i] = alpha
Al[i, i] = 1 - (2 * alpha)
Al[i, i + 1] = alpha
# Corner elements for BC's.
Al[M, M], Al[0, 0] = 1 - alpha, 1 - alpha
Ar = np.zeros([len(x), len(x)], dtype = 'complex_')
for i in range (0, M):
Ar[i + 1, i] = beta
Ar[i, i] = 1 - (2 * beta)
Ar[i, i + 1] = beta
# Corner elements for BC's.
Ar[M, M], Ar[0, 0] = 1 - 2*beta, 1 - beta
# Thomas algorithm variables. Following similar naming as in Wiki article.
a = np.diag(Al, -1)
b = np.diag(Al)
c = np.diag(Al, 1)
NT = len(b)
cp = np.zeros(NT - 1, dtype = 'complex_')
for n in range(0, NT - 1):
if n == 0:
cp[n] = c[n] / b[n]
else:
cp[n] = c[n] / (b[n] - (a[n - 1] * cp[n - 1]))
d = np.zeros(NT, dtype = 'complex_')
dp = np.zeros(NT, dtype = 'complex_')
# Iterate over each time step to solve CN method. Maintain boundary
# conditions. Keep track of standard deviation.
for i in range(0, N):
# BC's.
u[i, 0], u[i, M] = 0, 0
# Find RHS.
d = np.dot(Ar, u[i, :])
for n in range(0, NT):
if n == 0:
dp[n] = d[n] / b[n]
else:
dp[n] = (d[n] - (a[n - 1] * dp[n - 1])) / (b[n] - (a[n - 1] * \
cp[n - 1]))
nc = NT - 1
while nc > -1:
if nc == NT - 1:
u[i + 1, nc] = dp[nc]
nc -= 1
else:
u[i + 1, nc] = dp[nc] - (cp[nc] * u[i + 1, nc + 1])
nc -= 1
norm[i] = normf(dx, u, i)
xexp[i] = xexpf(dx, x, u, i)
xexps[i] = xexpsf(dx, x, u, i)
sda[i] = sdaf(xexp, xexps, i)
# Fill in final norm value.
norm[N] = normf(dx, u, N)
# Fill in final position expectation value.
xexp[N] = xexpf(dx, x, u, N)
# Fill in final squared position expectation value.
xexps[N] = xexpsf(dx, x, u, N)
# Fill in final standard deviation value.
sda[N] = sdaf(xexp, xexps, N)

How to print an index of element in a list - python

#Program that will load 2 arrays. ELements of the first array are coordinates X. and#the elements of the second array are coordinates Y of a point on a plane.# find the point and print the index of coordinates of the point which is the closest to the#starting point, coordinate 0,0.
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
else:
min = min
i = i + 1
mindex = X.index(min)
print(min)
print(mindex)
so basically the coordinates should be 1,1 since that is the shortest distance from the nul-point with the distance D = 2.But how do I also print the index of that element 1. With the index being 7
Edit: in python
Here you go:
import math
X = [3, 32, 15, 43, 5, 22, 90, 1]
Y = [3, 32, 15, 43, 5, 22, 90, 1]
# calculate distances using list comprehension
distances = [math.sqrt(x) ** 2 + math.sqrt(y) ** 2 for x, y in zip(X, Y)]
# find minimal distance
min_distance = min(distances)
# find index of minimal index
min_distance_index = distances.index(min_distance)
print(min_distance, min_distance_index) # Output: 2.0 7
Just a heads up, you got the wrong formula for euclidean distance. Your formula comes down to x + y if they're both positive, otherwise you get an error. The actual formula is math.sqrt(x ** 2 + y ** 2)
From the phrasing of your question it sounds like you only want to print the index, in which case the following is enough
import math
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min_index = min(range(len(X)), key=lambda i: math.sqrt(X[i] ** 2 + Y[i] ** 2))
print(min_index)
Super easy, barely an inconvenience.
>>> min(range(len(X)), key=lambda i: X[i] + Y[i])
7
(No idea what you think squaring square roots achieves, so I removed that.)
check this:
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
idx = 0
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
idx = i
i = i + 1
print(min)
print(idx)

Find how many random points lie inside ellipse centered at a point

The below code generates set of random x,y coordinates and uses the equation of an ellipse to compare how many of those points lie inside ellipse centered at (1,1) and a rectangle of area 2a*2b constructed around the ellipse whose semimajor and semiminor axis are a and b but b is variable and takes a value from the list b every single time. I want to have all the values of b for which the ratio of all the points lying inside the ellipse to the points lying inside the rectangle is greater than 0.5.
The problem I'm facing is If I check for a single value of b = 0.63. the condition ellipse_points/rectangle_points is approximately equal to 0.5 but when I loop throught the list b and use the If statement to get all the points for which ellipse_points/rectangle_points > 0.5, I do not see any value close to 0.63 instead I see values from 1.2 till 1.9, I do not understand why when I loop through a list of values for b the if statement seems to give faulty values. please refer to the next set of code where I set value of b = 0.63 and find ratio ellipse_points/rectangle_points
import numpy as np
x = np.random.uniform(0, 2, 10000) #generates random x coordinates
y = np.random.uniform(0, 2, 10000) #generates random y coordinates
ellipse_points, rectangle_points = 0, 0
a = 1
b = []
for i in range(1, 200):
b.append(i/100)
#print(b)
for p in b:
for i, j in zip(x, y):
if (((i - 1) ** 2) / a ** 2 + ((j - 1) ** 2) / p ** 2) < 1:
ellipse_points += 1
rectangle_points += 1
if ellipse_points/rectangle_point > 0.5:
print(p)
OUTPUT: 1.2, 1.21.............1.9
#
x = np.random.uniform(0, 2, 10000) #generates random x coordinates
y = np.random.uniform(0, 2, 10000) #generates random y coordinates
ellipse_points, rectangle_points = 0, 0
a = 1
b = 0.63
for i, j in zip(x, y):
if (((i - 1) ** 2) / a ** 2 + ((j - 1) ** 2) / b ** 2) < 1:
ellipse_points += 1
rectangle_points += 1
print(ellipse_points/rectangle_points)
OUTPUT 0.5001
If I understood your problem correctly, here's a vectorized solution.
It creates a binary mask for points inside the ellipse, counts where the mask is True and divides it by the total number of points.
# np.random.seed(42)
N = 10000
x = np.random.uniform(0, 2, N) #generates random x coordinates
y = np.random.uniform(0, 2, N) #generates random y coordinates
a = 1
b = 0.63
ratio = ((((x - 1)/a)**2 + ((y - 1)/b)**2) < 1).sum()/N
>>> print(ratio)
0.4954

Norm of moving window submatrix

I try to create a function for performing a convolution between a matrix and a filter. I managed to do the basic operations, but I stumbled on calculating the norm of the sliced matrix (the submatrix of the main matrix), corresponding to each position in the output.
The code is this:
def convol2d(matrix, kernel):
# matrix - input matrix indexed (v, w)
# kernel - filtre indexed (s, t),
# h -output indexed (x, y),
# The output size is calculated by adding smid, tmid to each side of the dimensions of the input image.
norm_filter = np.linalg.norm(kernel) # The norm of the filter
vmax = matrix.shape[0]
wmax = matrix.shape[1]
smax = kernel.shape[0]
tmax = kernel.shape[1]
smid = smax // 2
tmid = tmax // 2
xmax = vmax + 2 * smid
ymax = wmax + 2 * tmid
window_list = [] # Initialized an empty list for storing the submatrix
print vmax
print xmax
h = np.zeros([xmax, ymax], dtype=np.float)
for x in range(xmax):
for y in range(ymax):
s_from = max(smid - x, -smid)
s_to = min((xmax - x) - smid, smid + 1)
t_from = max(tmid - y, -tmid)
t_to = min((ymax - y) - tmid, tmid + 1)
value = 0
for s in range(s_from, s_to):
for t in range(t_from, t_to):
v = x - smid + s
w = y - tmid + t
print matrix[v, w]
value += kernel[smid - s, tmid - t] * matrix[v, w]
# This does not work
window_list.append(matrix[v,w])
norm_window = np.linalg.norm(window_list)
h[x, y] = value / norm_filter * norm_window
return h
For example, my input matrix is A(v, w), I want that my output values in the output matrix h (x,y), be calculated as:
h(x,y) = value/ (norm_of_filer * norm_of_sumbatrix)
Thanks for any help!
Edit: Following the suggestions, I modified like this:
I modified like this, but I only get the first row appended, and used in calculation and not the entire submatrix.
`for s in range(s_from, s_to):
for t in range(t_from, t_to):
v = x - smid + s
w = y - tmid + t
value += kernel[smid - s, tmid - t] * matrix[v, w]
window_list.append(matrix[v,w])
window_array = np.asarray(window_list, dtype=float)
window_list = []
norm_window = np.linalg.norm(window_array)
h[x, y] = value / norm_filter * norm_window`
The input of np.linalg.norm is supposed to be an "Input array." Try converting the list of matrices to an array. (python: list of matrices to numpy array?)
Also, maybe move the norm_window line out of the loop, since you only later use it as evaluated at the last step, with everything in it. In fact, wait 'til the loop is done, convert the finished list to an array (so it's only done once) and evaluate norm_window on that.

Categories