Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
 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
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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