# Lagrange’s Method in Physics/Mechanics#

sympy.physics.mechanics provides functionality for deriving equations of motion using Lagrange’s method. This document will describe Lagrange’s method as used in this module, but not how the equations are actually derived.

## Structure of Equations#

In sympy.physics.mechanics we are assuming there are 3 basic sets of equations needed to describe a system; the constraint equations, the time differentiated constraint equations and the dynamic equations.

$\begin{split}\mathbf{m_{c}}(q, t) \dot{q} + \mathbf{f_{c}}(q, t) &= 0\\ \mathbf{m_{dc}}(\dot{q}, q, t) \ddot{q} + \mathbf{f_{dc}}(\dot{q}, q, t) &= 0\\ \mathbf{m_d}(\dot{q}, q, t) \ddot{q} + \mathbf{\Lambda_c}(q, t) \lambda + \mathbf{f_d}(\dot{q}, q, t) &= 0\\\end{split}$

In this module, the expressions formed by using Lagrange’s equations of the second kind are rearranged into the following form:

$$\mathbf{M}(q, t) x = \mathbf{f}(q, \dot{q}, t)$$

where in the case of a system without constraints:

$$x = \ddot{q}$$

For a constrained system with $$n$$ generalized speeds and $$m$$ constraints, we will get n - m equations. The mass-matrix/forcing equations are then augmented in the following fashion:

$\begin{split}x = \begin{bmatrix} \ddot{q} \\ \lambda \end{bmatrix} \\ \mathbf{M}(q, t) &= \begin{bmatrix} \mathbf{m_d}(q, t) & \mathbf{\Lambda_c}(q, t) \end{bmatrix}\\ \mathbf{F}(\dot{q}, q, t) &= \begin{bmatrix} \mathbf{f_d}(q, \dot{q}, t) \end{bmatrix}\\\end{split}$

## Lagrange’s Method in Physics/Mechanics#

The formulation of the equations of motion in sympy.physics.mechanics using Lagrange’s Method starts with the creation of generalized coordinates and a Lagrangian. The Lagrangian can either be created with the Lagrangian function or can be a user supplied function. In this case we will supply the Lagrangian.

>>> from sympy.physics.mechanics import *
>>> q1, q2 = dynamicsymbols('q1 q2')
>>> q1d, q2d = dynamicsymbols('q1 q2', 1)
>>> L = q1d**2 + q2d**2


To formulate the equations of motion we create a LagrangesMethod object. The Lagrangian and generalized coordinates need to be supplied upon initialization.

>>> LM = LagrangesMethod(L, [q1, q2])


With that the equations of motion can be formed.

>>> mechanics_printing(pretty_print=False)
>>> LM.form_lagranges_equations()
Matrix([
[2*q1''],
[2*q2'']])


It is possible to obtain the mass matrix and the forcing vector.

>>> LM.mass_matrix
Matrix([
[2, 0],
[0, 2]])

>>> LM.forcing
Matrix([
,
])


If there are any holonomic or non-holonomic constraints, they must be supplied as keyword arguments (hol_coneqs and nonhol_coneqs respectively) in a list of expressions which are equal to zero. Modifying the example above, the equations of motion can then be generated:

>>> LM = LagrangesMethod(L, [q1, q2], hol_coneqs=[q1 - q2])


When the equations of motion are generated in this case, the Lagrange multipliers are introduced; they are represented by lam1 in this case. In general, there will be as many multipliers as there are constraint equations.

>>> LM.form_lagranges_equations()
Matrix([
[ lam1 + 2*q1''],
[-lam1 + 2*q2'']])


Also in the case of systems with constraints, the ‘full’ mass matrix is augmented by the $$k_{dc}(q, t)$$ matrix, and the forcing vector by the $$f_{dc}(q, \dot{q}, t)$$ vector. The ‘full’ mass matrix is of size (2n + o) x (2n + o), i.e. it’s a square matrix.

>>> LM.mass_matrix_full
Matrix([
[1, 0, 0,  0,  0],
[0, 1, 0,  0,  0],
[0, 0, 2,  0, -1],
[0, 0, 0,  2,  1],
[0, 0, 1, -1,  0]])
>>> LM.forcing_full
Matrix([
[q1'],
[q2'],
[  0],
[  0],
[  0]])


If there are any non-conservative forces or moments acting on the system, they must also be supplied as keyword arguments in a list of 2-tuples of the form (Point, Vector) or (ReferenceFrame, Vector) where the Vector represents the non-conservative forces and torques. Along with this 2-tuple, the inertial frame must also be specified as a keyword argument. This is shown below by modifying the example above:

>>> N = ReferenceFrame('N')
>>> P = Point('P')
>>> P.set_vel(N, q1d * N.x)
>>> FL = [(P, 7 * N.x)]
>>> LM = LagrangesMethod(L, [q1, q2], forcelist=FL, frame=N)
>>> LM.form_lagranges_equations()
Matrix([
[2*q1'' - 7],
[    2*q2'']])


Exploration of the provided examples is encouraged in order to gain more understanding of the LagrangesMethod object.