I'm implementing a solar system with VPython in GlowScript. Now I have received this error when running: Error cannot add scalar and a vector. I think I've done all correctly. Do I have to change something with the pos. ?
Here is the code:
GlowScript 2.7 VPython
from visual import *
scene = display(width = 800, height = 800, center = vec(0,0.5,0))
#sun
sonne = sphere(pos = vec (0,0,0), radius=8, color = color.orange, shininess=1)
#earth
erde = sphere(pos = vec (50,0,0), radius=1.5, color = color.blue, make_trail=True)
erdeV = vector(0,0,5)
#masses
erdeM = 5.97*10**24
sonneM = 1.989*10**30
#Grav-constant
G = 6.67259*10**-11
for i in range (1000):
rate(1000)
erde.pos = erde.pos + erdeV
#distance
entfernung = sqrt(erde.pos.y**2 + erde.pos.z**2)
#Gravitational law F = G * m * M / r*r --> G*s*e/AE*AE ae=Astr. Einheit
Fgrav = G *( erdeM * sonneM) / (entfernung*entfernung)
erdeV = erdeV + Fgrav
erde.pos += erdeV
if entfernung <= sonne.radius: break
Problem lines:
Fgrav = G *( erdeM * sonneM) / (entfernung*entfernung)
erdeV = erdeV + Fgrav
Fgrav here is a scalar (strength of gravitational force) whereas erdeV is a vector. To remedy this, include the direction of the force:
Fgrav = (-G * (erdeM * sonneM) / (entfernung ** 3)) * erde.pos
erdeV = erdeV + Fgrav
Related
I recently want to use #njit(parallel=True) in package numba to speed up my nbodysimulation code, but when I separate the original function out of the class, my code can not work anymore. How to fix this problem?
The following block is the original code to calculate acceleration.
def _calculate_acceleration(self, mass, pos, rsoft):
"""
Calculate the acceleration.
"""
# TODO:
N = self.particles
rsoft = self.rsoft
posx = pos[:,0]
posy = pos[:,1]
posz = pos[:,2]
G = self.G
npts = self.nparticles
acc = np.zeros((npts, 3))
for i in prange(npts):
for j in prange(npts):
if (j>i):
x = (posx[i]-posx[j])
y = (posy[i]-posy[j])
z = (posz[i]-posz[j])
rsq = x**2 + y**2 + z**2
req = np.sqrt(x**2 + y**2)
f = -G*mass[i,0]*mass[j,0]/rsq
theta = np.arctan2(y, x)
phi = np.arctan2(z, req)
fx = f*np.cos(theta)*np.cos(phi)
fy = f*np.sin(theta)*np.cos(phi)
fz = f*np.sin(phi)
acc[i,0] += fx/mass[i]
acc[i,1] += fy/mass[i]
acc[i,2] += fz/mass[i]
acc[j,0] -= fx/mass[j]
acc[j,1] -= fy/mass[j]
acc[j,2] -= fz/mass[j]
return acc
def initialRandomParticles(N = 100, total_mass = 10):
"""
Initial particles
"""
particles = Particles(N)
masses = particles.masses
mass = total_mass/particles.nparticles
particles.masses = (masses*mass)
positions = np.random.randn(N,3)
velocities = np.random.randn(N,3)
accelerations = np.random.randn(N,3)
particles.positions = positions
particles.velocities = velocities
particles.accelerations = accelerations
return particles
particles = initialRandomParticles(N = 10**5, total_mass = 20)
sim = NbodySimulation(particles)
sim.setup(G=G,method="RK4",io_freq=200,io_title=problem_name,io_screen=True,visualized=False, rsoft=0.01)
sim.evolve(dt=0.01,tmax=10)
# Particles and NbodySimulation are defined class.
I spearate the original function out of the class, and define another function to call it in the class, but it's still can not work.
The following is new code which is out of the class.
#njit(nopython=True, parallel=True)
def _calculate_acceleration(n, npts, G, mass, pos, rsoft):
"""
Calculate the acceleration. This function is out of the class.
"""
# TODO:
posx = pos[:,0]
posy = pos[:,1]
posz = pos[:,2]
acc = np.zeros((n, 3))
sqrt = np.sqrt
for i in prange(npts):
for j in prange(npts):
if (j>i):
x = (posx[i]-posx[j])
y = (posy[i]-posy[j])
z = (posz[i]-posz[j])
rsq = x**2 + y**2 + z**2
req = sqrt(x**2 + y**2 + z**2)
f = -G*mass[i,0]*mass[j,0]/(req + rsoft)**2
fx = f*x**2/rsq
fy = f*y**2/rsq
fz = f*z**2/rsq
acc[i,0] = fx/mass[i] + acc[i,0]
acc[i,1] = fy/mass[i] + acc[i,1]
acc[i,2] = fz/mass[i] + acc[i,2]
acc[j,0] = fx/mass[j] - acc[j,0]
acc[j,1] = fy/mass[j] - acc[j,1]
acc[j,2] = fz/mass[j] - acc[j,2]
return acc
Here is the error:
TypingError Traceback (most recent call last)
:428, in NbodySimulation._update_particles_rk4(self, dt, particles)
426 position = particles.positions # y0[0]
427 velocity = particles.velocities # y0[1], k1[0]
--> 428 acceleration = self._calculate_acceleration_inclass() # k1[1]
430 position2 = position + 0.5*velocity * dt # y1[0]
431 velocity2 = velocity + 0.5*acceleration * dt # y1[1], k2[0]
:381, in NbodySimulation._calculate_acceleration_inclass(self)
377 def _calculate_acceleration_inclass(self):
378 """
379 Calculate the acceleration.
...
<source elided>
acc[i,0] = fx/mass[i] + acc[i,0]
^
I would like to construct an ellipse given the major/minor axes (or radii) and two points. I would like the line between the two points to be on the major axis. This just means that I would like the two points to lie on the major axis, and then construct the ellipse around the major axis. I originally constructed the ellipse at the origin and attempted to rotate and translate the ellipse, which didn't work. The unfinished code I have is listed below. How can I go about constructing an ellipse in this manner? Ideally, this would just return a list. Any insights would be greatly appreciated, and if you have any code for this please feel free to share.
import numpy
import matplotlib.pyplot as plt
import random
import math
from math import sin, cos
# Returns theta in [-pi/2, 3pi/2]
def generate_theta(a, b):
u = random.random() / 4.0
theta = numpy.arctan(b/a * numpy.tan(2*numpy.pi*u))
v = random.random()
if v < 0.25:
return theta
elif v < 0.5:
return numpy.pi - theta
elif v < 0.75:
return numpy.pi + theta
else:
return -theta
def radius(a, b, theta):
return a * b / numpy.sqrt((b*numpy.cos(theta))**2 + (a*numpy.sin(theta))**2)
def random_point(a, b, third_point, center=(0, 0)):
angle = None
if a > b:
random_theta = generate_theta(a, b)
max_radius = radius(a, b, random_theta)
random_radius = max_radius * numpy.sqrt(random.random())
f = round(random_radius * numpy.cos(random_theta))
s = round(random_radius * numpy.sin(random_theta))
angle = math.atan2(third_point[1], third_point[0]) - math.atan2(center[1], center[0])
else:
random_theta = generate_theta(b, a)
max_radius = radius(b, a, random_theta)
random_radius = max_radius * numpy.sqrt(random.random())
f = round(random_radius * numpy.cos(random_theta))
s = round(random_radius * numpy.sin(random_theta))
angle = math.atan2(third_point[1], third_point[0]) - math.atan2(center[1], center[0])
lio = rotate(center, (f, s), angle)
lio = (int(lio[0]), int(lio[1]))
return numpy.array([third, ward])
def rotate(origin, point, angle):
#Rotate a point counterclockwise by a given angle around a given origin.
#The angle should be given in radians.
x = origin[0] + cos(angle) * (point[0] - origin[0]) - sin(angle) * (point[1] - origin[1])
y = origin[1] + sin(angle) * (point[0] - origin[0]) + cos(angle) * (point[1] - origin[1])
return (x, y)
#height
a = 95
#length
b = 25
#rand_p = (-random.randint(300, 400), -random.randint(100, 300))
rand_p = (0, 0)
points = numpy.array([random_point(a, b, (100, 100), (-25, 0)) for _ in range(200)])
#rando = rotate((0, 0), right_most_point, angle)
iopoints = []
# t = x[0] - (int(centroid[0]) - 100)
# t2 = x[1] - (int(centroid[1]) - 100)
centroid = numpy.mean(points, axis=0)
print(centroid)
#plt.plot(rando[0], rando[1], 'ro')
plt.plot(rand_p[0], rand_p[1], 'ro')
plt.scatter(points[:,0], points[:,1])
plt.show()
class ELLIPSE:
def __init__(self, a, b, num_points, start, end):
self.a = a
self.b = b
self.num_points = num_points
self.start = start
self.end = end
self.angle_gen = math.atan2(self.end[1]-self.start[1], self.end[0]-self.start[0])
def generate_theta(self, a, b):
u = random.random() / 4.0
theta = np.arctan(self.b/self.a * np.tan(2*np.pi*u))
v = random.random()
if v < 0.25:
return theta
elif v < 0.5:
return np.pi - theta
elif v < 0.75:
return np.pi + theta
else:
return -theta
def radius(self, a, b, theta):
return self.a * self.b / np.sqrt((b*np.cos(theta))**2 + (a*np.sin(theta))**2)
def random_point(self, major_axis, minor_axis, center, qa):
random_theta = self.generate_theta(self.a, self.b)
max_radius = self.radius(self.a, self.b, random_theta)
random_radius = max_radius * np.sqrt(random.random())
f = round(random_radius * np.cos(random_theta))
s = round(random_radius * np.sin(random_theta))
lio = self.rotate((0, 0), (f, s), self.angle_gen)
return (int(lio[0]+center[0]), int(lio[1]+center[1]))
def rotate(self, origin, point, angle):
"""
Rotate a point counterclockwise by a given angle around a given origin.
The angle should be given in radians.
"""
ox, oy = origin
px, py = point
qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
return qx, qy
def midpoint(self, p1, p2):
return ((p1[0]+p2[0])/2, (p1[1]+p2[1])/2)
def ret_list(self):
points = [self.random_point(self.a, self.b, self.midpoint(self.start, self.end), self.angle_gen) for _ in range(self.num_points)]
return points
I have been trying to simulate Two Temperature Model using fipy
the math of the model:
C_e(∂T_e)/∂t=∇[k_e∇T_e ]-G(T_e-T_ph )+ A(r,t)
C_ph(∂T_ph)/∂t=∇[k_ph∇T_ph] + G(T_e-T_ph)
the source supposed to heat the electrons T_e, then the heat transferred to phonons T_ph through G, when T_ph reach melting point for example 2700 K, some of heat (360000 J) goes as latent heat before melting.
here is my code:
from fipy.tools import numerix
import scipy
import fipy
import numpy as np
from fipy import CylindricalGrid1D
from fipy import Variable, CellVariable, TransientTerm, DiffusionTerm, Viewer, LinearLUSolver, LinearPCGSolver, \
LinearGMRESSolver, ImplicitDiffusionTerm, Grid1D, ImplicitSourceTerm
## Mesh
nr = 50
dr = 1e-7
# r = nr * dr
mesh = CylindricalGrid1D(nr=nr, dr=dr, origin=0)
x = mesh.cellCenters[0]
# Variables
T_e = CellVariable(name="electronTemp", mesh=mesh,hasOld=True)
T_e.setValue(300)
T_ph = CellVariable(name="phononTemp", mesh=mesh, hasOld=True)
T_ph.setValue(300)
G = CellVariable(name="EPC", mesh=mesh)
t = Variable()
# Material parameters
C_e = CellVariable(name="C_e", mesh=mesh)
k_e = CellVariable(name="k_e", mesh=mesh)
C_ph = CellVariable(name="C_ph", mesh=mesh)
k_ph = CellVariable(name="k_ph", mesh=mesh)
C_e = 4.15303 - (4.06897 * numerix.exp(T_e / -85120.8644))
C_ph = 4.10446 - 3.886 * numerix.exp(-T_ph / 373.8)
k_e = 0.1549 * T_e**-0.052
k_ph =1.24 + 16.29 * numerix.exp(-T_ph / 151.57)
G = numerix.exp(21.87 + 10.062 * numerix.log(numerix.log(T_e )- 5.4))
# Boundary conditions
T_e.constrain(300, where=mesh.facesRight)
T_ph.constrain(300, where=mesh.facesRight)
# Source 𝐴(𝑟,𝑡) = 𝑎𝐷(𝑟)𝜏−1 𝑒−𝑡/𝜏 , 𝐷(𝑟) = 𝑆𝑒 exp (−𝑟2/𝜎2)/√2𝜋𝜎2
sig = 1.0e-6
tau = 1e-15
S_e = 35
d_r = (S_e * 1.6e-9 * numerix.exp(-x**2 /sig**2)) / (numerix.sqrt(2. * 3.14 * sig**2))
A_t = numerix.exp(-t/tau)
a = (numerix.sqrt(2. * 3.14)) / (3.14 * sig)
A_r = a * d_r * tau**-1 * A_t
eq0 = (
TransientTerm(var=T_e, coeff=C_e) == \
DiffusionTerm(var=T_e, coeff=k_e) - \
ImplicitSourceTerm(coeff=G, var=T_e) + \
ImplicitSourceTerm(var=T_ph, coeff=G) + \
A_r)
eq1 = (TransientTerm(var=T_ph, coeff=C_ph) == DiffusionTerm(var=T_ph, coeff=k_ph) + ImplicitSourceTerm(var=T_e, coeff=G) - ImplicitSourceTerm(coeff=G, var=T_ph))
eq = eq0 & eq1
dt = 1e-18
steps = 7000
elapsed = 0.
vi = Viewer((T_e, T_ph), datamin=0., datamax=2e4)
for step in range(steps):
T_e.updateOld()
T_ph.updateOld()
vi.plot()
res = 1e100
dt *= 1.01
count = 0
while res > 1:
res = eq.sweep(dt=dt, underRelaxation=0.5)
print(t, res)
t.setValue(t + dt)
As I understood I can include the latent heat as source term as sink in eq1, or add a gaussian peak to C_ph and the peak center should be around melting point.
I have no idea which one is better and more stable, I have no idea how to implement any one of them .
please help me with that
Based on the comments (please edit that into the question), change eq1 to
eq1 = (TransientTerm(var=T_ph, coeff=C_ph)
== DiffusionTerm(var=T_ph, coeff=k_ph)
+ ImplicitSourceTerm(var=T_e, coeff=G)
- ImplicitSourceTerm(coeff=G, var=T_ph)
+ (1/numerix.sqrt(2*numerix.pi * sig2)) * numerix.exp(-(T_ph - 1850)**2 / 2 * sig2)))
It will be evaluated explicitly, but it will update whenever T_ph updates.
I'm trying to simulate a vehicle using a dynamic bicycle model but I cannot seem to get it working. If I set a constant steering angle the lateral velocity grows exponentially and creates impossible results.
a = 0.34284
b = 0.40716
m = 155
I = 37.29
def f_DynBkMdl(x, y, delta, theta, dt, states):
dtheta = states[0]
vlat = states[1]
vlon = states[2]
if delta > math.radians(180):
delta = delta - math.radians(360)
if delta<0:
j = 1
else:
j = 0
if dtheta<0:
q = 1
else:
q = 0
dtheta = abs(dtheta)
delta = abs(delta)
sf = delta - (a*dtheta)/vlon
ff = 30.77*math.degrees(sf)
pf = 0
sr = (b*dtheta)/vlon
fr = 30.77*math.degrees(sr)
pr = 0
if j == 1:
fr = -fr
ff = -ff
if q == 1:
dtheta = -dtheta
theta = theta%math.radians(360)
ddtheta = (a*pf*delta + a*ff - b*fr)/I
dvlat = (pf*delta + ff + fr)/m - vlon*dtheta
dvlon = (pf + pr - ff*delta)/m - vlat*dtheta
dx = -vlat*np.sin(theta) + vlon*np.cos(theta)
dy = vlat*np.cos(theta) + vlon*np.sin(theta)
theta = theta + dtheta*dt + (1/2)*ddtheta*dt**2
dtheta = dtheta + ddtheta*dt
vlat = vlat + dvlat*dt
vlon = vlon + dvlon*dt
vabs = np.sqrt(vlat**2 + vlon**2)
x = x + dx*dt
y = y + dy*dt
states = [dtheta, vlat, vlon]
array = np.array([x, y, theta, vabs, states])
return array
With a and b being the distance between the front and rear axle to the vehicle's centre of gravity, m being the mass and I the inertia. x and y are the global position and theta is the heading with delta being the steering angle. I got these equations from this document. Please note I used a simplified tyre model to calculate the lateral forces and I assumed infinite friction so the friction circle was not needed.
Is there something I am missing to make this work?
I've been working on a computational physics project (plotting related rates of chemical reactants with respect to eachother to show oscillatory behavior) with a fair amount of success. However, one of my simulations involves more than two active oscillating agents (five, in fact) which would obviously be unsuitable for any single visual plot...
My scheme was hence to have the user select which two reactants they wanted plotted on the x-axis and y-axis respectively. I tried (foolishly) to convert string input values into the respective variable names, but I guess I need a radically different approach if any exist?
If it helps clarify any, here is part of my code:
def coupledBrusselator(A, B, t_trial,display_x,display_y):
t = 0
t_step = .01
X = 0
Y = 0
E = 0
U = 0
V = 0
dX = (A) - (B+1)*(X) + (X**2)*(Y)
dY = (B)*(X) - (X**2)*(Y)
dE = -(E)*(U) - (X)
dU = (U**2)*(V) -(E+1)*(U) - (B)*(X)
dV = (E)*(U) - (U**2)*(V)
array_t = [0]
array_X = [0]
array_Y = [0]
array_U = [0]
array_V = [0]
while t <= t_trial:
X_1 = X + (dX)*(t_step/2)
Y_1 = Y + (dY)*(t_step/2)
E_1 = E + (dE)*(t_step/2)
U_1 = U + (dU)*(t_step/2)
V_1 = V + (dV)*(t_step/2)
dX_1 = (A) - (B+1)*(X_1) + (X_1**2)*(Y_1)
dY_1 = (B)*(X_1) - (X_1**2)*(Y_1)
dE_1 = -(E_1)*(U_1) - (X_1)
dU_1 = (U_1**2)*(V_1) -(E_1+1)*(U_1) - (B)*(X_1)
dV_1 = (E_1)*(U_1) - (U_1**2)*(V_1)
X_2 = X + (dX_1)*(t_step/2)
Y_2 = Y + (dY_1)*(t_step/2)
E_2 = E + (dE_1)*(t_step/2)
U_2 = U + (dU_1)*(t_step/2)
V_2 = V + (dV_1)*(t_step/2)
dX_2 = (A) - (B+1)*(X_2) + (X_2**2)*(Y_2)
dY_2 = (B)*(X_2) - (X_2**2)*(Y_2)
dE_2 = -(E_2)*(U_2) - (X_2)
dU_2 = (U_2**2)*(V_2) -(E_2+1)*(U_2) - (B)*(X_2)
dV_2 = (E_2)*(U_2) - (U_2**2)*(V_2)
X_3 = X + (dX_2)*(t_step)
Y_3 = Y + (dY_2)*(t_step)
E_3 = E + (dE_2)*(t_step)
U_3 = U + (dU_2)*(t_step)
V_3 = V + (dV_2)*(t_step)
dX_3 = (A) - (B+1)*(X_3) + (X_3**2)*(Y_3)
dY_3 = (B)*(X_3) - (X_3**2)*(Y_3)
dE_3 = -(E_3)*(U_3) - (X_3)
dU_3 = (U_3**2)*(V_3) -(E_3+1)*(U_3) - (B)*(X_3)
dV_3 = (E_3)*(U_3) - (U_3**2)*(V_3)
X = X + ((dX + 2*dX_1 + 2*dX_2 + dX_3)/6) * t_step
Y = Y + ((dX + 2*dY_1 + 2*dY_2 + dY_3)/6) * t_step
E = E + ((dE + 2*dE_1 + 2*dE_2 + dE_3)/6) * t_step
U = U + ((dU + 2*dU_1 + 2*dY_2 + dE_3)/6) * t_step
V = V + ((dV + 2*dV_1 + 2*dV_2 + dE_3)/6) * t_step
dX = (A) - (B+1)*(X) + (X**2)*(Y)
dY = (B)*(X) - (X**2)*(Y)
t_step = .01 / (1 + dX**2 + dY**2) ** .5
t = t + t_step
array_X.append(X)
array_Y.append(Y)
array_E.append(E)
array_U.append(U)
array_V.append(V)
array_t.append(t)
where previously
display_x = raw_input("Choose catalyst you wish to analyze in the phase/field diagrams (X, Y, E, U, or V) ")
display_y = raw_input("Choose one other catalyst from list you wish to include in phase/field diagrams ")
coupledBrusselator(A, B, t_trial, display_x, display_y)
Thanks!
Once you have calculated the different arrays, you could add them to a dict that maps names to arrays. This can then be used to look up the correct arrays for display_x and display_y:
named_arrays = {
"X": array_X,
"Y": array_Y,
"E": array_E,
...
}
return (named_arrays[display_x], named_arrays[display_y])