I am trying to figure to find out an alternative way to rewrite
Initial and boundary condition for the 1 dimensional heat eqaution
I have the following examples for 1D
#Methodd used during classes
import math
import numpy as np
import matplotlib.pyplot as plt
#D, Nx, Nt, L, T = 1.0, 14, 100, 1.0, 0.1
D, Nx, Nt, L, T = 1.0, 20, 250, 1.0, 0.1
#D, Nx, Nt, L, T = 1.0, 40, 500, 1.0, 0.1
t = np.linspace(0, T, num=Nt+1, dtype = float)
x = np.linspace(0, L, num=Nx+1, dtype = float)
dx = x[1] - x[0]
dt = t[1] - t[0]
r = D*dt/ (dx*dx)
print('r = {}'.format(r))
assert r < 0.5
#u = np.zeros((Nx+1, Nt+1), dtype = float)
u = np.empty((Nx+1, Nt+1), dtype = float)
#initial condition
#u[:,0] = 4.0*x*(1-x)
#u[:,0] = 0.5(np.sign(x-0.4) + np.sign(0.6 - x))
#u[:,0] = np.where(x < 0.5, 2*x, 2*(x -1))
u[:,0] = np.where(x < 0.5, 0, 1)
#boundary conditon
u[0,:] = 0.0
u[Nx,:] = 0.0
#u[Nx,:] = 1.0
#iteration solution
for j in range (Nt):
#for i in range(1, Nx):
#u[i, j+1] = r*u[i - 1, j] + (1 -2r)*u[i, j] + r*u[i + 1, j]
#vectorization
u[1:-1,j+1] = r*u[:-2,j] + (1-2*r)*u[1:-1,j] + r*u[2:,j]
#visualization
print(u)
plt.title("1D heat equation")
plt.xlabel("time")
plt.ylabel("X")
plt.imshow(u[:,::3], cmap = "hot", interpolation = "nearest")
#plt.imshow(u[:,::3], cmap = "hot", interpolation = "bilinear")
#plt.imshow(u[:,::3], cmap = "hot", interpolation = "hamming")
#plt.imshow(u[:,::5], cmap = "hot", interpolation = "nearest")
As you could see I have different choices to pick up. But I would like to add some alternative initial and boundary conditions. The graphics I should get are like the following one:
Could anyone possibly suggest any alternative patterns for them? Thank you so much.
Related
I have a Python function that uses normally scalar values as arguments, transforms them as arrays during the computation and returns scalar values at the end.
def referentialConversion(thetaI, thetaO, deltaPhi):
omegaI = np.array([-np.sin(thetaI), 0, np.cos(thetaI)])
omegaO = np.array([np.sin(thetaO) * np.cos(deltaPhi), np.sin(thetaO) * np.sin(deltaPhi), np.cos(thetaO)])
h = (omegaI + omegaO) / np.linalg.norm(omegaI + omegaO)
b = np.array([1, 0, 0])
t = np.array([0, 1, 0])
n = np.array([0, 0, 1])
b_prime = np.cross(n, h) / np.linalg.norm(np.cross(n, h))
t_prime = np.cross(b_prime, h)
x_h, y_h, z_h = np.dot(h, b), np.dot(h, t), np.dot(h, n)
x_d, y_d, z_d = np.dot(omegaI, b_prime), np.dot(omegaI, b_prime), np.dot(omegaI, h)
phi_h = np.arctan2(y_h, x_h)
phi_d = np.arctan2(y_d, x_d)
theta_h = np.arccos(z_h)
theta_d = np.arccos(z_d)
return phi_d, theta_h, theta_d
If I am using the function with scalar arguments, it is perfectly working:
thetaI = np.linspace(0, np.pi/2, 500)
thetaO = thetaI
deltaPhi = np.linspace(0, 2*np.pi, 2000)
phiD = np.array([])
thetaH = np.array([])
thetaD = np.array([])
for theta_i in thetaI:
for theta_o in thetaO:
for delta_phi in deltaPhi:
phi_d, theta_h, theta_d = referentialConversion(0.5, 0.5, 0.5) # This works
phiD = np.append(phiD, phi_d)
thetaH = np.append(thetaH, theta_h)
thetaD = np.append(thetaD, theta_d)
But since I need to do the computation for a lot of values, I would prefer to do it using NumPy arrays rather than a for loop.
thetaI = np.linspace(0, np.pi/2, 500)
thetaO = thetaI
deltaPhi = np.linspace(0, 2*np.pi, 2000)
phi_d, theta_h, theta_d = referentialConversion(thetaI, thetaO, deltaPhi) # Doesn't work
# ValueError: operands could not be broadcast together with shapes...
I am not very used to NumPy, is there a way to enable my function to do the last example ?
I was a bit curious on plotting the contour plots for a 2 dimensional gaussian distribution. In my case, for a given set of 2D points, I cluster them into different grid cells and compute the covariance matrix for every cell and plot the gaussian distribution for each and every cell. When I plot I do not want the entire contour for the cell but the distribution restricted within 3 sigma of the data points. Is there anyway it could be done ?
My code is as follows:
import numpy as np
import matplotlib.pyplot as plt
def createCells():
partition = 4
coords = [np.linspace(-1.0 , 1.0, num = partition + 1) for i in range(2)]
x, y = np.meshgrid(*coords)
return x, y
def probab(mean, covMat, lPoints):
lPoints = lPoints[..., np.newaxis] if lPoints.ndim == 2 else lPoints ## Create vectorized values for the x, y
if np.linalg.det(covMat) > 0:
factor1 = (2*np.pi)*(np.linalg.det(covMat)**(-1/2))
factor2 = np.exp((-1/2)*np.einsum('ijk,jl,ilk->ik', lPoints - mean, np.linalg.inv(covMat), lPoints - mean))
return factor1*factor2
if __name__ == '__main__':
points = np.array([[-0.35, -0.15], [0.1, 0.1], [-0.1, 0.1], [0.05, 0.05],[0.25, 0.05], [0.1, 0.15], [0.1, 0.2], [-0.2, -0.2], [-0.25, 0.25], [0.45, 0.45], [0.75, 0.75], [0.6, 0.6], [0.55, 0.55], [0.7, 0.7], [0.68, 0.73]])
x1, y1 = createCells()
x = x1[0]
y = y1[:,0]
lP = np.array([])
numberOftimes = 0
for i in range(len(x) - 1):
for j in range(len(y) - 1):
count = 0
meanX = 0.0
meanY = 0.0
localPoints = []
covMat1 = np.array([])
covMat2 = np.array([])
for point in points:
inbetween_x = x[i] <= point[0] <= x[i + 1]
inbetween_y = y[j] <= point[1] <= y[j + 1]
if inbetween_x and inbetween_y:
count += 1
meanX += point[0]
meanY += point[1]
localPoints.append([point[0], point[1]])
if count >= 2:
numberOftimes += 1
#print(f"The local points are {localPoints}")
localPoints = np.array(localPoints)
meanX /= count
meanY /= count
meanXY = np.array([meanX, meanY])
#print(meanXY.shape)
#print(localPoints.shape)
lP = localPoints - meanXY
for k in range(count):
lPtranspose = (np.array([lP[k]])).T
lPCurrent = (np.array([lP[k]]))
if len(covMat1) > 0:
covMat1 += lPtranspose.dot(lPCurrent)
else:
covMat1 = lPtranspose*lP[k]
covMat1 /= count
lPoints = localPoints[..., np.newaxis] if lP.ndim == 2 else lP ## Create vectorized values for the x, y
meanXY1 = localPoints.mean(0)
meanXY2 = lPoints.mean(0)
covMat3 = np.einsum('ijk, ikj->jk', lPoints - meanXY2, lPoints - meanXY2) / lPoints[0] - 1
#yamlStatus = self.savingYaml(i, j, meanXY, covMat3) ## To store the cell parameters in a yaml file (for now its just out of scope for the question)
if np.linalg.det(covMat3) > 0: #compute the probability only if the det is not 0
Xx = np.linspace(x[i], x[i + 1], 1000)
Yy = np.linspace(y[i], y[i + 1], 1000)
Xx,Yy = np.meshgrid(Xx, Yy)
lPoints = np.vstack((Xx.flatten(), Yy.flatten())).T
pos = np.empty(Xx.shape + (2,))
pos[:, :, 0] = Xx
pos[:, :, 1] = Yy
z2 = probab(meanXY2, covMat3, lPoints)
summed = np.sum(z2)
z2 = z2.reshape(1000, 1000)
cs = plt.contourf(Xx, Yy, z2)#, cmap=cm.viridis)
plt.clabel(cs)
localPoints = []
#print(f"The number of times count is greater than 1 is {numberOftimes}")
plt.plot(x1, y1, marker='.', linestyle='none', markersize=20)
plt.plot(points[:,0 ], points[:, 1], marker='.', linestyle='none', markersize=10)
plt.grid(linewidth=0.5)#abs(x1[0][0]-y1[0][0]))
plt.show()
Is there something like Matlab's procrustes function in NumPy/SciPy or related libraries?
For reference. Procrustes analysis aims to align 2 sets of points (in other words, 2 shapes) to minimize square distance between them by removing scale, translation and rotation warp components.
Example in Matlab:
X = [0 1; 2 3; 4 5; 6 7; 8 9]; % first shape
R = [1 2; 2 1]; % rotation matrix
t = [3 5]; % translation vector
Y = X * R + repmat(t, 5, 1); % warped shape, no scale and no distortion
[d Z] = procrustes(X, Y); % Z is Y aligned back to X
Z
Z =
0.0000 1.0000
2.0000 3.0000
4.0000 5.0000
6.0000 7.0000
8.0000 9.0000
Same task in NumPy:
X = arange(10).reshape((5, 2))
R = array([[1, 2], [2, 1]])
t = array([3, 5])
Y = dot(X, R) + t
Z = ???
Note: I'm only interested in aligned shape, since square error (variable d in Matlab code) is easily computed from 2 shapes.
I'm not aware of any pre-existing implementation in Python, but it's easy to take a look at the MATLAB code using edit procrustes.m and port it to Numpy:
def procrustes(X, Y, scaling=True, reflection='best'):
"""
A port of MATLAB's `procrustes` function to Numpy.
Procrustes analysis determines a linear transformation (translation,
reflection, orthogonal rotation and scaling) of the points in Y to best
conform them to the points in matrix X, using the sum of squared errors
as the goodness of fit criterion.
d, Z, [tform] = procrustes(X, Y)
Inputs:
------------
X, Y
matrices of target and input coordinates. they must have equal
numbers of points (rows), but Y may have fewer dimensions
(columns) than X.
scaling
if False, the scaling component of the transformation is forced
to 1
reflection
if 'best' (default), the transformation solution may or may not
include a reflection component, depending on which fits the data
best. setting reflection to True or False forces a solution with
reflection or no reflection respectively.
Outputs
------------
d
the residual sum of squared errors, normalized according to a
measure of the scale of X, ((X - X.mean(0))**2).sum()
Z
the matrix of transformed Y-values
tform
a dict specifying the rotation, translation and scaling that
maps X --> Y
"""
n,m = X.shape
ny,my = Y.shape
muX = X.mean(0)
muY = Y.mean(0)
X0 = X - muX
Y0 = Y - muY
ssX = (X0**2.).sum()
ssY = (Y0**2.).sum()
# centred Frobenius norm
normX = np.sqrt(ssX)
normY = np.sqrt(ssY)
# scale to equal (unit) norm
X0 /= normX
Y0 /= normY
if my < m:
Y0 = np.concatenate((Y0, np.zeros(n, m-my)),0)
# optimum rotation matrix of Y
A = np.dot(X0.T, Y0)
U,s,Vt = np.linalg.svd(A,full_matrices=False)
V = Vt.T
T = np.dot(V, U.T)
if reflection != 'best':
# does the current solution use a reflection?
have_reflection = np.linalg.det(T) < 0
# if that's not what was specified, force another reflection
if reflection != have_reflection:
V[:,-1] *= -1
s[-1] *= -1
T = np.dot(V, U.T)
traceTA = s.sum()
if scaling:
# optimum scaling of Y
b = traceTA * normX / normY
# standarised distance between X and b*Y*T + c
d = 1 - traceTA**2
# transformed coords
Z = normX*traceTA*np.dot(Y0, T) + muX
else:
b = 1
d = 1 + ssY/ssX - 2 * traceTA * normY / normX
Z = normY*np.dot(Y0, T) + muX
# transformation matrix
if my < m:
T = T[:my,:]
c = muX - b*np.dot(muY, T)
#transformation values
tform = {'rotation':T, 'scale':b, 'translation':c}
return d, Z, tform
There is a Scipy function for it: scipy.spatial.procrustes
I'm just posting its example here:
>>> import numpy as np
>>> from scipy.spatial import procrustes
>>> a = np.array([[1, 3], [1, 2], [1, 1], [2, 1]], 'd')
>>> b = np.array([[4, -2], [4, -4], [4, -6], [2, -6]], 'd')
>>> mtx1, mtx2, disparity = procrustes(a, b)
>>> round(disparity)
0.0
You can have both Ordinary Procrustes Analysis and Generalized Procrustes Analysis in python with something like this:
import numpy as np
def opa(a, b):
aT = a.mean(0)
bT = b.mean(0)
A = a - aT
B = b - bT
aS = np.sum(A * A)**.5
bS = np.sum(B * B)**.5
A /= aS
B /= bS
U, _, V = np.linalg.svd(np.dot(B.T, A))
aR = np.dot(U, V)
if np.linalg.det(aR) < 0:
V[1] *= -1
aR = np.dot(U, V)
aS = aS / bS
aT-= (bT.dot(aR) * aS)
aD = (np.sum((A - B.dot(aR))**2) / len(a))**.5
return aR, aS, aT, aD
def gpa(v, n=-1):
if n < 0:
p = avg(v)
else:
p = v[n]
l = len(v)
r, s, t, d = np.ndarray((4, l), object)
for i in range(l):
r[i], s[i], t[i], d[i] = opa(p, v[i])
return r, s, t, d
def avg(v):
v_= np.copy(v)
l = len(v_)
R, S, T = [list(np.zeros(l)) for _ in range(3)]
for i, j in np.ndindex(l, l):
r, s, t, _ = opa(v_[i], v_[j])
R[j] += np.arccos(min(1, max(-1, np.trace(r[:1])))) * np.sign(r[1][0])
S[j] += s
T[j] += t
for i in range(l):
a = R[i] / l
r = [np.cos(a), -np.sin(a)], [np.sin(a), np.cos(a)]
v_[i] = v_[i].dot(r) * (S[i] / l) + (T[i] / l)
return v_.mean(0)
For testing purposes, the output of each algorithm can be visualized as follows:
import matplotlib.pyplot as p; p.rcParams['toolbar'] = 'None';
def plt(o, e, b):
p.figure(figsize=(10, 10), dpi=72, facecolor='w').add_axes([0.05, 0.05, 0.9, 0.9], aspect='equal')
p.plot(0, 0, marker='x', mew=1, ms=10, c='g', zorder=2, clip_on=False)
p.gcf().canvas.set_window_title('%f' % e)
x = np.ravel(o[0].T[0])
y = np.ravel(o[0].T[1])
p.xlim(min(x), max(x))
p.ylim(min(y), max(y))
a = []
for i, j in np.ndindex(len(o), 2):
a.append(o[i].T[j])
O = p.plot(*a, marker='x', mew=1, ms=10, lw=.25, c='b', zorder=0, clip_on=False)
O[0].set(c='r', zorder=1)
if not b:
O[2].set_color('b')
O[2].set_alpha(0.4)
p.axis('off')
p.show()
# Fly wings example (Klingenberg, 2015 | https://en.wikipedia.org/wiki/Procrustes_analysis)
arr1 = np.array([[588.0, 443.0], [178.0, 443.0], [56.0, 436.0], [50.0, 376.0], [129.0, 360.0], [15.0, 342.0], [92.0, 293.0], [79.0, 269.0], [276.0, 295.0], [281.0, 331.0], [785.0, 260.0], [754.0, 174.0], [405.0, 233.0], [386.0, 167.0], [466.0, 59.0]])
arr2 = np.array([[477.0, 557.0], [130.129, 374.307], [52.0, 334.0], [67.662, 306.953], [111.916, 323.0], [55.119, 275.854], [107.935, 277.723], [101.899, 259.73], [175.0, 329.0], [171.0, 345.0], [589.0, 527.0], [591.0, 468.0], [299.0, 363.0], [306.0, 317.0], [406.0, 288.0]])
def opa_out(a):
r, s, t, d = opa(a[0], a[1])
a[1] = a[1].dot(r) * s + t
return a, d, False
plt(*opa_out([arr1, arr2, np.matrix.copy(arr2)]))
def gpa_out(a):
g = gpa(a, -1)
D = [avg(a)]
for i in range(len(a)):
D.append(a[i].dot(g[0][i]) * g[1][i] + g[2][i])
return D, sum(g[3])/len(a), True
plt(*gpa_out([arr1, arr2]))
Probably you want to try this package with various flavors of different Procrustes methods, https://github.com/theochem/procrustes.
I am trying to solve for the following equation with a simple algorithm. I am not sure if the algorithm that I'm using is the best one or not but it is the only way that I could think of.
In this equation, everything other than P is known, and I am trying to solve for that. N is an array of counts, an i is the channel number. S(n) is the probability of having a certain n and C is binomial coefficient of (n, r). Pi is the probability in i channel and Pj is the probability in the previous channels with D distance to i. The code itself is not working but I believe that the main problem is in the way that I am trying to solve for it.
import numpy as np
import matplotlib.pyplot as plt
import math as ms
from scipy.misc import derivative
import scipy as sp
def next_guess(f, x):
slop = derivative(f, x, dx = 0.01)
return x - float(f(x))/slop
def my_newton(f, guess):
for i in range(30):
#print(guess)
guess = next_guess(f, guess)
return guess
def binomial(n, r):
dif = ms.factorial(n - r)
n = ms.factorial(n)
r = ms.factorial(r)
return (n/(r*dif))
def wrap_func(x, S = np.array([0.1, 0.5, 0.2, 0.1, 0.1]), D = 1, N = np.array([10, 15, 20, 1, 13])):
if type(x) == float:
z = np.zeros(1)
else:
z = np.zeros(x.shape[0])
N_tot = N.sum()
n_max = S.shape[0]
for i in range(z.shape[0]):
z[i] += my_newton(func(x, S = S, D = 1, N = N[i], n_max = n_max, N_tot = N_tot, i = i), i/100)
return z
def func(x, S = np.array([0.1, 0.5, 0.2, 0.1, 0.1]), D = 1, N = 0, n_max = 5, N_tot = 10, i = 0):
S_sum = 0
binom_sum = 0
y = 0
for n in range(n_max):
S_sum += S[n]
for r in range(n):
binom_sum += binomial(n, r)
y += S_sum * binom_sum * (x**r) * (1 - x - summ_x(x, D, i, S, N, n_max, N_tot))**(n-r)
return N_tot * y - N
def summ_x(x, D, i, S, N, n_max, N_tot):
j_min = max(i - D - 1, 0)
j_max = i - 1
x_values = 0
if i == 0:
return x_values
else:
for j in range(j_min, j_max):
x_values += func(x, S, D, N, n_max, N_tot, i)
return x_values
x = np.linspace(0, 1, 1000)
S = np.array([0.1, 0.5, 0.2, 0.1, 0.1])
N = np.random.choice(50, size = 1000)
print(my_newton(wrap_func, 0.1))
plt.plot(x, wrap_func(x, S = S, D = 1, N = N ))
plt.axhline(0, lw = 0.5, color = 'grey')
#plt.plot(my_newton(wrap_func, 1), wrap_func(my_newton(wrap_func, 1), S = S, D = 1, N = N), 'd')
plt.show()
I am trying to write a program using the Lotka-Volterra equations for predator-prey interactions. Solve Using ODE's:
dx/dt = a*x - B*x*y
dy/dt = g*x*y - s*y
Using 4th order Runge-Kutta method
I need to plot a graph showing both x and y as a function of time from t = 0 to t=30.
a = alpha = 1
b = beta = 0.5
g = gamma = 0.5
s = sigma = 2
initial conditions x = y = 2
Here is my code so far but not display anything on the graph. Some help would be nice.
#!/usr/bin/env python
from __future__ import division, print_function
import matplotlib.pyplot as plt
import numpy as np
def rk4(f, r, t, h):
""" Runge-Kutta 4 method """
k1 = h*f(r, t)
k2 = h*f(r+0.5*k1, t+0.5*h)
k3 = h*f(r+0.5*k2, t+0.5*h)
k4 = h*f(r+k3, t+h)
return (k1 + 2*k2 + 2*k3 + k4)/6
def f(r, t):
alpha = 1.0
beta = 0.5
gamma = 0.5
sigma = 2.0
x, y = r[2], r[2]
fxd = x*(alpha - beta*y)
fyd = -y*(gamma - sigma*x)
return np.array([fxd, fyd], float)
tpoints = np.linspace(0, 30, 0.1)
xpoints = []
ypoints = []
r = np.array([2, 2], float)
for t in tpoints:
xpoints += [r[2]]
ypoints += [r[2]]
r += rk4(f, r, t, h)
plt.plot(tpoints, xpoints)
plt.plot(tpoints, ypoints)
plt.xlabel("Time")
plt.ylabel("Population")
plt.title("Lotka-Volterra Model")
plt.savefig("Lotka_Volterra.png")
plt.show()
A simple check of your variable tpoints after running your script shows it's empty:
In [7]: run test.py
In [8]: tpoints
Out[8]: array([], dtype=float64)
This is because you're using np.linspace incorrectly. The third argument is the number of elements desired in the output. You've requested an array of length 0.1.
Take a look at np.linspace's docstring. You won't have a problem figuring out how to adjust your code.
1) define 'h' variable.
2) use
tpoints = np.arange(30) #array([0, 1, 2, ..., 30])
not
np.linspace()
and don't forget to set time step size equal to h:
h=0.1
tpoints = np.arange(0, 30, h)
3) be careful with indexes:
def f(r,t):
...
x, y=r[0], r[1]
...
for t in tpoints:
xpoints += [r[0]]
ypoints += [r[1]]
...
and better use .append(x):
for t in tpoints:
xpoints.append(r[0])
ypoints.append(r[1])
...
Here's tested code for python 3.7 (I've set h=0.001 for more presize)
import matplotlib.pyplot as plt
import numpy as np
def rk4(r, t, h): #edited; no need for input f
""" Runge-Kutta 4 method """
k1 = h*f(r, t)
k2 = h*f(r+0.5*k1, t+0.5*h)
k3 = h*f(r+0.5*k2, t+0.5*h)
k4 = h*f(r+k3, t+h)
return (k1 + 2*k2 + 2*k3 + k4)/6
def f(r, t):
alpha = 1.0
beta = 0.5
gamma = 0.5
sigma = 2.0
x, y = r[0], r[1]
fxd = x*(alpha - beta*y)
fyd = -y*(gamma - sigma*x)
return np.array([fxd, fyd], float)
h=0.001 #edited
tpoints = np.arange(0, 30, h) #edited
xpoints, ypoints = [], []
r = np.array([2, 2], float)
for t in tpoints:
xpoints.append(r[0]) #edited
ypoints.append(r[1]) #edited
r += rk4(r, t, h) #edited; no need for input f
plt.plot(tpoints, xpoints)
plt.plot(tpoints, ypoints)
plt.xlabel("Time")
plt.ylabel("Population")
plt.title("Lotka-Volterra Model")
plt.savefig("Lotka_Volterra.png")
plt.show()
You can also try to plot "cycles":
plt.xlabel("Prey")
plt.ylabel("Predator")
plt.plot(xpoints, ypoints)
plt.show()
https://i.stack.imgur.com/NB9lc.png