[sympy] Added co-ord functions to ReferenceFrame (#1702)

22 views
Skip to first unread message

Sachin Joglekar

unread,
Dec 25, 2012, 1:00:45 AM12/25/12
to sympy/sympy

You can merge this Pull Request by running:

  git pull https://github.com/srjoglekar246/sympy coordfunctions

Or view, comment on, or merge it at:

  https://github.com/sympy/sympy/pull/1702

Commit Summary

  • Added co-ord functions to ReferenceFrame

File Changes

  • M sympy/physics/mechanics/essential.py (46)
  • M sympy/physics/mechanics/tests/test_essential.py (12)

Patch Links


Reply to this email directly or view it on GitHub.

Aaron Meurer

unread,
Dec 26, 2012, 5:01:20 AM12/26/12
to sympy/sympy

Aaron Meurer

unread,
Dec 26, 2012, 7:19:57 PM12/26/12
to sympy/sympy

SymPy Bot Summary: :red_circle: Failed after merging srjoglekar246/coordfunctions (2c71605) into master (2abef4f).
@srjoglekar246: Please fix the test failures.
:red_circle:Python 2.5.0-final-0: fail
:red_circle:Python 2.6.6-final-0: fail
:red_circle:Python 2.7.2-final-0: fail
:red_circle:Python 2.6.8-final-0: fail
:red_circle:Python 2.7.3-final-0: fail
:red_circle:PyPy 2.0.0-beta-1; 2.7.3-final-42: fail
:eight_spoked_asterisk:Python 3.2.2-final-0: pass
:eight_spoked_asterisk:Python 3.3.0-final-0: pass
:eight_spoked_asterisk:Python 3.2.3-final-0: pass
:eight_spoked_asterisk:Python 3.3.0-final-0: pass
:eight_spoked_asterisk:Python 3.3.0-final-0: pass
:eight_spoked_asterisk:**Sphinx 1.1.3:** pass

Jason Moore

unread,
Dec 27, 2012, 1:48:45 AM12/27/12
to sympy/sympy

@srjoglekar246 I see that you are interested in adding the concept of an origin to a reference frame and that your code allows you to easily create additional points in a reference frame relative to the origin. Can you give us some examples of how you make use of this in an example problem and how it contrasts with the way you would write the program without this functionality?

Dale Lukas Peterson

unread,
Dec 27, 2012, 2:00:15 PM12/27/12
to sympy/sympy
I am out of town and can't comment much at the moment but would like to
state that ReferenceFrame was purposely designed to not have a Point -- it
is solely designed for keeping track of orientation. What about a new class
that uses composition to combine the features of ReferenceFrame and Point?
I am hesitant to make ReferenceFrame depend on Point and vice versa.
On Dec 27, 2012 1:48 AM, "Jason Moore" <notifi...@github.com> wrote:

> @srjoglekar246 <https://github.com/srjoglekar246> I see that you are
> interested in adding the concept of an origin to a reference frame and that
> your code allows you to easily create additional points in a reference
> frame relative to the origin. Can you give us some examples of how you make
> use of this in an example problem and how it contrasts with the way you
> would write the program without this functionality?
>
> —
> Reply to this email directly or view it on GitHub<https://github.com/sympy/sympy/pull/1702#issuecomment-11702208>.

Sachin Joglekar

unread,
Dec 27, 2012, 2:12:59 PM12/27/12
to sympy/sympy

@hazelnusse and @moorepants , may I know why you want to avoid linking the two? Creating another class would be just fine I guess. As it is, the functions I created dont interfere with any other methods/parameters of ReferenceFrame. A user may never use those functions at all, and as you pointed out, just use the ReferenceFrame for dealing with orientation. But while dealing with problems relating to kinematics/electric fields (something I am working on in another PR), a user may need to define points in 'space' using a ReferenceFrame.
Under the current architecture the user would have to do.
N = ReferenceFrame('N')
o = Point('o') #origin of N
p = Point('p')
p.set_pos(o, a * N.x + b * N.y) # define a point at [a, b, 0]

But with the added functions p = N.get_point_at('p', a, b, 0) and o = N.get_origin()

The user does not need to think about an origin, unless he wants to shift it or link two frames. Moreover, dealing with the idea of shifting origins and getting subsequent co-ordinates becomes simpler. I am not saying it cannot be done or it is difficult, it just gets simpler. And while dealing with points in an electric field I found myself doing it over and over again so thought it would be simpler.

Another thing being, if the physics.mechanics module is ever extended to solve problems relating to force, relative motion etc, these functions would reduce the length of the code. The code is not a necessity, just a simplifying tweak.

Jason Moore

unread,
Dec 27, 2012, 4:17:05 PM12/27/12
to sympy/sympy

This seems useful to me. It makes setting and getting points in a particular reference frame more convenient and less code to type. Checkout out the other pull request #1695 that shows the electrical work.

BTW, the mechanics module can take care of force and relative motion already.

Jason Moore

unread,
Dec 27, 2012, 4:18:50 PM12/27/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +        Examples
> +        ========
> +        >>> from sympy.physics.mechanics import ReferenceFrame, Point
> +        >>> N = ReferenceFrame('N')
> +        >>> p = N.get_point_at('p', 1, 2, 3)
> +        >>> N.get_coordinates(p)
> +        [1, 2, 3]
> +        >>> o = N.get_origin()
> +        >>> N.shift_origin_to(p)
> +        >>> N.get_coordinates(p)
> +        [0, 0, 0]
> +        >>> N.get_coordinates(o)
> +        [-1, -2, -3]
> +
> +        """
> +        from sympy.physics.mechanics import Point

I believe you already import Point at the top, not need to here. It is good PEP8 practice to leave imports all at the top, except for special cases.

Jason Moore

unread,
Dec 27, 2012, 4:21:26 PM12/27/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> @@ -1040,6 +1042,49 @@ def z(self):
>          """The basis Vector for the ReferenceFrame, in the z direction. """
>          return self._z
>  
> +    def get_point_at(self, pointname, x, y, z):

Seems like this is more like a set method than a get method. Or maybe "create_point_at" is a better method name.

Jason Moore

unread,
Dec 27, 2012, 4:23:06 PM12/27/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +        and names it to 'pointname'.
> +        """
> +        from sympy.physics.mechanics import Point
> +        temp = Point(pointname)
> +        temp.set_pos(self._origin, x * self._x + y * self._y + z * self._z)
> +        return temp
> +
> +    def get_origin(self):
> +        """The origin of the ReferenceFrame."""
> +        return self._origin
> +
> +    def shift_origin_to(self, neworigin):
> +        """Shift the origin of the Reference Frame to neworigin."""
> +        self._origin = neworigin
> +
> +    def get_coordinates(self, point):

So what happens when I ask for a point that isn't defined in this reference frame? Do you have error handling set up for that? Or does it just get handled by the Point class?

Sachin Joglekar

unread,
Dec 27, 2012, 11:21:51 PM12/27/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +        and names it to 'pointname'.
> +        """
> +        from sympy.physics.mechanics import Point
> +        temp = Point(pointname)
> +        temp.set_pos(self._origin, x * self._x + y * self._y + z * self._z)
> +        return temp
> +
> +    def get_origin(self):
> +        """The origin of the ReferenceFrame."""
> +        return self._origin
> +
> +    def shift_origin_to(self, neworigin):
> +        """Shift the origin of the Reference Frame to neworigin."""
> +        self._origin = neworigin
> +
> +    def get_coordinates(self, point):

The error handling is essentially done by Point. Maybe like if there are two ReferenceFrames R1 and R2, it will give the "no link between R1 and R2" error (ValueError). I will make the name changes in a short while.

Sachin Joglekar

unread,
Dec 27, 2012, 11:50:34 PM12/27/12
to sympy/sympy

@moorepants , for some reason, putting 'from sympy.physics.mechanics import Point' at the top of essential.py dosent seem to work. It gives the error 'Cannot import name Point'. Please help me out with that. Till then I have left the imports where I placed them earlier.

Jason Moore

unread,
Dec 28, 2012, 12:09:26 AM12/28/12
to sympy/sympy

I think it is a circular import problem. point.py imports from essential.py and now you are asking essential.py to import from point.py. Haven't thought of the best solution yet, this may be one of those cases where imports are permitted away from the top of the code.

Sachin Joglekar

unread,
Dec 28, 2012, 3:16:16 AM12/28/12
to sympy/sympy

@moorepants , as @hazelnusse suggested, we could create a separate class called CoordinateFrame which would extend ReferenceFrame, but with an added 'origin' parameter. Users could them use one of the two classes as per their need.

Jason Moore

unread,
Dec 28, 2012, 3:20:38 AM12/28/12
to sympy/sympy

I'm fine with either solution. @gilbertgede wrote the classes originally, maybe he'll chime in about it.

Gilbert Gede

unread,
Dec 28, 2012, 4:01:17 AM12/28/12
to sympy/sympy

Like @hazelnusse said, we intentionally separated the ReferenceFrame and Point classes. As I recall, we did this to avoid having to implicitly deal with defining bound/unbound vectors within reference frames.
Something I noticed in your code was that none of the points you create within ReferenceFrame have their velocities defined; you're just using the Point class for positions.
I would prefer a separate class, to keep the underlying framework as simple as possible (Vector, Dyadic, ReferenceFrame, Point, dynamicsymbols). But you also need to think a little more about how you want to be handling the velocities of points.

Gilbert Gede

unread,
Dec 28, 2012, 4:08:46 AM12/28/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +    def get_point_coordinates(self, point):
> +        """Returns the co-ordinates of 'point' in the ReferenceFrame, if possible.
> +
> +        Examples
> +        ========
> +        >>> from sympy.physics.mechanics import ReferenceFrame, Point
> +        >>> N = ReferenceFrame('N')
> +        >>> p = N.create_point_at('p', 1, 2, 3)
> +        >>> N.get_point_coordinates(p)
> +        [1, 2, 3]
> +        >>> o = N.get_origin()
> +        >>> N.shift_origin_to(p)
> +        >>> N.get_point_coordinates(p)
> +        [0, 0, 0]
> +        >>> N.get_point_coordinates(o)
> +        [-1, -2, -3]

I'm not really a fan of this; we made an conscious effort to not have the measure numbers of vectors show up; only the entire vector, and leave it to the user to get the measure numbers.
If you wanted to write a function that took a vector and frame and returned the measure numbers, that would be better. You could then use that within your code. Something like:

measure_numbers(N, 1*N.x + 2*N.y + 3*N.z)
[1, 2, 3]

Also, I would consider using the dot product a better way to get the measure numbers, rather than getting the values from the args:
[pos_vector & N.x, pos_vector & N.y, pos_vector & N.z]

Sachin Joglekar

unread,
Dec 28, 2012, 6:33:22 AM12/28/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +    def get_point_coordinates(self, point):
> +        """Returns the co-ordinates of 'point' in the ReferenceFrame, if possible.
> +
> +        Examples
> +        ========
> +        >>> from sympy.physics.mechanics import ReferenceFrame, Point
> +        >>> N = ReferenceFrame('N')
> +        >>> p = N.create_point_at('p', 1, 2, 3)
> +        >>> N.get_point_coordinates(p)
> +        [1, 2, 3]
> +        >>> o = N.get_origin()
> +        >>> N.shift_origin_to(p)
> +        >>> N.get_point_coordinates(p)
> +        [0, 0, 0]
> +        >>> N.get_point_coordinates(o)
> +        [-1, -2, -3]

I have added the get_point_coordinates method to facilitate the working of a ReferenceFrame as a Co-ordinate Frame. This is simply because, coordinates of a point with respect to the origin is something that I deal with a lot while working with 'frames' in general. As you suggested, I will change the implementation to use dot-product.

Sachin Joglekar

unread,
Dec 28, 2012, 6:36:16 AM12/28/12
to sympy/sympy

@gilbertgede , I will implement and add the code for handling velocities and accln shortly. How does creation of a new CoordinateFrame class sound to you? That would make it pretty useful for a user to choose according to his requirement. As you suggested, I could ass the measure_numbers method to the ReferenceFrame class, and extend it to form CoordinateFrame.

Aaron Meurer

unread,
Dec 28, 2012, 2:55:57 PM12/28/12
to sympy/sympy

The fix for circular imports is exactly like you have it, to put the imports inside the function definition.

Sachin Joglekar

unread,
Dec 29, 2012, 2:16:21 PM12/29/12
to sympy/sympy

@moorepants and @gilbertgede ,
isn't there something wrong with the following code-

N = ReferenceFrame('N')

B = ReferenceFrame('B')
N.set_ang_acc(B,N.x)
P = Point('P')
P.set_acc(B,B.y)
P.set_acc(N,N.x)
P.acc(N)
N.x
Q = Point('Q')
Q.set_acc(B,B.y)
Q.set_acc(N, 3 *N.x)
Q.acc(N)
3*N.x

Q's accln being 3*N.x in N and P's being N.x simultaneously, when there is a relationship between motions of N and B seems(is) wrong. I maybe wrong, but I would like this cleared up before I proceed with the code.

Angadh Nanjangud

unread,
Dec 29, 2012, 3:20:30 PM12/29/12
to sympy/sympy

@srjoglekar246, So I don't understand why you say those accelerations are wrong, when you are the one setting or defining them. According to your code, P and Q are two unrelated points in space so their accelerations (or any other kinematic quantities for that matter) wouldn't be interdependent.

Also it should be noted that, when one defines the angular acceleration of N in B, the angular position and velocities of N in B (and vice versa) do not get set or defined automatically.

Angadh Nanjangud

unread,
Dec 29, 2012, 3:34:47 PM12/29/12
to sympy/sympy

In sympy/physics/mechanics/essential.py:

> +    def get_point_coordinates(self, point):
> +        """Returns the co-ordinates of 'point' in the ReferenceFrame, if possible.
> +
> +        Examples
> +        ========
> +        >>> from sympy.physics.mechanics import ReferenceFrame, Point
> +        >>> N = ReferenceFrame('N')
> +        >>> p = N.create_point_at('p', 1, 2, 3)
> +        >>> N.get_point_coordinates(p)
> +        [1, 2, 3]
> +        >>> o = N.get_origin()
> +        >>> N.shift_origin_to(p)
> +        >>> N.get_point_coordinates(p)
> +        [0, 0, 0]
> +        >>> N.get_point_coordinates(o)
> +        [-1, -2, -3]

Getting a bit ahead of things perhaps, but I would also like to suggest that instead of 'measure_numbers' the method be named 'components' or something of the ilk.

Gilbert Gede

unread,
Dec 29, 2012, 4:26:37 PM12/29/12
to sympy/sympy

When defining the orientation between 2 frames, angular velocity is computed from the defined direction cosine matrix, and then angular acceleration is defined automatically from angular velocity when needed (unless a new quantity is specified by the user). You don't always have to define the orientation to set angular velocities/accelerations, as you have done here. An issue can also arrise when you set the angular velocity of A in B and B in C, and then C in A as something inconsistent. The burden is on the user to "not mess up".

What @angadhn is talking about is a similar case. If points P and Q have the same position and velocity, then you are correct in that they should have the same acceleration. But there is no guarantee that they are "the same" with the above code you have written. Consider this very, very crude drawing I have created: http://imgur.com/lHspl . Here, Points P and Q are not coincident but have equal accelerations on the body B. Considering the rotation of body B within the frame N, we see that they will most certainly have different accelerations within the frame N.

Cases like this were the original reason for the strict separation of Point and ReferenceFrame. We chose to make slightly more work for the user in order to make it harder to create physically inconsistent definitions. As such, I am wary of creating a class which makes it easier for this to occur. I think if you could show some more examples of how you want to use this (real, full scale problems - not trivial test cases - either by hand or code), we might all be able to think of something which can maintain the current "safety" of the mechanics code but still make things easier for users of your code.

Sachin Joglekar

unread,
Dec 30, 2012, 12:47:49 AM12/30/12
to sympy/sympy

The problem I saw was, that if ang accln of N in B is defined, then I shouldn't be allowed to define two points such that their accelerations are same in N and different in B. If this is possible, please give an example. Its just a doubt that I encountered.

Gilbert Gede

unread,
Jan 2, 2013, 5:15:10 PM1/2/13
to sympy/sympy

@srjoglekar246 Hopefully this example is legible enough to be of use: http://imgur.com/CrYLL
When the 2 points are coincident (l=0) they will have the same acceleration in both frames. But when they are not coincident (l =/= 0) they will have different accelerations in the N frame, but the same acceleration in the B frame.

Does this clear things up a little?

Reply all
Reply to author
Forward
0 new messages