Transformation under Euclidean symmetries
Transformation under Euclidean symmetries#
In this section, we will show how the action of a symmetry element denoted by Irrep
of the input data.
For example, we take the irreducible representation obtained through decomposing an arbitrary rank-2 tensor: “1x0e + 1x1o + 1x2o” from the previous section. Irrep objects are represented as a vector by concatenating irreducible componentes of increasing order
Under this definition, any symmetry elements block diagonal square matrix
Notice that
For the illustration below we will use the example of a particle sitting at location
The illustration plotted here showcases how the block diagonal matrix
Click to show
from numpy import *
import numpy as np
n_vec = 4
x = np.zeros(n_vec)
y = np.zeros(n_vec)
z = np.zeros(n_vec)
# phi = 2*np.pi*(np.random.random(n_vec)*0.05+0.125)
phi = 2*np.pi*(0.125)
# theta = np.arccos(-1 + 2*(np.random.random(n_vec)*0.05+sqrt(2)/2))
theta = np.arccos(-1 + 2*(sqrt(2)/2))
R = np.ones(n_vec)
u = np.abs(R * sin(theta) * cos(phi)) * np.array([-1,1,-1,1])
v = np.abs(R * sin(theta) * sin(phi)) * np.array([1,-1,-1,1])
w = np.abs(R * cos(theta)) * np.array([1,1,-1,-1])
Click to show
import plotly.figure_factory as ff
import plotly.graph_objects as go
import plotly.express as px
from plotly.express.colors import sample_colorscale
c = px.colors.qualitative.Plotly
# c = sample_colorscale('Viridis', np.linspace(0,1,4))
vector_flattened = np.concatenate((u[None,:],v[None,:],w[None,:]), axis=0).flatten("F")
vector_in = np.concatenate(([0,0,0], vector_flattened))
from e3nn.o3 import Irreps
irreps = Irreps("3x0e + 4x1o")
import plotly.graph_objects as go
import numpy as np
from plotly.subplots import make_subplots
import torch
t = torch.tensor
# Create figure
fig = make_subplots(rows=1, cols=2,
specs=[[{"type": "xy"}, {"type": "scene"}]],
column_widths=[0.45, 0.55])
# Add traces, one for each slider step
rotations = np.linspace(0, 2*np.pi, 101)
for step in rotations:
# a small rotation around the y axis
D = irreps.D_from_angles(alpha=t(float(step)), beta=t(float(step)), gamma=t(float(step)), k=t(0))
# Display Heatmap
fig.add_trace(
go.Heatmap(visible=False, z=D, colorscale="RdYlBu", zmin=-1, zmax=1,
colorbar=dict(x=0.40,
y=0,
xanchor='left',
yanchor='bottom',
len=1,
thickness=20)),
row=1, col=1)
# Calculate vector after rotation
v_out = vector_in @ np.array(D)
# Plot Points and Vectors after rotation
fig = fig.add_trace(go.Scatter3d(
x=v_out[0:1], y=v_out[1:2], z=v_out[2:3],
mode='markers',
name='point (3x0e)',
marker=dict(
size=12,
color=c[0]),
visible=False),
row=1,
col=2
)
for idx in range(n_vec):
x_vec = np.array([v_out[0], v_out[3*idx+3]])
y_vec = np.array([v_out[1], v_out[3*idx+4]])
z_vec = np.array([v_out[2], v_out[3*idx+5]])
fig.add_trace(go.Scatter3d(
visible=False,
x=x_vec, y=y_vec, z=z_vec,
mode='lines', name='vector {} (1x1o)'.format(idx),
line=dict(color=c[idx],width=2)
), row=1, col=2)
x_cone = [v_out[3*idx+3]*0.9]
y_cone = [v_out[3*idx+4]*0.9]
z_cone = [v_out[3*idx+5]*0.9]
u_cone = [v_out[3*idx+3]*0.3]
v_cone = [v_out[3*idx+4]*0.3]
w_cone = [v_out[3*idx+5]*0.3]
fig.add_trace(go.Cone(
x=x_cone, y=y_cone, z=z_cone, u=u_cone, v=v_cone, w=w_cone,
showscale=False, colorscale=[[0, c[idx]], [1, c[idx]]], sizemode="absolute", visible=False
), row=1, col=2)
# Make first set of traces visible
# for idx in range(410, 420):
for idx in range(10):
fig.data[idx].visible = True
# Create and add slider
steps = []
for i in range(len(rotations)):
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": 'Rotation with angle α = β = γ = {:.2f}π'.format(0.02*i)}], # layout attribute
# {"title": 'α =β=γ=π'}]
)
for idx in range(10):
step["args"][0]["visible"][10*i+idx] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active=0,
currentvalue={"prefix": "Rotation "},
steps=steps
)]
fig.update_layout(
sliders=sliders,
title_text='Rotation with angle α = β = γ = 0π'
)
fig.update_yaxes(autorange="reversed")
fig.update_layout(
scene = dict(
xaxis = dict(nticks=4, range=[-1,1]),
yaxis = dict(nticks=4, range=[-1,1]),
zaxis = dict(nticks=4, range=[-1,1]),
),
scene_aspectmode='cube',
autosize=False,
width=1000,
height=500)
fig.show()
# fig.write_image('figs/transformation.pdf')
/Users/killiansheriff/opt/miniconda3/lib/python3.9/site-packages/e3nn/o3/_wigner.py:92: UserWarning:
An output with one or more elements was resized since it had shape [1, 3, 3], which does not match the required output shape [1, 1, 3, 3]. This behavior is deprecated, and in a future PyTorch release outputs will not be resized unless they have zero elements. You can explicitly reuse an out tensor t by resizing it, inplace, to zero elements with t.resize_(0). (Triggered internally at /Users/runner/work/pytorch/pytorch/pytorch/aten/src/ATen/native/Resize.cpp:24.)