GSoC 2016 Application James Brandon Milam: Base Class and Increased Efficiency for Equation of Motion Generators - sympy/sympy GitHub Wiki

Personal Information

Name: James Brandon Milam (Prefer Brandon) College: University of Florida, Gainesville, Masters in Mechanical Engineering Email: [email protected] Github: jbm950

Short Bio

I'm from Missouri and have obtained my bachelor's degree in mechanical engineering from the University of Missouri - Columbia. I began working with python during my undergraduate experience around four years ago and have loved programming ever since. I am currently pursuing my master's degree also in mechanical engineering at the University of Florida.

Programming Details

I currently do the majority of my programming on a MacBook pro, however, I have access to a Windows platform and virtual Linux machines for testing cross platform compatibility. My preferred editor of choice is vim. Not needing the mouse in the editor and the myriad of available short cut keys streamlines and greatly enhances productivity. In addition, by working in vim I have immediate access to the terminal which is of extreme use whenever I need to run code or use Git commands, etc.

I spend the majority of my programming time working with python, though in my undergraduate experience I was taught and used MATLAB. In addition, I have taught myself some C coding in order to work with an Arduino micro controller. Using the Arduino, I have created a temperature controller for my senior design class, I have implemented a four-wheel robot platform and have done some basic interactions with the Arduino and python over a serial connection.

My python background consists of being completely self taught, including reading all the way through "Learning Python" which is a hefty book that covers all of the basic language fundamentals from lists to metaclasses to decorators. I have used python to make some simple video games, a flashcard application utilizing tkinter, solve complicated engineering coursework, create a fuzzy speed controller for an aircraft and communicate through UDP to a flight simulator to run the fuzzy controller. While using python to make video games I made my own library to extend the functionality of the pygame library. My library, pygame_toolbox, is currently hosted on Github and is available through pypi (majority of the code lies in graphics/_init_.py). I feel this library best showcases my coding capabilities with object oriented design and cleanness/documentation of code. In addition to these projects I have also made contributions to python core.

The features that I love about python that I feel differentiate it from other programming languages are that it is open source, extremely versatile, it is dynamically typed and it was created with the specific intention of portraying clarity. The most advanced features/standard library functionalities I have used are communications through serial ports and UDP, creating and distributing my custom made library and designing class hierarchy trees to efficiently extend functionalities.

I have experience in using Git extensively for personal notes and projects as well as any other files that I do not want to lose. I have even created a PowerPoint presentation introducing the ideas of version control and Git that I have presented to friends and classmates. I use Git both with Github and with creating private repositories that I put on Dropbox. In addition to Git I have some experience working with Mercurial from contributing to python core, however, I am much more comfortable with Git.

Sympy Use/Involvement

Sympy drew me in with its ability to compute and create expressions symbolically for engineering design purposes. To show this I will expand on the simple mass, spring, damper example in LagrangesMethod's docstring with a simple input force, F which produces the following output.

>>> from sympy import *
>>> from sympy.physics.mechanics import LagrangesMethod, Lagrangian
>>> from sympy.physics.mechanics import ReferenceFrame, Particle, Point
>>> from sympy.physics.mechanics import dynamicsymbols, kinetic_energy
>>> q = dynamicsymbols('q')
>>> qd = dynamicsymbols('q', 1)
>>> m, k, c, F = symbols('m k c F')
>>> N = ReferenceFrame('N')
>>> P = Point('P')
>>> P.set_vel(N, qd * N.x)
>>> Pa = Particle('Pa', P, m)
>>> Pa.potential_energy = k * q**2 / 2.0
>>> L = Lagrangian(N, Pa)
>>> fl = [(P, -c * qd * N.x), (P, F * N.x)]
>>> l = LagrangesMethod(L, [q], forcelist=fl, frame=N)
>>> l.form_lagranges_equations()
>>> print(l.rhs())
Matrix([Derivative(q(t), t)], [(F - c*Derivative(q(t), t) - 1.0*k*q(t))/m](/sympy/sympy/wiki/Derivative(q(t),-t)],-[(F---c*Derivative(q(t),-t)---1.0*k*q(t))/m))

This set of equations naturally lends to controls analysis because in order to better design control laws the dynamics of the system need to be known. With some simple, by hand re-arranging the output from LagrangesMethod can be put into state space form (xdot = Ax + Bu). Now with sympy the controllability of the system and the natural system response can be determined.

>>> A = Matrix([0, 1], [-k/m, -c/m](/sympy/sympy/wiki/0,-1],-[-k/m,--c/m))
>>> B = Matrix([0, 1/m])
>>> M = Matrix([B.transpose(), (A*B).transpose()]).transpose()
>>> print(M.rank())
2
>>> eigA = A.eigenvals()
>>> print(eigA)
{-c/(2*m) + sqrt(c**2 - 4*k*m)/(2*m): 1, -c/(2*m) - sqrt(c**2 - 4*k*m)/(2*m): 1}

The system is full rank (rank = the number of states, x) and is therefore controllable by the input force. Also the eigenvalues are solved symbolically and this is where sympy shines over numeric tools such as scipy. As a controls engineer, the system response due to choice of damping and spring stiffness for a given mass are clearly visible in this symbolic representation, allowing for a more streamlined design stage. Obviously this is a simple example but it is these sort of uses that drew me to sympy and is the reason I wish to contribute to its development.

Pull Requests:

The Project

For the project I propose working on creating a base class for the equations of motion generators in the physics module and add a Newton-Euler equation of motion generator. The benefits of creating a base class for equations of motion generators would include ease of adding additional equations of motion generators and making the code more compact and so speed enhancements and bug fixes will affect all generators simultaneously rather than having to be implemented on a per generator basis. In addition to this work I would also be working on increasing the speed/efficiency of the existing python code for the equations of motion generators since I will already be digging into their base functionality.

Just last semester I took a graduate level course on analytical dynamics during which we learned how to perform the Newton-Euler and Lagrange methods of equation of motion generation by hand. This will allow me to develop the Newton-Euler equation of motion generator in addition to having the base knowledge to be able to work with the Lagrange method and learn additional methods.

Another qualification I possess is experience in refactoring code and making base classes to organize shared functionality from my work with python core and from the library I built to work with pygame. When working with python core I altered the base class for the Windows web browser and subclassed it to allow specific browsers (ie. Google Chrome, Firefox) to pass their own flags. With my work on my personal library I created a base class for screens and subclassed it to make menus, or a screen that read like a book. This prior work with subclassing will aid greatly as I abstract the equations of motion generators in order to form a generic base class.

Lastly I have implemented python's multiprocessing capabilities while coding numerical integration methods. This is experience I can draw upon as I work to increase the speed of the python code any where that seems inherently parallelizable.

My background and qualifications directly point towards this specific project and is why I am excited to attempt to implement it. I will be able to translate in-class theoretical learning to applications and work towards creating a structure that promotes code growth. In addition, my mechanical engineering background includes an emphasis in control systems and so my interest in the equations of motion generators is that it would be useful for modeling the dynamics of the system and streamline the design process for control engineers.

No previous work has been done in creating a shared base class for the equations of motion generators, implementing a Newton-Euler equation of motion generator or specifically enhancing the run time of the python code of the existing equations of motion generators. There are existing equations of motion generators, however, that utilize Kane's and Lagrange's methods for equation of motion generation and this will be the starting point for the project.

The basic idea that I have for the base class is to round up methods that are the same in both KanesMethod and LagrangesMethod classes. There are currently ten methods in these classes with shared names. Of these methods there are some that appear to run very differently or make use of different attributes (to_linearlizer, mass_matrix, mass_matrix_full, forcing, forcing_full) but there are others that have very similar code with only slight variations (linearize, rhs). For the methods that are more different, research will need to be done into whether or not these differences stem from the use of different naming conventions and processes or if the methods are truly different. An attempt will then be made to rewrite these methods such that they perform similarly for both classes and could therefore be transferred to the base class. For the methods that are very close, the identical code can be put in the base class and let the specific equation of motion generators modify it as needed such as shown below.

class LagrangesMethod(BaseClass):
    def rhs():
        run Lagrange specific code/warnings

        BaseClass.rhs()

In addition to the above mentioned methods, there are some methods that are identical (q, u, forcelist) and these would directly lend themselves to being placed in the base class. Aside from the methods, any similar attributes found between the two classes will also be transferred to the base class. This will be done in the appropriate method that requires the attributes or in the base class's init method which would result in the same call form as was shown above (note the base class will be called something along the lines of EOMBase)

class KanesMethod(BaseClass):
    def __init__(inputs):
        Kanes Method specific attributes
        BaseClass.__init__(base_class_inputs)

In general the API for KanesMethod and LagrangesMethod will be entirely preserved as best as possible to allow backwards compatibility. The only changes that would be made would be for consistency between the two methods. For instance in KanesMethod the equations of motion are generated by KM.kanes_equations() whereas LagrangesMethod produces the equations of motion by LM.form_lagranges_equation(). For situations such as these an agreed upon consistency would be implemented and the replaced method will issue a deprecation warning then call the new method. The other possible API changes/additions would be in response to looking through pydy.system.System's code. In this code there are some methods implemented to access attributes of KanesMethod that are not currently accessible directly from KanesMethod's API. These methods are _kane_inlist_syms, _kane_undefined_dynamic_symbols and _kane_constant_symbols and would be better off implemented in sympy's code. In addition these are methods that can be non-generator specific and could possibly be implemented in the base class rather than specifically KanesMethod or LagrangesMethod.

For the NewtonEulerMethod class I will attempt to build the same general API as KanesMethod and LagrangesMethod where creating an instance of the class initializes key information needed to compute the equations of motion and a call to the class method named after the generation method will actually generate the equations of motion.

>>> NEM = NewtonEulerMethod(inputs)
>>> NEM.newton_euler_equations()

In addition, NewtonEulerMethod should in the very least provide the same methods as are shared between KanesMethod and LagrangesMethod as described in detail above. I plan on including the example code for a mass, spring, damper system in the docstring of the NewtonEulerMethod for consistency between the three equations of motion generators.

I have already run a profiler on the n_link_pendulum_on_cart() function found in the pydy source as it makes use of sympy's KanesMethod class. With this profile I can prove that the work on speeding the code up for the equations of motion generators will have an impact across all of sympy rather than just the physics module. For instance, while running kanes_equations the code spent about 45% of its time in the sympy/matrices module. Therefore in order to speed up the equations of motion generator the other parts of sympy will need to be made to run more efficiently as well.

Currently my ideas for speeding up the code are rather sparse. My plan is to go through function calls from the profiler and see if any functions are trying to perform too many different tasks which are not necessarily related. Such functions would be better off split so that unnecessary bits of code are not run. In addition, looking through the profile generated of the n_link_pendulum_on_cart() function, there are some calls that appear to occur often and do not take much time per call. I would look into seeing if such calls could be parallelized. This could also apply to code within some of the larger function calls. Lastly I will be making sure the code blocks are written efficiently (use elif statements instead of separate if statements or rearrange for loops so that unnecessary code is pulled out where applicable). These are the sorts of things I will be looking for and will take greater advantage of near the end of the project after having been fully immersed in the code for most of the summer.

Before the project officially begins I will be spending time working on the project as I can while school is still in session. The school semester is completely over before May begins, however, and so I would be able to essentially start my project early by about two to three weeks. During this time, I would be familiarizing myself with Kane's method of equation of motion generation and beginning work in creating a benchmarking tool for use during the project.

During the project I have no other obligations and will be able to put in 40+ hours each week. I am thinking about taking a trip back home around the 4th of July, however, I will still be able to get work done and so this would not create a huge disturbance in the amount of weekly hours I put in.

After the summer ends I will be beginning my final semester of graduate school and so the amount of time I could continue to devote to sympy would be limited. This limitation would only last until December, though, and I would be able to more regularly return at the beginning of the new year.

Timeline

Week 1 [May 23rd - May 30th]

  • Create benchmarking tool to track project progress

    • The tool will run test code and simulations using both KanesMethod and LagrangesMethod and save the results in an SQLite database where each table represents a different test
    • In addition to the speed results, each row in the table will include information on who ran the tests (probably see if I can access Github username for this),what version of python was used, what operating system was used and the hardware details of the computer used (CPU speed and RAM)
    • A profile of portions of the tested code will be saved in a subfolder
    • A viewer of the results would be made using the matplotlib library
      • Sub options for viewing results will be added as time allows
    • Tool will be made such that it is easily extendable
      • Can be used by other members of the community for their projects
      • Can be used with the NewtonEuler class that will be created later in the project
    • PR: Resulting tool could be introduced as a pull request depending on whether or not this is desired in the main code base
  • Learn and practice Kane's method of generating equations of motion so that I will have a better understanding of how the code works

  • Note: The items listed for week 1 would begin at the beginning of May much before the project officially begins

Week 2, 3 [May 30th - June 13th]

  • Begin going through internals of the KanesMethod and LagrangesMethod to determine what the commonalities are that could be drawn from a base class

  • Create a basic implementation of the base class from which KanesMethod and LagrangesMethod would be subclasses

Week 4, 5 [June 13th - June 27th]

  • Continue working out and condensing code to complete the base class for the equations of motion generators

    • Keeping attention to enhancing speed and performance of code during consolidation
  • Develop the supporting documentation for the base equations of motion generation class

  • Complete the midterm evaluation with the functioning base class, test code for the base class and the supporting documentation as the deliverable

    • PR: Base class code, test code for the base class and documentation for the base class

Week 6, 7 [June 27th - July 11th]

  • Look into best practices for coding a NewtonEulerMethod class and begin creation of that class. This will be a general design period and as the desired API is developed. Test code will be written to verify the agreed upon API.

Week 8, 9 [July 11th - July 25th]

  • Complete NewtonEulerMethod class

  • Update the documentation explaining the new method

  • PR: NewtonEulerMethod class code, test code and documentation

Week 10 - 13 [July 25th - August 23rd]

  • Finish any documentation or code that is still needing to be completed

  • Continue to refactor and improve the quality of the code written for the project

  • By this point a complete understanding of the code underlying the methods should be obtained and thus effort towards performance enhancement and speed would return the greatest results

  • Make final preparations for the final evaluation

    • Final deliverables would include
      • Equations of motion generator base class
      • Newton-Euler equations of motion generator class
      • Benchmarking results
    • PR: Any remaining items, code, documentation fixes etc.

Note: Any spare time during the weeks will be used towards speeding up the python code.

Contingency Plan

In the case that time runs short this section details the priority that the different aspect of the project will receive. Top priority will be given to the test code for the base class and the completeness and stability of the base class code for the equations of motion generation. Next priority will be the complete documentation of the base class. This is followed by completeness of the test code and actual code for the NewtonEulerMethod then by the documentation for NewtonEulerMethod. The last priority will be given to speeding up the equations of motion generation code. Note that the tests, code and documentation will be developed simultaneously and this is just a declaration of priorities should time start to run out near the end of the project.