compute_kinetic_energy#
- movement.kinematics.compute_kinetic_energy(position, keypoints=None, masses=None, decompose=False)[source]#
Compute kinetic energy per individual.
We consider each individual’s set of keypoints (pose) as a classical system of particles in physics (see Notes).
- Parameters:
position (xr.DataArray) – The input data containing position information, with
time
,space
andkeypoints
as required dimensions.keypoints (list, optional) – A list of keypoint names to include in the computation. By default, all are used.
masses (dict, optional) – A dictionary mapping keypoint names to masses, e.g. {“snout”: 1.2, “tail”: 0.8}. By default, unit mass is assumed for all keypoints.
decompose (bool, optional) – If True, the kinetic energy is decomposed into “translational” and “internal” components (see Notes). This requires at least two keypoints per individual, but more would be desirable for a meaningful decomposition. The default is False, meaning the total kinetic energy is returned.
- Returns:
A data array containing the kinetic energy per individual, for every time point. Note that the output array lacks
space
andkeypoints
dimensions. Ifdecompose=True
an extraenergy
dimension is added, with coordinatestranslational
andinternal
.- Return type:
xr.DataArray
Notes
Considering a given individual at time point \(t\) as a system of keypoint particles, its total kinetic energy \(T_{total}\) is given by:
\[T_{total} = \sum_{i} \frac{1}{2} m_i \| \mathbf{v}_i(t) \|^2\]where \(m_i\) is the mass of the \(i\)-th keypoint and \(\mathbf{v}_i(t)\) is its velocity at time \(t\).
From Samuel König’s second theorem, we can decompose \(T_{total}\) into:
Translational kinetic energy: the kinetic energy of the individual’s total mass \(M\) moving with the centre of mass velocity;
Internal kinetic energy: the kinetic energy of the keypoints moving relative to the individual’s centre of mass.
We compute translational kinetic energy \(T_{trans}\) as follows:
\[T_{trans} = \frac{1}{2} M \| \mathbf{v}_{cm}(t) \|^2\]where \(M = \sum_{i} m_i\) is the total mass of the individual and \(\mathbf{v}_{cm}(t) = \frac{1}{M} \sum_{i} m_i \mathbf{v}_i(t)\) is the velocity of the centre of mass at time \(t\) (computed as the weighted mean of keypoint velocities).
Internal kinetic energy \(T_{int}\) is derived as the difference between the total and translational components:
\[T_{int} = T_{total} - T_{trans}\]Examples
>>> from movement.kinematics import compute_kinetic_energy >>> import numpy as np >>> import xarray as xr
Compute total kinetic energy:
>>> position = xr.DataArray( ... np.random.rand(3, 2, 4, 2), ... coords={ ... "time": np.arange(3), ... "individuals": ["id0", "id1"], ... "keypoints": ["snout", "spine", "tail_base", "tail_tip"], ... "space": ["x", "y"], ... }, ... dims=["time", "individuals", "keypoints", "space"], ... )
>>> kinetic_energy_total = compute_kinetic_energy(position)
>>> kinetic_energy_total <xarray.DataArray (time: 3, individuals: 2)> Size: 48B 0.6579 0.7394 0.1304 0.05152 0.2436 0.5719 Coordinates: * time (time) int64 24B 0 1 2 * individuals (individuals) <U3 24B 'id0' 'id1'
Compute kinetic energy decomposed into translational and internal components:
>>> kinetic_energy = compute_kinetic_energy(position, decompose=True)
>>> kinetic_energy <xarray.DataArray (time: 3, individuals: 2, energy: 2)> Size: 96B 0.0172 1.318 0.02069 0.6498 0.02933 ... 0.1716 0.07829 0.7942 0.06901 0.857 Coordinates: * time (time) int64 24B 0 1 2 * individuals (individuals) <U3 24B 'id0' 'id1' * energy (energy) <U13 104B 'translational' 'internal'
Select the ‘internal’ component:
>>> kinetic_energy_internal = kinetic_energy.sel(energy="internal")
Use unequal keypoint masses and exclude an unreliable keypoint (e.g. “tail_tip”):
>>> masses = {"snout": 1.2, "spine": 0.8, "tail_base": 1.0}
>>> kinetic_energy = compute_kinetic_energy( ... position, ... keypoints=["snout", "spine", "tail_base"], ... masses=masses, ... decompose=True, ... )