I've implemented a simple direct Nbody simulation in python. I'm looking to parallelize it as we are doing the same operation again and again. In C++, I would have use openmp, but python doesn't have it.
So I was thinking to use the multiprocessing module. From what I understand, I would need a manager to manage the class (and the list particles?) and I was thinking of using a starmap pool.
I'm quite lost on how to use these function to achieve any semblance of parallelization, so any help is appreciated.
PS: I'm open to use other module too, the easier the better. The class is ditchable if using numpy array (for position velocity mass) solves the problem, I'll go with it.
Code:
import numpy as np
import matplotlib.pyplot as plt
import multiprocessing as mp
class particle:
def __init__(self, xy, uv, m):
self.xy =xy # position
self.uv = uv # velocity
self.m = m # mass
self.force = np.zeros([2]) # at t=0s, force =0
def update(self,dt):
self.uv += self.force/self.m * dt
self.xy += self.uv*dt
self.force=np.zeros([2])
def interaction(self,p,jj,eps):
dr = p[jj].xy - self.xy
dr_norm = np.linalg.norm(dr + eps)
self.force += G*self.m*p[jj].m/(dr_norm**2) * dr/dr_norm
p[jj].force -= G*self.m*p[jj].m/(dr_norm**2) * dr/dr_norm
def init_world(n_part):
p=[]
for ii in range(n_part):
p.append(particle(np.random.uniform(0,50,size=(2))*1e15,np.random.uniform(-10,10,size=(2))*0,np.random.uniform(2,25)*1e28))
return p
G = 6.67e-11 # in SI units
dt= 1e5 # in second, 86400s = one day
niter = 10000
n_part = 300
eps = 1e8 #softening to avoid infinite force a small distance
p = init_world(n_part)
xy = np.asarray([p[ii].xy for ii in range(n_part)])
fig, ax1 = plt.subplots()
im = ax1.scatter(xy[:,0],xy[:,1])
plt.show()
for tt in range(niter):
for ii in range(n_part):
for jj in range(ii+1,n_part):
p[ii].interaction(p,jj,eps)
for ii in range(n_part):
p[ii].update(dt)
xy = np.asarray([p[ii].xy for ii in range(n_part)])
ax1.set_title(tt)
im.set_offsets(xy)
plt.pause(0.01)
If you want to share a list of custom objects (such as particle in the question) among processes, you can consider a simplified example here:
import multiprocessing
from multiprocessing.managers import BaseManager
TOTAL_PROCESS = 3
class Particle():
def __init__(self, x, y):
self.x = x
self.y = y
def multiply(self, z):
self.x *= z
self.y *= z
def __repr__(self):
return f'(x={self.x},y={self.y})'
def worker(sharedList, ix):
# Call multiply() for the specific item in the list
sharedList[ix].multiply(2)
def main():
BaseManager.register('Particle', Particle) # Register your custom class
clsManager = BaseManager() # A manager to manage Particle objects
clsManager.start()
manager = multiprocessing.Manager() # Another manager to manage a shared list
# Create a list of Particle objects
sharedList = manager.list([clsManager.Particle(x, x+1) for x in range(0, TOTAL_PROCESS)])
# See the origina list
for x in sharedList:
print(x, end=' ')
else:
print()
# Run multiple processes and to make each of them them to work on a specific object only
processes = []
for i in range(TOTAL_PROCESS):
p = multiprocessing.Process(target=worker, args=[sharedList, i])
p.start()
processes.append(p)
for p in processes:
p.join()
# See the updated list of Pariticle objects
for x in sharedList:
print(x, end=' ')
else:
print()
if __name__ == '__main__':
main()
Related
import random
class point:
def __init__(self,p):
self.p = p
def fill_point(self):
x = random.uniform(0,100)
y = random.uniform(0,100)
z = random.uniform(0,100)
self.p = [x,y,z]
return self.p
def distance_between_points(self,p1,p2):
D = ((self.p1[0]-self.p2[0])**2 + (self.p1[1]-self.p2[1])**2 + (self.p1[2]-self.p2[2])**2)**(1/2)
return D
def main():
point1 = point(fill_point())
point2 = point(fill_point())
Distance = distance_between_points(point1,point2)
print(Distance)
main()
im quite new to classes and am having a hard time understanding what im doing wrong.
import random
from math import sqrt
class Point:
def __init__(self, name='anonym_point',x=0,y=0,z=0):
self.name = name
self.x = x
self.y = y
self.z = z
#property
def coord(self):
return (self.x, self.y, self.z)
def __repr__(self):
return ("{} has coordinate {} {} {}".format(self.name, self.x, self.y, self.z))
def makepoint(namepoint):
return Point(namepoint, random.uniform(0,100), random.uniform(0,100), random.uniform(0,100))
def distance_between_points(p1,p2):
dist = sqrt((p2.x-p1.x)**2 + (p2.y-p1.y)**2 + (p2.z-p1.z)**2)
print("distance between point ",p1.name," and the point ",p2.name," : ",dist)
point1 = makepoint("p1")
point2 = makepoint("p2")
print(point1)
print(point2)
Distance = distance_between_points(point1,point2)
The issue is that you are accessing the class method just as a normal method, you need to initialize class object first then call the method by class object you created, again use only the variables you are sure you need,. keeping code easy for you because I think you already know what you needed I did this
import random
class Point:
def fill_point(self):
x = random.uniform(0,100)
y = random.uniform(0,100)
z = random.uniform(0,100)
p = [x,y,z]
return p
def distance_between_points(self,p1,p2):
D = ((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2 + (p1[2]-p2[2])**2)**(1/2)
return D
def main():
obj = Point()
point1 = obj.fill_point()
point2 = obj.fill_point()
distance = obj.distance_between_points(point1,point2)
print(distance)
main()
it would not kill if you try to understand python classes better, python best naming, etc...
i think that what you are trying to do is something like this.
import math
class Point():
def __init__(self,x,y,z):
self.coordinates = (x,y,z)
def distance(self,point):
return math.sqrt((point.coordinates[0] - self.coordinates[0])**2 + (point.coordinates[1] - self.coordinates[1])**2 + (point.coordinates[1] - self.coordinates[1])**2)
a = Point(4,2,8)
b = Point(2,7,3)
print(a.distance(b))
what you are doing by executing this python code is simply creating a "Point" class, this point class has an attribute (coordinates) that contains its coordinates into a tuple.
so to create a point object you just have to use this code point = Point(x_coordinates,y_coordinates,z_coordinates).
In the last line the code calculates the distance between two points, in that case you are calculating the distance of "b" respect to "a", but you could also do viceversa by doing something like this: print(b.distance(a))
to calculate the distance between random point all you have to do is this:
import math, random
class Point():
def __init__(self,x,y,z):
self.coordinates = (x,y,z)
def distance(self,point):
return math.sqrt((point.coordinates[0] - self.coordinates[0])**2 + (point.coordinates[1] - self.coordinates[1])**2 + (point.coordinates[1] - self.coordinates[1])**2)
r = lambda: random.uniform(0,100)
a = Point(r(),r(),r())
b = Point(r(),r(),r())
print(a.distance(b))
this is how to do that, but i really don't understand why you should calculate the distance between two random numbers
In the following code, I have made a class that plots a point:
import matplotlib.pyplot as plt
import random
class Point:
def __init__(self):
X = random.randint(0,50)
Y = random.randint(0,50)
plt.plot(X, Y,'o')
What I am wondering is that how can you make many instances of this class without manually typing every single one in.
[Point() for _ in range(100)]
gives you a list of 100 instances of class Point.
First, we'll remove the plotting:
import matplotlib.pyplot as plt
import random
class Point:
def __init__(self):
self.x = random.randint(0, 50)
self.y = random.randint(0, 50)
Next, let's define a function that returns a list of n points:
def getNPoints(n):
points = []
for i in range(0, n):
points.append(Point())
return points
Finally, do whatever you want with those points:
points = getNPoints(10)
for point in points:
plt.plot(point.x, point.y, 'o')
Putting it all together:
import matplotlib.pyplot as plt
import random
class Point:
def __init__(self):
self.x = random.randint(0, 50)
self.y = random.randint(0, 50)
def getNPoints(n):
points = []
for i in range(0, n):
points.append(Point())
return points
points = getNPoints(10)
for point in points:
plt.plot(point.x, point.y, 'o')
I am currently trying to write a Python ROS program which can be executed as a ROS node (using rosrun) that implements the defs declared in a separate Python file arm.py (available at: https://github.com/nortega1/dvrk-ros/...). The program initially examines the current cartesian position of the arm. Subsequently, when provided with a series of points that the arm must pass through, the program calculates a polynomial equation and given a range of x values the program evaluates the equation to find the corresponding y values.
Within the arm.py file there is a publisher set_position_cartesian_pub that sets the Cartesian position of the arm as follows:
self.__set_position_cartesian_pub = rospy.Publisher(self.__full_ros_namespace + '/set_position_cartesian', Pose, latch = True, queue_size = 1)
The issue is that the publisher set_position_cartesian is not publishing the values of the newPose to the robot - can anyone figure out what the issue might be? I can confirm that the def lagrange correctly calculates the values of the x and y coordinates, which are printed out to the terminal via the command rospy.loginfo(newPose). Any help would be greatly appreciated as I've been trying to solve this issue for the last 2 days!
#! /usr/bin/python
import rospy
import sys
from std_msgs.msg import String, Bool, Float32
from geometry_msgs.msg import Pose
from geometry_msgs.msg import PoseStamped
from geometry_msgs.msg import Vector3
from geometry_msgs.msg import Quaternion
from geometry_msgs.msg import Wrench
class example_application:
def callback(self, data):
self.position_cartesian_current = data.pose
rospy.loginfo(data.pose)
def configure(self,robot_name):
self._robot_name = 'PSM1'
ros_namespace = '/dvrk/PSM1'
rospy.Subscriber('/dvrk/PSM1/position_cartesian_current', PoseStamped, self.callback)
self.set_position_cartesian = rospy.Publisher('/dvrk/PSM1/set_position_cartesian', Pose, latch=True, queue_size = 10)
rospy.sleep(3)
rospy.init_node('listener', anonymous=True)
rospy.spin()
def lagrange(self, f, x):
total = 0
n = len(f)
for i in range(n):
xi, yi = f[i]
def g(i, n):
g_tot = 1
for j in range(n):
if i == j:
continue
xj, yj = f[j]
g_tot *= (x - xj) / float(xi - xj)
return g_tot
total += yi * g(i, n)
return total
def trajectoryMover(self):
newPose = Pose()
points =[(0.0156561,0.123151),(0.00715134,0.0035123151),(0.001515177,0.002123151),(0.0071239751,0.09123150)]
xlist = [i*0.001 for i in range(10)]
ylist = [self.lagrange(points, xlist[i])*0.001 for i in range(10)]
for x, y in zip(xlist, ylist):
newPose.position.x = x
newPose.position.y = y
newPose.position.z = 0.001
newPose.orientation.x = 0.001
newPose.orientation.y = 0.001
newPose.orientation.z = 0.005
newPose.orientation.w = 0.002
rospy.sleep(1)
self.set_position_cartesian.publish(newPose)
rospy.loginfo(newPose)
rospy.spin()
def run(self):
# self.home()
self.trajectoryMover()
if __name__ == '__main__':
try:
if (len(sys.argv) != 2):
print(sys.argv[0] + ' requires one argument, i.e. name of dVRK arm')
else:
application = example_application()
application.configure(sys.argv[1])
application.run()
except rospy.ROSInterruptException:
pass
You are not publishing because the code stops at rospy.spin() when you call application.configure(). For what I understand of what you are trying to do, the code will publish 10 poses to a topic, then you don't need it anymore.
I've moved the location of rospy.spin(), but the code needs more revision than that.
#! /usr/bin/python
import rospy
import sys
from std_msgs.msg import String, Bool, Float32
from geometry_msgs.msg import Pose
from geometry_msgs.msg import PoseStamped
from geometry_msgs.msg import Vector3
from geometry_msgs.msg import Quaternion
from geometry_msgs.msg import Wrench
class example_application(object):
def callback(self, data):
self.position_cartesian_current = data.pose
rospy.loginfo(data.pose)
def configure(self,robot_name):
self._robot_name = 'PSM1'
ros_namespace = '/dvrk/PSM1'
rospy.Subscriber('/dvrk/PSM1/position_cartesian_current', PoseStamped, self.callback)
self.set_position_cartesian = rospy.Publisher('/dvrk/PSM1/set_position_cartesian', Pose, latch=True, queue_size = 10)
def lagrange(self, f, x):
total = 0
n = len(f)
for i in range(n):
xi, yi = f[i]
def g(i, n):
g_tot = 1
for j in range(n):
if i == j:
continue
xj, yj = f[j]
g_tot *= (x - xj) / float(xi - xj)
return g_tot
total += yi * g(i, n)
return total
def trajectoryMover(self):
newPose = Pose()
points =[(0.0156561,0.123151),(0.00715134,0.0035123151),(0.001515177,0.002123151),(0.0071239751,0.09123150)]
xlist = [i*0.001 for i in range(10)]
ylist = [self.lagrange(points, xlist[i])*0.001 for i in range(10)]
for x, y in zip(xlist, ylist):
newPose.position.x = x
newPose.position.y = y
newPose.position.z = 0.001
newPose.orientation.x = 0.001
newPose.orientation.y = 0.001
newPose.orientation.z = 0.005
newPose.orientation.w = 0.002
self.set_position_cartesian.publish(newPose)
rospy.loginfo(newPose)
def run(self):
# self.home()
self.trajectoryMover()
if __name__ == '__main__':
if (len(sys.argv) != 2):
print(sys.argv[0] + ' requires one argument, i.e. name of dVRK arm')
else:
application = example_application()
application.configure(sys.argv[1])
application.run()
try:
rospy.spin()
except KeyboardInterrupt:
rospy.loginfo("Keyboard Interrupt")
Think of:
making the script argument a parameter of the node.
moving the configure method to the __init__ method.
taking the g() function outside lagrange().
It's a good practice to use relative topic names, instead of absolute ones (absolute: topic name start with /, e.g.: '/dvrk/PSM1').
The below code simulates a stock price and calculates its payoff. I am trying to use multiprocessing to speed up the simulations. The problem is that in CallUpAndOut where I have pool.map, I am not sure how to access total from simulations
I have tried several things like self.Simulations.Total or self.total but it doesn't work.
import numpy as np
from multiprocessing import Pool
import time
class PricingSimulatedBarrierOption:
def __init__(self, spot, strike, barrier, rate, sigma, time, sims, steps):
self.spot = spot
self.strike = strike
self.barrier = barrier
self.rate = rate
self.sigma = sigma
self.time = time
self.sims = sims
self.steps = steps
self.dt = self.time / self.steps
def Simulations(self):
total = np.zeros((self.sims,self.steps+1),float)
pathwiseS= np.zeros((self.steps+1),float)
for j in range(self.sims):
pathwiseS[0] =self.spot
total[j,0] = self.spot
for i in range(1,self.steps+1):
phi = np.random.normal()
pathwiseS[i] = pathwiseS[i-1]*(1+self.rate*self.dt+self.sigma*phi*np.sqrt(self.dt))
total[j,i]= pathwiseS[i]
return total.reshape(self.sims, self.steps+1)
def CallUpAndOut(self):
start_time = time.time()
p = Pool()
getpayoff = p.map(self.Simulations(),self.total) ###How to pass total here?
p.close()
p.join()
end_time = time.time()-start_time
print(end_time)
# getpayoff = self.Simulations()
callpayoff = np.zeros((self.sims),float)
for j in range(self.sims):
if max(getpayoff[j,])>=self.barrier:
callpayoff[j] = 0
else:
callpayoff[j] = max(getpayoff[j,self.steps-1]-self.strike,0)
return np.exp(-self.rate*self.time)*np.average(callpayoff)
c = PricingSimulatedBarrierOption(100,100,170,0.05,0.2,1,10000,252)
print(c.CallUpAndOut())
In function definition add parameter see below example:
def CallUpAndOut(self, total):
And pass array of total values in map see below example:
total = [1,2,3]
getpayoff = p.map(self.Simulations,total)
To work this I had to move the declaration outside. Below code is now able to accept variable in the Pool function.
import numpy as np
from multiprocessing import Pool
import time
class PricingSimulatedBarrierOption:
def __init__(self, spot, strike, barrier, rate, sigma, time, sims, steps):
self.spot = spot
self.strike = strike
self.barrier = barrier
self.rate = rate
self.sigma = sigma
self.time = time
self.sims = sims
self.steps = steps
self.dt = self.time / self.steps
self.pathwiseS= np.zeros((self.steps+1),float)
def Simulations(self):
print("Called")
total = np.zeros((self.sims,self.steps+1),float)
self.pathwiseS= np.zeros((self.steps+1),float)
for j in range(self.sims):
self.pathwiseS[0] =self.spot
total[j,0] = self.spot
for i in range(1,self.steps+1):
phi = np.random.normal()
self.pathwiseS[i] = self.pathwiseS[i-1]*(1+self.rate*self.dt+self.sigma*phi*np.sqrt(self.dt))
total[j,i]= self.pathwiseS[i]
return total.reshape(self.sims, self.steps+1)
def CallUpAndOut(self):
start_time = time.time()
p = Pool()
getpayoff = p.map(self.Simulations(),self.pathwiseS)
p.close()
p.join()
end_time = time.time()-start_time
print(end_time)
# getpayoff = self.Simulations()
callpayoff = np.zeros((self.sims),float)
for j in range(self.sims):
if max(getpayoff[j,])>=self.barrier:
callpayoff[j] = 0
else:
callpayoff[j] = max(getpayoff[j,self.steps-1]-self.strike,0)
return np.exp(-self.rate*self.time)*np.average(callpayoff)
I've got a class called Point with many functions. I put an extract code:
#/usr/bin/env python3
# -*- coding: utf-8 -*-
from math import sqrt, pow, hypot, atan2, cos, sin
class Point(object):
__slots__ = ['x', 'y', 'z']
def __init__(self, x=0, y=0, z=None):
self.x = x
self.y = y
self.z = z
def __del__(self):
#del P destroy (delete) a point
class_name = self.__class__.__name__
def dist(self, P):
if self.z is not None:
d = sqrt(pow(self.x - P.x, 2) + pow(self.y - P.y, 2) +
pow(self.z - P.z, 2))
return d
else:
d = sqrt(pow(self.x - P.x, 2) + pow(self.y - P.y, 2))
return d
def pto_medio(self, P):
Q = Point(self.x, self.y)
if self.z is not None:
Q = Point(self.x, self.y, self.z)
else:
Q = Point(self.x, self.y)
R = (1. / 2.) * (P + Q)
return R
def entrada(self):
point = raw_input('Introduce un punto:\n')
point = point.replace('(', '')
point = point.replace(')', '')
l1 = point.rsplit(',')
self.x = float(l1[0])
self.y = float(l1[1])
if len(l1) == 3:
self.z = float(l1[2])
l1 = []
def __repr__(self):
if self.z is not None:
return('({}, {}, {})'.format(self.x, self.y, self.z))
else:
return('({}, {})'.format(self.x, self.y))
When I call the functions I put this code:
def main():
p = Point()
q = Point()
Point.entrada(p)
Point.entrada(q)
s = p + q
r = p - q
m = 5 * p
print(('Distancia = {}'.format(p.dist(q))))
print(('Punto Medio = {}'.format(p.pto_medio(q))))
if __name__ == '__main__':
main()
I put p.dist(q) and p.pto_medio(q) but I want to write dist(p, q) and pto_medio(p, q), respectivily. I've seen several solutions about that but all solutions give me error.
Thanks!
I don't know why you want to do this… but if you want to, it's easy.
In Python, an unbound method (that is, a method accessed as a member of the class object) can be called just like a function, by passing the self argument explicitly. So:
dist = Point.dist
pto_medio = Point.pto_medio
dist(p, q)
pto_medio(p, q)
In other words, the unbound method is the function you def'd in the class definition, with no magic whatsoever.*
If you want to know how this all works under the covers, see the Descriptor HOWTO and how methods work.
And there are plenty of cases where this is useful, beyond just adapting two pieces of code that were written incompatibly. For example, map and filter don't take a function, they take any callable. Sometimes it makes sense to pass them an unbound method:
with open(path) as f:
strippedlines = map(str.strip, f)
If you couldn't pass unbound methods around like functions, you'd have to write that as:**
with open(path) as f:
strippedlines = map(lambda line: line.strip(), f)
* In Python 2.x, this isn't true; an unbound method is instead a bound method with None for the bound instance, and there's special magic to make it work. But in 3.0+, unbound methods are just plain functions.
** Well, actually you could just use a comprehension: (line.strip() for line in f). But if you wanted to use map, you'd have to build a wrapper.