I've written the following piece of code using the Euler method to plot a graph of velocity against time for a free-falling object, which eventually reaches terminal velocity:
import numpy as np
import matplotlib.pyplot as plt
g = -9.81
Cd = 0.47
p0 = 1.2
A = 0.0034
k = (Cd*p0*A)/2
m = 0.058
def euler(vyn, yn): #takes the starting velocity and height as arguments
i = 0
while i < 10000:
dt = 0.01
i += 1
vyn = vyn - dt * (g + ((k/m) * abs(vyn) * vyn))
yn = yn - dt * vyn
print(vyn, yn)
if yn < 0: #stops iterations when ball hits ground
break
return vyn
NumPoints = 2000
xmin = 0
xmax = 1000
dx = (xmax - xmin) / (NumPoints - 1)
xvals = [0.0] * NumPoints
yvals = np.zeros(NumPoints)
for i in range(NumPoints):
xvals[i] = xmin + i * dx
yvals[i] = euler(0,1000)
plt.plot(xvals,yvals)
plt.show()
I put the print statement in the while loop by the way so that it prints the velocity and height of object from the ground each iteration, and the break is so that it breaks out of the loop by the time the ball hits the ground. However, when I add the graphing code at the bottom, the iterations loop back round for some reason, without breaking. A graph is also not printed.
Removing the print statement does produce a graph, however it is just a horizontal line.
How could I modify the code to produce a graph of velocity against time, and also height against time? Do I need to embed the graph code within the while loop?
Thanks
Related
I am attempting to write a Python code to simulate many particles in a confined box. These particles behave in such a way that they move in the box in straight lines with a slight angular noise (small changes in the direction of the particle path). They should interact by acknowledging the other particle and 'shuffle/squeeze' past each other and continue on their intended path, much like humans on a busy street. Eventually, the particles should cluster together when the density of particles (or packing fraction) reaches a certain value, but I haven't got to this stage yet.
The code currently has particle interactions and I have attempted the angular noise but without success so far. The problems I would like some help with are the angular noise and the particle interactions. My idea for the angular noise was to multiply the data by a number between roughly 0.9 and 1.1 to change the direction of the particle slightly but after adding the lines in, nothing changed. The particles do interact but they seem to move in a fast semi-circle around the other interacting which is not what I want.
I don't think any knowledge or understanding of ABM is needed to write the angular noise code but some may be needed for the forces, I am not 100% sure though.
If anyone has any improvements for the code speed or ideas which may help with the interactions and/or angular noise that would be much appreciated. I will also leave an example of an animation which is my aim: https://warwick.ac.uk/fac/sci/physics/staff/research/cwhitfield/abpsimulations
The above link shows the animation I am looking for, although I don't need the sliders, just the box, and moving particles. The whole code is shown below:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def set_initial_coordinates():
x_co = [np.random.uniform(0, 2) for i in range(n_particles)]
y_co = [np.random.uniform(0, 2) for i in range(n_particles)]
return x_co, y_co
def set_initial_velocities():
x_vel = np.array([np.random.uniform(-1, 1) for i in range(n_particles)])
y_vel = np.array([np.random.uniform(-1, 1) for i in range(n_particles)])
return x_vel, y_vel
def init():
ax.set_xlim(-0.05, 2.05)
ax.set_ylim(-0.07, 2.07)
return ln,
def update(dt):
xdata = initialx + vx * dt
ydata = initialy + vy * dt
fx = np.abs((xdata + 2) % 4 - 2)
fy = np.abs((ydata + 2) % 4 - 2)
for i in range(n_particles):
for j in range(n_particles):
if i == j:
continue
dx = fx[j] - fx[i] # distance in x direction
dy = fy[j] - fy[i] # distance in y direction
dr = np.sqrt((dx ** 2) + (dy ** 2)) # distance between x
if dr <= r:
force = k * ((2 * r) - dr) # size of the force if distance is less than or equal to radius
# Imagine a unit vector going from i to j
x_comp = dx / dr # x component of force
y_comp = dy / dr # y component of force
fx[i] += -x_comp * force # x force
fy[i] += -y_comp * force # y force
ln.set_data(fx, fy)
return ln,
# theta = np.random.uniform(0, 2) for i in range(n_particles)
n_particles = 10
initialx, initialy = set_initial_coordinates()
vx, vy = set_initial_velocities()
fig, ax = plt.subplots()
x_co, y_co = [], []
ln, = plt.plot([], [], 'bo', markersize=15) # radius 0.05
plt.xlim(0, 2)
plt.ylim(0, 2)
k = 1
r = 0.1
t = np.linspace(0, 10, 1000)
ani = FuncAnimation(fig, update, t, init_func=init, blit=True, repeat=False)
plt.show()
I hope you can help! I need to show the trajectory of a particle that is under gravity of g = -9.81 m/s2 and time step of dt = 0.05 sec, where the position and velocity of the particle are:
x_1 = x_0 + v_x1 * dt
y_1 = y_0 + v_y1 * dt
v_x1 = v_x0
v_y1 = v_y0 + g * dt
This is what I should achieve:
This is what I've done so far:
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1, figsize=(12,12))
ax = plt.subplot(111, aspect='equal')
ax.set_ylim(0,50)
ax.set_title('Boom --- Weeee! --- Ooof')
r = np.array([0.,0.,15.,30.])
g = -9.81
dt = 0.05
y = 0
x = 0
while y > 0:
plt.plot(x_1,y_2,':', ms=2)
x_1 = v_x1 * dt
y_1 = v_y1 * dt
v_x1 = v_x0
v_y1 = v_y0 + g * dt
This doesn't produce an image only the plt.figure stated in the beginning, I've tried to integrate the r vector into the loop but I can't figure out how.
Thank you.
Here's a modified version of your code that I believe gives you the result you desire (you may want to choose different initial velocity values):
import matplotlib.pyplot as plt
# Set up our plot surface
plt.figure(1, figsize=(12,12))
ax = plt.subplot()
# ax = plt.subplot(111, aspect='equal')
# ax.set_ylim(0,50)
ax.set_title('Boom --- Weeee! --- Ooof')
# Initial conditions
g = -9.81
dt = 0.05
y = 0
x = 0
v_x = 5
v_y = 5
# Create our lists that will store our data points
points_x = []
points_y = []
while True:
# Add the current position of our projectile to our data
points_x.append(x)
points_y.append(y)
# Move our projectile along
x += v_x * dt
y += v_y * dt
# If our projectile falls below the X axis (y < 0), end the simulation
if y < 0:
break
# Update our y velocity per gravity
v_y = v_y + g * dt
# Plot our data
ax.plot(points_x, points_y)
# Show the plot on the screen
plt.show()
I'm sorry if I could have made fewer changes. Here are the substantive ones I can think of:
You weren't using the r value you computed, so got rid of it, along with the import of numpy that was then no longer needed.
I took out calls you made explicitly size your plot. You're better off letting the plot library decide upon the bounds of the plot for you
I don't know if there's another way to do it, but I've always supplied data to the plotting library as arrays of points rather than by providing the points one at a time. So here, I collect up all of the x and y coordinates into two lists while running the simulation, and then add those arrays to the plot at the end to plot the data.
The x_0 vs x_1, etc., got confusing for me. I didn't see any reason to keep track of multiple position and velocity values, so I reduced the code down to using just one set of positions and velocities, x, y, v_x and v_y.
See the comments for more info
Result:
I am trying to create a plot that looks like the picture.
Wave Particle Motions under Wave
This is not homework, i'm trying to do this for experience.
I have the following parameters:
Plot the water particle motions under Trough (Lowest point on wave elevation profile) at water depths
from 0 to 100 meters in increments of 10 m below mean water line.
The wave profile varying over space is π(π₯) = π΄cos(πx) at time = 0. Plot this wave profile first for one wave.
π(π₯) = π΄*cos(πx) #at time = 0
Next compute vertical and horizontal particle displacements for different water depths of 0 to 100m
XDisp = -A * e**(k*z) * np.sin(-w*t)
YDisp = -A * e**(k*z) * np.cos(-w*t) # when x=0
You could use any x.
Motion magnitudes donβt change. Where z is depth below mean water level. All other parameters are as defined in earlier problems above.
Do not forget to shift the horizontally particle displacement to under trough and βzβ below water line for vertical particle displacement.
Here is my code, but im doing something wrong. I have the plot looking like the example but my circles are not right. I think it has to do with the x&y disp.
import numpy as np
import matplotlib.pyplot as plt
A = 1 # Wave amplitude in meters
T = 10 # Time Period in secs
n_w = 1 # Number of waves
wavelength = 156 # Wavelength in meters
# Wave Number
k = (2 * np.pi) / wavelength
# Wave angular frequency
w = (2 * np.pi) / T
def XDisp(z,t):
return -A * np.e**(k * z) * np.sin(-w * t)
def YDisp(z,t):
return -A * np.e**(k * z) * np.cos(-w * t)
def wave_elevation(x):
return A * np.cos(k * x)
t_list = np.array([0,0.25,0.5,0.75,1.0])*T
z = [0,-10,-20,-30,-40,-50,-60,-70,-80,-90,-100]
A_d = []
x_plot2 = []
for i in z:
A_d.append(A * np.e**(k * i))
x_plot2.append(wavelength/2)
x_plot = np.linspace(0,wavelength)
Y_plot = []
for i in x_plot:
Y_plot.append(wave_elevation(i))
plt.plot(x_plot,Y_plot,'.-r')
plt.scatter(x_plot2,z,s= A_d, facecolors = 'none',edgecolors = 'b',marker='o',linewidth=2)
plt.xlabel('X (m)')
plt.ylabel("\u03B7 & Water Depth")
plt.title('Wave Particle Motions Under Wave')
plt.legend()
plt.grid()
plt.show()
I am afraid with provided information, I don't follow science part of the question, but if you have problem in marker size you can put an array of sizes as third argument of plt.scatter. I think this code may help you, although I change your code a little bit to make it simpler
import numpy as np
import matplotlib.pyplot as plt
A = 1 # Wave amplitude in meters
T = 10 # Time Period in secs
n_w = 1 # Number of waves
wavelength = 156 # Wavelength in meters
k = (2 * np.pi) / wavelength # Wave Number
w = (2 * np.pi) / T # Wave angular frequency
def wave_elevation(x):
return A * np.cos(k * x)
A_d = [] # marker size
x2 = [] # for particle place on x axis which is wavelength/2
y2 = [] # for particle place on y axis
for i in range(0,100,10):
x2.append(wavelength/2)
y2.append(-i)
A_d.append(15 * np.exp(-k * i)) # here I change A to 15
x = []
y = []
for i in range(0,wavelength):
x.append(i)
y.append(wave_elevation(i))
plt.plot(x,y,'red')
plt.scatter(x2,y2,A_d)
plt.ylim(-100, 10)
plt.xlabel('X (m)')
plt.ylabel("\u03B7 & Water Depth")
plt.title('Wave Particle Motions Under Wave')
plt.grid()
plt.show()
I have an assignment that asks me to use some given code to write a function which calculates the angle needed to hit a target 10 metres away.
here is the given code:
from visual import *
from visual.graph import * # For the graphing functions
#Create a graph display window (gdisplay)
win = gdisplay(xtitle="Distance [m]", ytitle="Height [m]")
#And a curve on this display
poscurve = gcurve(gdisplay=win, color=color.cyan)
#Target position (10 meters away)
target_pos = vector(10,0,0)
#Set the starting angle (in degrees)
angle = 45
#Set the magnitude of the starting velocity (in m/s)
v0 = 12.0
#Gravity vector (m/s**2)
g = vector(0, -9.8, 0)
#Create a vector for the projectile's velocity
velocity = v0 * vector(cos(anglepi/180), sin(anglepi/180), 0)
#and the position
position = vector(0,0,0)
dt = 0.01 # Time step
#Start loop. Each time taking a small step in time
while (position.y > 0) or (velocity.y > 0): # Change in position # dx = (dx/dt) * dt dx = velocity * dt
# Change in velocity
# dv = (dv/dt) * dt
dv = g * dt
# Update the position and velocity
position = position + dx
velocity = velocity + dv
# Plot the current position
poscurve.plot(pos=position)
#When loop finishes, velocity.y must be < 0, and position.y < 0
print "Landed at X position: ", position.x print "X distance to target: ", position.x - target_pos.x
How would I now write a function to calculate the required value? I have no idea where to start, any help would be greatly appreciated!
Thanks
You could use maths to work out an equation for the result.
This works out as:
range = 2v^2/g *cos(a)sin(a)
where v=initial velocity
a=angle
g=gravitational acceleration
You can use this python script to find the answer:
from math import cos
from math import sin
from math import radians
from math import fabs
a=0 # angle in degrees
target=10 # How far you want it to go in m
v=12 # initial velocity in m/s
g=9.81 #gravitational acceleration m/s/s
best_angle=None
nearest_answer=None
while a<45: # we only need to check up to 45 degrees
r = 2*v*v/g*cos(radians(a))*sin(radians(a))
if not nearest_answer or fabs(r-target)<fabs(nearest_answer-target):
nearest_answer = r
best_angle = a
print("{0} -> {1}".format(a,r))
a+=.1 # try increasing the angle a bit. The lower this is the more accurate the answer will be
print("Best angle={}".format(best_angle))
What the problem is
I have to simulate balls in a box of 1 by 1.
i have to give the ball a random speed and a random angle it takes off in.
however when i plot the balls they go straight and have an asymptote at 0.25.
i double cheked my math but i cant find the problem?
My code
import numpy
import matplotlib.pyplot as plt
import math
import random
def rand_tuples(aantalballen): # here i make a function that randomly makes a list with lists in #
list_balls = [] # the list, every index is a ball with x_pos , y_pos , speed , rotation #
for i in range(aantalballen):
list_balls.append([0.25, 0.75,0.1* random.random(), 2* math.pi*random.random()])
return list_balls
def ball_step(list_balls, dt): # this function calculates the steps the balls takes #
x = list_balls[0]
y = list_balls[1]
vx = math.cos(list_balls[3]) * list_balls[2] # speed in the x direction #
vy = math.sin(list_balls[3]) * list_balls[2] # speed in the y direction #
dt = dt
x_pos = x + (vx * dt) # calculates the actual positions #
y_pos = y + (vy * dt)
if x_pos <= 0 or x_pos >= 1: # collision detection #
vx = -vx
if y_pos <= 0 or y_pos >= 1:
vy = -vy
return x_pos, y_pos, vx , vy # returns the new positions but the same speed so that they can be used again#
def move_ball(ballen, tijd, dt): # takes a list of balls, time they move and the time steps they take#
positions_balls = { } # hold my position in {0:{'x':[positions}, 'y':{...}}}
time_1 = 0
for i in range(len(ballen)) :
positions_balls[i] = None # make a key with empty value #
time_1 = 0
cordinates = {'x':[], 'y':[]} # make the dictionary where my values go into #
while time_1 < tijd:
bal = ball_step(ballen[i] , dt) # call bal step to calculate my x and y position #
ballen[i] = bal
cordinates['x'].append(bal[0])
cordinates['y'].append(bal[1])
time_1 += dt
if int(time_1) == tijd:
positions_balls[i] = cordinates # finally add the dictionary to my main dictionary #
print positions_balls
return positions_balls
dic = move_ball(rand_tuples(30), 3, 0.01)
plt.plot(dic[0]['x'], dic[0]['y'])
plt.show()
i do not have enough reputation to post a picture of the plot :(
ball_step() takes in (I think; comments are your friend) x, y, speed, rotation. It outputs x, y, speed x, speed y. That's assigned back to the original list.