0% found this document useful (0 votes)
21 views20 pages

NACP Group Project

The document discusses simulating the Fraunhofer diffraction pattern from different types of apertures. It describes simulating rectangular, square, and circular slits by numerically calculating the 2D discrete Fourier transform of the aperture function. The code initializes parameters, aperture functions, and arrays before computing the Fourier transforms and visualizing the resulting diffraction patterns through 3D and 2D plots.

Uploaded by

Movie Man
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views20 pages

NACP Group Project

The document discusses simulating the Fraunhofer diffraction pattern from different types of apertures. It describes simulating rectangular, square, and circular slits by numerically calculating the 2D discrete Fourier transform of the aperture function. The code initializes parameters, aperture functions, and arrays before computing the Fourier transforms and visualizing the resulting diffraction patterns through 3D and 2D plots.

Uploaded by

Movie Man
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

NACP Group Project

Akshat Singh 21122007


Ankit Patel 21122008
November 18, 2023

1 Problem 9
Consider the logistic map x( n + 1) = Axn (1xn ) where xn is the nth iteration for 0x1. Here A is a
constant. Vary the value of A from 0.89 to 3.995 in an interval of 0.0125 in each step. 1) For each
value of A, note the values of xn for 15 < n < 200. Then make a plot of Xn versus A to show the
bifurcation and chaos. 2) For A = 4, choose two points x and x where x = x + 0.01 and iterate.
Plot log(|xn xn |/0.01) as a function of n. See if it is approaching a straight line.

1.1 Method
1. Firtsly, will define the range of A values from 0.89 to 3.995 with an interval of 0.0125.
2. Then initializing the parameters: n_min (start iteration), n_max (end iteration),
num_iterations (to stabilize the system), and num_points (number of data points for each
A).
3. Creating an array to store A values and x_n values.
4. For each A value:
• Initializing x with an arbitrary value (e.g., 0.5).
• Iterating for num_iterations to stabilize the system.
• Iterating from n_min to n_max, applying the logistic map equation to calculate x_n
values.
• Storing the A and x_n values in the respective arrays.
5. Creating a bifurcation diagram using matplotlib, where x_n is plotted against A.
6. Using a colormap to assign different colors based on the A values for visual distinction.
7. Displaying the bifurcation diagram to visualize the transition from order to chaos as A varies.

1.2 Program
[12]: import numpy as np
import matplotlib.pyplot as plt

# Defining parameters
A_values = np.arange(0.89, 4.0, 0.0125) # Values of A
n_min = 15 # Starting iteration at n = 15
n_max = 200 # Ending iteration at n = 200
num_iterations = 1000 # Number of iterations to stabilize the system
num_points = n_max - n_min # Number of data points for each A

1
# Creating a colormap for different A values
colormap = plt.cm.viridis
normalize = plt.Normalize(vmin=A_values.min(), vmax=A_values.max())

# Initializing arrays to store data


A_data = []
x_data = []

# Iterating through different values of A


for A in A_values:
x = 0.5 # Initial value of x
for _ in range(num_iterations):
x = A * x * (1 - x) # Stabilizing the system

x_values = []
for n in range(n_min, n_max):
x = A * x * (1 - x)
x_values.append(x)

A_data.extend([A] * num_points)
x_data.extend(x_values)

# Creating the bifurcation diagram with different colors for each A


plt.figure(figsize=(12, 6))
sc = plt.scatter(A_data, x_data, c=A_data, cmap=colormap, norm=normalize, s=1)
plt.colorbar(sc, label='Value of A')
plt.xlabel('A')
plt.ylabel('$x_n$')
plt.title('Bifurcation Diagram of the Logistic Map')
plt.show()

2
[13]: import numpy as np
import matplotlib.pyplot as plt

def logistic_map(x, A):


return A * x * (1 - x)

# (b) Iteration behavior for A = 4


A = 4
x = 0.5
x_prime = x + 0.01
iterations = 100
log_differences = []

for n in range(iterations):
x = logistic_map(x, A)
x_prime = logistic_map(x_prime, A)
log_diff = np.log(np.abs(x - x_prime) / 0.01)
log_differences.append(log_diff)

# Plotting the log differences


plt.plot(log_differences, marker='.', linestyle='-', color='blue')
plt.title('Iteration Behavior for A = 4')
plt.xlabel('n')
plt.ylabel('log(|xn - x\'n|/0.01)')
plt.show()

3
1.3 Result
The provided code generates a bifurcation diagram illustrating the behavior of the logistic map
for a range of A values from 0.89 to 3.995. Each point on the diagram represents the value of xn
(population) for a specific A value after a certain number of iterations. As A varies, the bifurcation
diagram reveals a transition from order to chaos, with the emergence of complex and unpredictable
patterns in the population dynamics. The use of different colors for each A value enhances the
visualization, making it easier to distinguish the different regimes of the logistic map.
In the bifurcation diagram of the logistic map, the transition from order to chaos is characterized
by distinct patterns of population behavior. Initially, as A increases, the system exhibits stable,
periodic oscillations with clear, well-defined values of xn . However, as A continues to rise, these
periodic orbits bifurcate, leading to a cascade of increasingly complex and unpredictable behavior.
Eventually, chaos emerges, marked by a seemingly random, aperiodic sequence of xn values. This
transition demonstrates how small variations in A can result in a dramatic shift from ordered, pre-
dictable dynamics to chaotic, highly sensitive behavior, a fundamental aspect of nonlinear systems.

4
2 Problem 5
It is late at night and a drunkard is walking along a very long street. The drunkard is not sure
which is the way home, so he randomly takes steps of length 1m forward or backward. He takes
one step every second continuously for 1 hour.
(a) Simulate the drunkard’s walk by using a random number generator.
(b) Generate 100 different realizations of the random sequence of steps by using a different seed
each time.
(c) Graphically show the random walks.
(d) Calculate the displacement of the drunkard for each realization, and show graphically how
these are distributed using a histogram.
(e) Calculate the mean and the root mean square (RMS) displacement of the drunkard after 1
hour.
(f) Increase the time (number of steps) and show that the mean displacement tends to 0 and the
RMS displacement scales as the square-root of the time.

2.1 Program
[17]: import random

# (a) Simulating drunkard's walk


def drunkard_walk(steps):
position = 0
walk = []
for _ in range(steps):
step = random.choice([-1, 1]) # -1 for backward, 1 for forward
position += step
walk.append(position)
return walk

# Example usage:
random_walk = drunkard_walk(3600) # 1 hour, 1 step per second

#(b) Generating 100 different realizations


realizations = []
for _ in range(100):
random.seed(_) # Use a different seed each time
walk = drunkard_walk(3600) # 1 hour, 1 step per second
realizations.append(walk)

# (c) Graphically showing random walks


import matplotlib.pyplot as plt

for walk in realizations:


plt.plot(range(3600), walk)

5
plt.xlabel('Time (seconds)')
plt.ylabel('Position')
plt.title('Random Walks')
plt.show()

# (d) Calculating the displacement of the drunkard for each realization


displacements = [walk[-1] for walk in realizations]

# Showing graphically how these are distributed using a histogram


plt.hist(displacements, bins=20, density=True)
plt.xlabel('Displacement')
plt.ylabel('Probability')
plt.title('Displacement Histogram')
plt.show()

# (e) Calculating the mean and the root mean square (RMS) displacement of the␣
,→drunkard after 1 hour.

import numpy as np

mean_displacement = np.mean(displacements)
rms_displacement = np.sqrt(np.mean([d ** 2 for d in displacements]))

print(f'Mean Displacement: {mean_displacement}')


print(f'RMS Displacement: {rms_displacement}')

6
7
Mean Displacement: 8.78
RMS Displacement: 61.2427954946539

2.2 Result
The code simulates a drunkard’s random walk, generating 100 different realizations of 1-hour walks
with one step per second. Graphically, these random walks are visualized, showcasing the diverse
paths taken. The displacement of the drunkard is calculated for each realization, and a histogram
illustrates the distribution of displacements. The mean displacement and root mean square (RMS)
displacement after 1 hour are computed, providing quantitative measures of the overall movement.
The code employs modular functions, promoting clarity and reusability, and matplotlib for visual-
izations, enhancing understanding. The results demonstrate the stochastic nature of the drunkard’s
walk, with statistical metrics characterizing the overall displacement.

3 Problem 2
The Fraunhofer diffraction pattern from an aperture can be described by theFourier transform of
the aperture function. Using this information, numeri-cally simulate the Fraunhoffer diffraction
pattern for the following slits:
1) Rectangular Slit

8
2) Square Slit
3) Circular Slit

3.1 Method
We will begin by defining essential parameters, including the number of sub-intervals and aperture
dimensions. Then will initialize a rectangular function in the spatial domain, representing the
aperture. Afterward, the frequency domain array is initialized, paving the way for the calculation
of the 2D Discrete Fourier Transform (DFT). The DFT captures the diffraction pattern resulting
from the rectangular aperture. Visualization is achieved through both 3D plots and 2D images,
offering insights into the spatial distribution of diffraction. The code will employ nested loops for
computations and rely on the matplotlib library for effective visual representation, contributing to
a comprehensive understanding of light diffraction phenomena.

3.2 Program
[12]: import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d

# (a) Rectangular Slit

# Defining parameters
N = 31 # Total sub-intervals
M = 31 # Total sub-intervals
a = 7 # Slit width = a
b = 6 # Slit height = b

# Initialize the rectangular function in spatial domain


f = np.zeros((N, M))
for i in range(a):
for j in range(b):
f[i, j] = (-1) ** (i + j)

# Initialize the frequency domain array


dft = np.zeros((N, M), complex)

# Calculating the 2D Discrete Fourier Transform (DFT)


for u in range(N):
for v in range(M):
add = 0
for x in range(N):
for y in range(M):
add += f[x, y] * np.exp(-2j * np.pi * ((u * x / M) + (v * y /␣
,→N)))

dft[u, v] = add

# 3D plotting of the diffraction pattern

9
x = np.linspace(0, N, N)
y = np.linspace(0, M, M)
xx, yy = np.meshgrid(x, y)
fig = plt.figure(1)
ax = fig.add_subplot(1, 2, 1, projection='3d')
p = ax.plot_surface(xx, yy, np.abs(dft) / np.max(np.abs(dft)), cmap='hot')
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.set_zticklabels([])

# 3D plotting of the rectangular aperture


f1 = np.zeros((N, M))
a = 1
b = 8
m = int((N + 1) / 2)
for i in range(m - a - 1, m + a):
for j in range(m - b - 1, m + b):
f1[i, j] = 1
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(xx, yy, f, cmap='hot')
ax.set_ylabel('y')
ax.set_xlabel('x')
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.set_zticklabels([])

# Plot the diffraction pattern as an image


fig, ax = plt.subplots()
im = ax.imshow(np.abs(dft), cmap=plt.cm.gray, vmin=np.abs(dft).min(), vmax=np.
,→abs(dft).max())

im.set_interpolation('bilinear')
ax.set_yticklabels([])
ax.set_xticklabels([])

# Show the plots


plt.show()

10
[1]: # (b) Square slit

# Defining parameters
N = 31 # Total sub-intervals
M = 31 # Total sub-intervals
a = 7 # Slit width = a

11
b = 7 # Slit height = b (making it a square slit)

# Initialize the rectangular function in spatial domain


f = np.zeros((N, M))
for i in range(a):
for j in range(b):
f[i, j] = (-1) ** (i + j)

# Initialize the frequency domain array


dft = np.zeros((N, M), complex)

# Calculating the 2D Discrete Fourier Transform (DFT)


for u in range(N):
for v in range(M):
add = 0
for x in range(N):
for y in range(M):
add += f[x, y] * np.exp(-2j * np.pi * ((u * x / M) + (v * y /␣
,→N)))

dft[u, v] = add

# 3D plotting of the diffraction pattern


x = np.linspace(0, N, N)
y = np.linspace(0, M, M)
xx, yy = np.meshgrid(x, y)
fig = plt.figure(1)
ax = fig.add_subplot(1, 2, 1, projection='3d')
p = ax.plot_surface(xx, yy, np.abs(dft) / np.max(np.abs(dft)), cmap='hot')
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.set_zticklabels([])

# 3D plotting of the square aperture


f1 = np.ones((N, M)) # Square aperture
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(xx, yy, f1, cmap='hot')
ax.set_ylabel('y')
ax.set_xlabel('x')
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.set_zticklabels([])

# Plot the diffraction pattern as an image


fig, ax = plt.subplots()
im = ax.imshow(np.abs(dft), cmap=plt.cm.gray, vmin=np.abs(dft).min(), vmax=np.
,→abs(dft).max())

im.set_interpolation('bilinear')

12
ax.set_yticklabels([])
ax.set_xticklabels([])

# Show the plots


plt.show()

13
3.3 Result
The provided codes simulate the diffraction pattern produced by a rectangular slit and square slit
using the Discrete Fourier Transform (DFT). The spatial domain representation of a rectangular
aperture is created and transformed to the frequency domain using the 2D DFT. The resulting
diffraction pattern is visualized in 3D and as an image. Additionally, the code demonstrates the
transformation of a rectangular aperture and its diffraction pattern. Parameters such as the slit
width and height influence the diffraction pattern, which is crucial in understanding the behavior
of light when encountering obstacles. The code utilizes nested loops for computations and utilizes
the matplotlib library for 3D and 2D visualizations.

4 Problem 8
Numerically solve the Schroedinger’s equation for a simple harmonic poten-tial and the Lennard-
Jonnes potential. Plot the wave functions for the groundstate and first two excited states. For both
cases, compare the results with the analytical results.

4.1 Method
The provided code should numerically solve the Schrödinger equation for an anharmonic oscillator
with a quartic perturbation using a finite difference method. It initializes the potential and kinetic
energy matrices, constructs the Hamiltonian matrix, and employs NumPy’s eigenvalue solver to
find the eigenvalues and eigenvectors. The resulting normalized wavefunctions are then plotted.
User inputs define the domain limits and the number of grid points. The code’s modularity en-
hances clarity, with clearly defined functions for potential energy, grid creation, and Hamiltonian
construction.

4.2 Program
[16]: import numpy as np
import matplotlib.pyplot as plt

# Function to define the potential energy


def Vpot(x):
return 400*((1/x)**(12) - (1/x)**(6))

# User inputs for domain limits and grid points


a = float(input('Enter the lower limit of the domain: '))
b = float(input('Enter the upper limit of the domain: '))
N = int(input('Enter the number of grid points: '))

# Creating the grid


x = np.linspace(a, b, N)
h = x[1] - x[0]

# Kinetic energy matrix (finite difference approximation to second derivative)


T = np.zeros((N-2)**2).reshape(N-2, N-2)
for i in range(N-2):

14
for j in range(N-2):
if i == j:
T[i, j] = -2
elif np.abs(i - j) == 1:
T[i, j] = 1
else:
T[i, j] = 0

# Potential energy matrix


V = np.zeros((N-2)**2).reshape(N-2, N-2)
for i in range(N-2):
for j in range(N-2):
if i == j:
V[i, j] = Vpot(x[i+1]) # Using x[i+1] to exclude the endpoints
else:
V[i, j] = 0

# Hamiltonian matrix
H = -T / (2 * h**2) + V

# Solving the eigenvalue problem


val, vec = np.linalg.eig(H)
z = np.argsort(val)
z = z[0:3]
energies = val[z] / val[z][0]

# Plotting the wavefunctions


plt.figure(figsize=(12, 10))
for i in range(len(z)):
y = np.zeros(N)
y[1:-1] = vec[:, z[i]]
plt.plot(x, y, lw=3, label="{} ".format(i))

plt.xlabel('x', size=14)
plt.ylabel('$\psi$(x)', size=14)
plt.legend()
plt.title('Normalized Wavefunctions for a Leonard Jones Potential', size=14)
plt.show()

Enter the lower limit of the domain: 0.75


Enter the upper limit of the domain: 5
Enter the number of grid points: 200

15
[14]: import numpy as np
import matplotlib.pyplot as plt

# Function to define the potential energy


def Vpot(x):
return x**2/2

# User inputs for domain limits and grid points


a = float(input('Enter the lower limit of the domain: '))
b = float(input('Enter the upper limit of the domain: '))
N = int(input('Enter the number of grid points: '))

# Creating the grid


x = np.linspace(a, b, N)
h = x[1] - x[0]

# Kinetic energy matrix (finite difference approximation to second derivative)

16
T = np.zeros((N-2)**2).reshape(N-2, N-2)
for i in range(N-2):
for j in range(N-2):
if i == j:
T[i, j] = -2
elif np.abs(i - j) == 1:
T[i, j] = 1
else:
T[i, j] = 0

# Potential energy matrix


V = np.zeros((N-2)**2).reshape(N-2, N-2)
for i in range(N-2):
for j in range(N-2):
if i == j:
V[i, j] = Vpot(x[i+1]) # Using x[i+1] to exclude the endpoints
else:
V[i, j] = 0

# Hamiltonian matrix
H = -T / (2 * h**2) + V

# Solving the eigenvalue problem


val, vec = np.linalg.eig(H)
z = np.argsort(val)
z = z[0:3]
energies = val[z] / val[z][0]

# Plotting the wavefunctions


plt.figure(figsize=(12, 10))
for i in range(len(z)):
y = np.zeros(N)
y[1:-1] = vec[:, z[i]]
plt.plot(x, y, lw=3, label="{} ".format(i))

plt.xlabel('x', size=14)
plt.ylabel('$\psi$(x)', size=14)
plt.legend()
plt.title('Normalized Wavefunctions for an Harmonic Oscillator', size=14)
plt.show()

Enter the lower limit of the domain: -8


Enter the upper limit of the domain: 8
Enter the number of grid points: 200

17
4.3 Results
From the graph (1), we can see that the wave functions obtained numerically by the finite differ-
ence method for the Lennard - Jones potential match perfectly with the wave functions calculated
analytically except the ground state wave function (which is inverted). The eigenvalues are also
consistent with the theoretical results. The GS wave function is inverted because we are doing an
eigenvalue problem and python, instead of taking the eigenvector v took -v fir this, so the wf got
inverted . To interpret these results, we just need to understand that the GS wf is inverted and all
other WF are perfectly good, because the procedure for solving for excited states doesn’t involve
any contribution from the prior ones after getting the eigenvalues .
From the graph (2), we can see that the wave functions obtained numerically by the finite difference
method for the harmonic oscillator match perfectly with the wave functions calculated analytically.
The eigenvalues are also consecutive odd integers .

4.4 Standard Wavefunctions for Leonard Jones potential

18
1 Contribution of individual group members

1.1 Problem 9
Akshat Singh - 9) b)
Ankit Patel - 9) a)

1.2 Problem 5
Both of us contributed almost equally to the discussions and code writing .

1.3 Problem 2
Akshat Singh - Code
Ankit Patel - Code Modification and Discussions .

1.4 Problem 8
Akshat Singh - Finding out the standard results .
Ankit Patel - Code for finite difference Method and application of that to the
problems .

You might also like