Repository: sympy/sympy
Pull request: point.vel() calculates velocity
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->
fixes #17761 

#### Brief description of what is fixed or changed
Update vel() in point , now it calculates velocity if position vector is given.

#### Other comments
If appropriate position vectors are given , calculates velocity 

#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->

- physics.vector 
       - Point.vel() now attempts to calculate the velocity using the relative position from other points if it has not been already set by the user. This behavior mimics the existing behavior in ReferenceFrame.ang_vel_in().  

<!-- END RELEASE NOTES -->

Problem statement:
Point.vel() should calculate the velocity if possible
If you specify the orientation of two reference frames and then ask for the angular velocity between the two reference frames the angular velocity will be calculated. But if you try to do the same thing with velocities, this doesn't work. See below:

```
In [1]: import sympy as sm                                                                               

In [2]: import sympy.physics.mechanics as me                                                             

In [3]: A = me.ReferenceFrame('A')                                                                       

In [5]: q = me.dynamicsymbols('q')                                                                       

In [6]: B = A.orientnew('B', 'Axis', (q, A.x))                                                           

In [7]: B.ang_vel_in(A)                                                                                  
Out[7]: q'*A.x

In [9]: P = me.Point('P')                                                                                

In [10]: Q = me.Point('Q')                                                                               

In [11]: r = q*A.x + 2*q*A.y                                                                             

In [12]: Q.set_pos(P, r)                                                                                 

In [13]: Q.vel(A)                                                                                        
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-13-0fc8041904cc> in <module>
----> 1 Q.vel(A)

~/miniconda3/lib/python3.6/site-packages/sympy/physics/vector/point.py in vel(self, frame)
    453         if not (frame in self._vel_dict):
    454             raise ValueError('Velocity of point ' + self.name + ' has not been'
--> 455                              ' defined in ReferenceFrame ' + frame.name)
    456         return self._vel_dict[frame]
    457 

ValueError: Velocity of point Q has not been defined in ReferenceFrame A
```

The expected result of the `Q.vel(A)` should be:

```
In [14]: r.dt(A)                                                                                         
Out[14]: q'*A.x + 2*q'*A.y
```

I think that this is possible. Maybe there is a reason it isn't implemented. But we should try to implement it because it is confusing why this works for orientations and not positions.

Hints from issue discussion:
Hi @moorepants, I think I could fix this. It would be implemented as a part of `ReferenceFrame` in `sympy/physics/vector/frame.py`, right?
No, it is part of Point. There are some nuances here and likely not a trivial PR to tackle. I'd recommend some simpler ones first if you are new to sympy and dynamics.
Sure, understood. Thank you @moorepants .
> No, it is part of Point. There are some nuances here and likely not a trivial PR to tackle. I'd recommend some simpler ones first if you are new to sympy and dynamics.

I would like to work on this issue.

The current Point.vel() returns velocity already defined in a reference frame , it doesn't calculate velocity between two points , so it would require a new function to calculate velocity between two points this would make it fully automatic.

So I propose , a change in vel() function to set  velocity of particle from r and a new function to which calculates and returns velocity by calculating displacement vector , this function wouldn't set the velocity of particle but would return it on being called.
The idea is that if there is sufficient information about the relative position of points, that Point.vel() can determine there is sufficient information and calculate the velocity. You should study how ReferenceFrame does this with ang_vel().
> The idea is that if there is sufficient information about the relative position of points, that Point.vel() can determine there is sufficient information and calculate the velocity. You should study how ReferenceFrame does this with ang_vel().

Okay on it!!
@moorepants pls check my PR and tell if something's missing or wrong.

Commit message: Added Comments

Patch to review:
diff --git a/sympy/physics/vector/point.py b/sympy/physics/vector/point.py
index ddb3a4d09265..7a3b44764d11 100644
--- a/sympy/physics/vector/point.py
+++ b/sympy/physics/vector/point.py
@@ -56,6 +56,7 @@ def __init__(self, name):
         self._pos_dict = {}
         self._vel_dict = {}
         self._acc_dict = {}
+        self._vel_dict_pos = {}
         self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict]
 
     def __str__(self):
@@ -471,6 +472,44 @@ def v2pt_theory(self, otherpoint, outframe, fixedframe):
         self.set_vel(outframe, v + (omega ^ dist))
         return self.vel(outframe)
 
+    def _calc_vel(self, frame, pos_vect):
+        # Helper Function for velocty
+        if len(self._pos_dict) == 1:
+        #If len of post_dict is one it implies it only has that point from which it's being called
+        #Stops infinite recursion
+            return False
+        #Copies vel_dict of current point(the one through which it's called, self for this function)
+        self._vel_dict_pos = self._vel_dict.copy()
+        #Loop 1 for checking all points at same level in self's pos_dict(to find nearest point in Tree)
+        for p, p_pos in self._pos_dict.items():
+            try:
+                p_vel = p._vel_dict[frame] #Checks if the point's velocity is defined wrt req frame, if not throws Keyerror
+                p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
+            except KeyError:
+                continue
+            except ValueError:
+                continue
+            self._vel_dict_pos[frame] = p_vel + p_pos.dt(frame) #Updates current point's copied dict
+            return True #Returns True, this point has it's velocity defined in appropriate ref frame
+        for p, p_pos in self._pos_dict.items():
+            #Loop 2 for searching in next level, if not found in same level
+            if p_pos == -pos_vect:
+            #If pos of this point is equal and negative of pos passed, this implies, referring back to point through which funct is called.
+            #Prevents infinite recursion
+                continue
+            try:
+                p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
+                cond = p._calc_vel(frame, p_pos) # IF pos vector's condition is satisfied, calls helper function(recursive call)
+                if not cond: # If funct returns False, next iteration takes place
+                    continue
+                else: #If funct returned True , upto current point velocities have been calculated in Tree(not of current point)
+                    p_vel = p._vel_dict_pos[frame]
+            except ValueError:
+                continue
+            self._vel_dict_pos[frame] = p_vel + p_pos.dt(frame) # Updates Velocity of current point in copied dict
+            return True # Returns True to main funt, implies using current points calculated velocity thr req point's velocity can be calculated.
+        return False #Return False to main funct for next iteration
+
     def vel(self, frame):
         """The velocity Vector of this Point in the ReferenceFrame.
 
@@ -483,19 +522,54 @@ def vel(self, frame):
         Examples
         ========
 
-        >>> from sympy.physics.vector import Point, ReferenceFrame
+        >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
         >>> N = ReferenceFrame('N')
         >>> p1 = Point('p1')
         >>> p1.set_vel(N, 10 * N.x)
         >>> p1.vel(N)
         10*N.x
+        >>> p = Point('p')
+        >>> q = dynamicsymbols('q')
+        >>> p.set_vel(N, 10 * N.x)
+        >>> p2 = Point('p2')
+        >>> p2.set_pos(p, q*N.x)
+        >>> p2.vel(N)
+        (Derivative(q(t), t) + 10)*N.x
 
         """
 
         _check_frame(frame)
-        if not (frame in self._vel_dict):
-            raise ValueError('Velocity of point ' + self.name + ' has not been'
-                             ' defined in ReferenceFrame ' + frame.name)
+        if not (frame in self._vel_dict):#If required point doesn't have its velocity defined in req frame.
+            #Copies vel_dict so that velocity calculation doesn't affect user defined velocity.
+            self._vel_dict_pos = self._vel_dict.copy()
+            # p being point in pos_dit and p_pos being pos vector
+            for p, p_pos in self._pos_dict.items():
+            #Loop 1 for checking all points at same level in self's pos_dict(to find nearest point in Tree)
+                try:
+                    p_vel = p._vel_dict[frame] #Checks if the point's velocity is defined wrt req frame, if not throws Keyerror
+                    p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
+                except KeyError:
+                    continue
+                except ValueError:
+                    continue
+                self._vel_dict_pos[frame] = p_vel + p_pos.dt(frame) #Updates new dict(copied one)
+                return self._vel_dict_pos[frame]
+            #Loop 2 for searching in next level, if not found in same level
+            for p, p_pos in self._pos_dict.items():
+                try:
+                    p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
+                    p_vel_check = p._calc_vel(frame, p_pos) #If position vector is satisfied calls helper funct
+                    if not p_vel_check:
+                        continue # If helper function returns False next point is iterated
+                    else:
+                        p_vel = p._vel_dict_pos[frame] #If helper function returns True, velocity upto this particle(p) is calculated.
+                except ValueError:
+                    continue
+                self._vel_dict_pos[frame] = p_vel + p_pos.dt(frame) #  Self's Copied dict is updated with the required velocity value.
+                return self._vel_dict_pos[frame]
+            else: #If no point satisfies condition
+                raise ValueError('Velocity of point ' + self.name + ' has not been'
+                    ' defined in ReferenceFrame ' + frame.name)
         return self._vel_dict[frame]
 
     def partial_velocity(self, frame, *gen_speeds):
diff --git a/sympy/physics/vector/tests/test_point.py b/sympy/physics/vector/tests/test_point.py
index 052b5c3af7d8..c6c1226c6795 100644
--- a/sympy/physics/vector/tests/test_point.py
+++ b/sympy/physics/vector/tests/test_point.py
@@ -1,5 +1,6 @@
 from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame
 from sympy.testing.pytest import raises
+from sympy import Derivative
 
 
 def test_point_v1pt_theorys():
@@ -82,6 +83,7 @@ def test_point_funcs():
     assert P.vel(B) == qd * B.x + q2d * B.y
     O.set_vel(N, 0)
     assert O.vel(N) == 0
+
     assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y +
                                (-10 * qd) * B.z)
 
@@ -126,3 +128,67 @@ def test_point_partial_velocity():
     assert p.partial_velocity(N, u1) == A.x
     assert p.partial_velocity(N, u1, u2) == (A.x, N.y)
     raises(ValueError, lambda: p.partial_velocity(A, u1))
+
+def test_point_vel():
+    q1, q2 = dynamicsymbols('q1 q2')
+    N = ReferenceFrame('N')
+    B = ReferenceFrame('B')
+    S = ReferenceFrame('S')
+    O = Point('O')
+    Q = Point('Q')
+    Q.set_pos(O, q1 * N.x)
+    raises(ValueError , lambda : Q.vel(N)) #Velocity of Q is not defined
+    O.set_vel(N, q2 * N.y)
+    assert Q.vel(N) == Derivative(q1) * N.x + q2 * N.y  # Velocity of Q using O
+    P1 = Point('P1')
+    P1.set_pos(O, q1 * B.x)
+    raises(ValueError, lambda : P1.vel(B)) # O's velocity is defined in different frame
+    raises(ValueError, lambda : P1.vel(N)) # Pos vector is defined in different frame
+    P2 = Point('P2')
+    P2.set_pos(P1, q2 * B.z)
+    raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no
+    #point in between has its velocity defined
+    P3 = Point('P3')
+    P3.set_pos(P2, q1 * B.x)
+    raises(ValueError, lambda : P3.vel(B)) # O's velocity is defined in different frame, and no
+    #point in between has its velocity defined
+    P1.set_vel(B, 10 * q1 * B.x) #Defined P1's velocity
+    assert P3.vel(B) == (10 * q1 + Derivative(q1)) * B.x + Derivative(q2) * B.z # Tree traversal upto P1
+    # Vel of P3 = Vel of P1 + Calculated Vel of P2 + time derivative of pos vector
+    P5 = Point('P5')
+    P5.set_vel(B, q1 * B.x)
+    P3.set_pos(P5, q2 * B.y)
+    assert P3.vel(B) == q1 * B.x + Derivative(q2) * B.y # P5 closer in tree than P1
+    Q1 = Point('Q1')
+    Q1.set_vel(N, q1 * N.x)
+    Q2 = Point('Q2')
+    Q3 = Point('Q3')
+    Q4 = Point('Q4')
+    Q2.set_pos(Q1, q2 * N.x)
+    Q3.set_pos(Q2, q1 * N.x)
+    Q4.set_pos(Q3, q2 * N.x)
+    assert Q4.vel(N) == (q1 + Derivative(q1) + 2 * Derivative(q2)) * N.x # Calculated velocity using
+    # Q1, Q2, Q3
+    Q3.set_vel(N, q1 * N.x)
+    assert Q3.vel(N) == q1 * N.x # Outputs user defined velocity
+    assert Q4.vel(N) == (q1 + Derivative(q2)) * N.x # If vel of one point in tree is changed the
+    # resulting velocity is changed
+    assert Q3.vel(N) == q1 * N.x # Automated vel calculation doesnt overwrite user defined vel
+    #Complex Operations
+    T1 = Point('T1')
+    T1.set_vel(S, q1 * S.x)
+    T2 = Point('T2')
+    T2.set_pos(T1, q2 * S.x)
+    T2.set_vel(N, q1 * N.y)
+    T3 = Point('T3')
+    T3.set_vel(B, q1 * B.z)
+    T3.set_pos(T2, q1 * B.x + q2 * B.y)
+    T3.set_pos(T1, q2 * S.x)
+    T4 = Point('T4')
+    T4.set_pos(T3, q1 * S.z)
+    T5 = Point('T5')
+    T5.set_pos(T4, q2 * S.y)
+    T6 = Point('T6')
+    T6.set_pos(T3, q1 * B.z)
+    T6.set_pos(T2, q1 * S.z)
+    assert T6.vel(S) + T6.vel(B) + T5.vel(S) + T2.vel(N) == q1*N.y + (q1 + Derivative(q1))*B.z + (2*q1 + 2*Derivative(q2))*S.x + Derivative(q2)*S.y + 2*Derivative(q1)*S.z


Code review comments:
diff_hunk: @@ -483,19 +522,54 @@ def vel(self, frame):
         Examples
         ========
 
-        >>> from sympy.physics.vector import Point, ReferenceFrame
+        >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
         >>> N = ReferenceFrame('N')
         >>> p1 = Point('p1')
         >>> p1.set_vel(N, 10 * N.x)
         >>> p1.vel(N)
         10*N.x
+        >>> p = Point('p')
+        >>> q = dynamicsymbols('q')
+        >>> p.set_vel(N, 10 * N.x)
+        >>> p2 = Point('p2')
+        >>> p2.set_pos(p, q*N.x)
+        >>> p2.vel(N)
+        (Derivative(q(t), t) + 10)*N.x
 
         """
 
         _check_frame(frame)
-        if not (frame in self._vel_dict):
-            raise ValueError('Velocity of point ' + self.name + ' has not been'
-                             ' defined in ReferenceFrame ' + frame.name)
+        if not (frame in self._vel_dict):#If required point doesn't have its velocity defined in req frame.
+            #Copies vel_dict so that velocity calculation doesn't affect user defined velocity.
+            self._vel_dict_pos = self._vel_dict.copy()
+            # p being point in pos_dit and p_pos being pos vector
+            for p, p_pos in self._pos_dict.items():
+            #Loop 1 for checking all points at same level in self's pos_dict(to find nearest point in Tree)
+                try:
+                    p_vel = p._vel_dict[frame] #Checks if the point's velocity is defined wrt req frame, if not throws Keyerror
+                    p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
path: sympy/physics/vector/point.py
text: @user1:
Why is this code duplicated here and in the helper method?

diff_hunk: @@ -483,19 +483,56 @@ def vel(self, frame):
         Examples
         ========
 
-        >>> from sympy.physics.vector import Point, ReferenceFrame
+        >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
         >>> N = ReferenceFrame('N')
         >>> p1 = Point('p1')
         >>> p1.set_vel(N, 10 * N.x)
         >>> p1.vel(N)
         10*N.x
+        >>> p = Point('p')
+        >>> q = dynamicsymbols('q')
+        >>> p.set_vel(N, 10 * N.x)
+        >>> p2 = Point('p2')
+        >>> p2.set_pos(p, q*N.x)
+        >>> p2.vel(N)
+        (Derivative(q(t), t) + 10)*N.x
 
         """
 
         _check_frame(frame)
         if not (frame in self._vel_dict):
-            raise ValueError('Velocity of point ' + self.name + ' has not been'
+            starting_node = self
+            visited = []
+            queue = [starting_node]
path: sympy/physics/vector/point.py
text: @user1:
```suggestion
            queue = [self]
```
And delete 504.

diff_hunk: @@ -471,6 +472,44 @@ def v2pt_theory(self, otherpoint, outframe, fixedframe):
         self.set_vel(outframe, v + (omega ^ dist))
         return self.vel(outframe)
 
+    def _calc_vel(self, frame, pos_vect):
+        # Helper Function for velocty
+        if len(self._pos_dict) == 1:
+        #If len of post_dict is one it implies it only has that point from which it's being called
+        #Stops infinite recursion
+            return False
+        #Copies vel_dict of current point(the one through which it's called, self for this function)
+        self._vel_dict_pos = self._vel_dict.copy()
+        #Loop 1 for checking all points at same level in self's pos_dict(to find nearest point in Tree)
+        for p, p_pos in self._pos_dict.items():
+            try:
+                p_vel = p._vel_dict[frame] #Checks if the point's velocity is defined wrt req frame, if not throws Keyerror
+                p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
path: sympy/physics/vector/point.py
text: @user1:
I've already commented that this is bad practice catching different errors from two lines, you don't know what lines the errors come from and why.

diff_hunk: @@ -483,19 +483,56 @@ def vel(self, frame):
         Examples
         ========
 
-        >>> from sympy.physics.vector import Point, ReferenceFrame
+        >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
         >>> N = ReferenceFrame('N')
         >>> p1 = Point('p1')
         >>> p1.set_vel(N, 10 * N.x)
         >>> p1.vel(N)
         10*N.x
+        >>> p = Point('p')
+        >>> q = dynamicsymbols('q')
+        >>> p.set_vel(N, 10 * N.x)
+        >>> p2 = Point('p2')
+        >>> p2.set_pos(p, q*N.x)
+        >>> p2.vel(N)
+        (Derivative(q(t), t) + 10)*N.x
 
         """
 
         _check_frame(frame)
         if not (frame in self._vel_dict):
-            raise ValueError('Velocity of point ' + self.name + ' has not been'
+            starting_node = self
+            visited = []
+            queue = [starting_node]
+            req_point = None
+            while queue: #BFS to find nearest point
+                node = queue.pop(0)
+                if node not in visited:
+                    visited.append(node)
+                    for neighbor, neighbor_pos in node._pos_dict.items():
+                        try:
+                            neighbor_pos.dt(frame) #Checks if pos vector is valid
+                        except ValueError:
+                            continue
path: sympy/physics/vector/point.py
text: @user1:
A `ValueErrror` could be returned from this for multiple reasons. I think the check you are after here is whether or not `neighbor_pos` can be expressed in the frame. I think checking `neighbor_pos.express(frame)` is the more direct check.

diff_hunk: @@ -126,3 +128,67 @@ def test_point_partial_velocity():
     assert p.partial_velocity(N, u1) == A.x
     assert p.partial_velocity(N, u1, u2) == (A.x, N.y)
     raises(ValueError, lambda: p.partial_velocity(A, u1))
+
+def test_point_vel():
+    q1, q2 = dynamicsymbols('q1 q2')
+    N = ReferenceFrame('N')
+    B = ReferenceFrame('B')
+    S = ReferenceFrame('S')
+    O = Point('O')
+    Q = Point('Q')
+    Q.set_pos(O, q1 * N.x)
+    raises(ValueError , lambda : Q.vel(N)) #Velocity of Q is not defined
+    O.set_vel(N, q2 * N.y)
+    assert Q.vel(N) == Derivative(q1) * N.x + q2 * N.y  # Velocity of Q using O
+    P1 = Point('P1')
+    P1.set_pos(O, q1 * B.x)
+    raises(ValueError, lambda : P1.vel(B)) # O's velocity is defined in different frame
+    raises(ValueError, lambda : P1.vel(N)) # Pos vector is defined in different frame
+    P2 = Point('P2')
+    P2.set_pos(P1, q2 * B.z)
+    raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no
+    #point in between has its velocity defined
+    P3 = Point('P3')
+    P3.set_pos(P2, q1 * B.x)
+    raises(ValueError, lambda : P3.vel(B)) # O's velocity is defined in different frame, and no
+    #point in between has its velocity defined
+    P1.set_vel(B, 10 * q1 * B.x) #Defined P1's velocity
+    assert P3.vel(B) == (10 * q1 + Derivative(q1)) * B.x + Derivative(q2) * B.z # Tree traversal upto P1
+    # Vel of P3 = Vel of P1 + Calculated Vel of P2 + time derivative of pos vector
+    P5 = Point('P5')
+    P5.set_vel(B, q1 * B.x)
+    P3.set_pos(P5, q2 * B.y)
+    assert P3.vel(B) == q1 * B.x + Derivative(q2) * B.y # P5 closer in tree than P1
+    Q1 = Point('Q1')
+    Q1.set_vel(N, q1 * N.x)
+    Q2 = Point('Q2')
+    Q3 = Point('Q3')
+    Q4 = Point('Q4')
+    Q2.set_pos(Q1, q2 * N.x)
+    Q3.set_pos(Q2, q1 * N.x)
+    Q4.set_pos(Q3, q2 * N.x)
+    assert Q4.vel(N) == (q1 + Derivative(q1) + 2 * Derivative(q2)) * N.x # Calculated velocity using
+    # Q1, Q2, Q3
+    Q3.set_vel(N, q1 * N.x)
+    assert Q3.vel(N) == q1 * N.x # Outputs user defined velocity
+    assert Q4.vel(N) == (q1 + Derivative(q2)) * N.x # If vel of one point in tree is changed the
+    # resulting velocity is changed
+    assert Q3.vel(N) == q1 * N.x # Automated vel calculation doesnt overwrite user defined vel
+    #Complex Operations
path: sympy/physics/vector/tests/test_point.py
text: @user1:
What specifically are you testing here? For a long multi-branch tree, you should be checking that the shortest path is properly selected. The code here certainly looks complex, but is it testing anything that isn't already tested above?

@author:
In line 174 , i'm checking that that if user changes any velocity in path then that should affect the calculated velocity as calculated velocity doesn't update _vel_dict

@user1:
This comment refers to line 177 and below.

@author:
I'll break the test cases

diff_hunk: @@ -483,19 +483,47 @@ def vel(self, frame):
         Examples
         ========
 
-        >>> from sympy.physics.vector import Point, ReferenceFrame
+        >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols
         >>> N = ReferenceFrame('N')
         >>> p1 = Point('p1')
         >>> p1.set_vel(N, 10 * N.x)
         >>> p1.vel(N)
         10*N.x
+        >>> p = Point('p')
+        >>> q = dynamicsymbols('q')
+        >>> p.set_vel(N, 10 * N.x)
+        >>> p2 = Point('p2')
+        >>> p2.set_pos(p, q*N.x)
+        >>> p2.vel(N)
+        (Derivative(q(t), t) + 10)*N.x
 
         """
 
         _check_frame(frame)
         if not (frame in self._vel_dict):
-            raise ValueError('Velocity of point ' + self.name + ' has not been'
+            visited = []
+            queue = [self]
+            while queue: #BFS to find nearest point
+                node = queue.pop(0)
+                if node not in visited:
+                    visited.append(node)
+                    for neighbor, neighbor_pos in node._pos_dict.items():
+                        try:
+                            neighbor_pos.express(frame) #Checks if pos vector is valid
+                        except ValueError:
+                            continue
+                        else:
path: sympy/physics/vector/point.py
text: @user1:
No need for this `else` since the `except` has a `continue`. Removing it will save you a level of indentation, which is almost always a good ideas

@author:
Done

diff_hunk: @@ -56,6 +56,7 @@ def __init__(self, name):
         self._pos_dict = {}
         self._vel_dict = {}
         self._acc_dict = {}
+        self._vel_dict_pos = {}
path: sympy/physics/vector/point.py
text: @user1:
I don't see why this new attribute is needed to solve this issue.

diff_hunk: @@ -471,6 +472,44 @@ def v2pt_theory(self, otherpoint, outframe, fixedframe):
         self.set_vel(outframe, v + (omega ^ dist))
         return self.vel(outframe)
 
+    def _calc_vel(self, frame, pos_vect):
+        # Helper Function for velocty
+        if len(self._pos_dict) == 1:
+        #If len of post_dict is one it implies it only has that point from which it's being called
+        #Stops infinite recursion
+            return False
+        #Copies vel_dict of current point(the one through which it's called, self for this function)
+        self._vel_dict_pos = self._vel_dict.copy()
+        #Loop 1 for checking all points at same level in self's pos_dict(to find nearest point in Tree)
+        for p, p_pos in self._pos_dict.items():
+            try:
+                p_vel = p._vel_dict[frame] #Checks if the point's velocity is defined wrt req frame, if not throws Keyerror
+                p_pos.dt(frame) #Checks if pos vector in defined with req frame, if not throws ValueError
+            except KeyError:
+                continue
+            except ValueError:
+                continue
+            self._vel_dict_pos[frame] = p_vel + p_pos.dt(frame) #Updates current point's copied dict
+            return True #Returns True, this point has it's velocity defined in appropriate ref frame
+        for p, p_pos in self._pos_dict.items():
+            #Loop 2 for searching in next level, if not found in same level
path: sympy/physics/vector/point.py
text: @user1:
This isn't clearly if this works for a tree depth of 100 or 1000. How can two loops do the breath first search of the entire tree?