Created
July 8, 2025 20:43
-
-
Save alisterburt/68b3e5ddb2e796483fd0f5578ae28f8f to your computer and use it in GitHub Desktop.
how to reason about RELION's Euler angles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "metadata": {}, | |
| "cell_type": "markdown", | |
| "source": [ | |
| "goal: try to understand physical meaning of RELION's Euler angles\n", | |
| "\n", | |
| "- RELION eulers are ZYZ intrinsic euler angles\n", | |
| "- these eulers rotate coordinates and sample at rotated positions\n", | |
| "- the above has the effect of inverting the transformation\n", | |
| "- inverting a rotation matrix is taking its transpose because it's orthogonal" | |
| ], | |
| "id": "2cf5d4299314cf62" | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:26.999542Z", | |
| "start_time": "2025-07-08T20:42:26.712185Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "import sympy\n", | |
| "from sympy import cos, sin, pi, Matrix, symbols, simplify" | |
| ], | |
| "id": "21f03dd7ba4265b0", | |
| "outputs": [], | |
| "execution_count": 1 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:27.094804Z", | |
| "start_time": "2025-07-08T20:42:27.092535Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# define rotation matrices\n", | |
| "\n", | |
| "# Define angle symbols\n", | |
| "rot, tilt, psi = symbols('α β γ', real=True)\n", | |
| "\n", | |
| "# Rotation matrix about X-axis\n", | |
| "def Rx(theta):\n", | |
| " return Matrix([\n", | |
| " [1, 0, 0],\n", | |
| " [0, cos(theta), -sin(theta)],\n", | |
| " [0, sin(theta), cos(theta)]\n", | |
| " ])\n", | |
| "\n", | |
| "# Rotation matrix about Y-axis\n", | |
| "def Ry(theta):\n", | |
| " return Matrix([\n", | |
| " [cos(theta), 0, sin(theta)],\n", | |
| " [0, 1, 0],\n", | |
| " [-sin(theta), 0, cos(theta)]\n", | |
| " ])\n", | |
| "\n", | |
| "# Rotation matrix about Z-axis\n", | |
| "def Rz(theta):\n", | |
| " return Matrix([\n", | |
| " [cos(theta), -sin(theta), 0],\n", | |
| " [sin(theta), cos(theta), 0],\n", | |
| " [0, 0, 1]\n", | |
| " ])\n" | |
| ], | |
| "id": "ad5dd2c64324c8fc", | |
| "outputs": [], | |
| "execution_count": 2 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:27.174141Z", | |
| "start_time": "2025-07-08T20:42:27.103854Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# intrinsic rotation\n", | |
| "# rotate around z by rot\n", | |
| "# rotate around new y by tilt\n", | |
| "# rotate around new z by psi\n", | |
| "zyz_intrinsic = Rz(rot) * Ry(tilt) * Rz(psi)\n", | |
| "zyz_intrinsic" | |
| ], | |
| "id": "448c5920bffeeb14", | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Matrix([\n", | |
| "[-sin(α)*sin(γ) + cos(α)*cos(β)*cos(γ), -sin(α)*cos(γ) - sin(γ)*cos(α)*cos(β), sin(β)*cos(α)],\n", | |
| "[ sin(α)*cos(β)*cos(γ) + sin(γ)*cos(α), -sin(α)*sin(γ)*cos(β) + cos(α)*cos(γ), sin(α)*sin(β)],\n", | |
| "[ -sin(β)*cos(γ), sin(β)*sin(γ), cos(β)]])" | |
| ], | |
| "text/latex": "$\\displaystyle \\left[\\begin{matrix}- \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} & - \\sin{\\left(α \\right)} \\cos{\\left(γ \\right)} - \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} & \\sin{\\left(β \\right)} \\cos{\\left(α \\right)}\\\\\\sin{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} + \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} & - \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} \\cos{\\left(β \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(α \\right)} \\sin{\\left(β \\right)}\\\\- \\sin{\\left(β \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(β \\right)} \\sin{\\left(γ \\right)} & \\cos{\\left(β \\right)}\\end{matrix}\\right]$" | |
| }, | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "execution_count": 3 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:27.189695Z", | |
| "start_time": "2025-07-08T20:42:27.183098Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# extrinsic rotation\n", | |
| "# rotate around z by rot\n", | |
| "# rotate around original y by tilt\n", | |
| "# rotate around original z by psi\n", | |
| "# different output\n", | |
| "zyz_extrinsic = Rz(psi) * Ry(tilt) * Rz(rot)\n", | |
| "zyz_extrinsic" | |
| ], | |
| "id": "1e301398648b24d", | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Matrix([\n", | |
| "[-sin(α)*sin(γ) + cos(α)*cos(β)*cos(γ), -sin(α)*cos(β)*cos(γ) - sin(γ)*cos(α), sin(β)*cos(γ)],\n", | |
| "[ sin(α)*cos(γ) + sin(γ)*cos(α)*cos(β), -sin(α)*sin(γ)*cos(β) + cos(α)*cos(γ), sin(β)*sin(γ)],\n", | |
| "[ -sin(β)*cos(α), sin(α)*sin(β), cos(β)]])" | |
| ], | |
| "text/latex": "$\\displaystyle \\left[\\begin{matrix}- \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} & - \\sin{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} - \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} & \\sin{\\left(β \\right)} \\cos{\\left(γ \\right)}\\\\\\sin{\\left(α \\right)} \\cos{\\left(γ \\right)} + \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} & - \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} \\cos{\\left(β \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(β \\right)} \\sin{\\left(γ \\right)}\\\\- \\sin{\\left(β \\right)} \\cos{\\left(α \\right)} & \\sin{\\left(α \\right)} \\sin{\\left(β \\right)} & \\cos{\\left(β \\right)}\\end{matrix}\\right]$" | |
| }, | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "execution_count": 4 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:27.223121Z", | |
| "start_time": "2025-07-08T20:42:27.216124Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# actual equivalent extrinsic rotation\n", | |
| "# rotate around z by psi\n", | |
| "# rotate around original y by tilt\n", | |
| "# rotate around original z by rot\n", | |
| "equivalent_zyz_extrinsic = Rz(rot) * Ry(tilt) * Rz(psi)\n", | |
| "equivalent_zyz_extrinsic" | |
| ], | |
| "id": "eebe494c6ce55c2f", | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Matrix([\n", | |
| "[-sin(α)*sin(γ) + cos(α)*cos(β)*cos(γ), -sin(α)*cos(γ) - sin(γ)*cos(α)*cos(β), sin(β)*cos(α)],\n", | |
| "[ sin(α)*cos(β)*cos(γ) + sin(γ)*cos(α), -sin(α)*sin(γ)*cos(β) + cos(α)*cos(γ), sin(α)*sin(β)],\n", | |
| "[ -sin(β)*cos(γ), sin(β)*sin(γ), cos(β)]])" | |
| ], | |
| "text/latex": "$\\displaystyle \\left[\\begin{matrix}- \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} & - \\sin{\\left(α \\right)} \\cos{\\left(γ \\right)} - \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} & \\sin{\\left(β \\right)} \\cos{\\left(α \\right)}\\\\\\sin{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} + \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} & - \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} \\cos{\\left(β \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(α \\right)} \\sin{\\left(β \\right)}\\\\- \\sin{\\left(β \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(β \\right)} \\sin{\\left(γ \\right)} & \\cos{\\left(β \\right)}\\end{matrix}\\right]$" | |
| }, | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "execution_count": 5 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:31.444352Z", | |
| "start_time": "2025-07-08T20:42:27.243901Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# inverse to account for fact that we are defining a transform applied to\n", | |
| "# the internal coordinate system of an image\n", | |
| "zyz_intrinsic_inverse = zyz_intrinsic.inv()\n", | |
| "simplify(zyz_intrinsic_inverse)" | |
| ], | |
| "id": "a0f4f7746bde59ab", | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Matrix([\n", | |
| "[-sin(α)*sin(γ) + cos(α)*cos(β)*cos(γ), sin(α)*cos(β)*cos(γ) + sin(γ)*cos(α), -sin(β)*cos(γ)],\n", | |
| "[-sin(α)*cos(γ) - sin(γ)*cos(α)*cos(β), -sin(α)*sin(γ)*cos(β) + cos(α)*cos(γ), sin(β)*sin(γ)],\n", | |
| "[ sin(β)*cos(α), sin(α)*sin(β), cos(β)]])" | |
| ], | |
| "text/latex": "$\\displaystyle \\left[\\begin{matrix}- \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} + \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} & - \\sin{\\left(β \\right)} \\cos{\\left(γ \\right)}\\\\- \\sin{\\left(α \\right)} \\cos{\\left(γ \\right)} - \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} & - \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} \\cos{\\left(β \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(β \\right)} \\sin{\\left(γ \\right)}\\\\\\sin{\\left(β \\right)} \\cos{\\left(α \\right)} & \\sin{\\left(α \\right)} \\sin{\\left(β \\right)} & \\cos{\\left(β \\right)}\\end{matrix}\\right]$" | |
| }, | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "execution_count": 6 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:31.555659Z", | |
| "start_time": "2025-07-08T20:42:31.458695Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# compute inverse with negative arguments and opposite order of axes\n", | |
| "# just to demonstrate this is the same as the analytical inverse above\n", | |
| "direct_inverse = Rz(-psi) * Ry(-tilt) * Rz(-rot)\n", | |
| "simplify(direct_inverse)" | |
| ], | |
| "id": "e2ac13d79978af6", | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Matrix([\n", | |
| "[-sin(α)*sin(γ) + cos(α)*cos(β)*cos(γ), sin(α)*cos(β)*cos(γ) + sin(γ)*cos(α), -sin(β)*cos(γ)],\n", | |
| "[-sin(α)*cos(γ) - sin(γ)*cos(α)*cos(β), -sin(α)*sin(γ)*cos(β) + cos(α)*cos(γ), sin(β)*sin(γ)],\n", | |
| "[ sin(β)*cos(α), sin(α)*sin(β), cos(β)]])" | |
| ], | |
| "text/latex": "$\\displaystyle \\left[\\begin{matrix}- \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(α \\right)} \\cos{\\left(β \\right)} \\cos{\\left(γ \\right)} + \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} & - \\sin{\\left(β \\right)} \\cos{\\left(γ \\right)}\\\\- \\sin{\\left(α \\right)} \\cos{\\left(γ \\right)} - \\sin{\\left(γ \\right)} \\cos{\\left(α \\right)} \\cos{\\left(β \\right)} & - \\sin{\\left(α \\right)} \\sin{\\left(γ \\right)} \\cos{\\left(β \\right)} + \\cos{\\left(α \\right)} \\cos{\\left(γ \\right)} & \\sin{\\left(β \\right)} \\sin{\\left(γ \\right)}\\\\\\sin{\\left(β \\right)} \\cos{\\left(α \\right)} & \\sin{\\left(α \\right)} \\sin{\\left(β \\right)} & \\cos{\\left(β \\right)}\\end{matrix}\\right]$" | |
| }, | |
| "execution_count": 7, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "execution_count": 7 | |
| }, | |
| { | |
| "metadata": { | |
| "ExecuteTime": { | |
| "end_time": "2025-07-08T20:42:31.569823Z", | |
| "start_time": "2025-07-08T20:42:31.567720Z" | |
| } | |
| }, | |
| "cell_type": "code", | |
| "source": [ | |
| "# so if the above transform, the inverse of the zyz intrinsic, is what's applied to our object\n", | |
| "# how to interpret the transformation in terms of euler angles?\n", | |
| "\n", | |
| "# answer:\n", | |
| "# - extrinsic Z(-rot) -> Y(-tilt) -> Z(-psi)\n", | |
| "# - intrinsic Z(-psi) -> Y'(-tilt) -> Z''(-rot)" | |
| ], | |
| "id": "3565c706c3cf0aec", | |
| "outputs": [], | |
| "execution_count": 8 | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 2 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython2", | |
| "version": "2.7.6" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 5 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment