======================================
Lagrange's Method in Physics/Mechanics
======================================
:mod:`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 :mod:`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.
.. math::
\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\\
In this module, the expressions formed by using Lagrange's equations of the
second kind are rearranged into the following form:
:math:`\mathbf{M}(q, t) x = \mathbf{f}(q, \dot{q}, t)`
where in the case of a system without constraints:
:math:`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:
.. math::
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}\\
Lagrange's Method in Physics/Mechanics
======================================
The formulation of the equations of motion in :mod:`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([
[0],
[0]])
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 :math:`k_{dc}(q, t)` matrix, and the forcing vector by the
:math:`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.