def wall_momentum_collision(self, bod:body.Body, wall_normal:vector.Vector): """ Compute new momentum using the equations for body-body momentum collision. However, let mass of wall -> infinity and initial velocity be zero. This gives, if A == bod, and B == Wall vA = ub + r*(uB-uA) = -r*uA vB = ub = 0 """ # let wall_normal be a unit vector # vector decomposition. projA = metrics.metric_inner_product(bod.V, wall_normal, self._nmetric) vA_normal = projA * wall_normal vA_plane = bod.V - vA_normal # main calculation: uA = sign(projA) * metrics.metric_norm(vA_normal, self._nmetric) r = self.get_wall_restitution_coefficient(bod) vA = -r*uA new_vA_normal = vA * wall_normal VA = new_vA_normal + vA_plane bod.V = VA return
def relativistic_acceleration(self, mass, V, force, warning): """ See here for more information about relativistic forces: https://en.wikipedia.org/wiki/Relativistic_mechanics#Force """ # SPECIAL RELATIVISTIC CALCULATIONS if self.max_speed > 0: mass = self.lorentz_factor(V) * mass c_sqr = self.max_speed * self.max_speed if self._nmetric != 2 and not warning: print("Warning: Inner product is ill defined for other non-euclidean metrics.") force = force - metrics.metric_inner_product(V,force, self._nmetric) *V / (c_sqr) return force/mass
def lorentz_factor(self, v:vector.Vector) -> float: """ Find the lorentz factor for a particular speed. y = 1/ sqrt{1-v^2/c^2} """ if self.max_speed < 0: return 1 # symbolises infinite max speed. elif self.max_speed == 0: raise ValueError("\nCannot find lorentz factor for universe with Speed Limit of 0.") else: v_sqr = 0 if self._nmetric == 2: v_sqr = metrics.metric_inner_product(v,v, self._nmetric) else: v_sqr = metrics.metric_norm(v,self._nmetric) ** 2 c_sqr = self.max_speed * self.max_speed if v_sqr > c_sqr: raise ValueError("\nVelocity faster than the Universal Speed limit.\n Vector: {0}\n Object Speed: {1}\n Max Speed: {2}"\ .format(v, math.sqrt(v_sqr), self.max_speed)) elif v_sqr == c_sqr: return float(sys.maxsize) return 1 / math.sqrt(1 - v_sqr/c_sqr)
def check_collision(self, bod:body.Body, del_x_unit:vector.Vector, del_x_len:float): """ Check whether any objects collide. """ collided = False min_length = -1 results = [None]*0 del_x = del_x_unit * del_x_len new_delta_x = None msg = "" if bod.can_collide: if del_x_len <= 0: # if del_x is a zero vector, then checking for collision is the same as colliding, # for both cases the object doesn't move. pass else: for other_body in self.bodies: collision = False if isinstance(other_body, body.Body): if other_body.id != bod.id: if other_body.can_collide: difference = None # see if the two bodies will collide. # if so, change the positions & velocities. # collision can occur if objects are stuck inside one another initially collision = Collide.n_sphere_collide(bod.X, bod.radius, other_body.X, other_body.radius, self._nmetric) # variable defintion. moving_towards_projection = 0 if not collision: # collision can only occur if the object is travelling towards 'other_body' # this occurs when the two projected onto each other are the same. difference = other_body.X - bod.X moving_towards_projection = metrics.metric_inner_product(difference, del_x_unit, self._nmetric) if moving_towards_projection > 0: #check whether further away than previous collided object if not collided or moving_towards_projection <= min_length: # if bod is moving towards other_body the projection is positive. # if the projection is zero, then moving counter clockwise. # if the projection is greater than del_x, then bod is moving towards # other body but hasn't hit it. # otherwise, del_x causes bod to move past other_body # Hence, adjust the length to be the projection. tmp_del_x = del_x if moving_towards_projection < del_x_len: # adjust del_x tmp_del_x = del_x_unit * moving_towards_projection else: pass new_x = bod.X + tmp_del_x collision = Collide.n_sphere_collide(new_x, bod.radius, other_body.X, other_body.radius, self._nmetric) #if collision: # del_x = tmp_del_x else: pass if collision: if moving_towards_projection < min_length or not collided: #msg = "" min_length = moving_towards_projection results = [other_body] else: #msg += ", and " # this means the object has collided with multiple bodies results.append(other_body) #msg += bod.name + " collided with " + other_body.name if not collided: collided = True new_delta_x = vector.Vector.zero_vector(len(del_x)) if not collided: new_delta_x = del_x return collided, results, new_delta_x
def momentum_collision(self, bodA:body.Body, bodB:body.Body): """ Given two objects, suppose they collided, now find their final velocities. https://en.wikipedia.org/wiki/Coefficient_of_restitution The velocity along the plane of intersection is unchanged, but the perpendicular component is adjusted by the following: """ metric = self._nmetric # 2 if self.relativistic: #for relativistic systems, unknown. print("Momentum collision NOT IMPLEMENTED for relativistic systems.") return None,None else: #for newtonian mechanics: # if vA, vB final speed, and uA, uB initial speed, and mA, mB masses, # (along perpendicular component) # r coefficient of restitution, # vA = ((mA-mB*r)uA + mB(r+1)uB) / (mA + mB) # vB = ((mB-mA*r)uB + mA(r+1)uA) / (mA + mB) mA = bodA.mass mB = bodB.mass if mA + mB == 0: print("Momentum collision NOT IMPLEMENTED for objects with net-zero mass.") return None,None A_to_B = bodB.X - bodA.X d = metrics.metric_norm(A_to_B, metric) if d == 0: return None,None A_to_B_unit = A_to_B / d # this is the normal vector for the plane of intersection. # vector decomposition. projA = metrics.metric_inner_product(bodA.V, A_to_B_unit, self._nmetric) projB = metrics.metric_inner_product(bodB.V, A_to_B_unit, self._nmetric) vA_normal = projA * A_to_B_unit vB_normal = projB * A_to_B_unit vA_plane = bodA.V - vA_normal vB_plane = bodB.V - vB_normal # main calculation: uA = sign(projA) * metrics.metric_norm(vA_normal, metric) uB = sign(projB) * metrics.metric_norm(vB_normal, metric) r = body.Body.get_coeff_restitution(bodA, bodB) vA = ((mA-mB*r)*uA + mB*(r+1)*uB) / (mA + mB) vB = ((mB-mA*r)*uB + mA*(r+1)*uA) / (mA + mB) #new_vA_normal = (vA/uA)*vA_normal #neg if swaps sign, pos if same sign as original #new_vB_normal = (vB/uB)*vB_normal new_vA_normal = vA * A_to_B_unit new_vB_normal = vB * A_to_B_unit VA = new_vA_normal + vA_plane VB = new_vB_normal + vB_plane # this is the maximum error allowed in terms of the ratio of the momenta before to after err = 6e-16 len_va = metrics.metric_inner_product(VA, VA, self._nmetric) if len_va > 0: projab = metrics.metric_inner_product(VA, VB, self._nmetric) / len_va if projab < 0: proja_dist = metrics.metric_inner_product(VA,A_to_B_unit) if proja_dist > 0: #print(bodA.get_name(), VA, new_vA_normal, vA_plane) #print(bodB.get_name(), VB, new_vB_normal, vB_plane) #print(bodA.get_name(), uA, vA) #print(VA, new_vA_normal) #print(bodB.get_name(), uB, vB) #print(VB, new_vA_normal) #print() pass #if VA == bodA.V and VB == bodB.V: #print("here") """ if self.assertion: momenta_inital = mA*bodA.V + mB*bodB.V momenta_final = mA*VA + mB*VB delta_momenta = momenta_final - momenta_inital delta_norm = delta_momenta.norm() inital_norm = momenta_inital.norm() final_norm = momenta_final.norm() if inital_norm == 0 and final_norm == 0: pass else: ratio = 0 if initial_norm > 0: ratio = delta_norm / inital_norm else: ratio = delta_norm / final_norm if ratio > err: print(final_norm / inital_norm) momenta_str = "Momenta before: {0}\nMomenta after: {1}"\ .format(momenta_inital, momenta_final) momentaA_str = "Momenta A: {0}\n {1}".format(mA*bodA.V, mA*VA) momentaB_str = "Momenta B: {0}\n {1}".format(mB*bodB.V, mB*VB) warning_str = "MOMENTUM IS NOT CONSERVED\n ratio {0}, delta p = {1}"\ .format(ratio, delta_norm) assert ratio <= err, warning_str + "\n\n" + momenta_str + "\n\n" + momentaA_str + "\n\n" + momentaB_str """ return VA,VB