def circular_random_walk(step_options = [0, 0.5, 1], size = 100000): fig, axs = plt.subplots() plt.xlabel("Position - x") plt.ylabel("Position - y") Radius = 100 step_addition = 0 randomWalk_x= [0] randomWalk_y= [0] counter = 1 while counter < (size + 1): i = counter angle = np.random.uniform(0, 2*np.pi, size = 1) distance = np.random.choice(step_options, size = 1) x_coordinate = distance[0] * np.cos(angle[0]) y_coordinate = distance[0] * np.sin(angle[0]) new_x = randomWalk_x[-1] + x_coordinate new_y = randomWalk_y[-1] + y_coordinate distance_from_origin = math.sqrt((new_x)**2 + (new_y)**2) if distance_from_origin >= (Radius): new_x = ('%.3f'%(new_x)) new_y = ('%.3f'%(new_y)) old_x = randomWalk_x[-1] old_y = randomWalk_y[-1] old_x = ('%.3f'%(old_x)) old_y = ('%.3f'%(old_y)) p1, p2 = Point(old_x, old_y) , Point(new_x, new_y) if p1.equals(p2): randomWalk_x.append(old_x) randomWalk_y.append(old_y) counter+=1 continue line = Line(p1, p2) a, b, c = line.coefficients x, y = symbols('x,y') eq1 = Eq((x)**2 + (y)**2 - (Radius)**2, 0, evaluate=False) eq2 = Eq((a*x) + (b*y) + c, 0, evaluate=False) sol = solve([eq1, eq2], [x, y]) #find the point on the circumference where our line will touch, call it circpoint try: sol1 = Point(sol[0][0], sol[0][1]) sol2 = Point(sol[1][0], sol[1][1]) dist_sol1 = p1.distance(sol1) dist_sol2 = p1.distance(sol2) if dist_sol1 > dist_sol2: circ_point = sol[1] elif dist_sol1 < dist_sol2: circ_point = sol[0] else: d1 = sol1.distance(p2) d2 = sol2.distance(p2) if d1 < d2: circ_point = sol[0] else: circ_point = sol[1] circ_point = Point(circ_point[0], circ_point[1]) except: randomWalk_x.append(old_x) randomWalk_y.append(old_y) counter+=1 continue #we know the overflow amount, call that overflowed overflowed = p2.distance(circ_point) #get the vector from our curr_pos to circpoint, call it incident incident = np.array([circ_point[0] - p1[0], circ_point[1] - p1[1]]) #circpoint to origin vector normal = np.array([circ_point[0], circ_point[1]]) #-find the angle between incident and normal using dot product wali equation, call that theta if p1.equals(circ_point): randomWalk_x.append(old_x) randomWalk_y.append(old_y) counter+=1 continue dot = (circ_point[0]*incident[0]) + (circ_point[1]*incident[1]) magnitude1 = (circ_point[0]**2 + circ_point[1]**2)**(0.5) magnitude2 = (incident[0]**2 + incident[1]**2)**(0.5) ang = dot / (magnitude1 * magnitude2) main_ang = math.acos(ang) Theta = main_ang if p2[0] < 0 and p2[1] > 0: #second Theta = -Theta elif p2[0] > 0 and p2[1] > 0: #first if incident[1] >= incident[0]: Theta = (-Theta) else: Theta = (Theta) elif p2[0] > 0 and p2[1] < 0: if incident[1] > -incident[0]: #fourth Theta = (-Theta) elif p2[0] < 0 and p2[1] < 0: if incident[1] <= incident[0]: Theta = (-Theta) #-form a 2x2 rotation matrix, uska format dekh lo aram se mile ga rotation_matrix = np.array([[np.cos(Theta), -np.sin(Theta)],[np.sin(Theta), np.cos(Theta)]]) #-multiply the rotation matrix by the normal vector to get another 2x1 vector, call it reflected reflected = np.dot(rotation_matrix, normal) reflected *= -1 #-find the unit vector in the direction of reflected, call it ref_unit ref_unit = reflected / math.sqrt(reflected[0]**2 + reflected[1]**2) #-scalar multiply ref_unit with overflow ref_point = ref_unit * overflowed #-us vector ke components ko add to circpoint ke coordinates to get the final coordinates final = circ_point + ref_point #-add both circ point (optional but will look better) and final coord to the arrays randomWalk_x.append(circ_point[0]) randomWalk_y.append(circ_point[1]) distance_from_origin = math.sqrt((final[0])**2 + (final[1])**2) counter+=1 if distance_from_origin >= Radius: continue else: randomWalk_x.append(final[0]) randomWalk_y.append(final[1]) step_addition += 1 continue randomWalk_x.append(new_x) randomWalk_y.append(new_y) counter += 1 ### Uncomment to see plot #return distance_from_origin ######################### size = size + step_addition ######################################################### #UNCOMMENT FOR ANIMATION # xdata, ydata = [], [] # ln, = plt.plot(xdata,ydata) # def init(): # #Radius = 5.64189584 when area of circle = 100 unit^2 # axs.set_xlim(-Radius,Radius) # axs.set_ylim(-Radius,Radius) # ln.set_data([], []) # return ln, # def update(frame): # xdata.append(randomWalk_x[int(frame)]) # ydata.append(randomWalk_y[int(frame)]) # ln.set_data(xdata, ydata) # return ln, # ani = FuncAnimation(fig, update, frames=np.linspace(0, size, size+1, endpoint=True), interval = 20, # init_func=init, blit=True, repeat=False) #ANIMATION CODE ######################################################## circle1=plt.Circle((0,0),Radius,color='r', alpha= 0.2) plt.gcf().gca().add_artist(circle1) plt.plot(randomWalk_x, randomWalk_y) plt.show()
def circular_random_walk(): fig, axs = plt.subplots() plt.xlabel("Position - x") plt.ylabel("Position - y") Radius = 100 step_addition_A = 0 step_addition_B = 0 ##### ##Choosing initial points r_A = np.random.uniform(0, Radius) r_B = np.random.uniform(0, Radius) thet_A = np.random.uniform(0, 2 * np.pi) thet_B = np.random.uniform(0, 2 * np.pi) x_A = r_A * np.cos(thet_A) y_A = r_A * np.sin(thet_A) x_B = r_B * np.cos(thet_B) y_B = r_B * np.sin(thet_B) #### randomWalk_x_A = [x_A] randomWalk_y_A = [y_A] randomWalk_x_B = [x_B] randomWalk_y_B = [y_B] flag_A_ref = False flag_B_ref = False steps = 0 counter = 0 while True: angle_A = np.random.uniform(0, 2 * np.pi, size=1) angle_B = np.random.uniform(0, 2 * np.pi, size=1) distance_A = np.random.uniform(0, 1, size=1) distance_B = np.random.uniform(0, 1, size=1) x_coordinate_A = distance_A[0] * np.cos(angle_A[0]) y_coordinate_A = distance_A[0] * np.sin(angle_A[0]) x_coordinate_B = distance_B[0] * np.cos(angle_B[0]) y_coordinate_B = distance_B[0] * np.sin(angle_B[0]) new_x_A = randomWalk_x_A[-1] + x_coordinate_A new_y_A = randomWalk_y_A[-1] + y_coordinate_A new_x_B = randomWalk_x_B[-1] + x_coordinate_B new_y_B = randomWalk_y_B[-1] + y_coordinate_B distance_from_origin_A = ((new_x_A)**2 + (new_y_A)**2)**(0.5) distance_from_origin_B = ((new_x_B)**2 + (new_y_B)**2)**(0.5) while distance_from_origin_A >= (Radius): new_x_A = '%.3f' % (new_x_A) new_y_A = '%.3f' % (new_y_A) old_x_A = '%.3f' % (randomWalk_x_A[-1]) old_y_A = '%.3f' % (randomWalk_y_A[-1]) p1, p2 = Point(old_x_A, old_y_A), Point(new_x_A, new_y_A) if p1.equals(p2): randomWalk_x_A.append(old_x_A) randomWalk_y_A.append(old_y_A) flag_A_ref = True break line = Line(p1, p2) a, b, c = line.coefficients x, y = symbols('x,y') eq1 = Eq((x)**2 + (y)**2 - (Radius)**2, 0, evaluate=False) eq2 = Eq((a * x) + (b * y) + c, 0, evaluate=False) sol = solve([eq1, eq2], [x, y]) #find the point on the circumference where our line will touch, call it circpoint sol1 = (sol[0][0], sol[0][1]) sol2 = (sol[1][0], sol[1][1]) d1 = ((p2[0] - sol1[0])**2 + (p2[1] - sol1[1])**2)**(0.5) d2 = ((p2[0] - sol2[0])**2 + (p2[1] - sol2[1])**2)**(0.5) if d1 <= d2: circ_point = sol[0] else: circ_point = sol[1] circ_point = Point(circ_point[0], circ_point[1]) #we know the overflow amount, call that overflowed overflowed = p2.distance(circ_point) #get the vector from our curr_pos to circpoint, call it incident incident = np.array([circ_point[0] - p1[0], circ_point[1] - p1[1]]) #circpoint to origin vector normal = np.array([circ_point[0], circ_point[1]]) #-find the angle between incident and normal using dot product wali equation, call that theta if p1.equals(circ_point): randomWalk_x_A.append(old_x_A) randomWalk_y_A.append(old_y_A) flag_A_ref = True break dot = (circ_point[0] * incident[0]) + (circ_point[1] * incident[1]) magnitude1 = math.sqrt(circ_point[0]**2 + circ_point[1]**2) magnitude2 = math.sqrt(incident[0]**2 + incident[1]**2) ang = dot / (magnitude1 * magnitude2) main_ang = math.acos(ang) Theta = main_ang if p2[0] < 0 and p2[1] > 0: #second Theta = -Theta elif p2[0] > 0 and p2[1] > 0: #first if incident[1] >= incident[0]: Theta = -Theta elif p2[0] > 0 and p2[1] < 0: if incident[1] > -incident[0]: #fourth Theta = -Theta elif p2[0] < 0 and p2[1] < 0: if incident[1] <= incident[0]: Theta = -Theta #-form a 2x2 rotation matrix, uska format dekh lo aram se mile ga rotation_matrix = np.array([[np.cos(Theta), -np.sin(Theta)], [np.sin(Theta), np.cos(Theta)]]) #-multiply the rotation matrix by the normal vector to get another 2x1 vector, call it reflected reflected = np.dot(rotation_matrix, normal) reflected *= -1 #-find the unit vector in the direction of reflected, call it ref_unit ref_unit = reflected / math.sqrt(reflected[0]**2 + reflected[1]**2) #-scalar multiply ref_unit with overflow ref_point = ref_unit * overflowed #-us vector ke components ko add to circpoint ke coordinates to get the final coordinates final = circ_point + ref_point #-add both circ point (optional but will look better) and final coord to the arrays randomWalk_x_A.append(circ_point[0]) randomWalk_y_A.append(circ_point[1]) distance_from_origin = math.sqrt((final[0])**2 + (final[1])**2) if distance_from_origin >= Radius: flag_A_ref = True break else: randomWalk_x_A.append(final[0]) randomWalk_y_A.append(final[1]) step_addition_A += 1 flag_A_ref = True break while distance_from_origin_B >= (Radius): new_x_B = '%.3f' % (new_x_B) new_y_B = '%.3f' % (new_y_B) old_x_B = '%.3f' % (randomWalk_x_B[-1]) old_y_B = '%.3f' % (randomWalk_y_B[-1]) p1, p2 = Point(old_x_B, old_y_B), Point(new_x_B, new_y_B) if p1.equals(p2): randomWalk_x_B.append(old_x_B) randomWalk_y_B.append(old_y_B) flag_B_ref = True break line = Line(p1, p2) a, b, c = line.coefficients x, y = symbols('x,y') eq1 = Eq((x)**2 + (y)**2 - (Radius)**2, 0, evaluate=False) eq2 = Eq((a * x) + (b * y) + c, 0, evaluate=False) sol = solve([eq1, eq2], [x, y]) #find the point on the circumference where our line will touch, call it circpoint sol1 = (sol[0][0], sol[0][1]) sol2 = (sol[1][0], sol[1][1]) d1 = ((p2[0] - sol1[0])**2 + (p2[1] - sol1[1])**2)**(0.5) d2 = ((p2[0] - sol2[0])**2 + (p2[1] - sol2[1])**2)**(0.5) if d1 <= d2: circ_point = sol[0] else: circ_point = sol[1] circ_point = Point(circ_point[0], circ_point[1]) #we know the overflow amount, call that overflowed overflowed = p2.distance(circ_point) #get the vector from our curr_pos to circpoint, call it incident incident = np.array([circ_point[0] - p1[0], circ_point[1] - p1[1]]) #circpoint to origin vector normal = np.array([circ_point[0], circ_point[1]]) #-find the angle between incident and normal using dot product wali equation, call that theta if p1.equals(circ_point): randomWalk_x_B.append(old_x_B) randomWalk_y_B.append(old_y_B) flag_B_ref = True break dot = (circ_point[0] * incident[0]) + (circ_point[1] * incident[1]) magnitude1 = math.sqrt(circ_point[0]**2 + circ_point[1]**2) magnitude2 = math.sqrt(incident[0]**2 + incident[1]**2) ang = dot / (magnitude1 * magnitude2) main_ang = math.acos(ang) Theta = main_ang if p2[0] < 0 and p2[1] > 0: #second Theta = -Theta elif p2[0] > 0 and p2[1] > 0: #first if incident[1] >= incident[0]: Theta = -Theta elif p2[0] > 0 and p2[1] < 0: if incident[1] > -incident[0]: #fourth Theta = -Theta elif p2[0] < 0 and p2[1] < 0: if incident[1] <= incident[0]: Theta = -Theta #-form a 2x2 rotation matrix, uska format dekh lo aram se mile ga rotation_matrix = np.array([[np.cos(Theta), -np.sin(Theta)], [np.sin(Theta), np.cos(Theta)]]) #-multiply the rotation matrix by the normal vector to get another 2x1 vector, call it reflected reflected = np.dot(rotation_matrix, normal) reflected *= -1 #-find the unit vector in the direction of reflected, call it ref_unit ref_unit = reflected / math.sqrt(reflected[0]**2 + reflected[1]**2) #-scalar multiply ref_unit with overflow ref_point = ref_unit * overflowed #-us vector ke components ko add to circpoint ke coordinates to get the final coordinates final = circ_point + ref_point #-add both circ point (optional but will look better) and final coord to the arrays randomWalk_x_B.append(circ_point[0]) randomWalk_y_B.append(circ_point[1]) distance_from_origin = ((final[0])**2 + (final[1])**2)**(0.5) if distance_from_origin >= Radius: flag_B_ref = True break else: randomWalk_x_B.append(final[0]) randomWalk_y_B.append(final[1]) step_addition_B += 1 flag_B_ref = True break if flag_A_ref: pass else: randomWalk_x_A.append(new_x_A) randomWalk_y_A.append(new_y_A) if flag_B_ref: pass else: randomWalk_x_B.append(new_x_B) randomWalk_y_B.append(new_y_B) flag_A_ref = False flag_B_ref = False steps += 1 curr_A = (randomWalk_x_A[-1], randomWalk_y_A[-1]) curr_B = (randomWalk_x_B[-1], randomWalk_y_B[-1]) dist_between_particles = ((curr_B[0] - curr_A[0])**2 + (curr_B[1] - curr_A[1])**2)**(0.5) counter += 1 if counter % 1000 == 0: print(counter) if dist_between_particles <= 1: break #return steps size_A = steps + step_addition_A size_B = steps + step_addition_B ######################################################## #UNCOMMENT FOR ANIMATION # xdata, ydata = [], [] # ln, = plt.plot(xdata,ydata) # def init(): # #Radius = 5.64189584 when area of circle = 100 unit^2 # axs.set_xlim(-Radius,Radius) # axs.set_ylim(-Radius,Radius) # ln.set_data([], []) # return ln, # def update(frame): # xdata.append(randomWalk_x[int(frame)]) # ydata.append(randomWalk_y[int(frame)]) # ln.set_data(xdata, ydata) # return ln, # ani = FuncAnimation(fig, update, frames=np.linspace(0, size, size+1, endpoint=True), interval = 20, # init_func=init, blit=True, repeat=False) #ANIMATION CODE ####################################################### circle1 = plt.Circle((0, 0), Radius, color='r', alpha=0.2) plt.gcf().gca().add_artist(circle1) plt.plot(randomWalk_x_A, randomWalk_y_A) plt.plot(randomWalk_x_B, randomWalk_y_B) plt.show()