# Lagrange’s Method in Physics/Mechanics¶

`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 `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.

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:

## Lagrange’s Method in Physics/Mechanics¶

The formulation of the equations of motion in `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 \(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.