"""
PyOR - Python On Resonance
Author:
Vineeth Francis Thalakottoor Jose Chacko
Email:
vineethfrancis.physics@gmail.com
Description:
This module provides functions related to spherical tensors, which are essential
in the quantum mechanical description of angular momentum operators and their
transformations.
Functions include the construction of irreducible spherical tensors,
tensor operator manipulation, and transformation properties under rotations,
relevant to magnetic resonance simulations.
"""
import numpy as np
try:
from .PyOR_QuantumObject import QunObj
except ImportError:
from PyOR_QuantumObject import QunObj
[docs]
def MatrixToSphericalTensors(AQ):
"""
Converts a 3x3 Cartesian matrix into its corresponding spherical tensor components.
This function decomposes a Cartesian second-rank tensor (typically used in NMR or other
physics applications) into spherical tensor components of rank 0 (isotropic), rank 1
(antisymmetric), and rank 2 (symmetric traceless). The decomposition follows the formalism
described in Pascal P. Man's 2014 paper on Cartesian and spherical tensors in NMR Hamiltonians.
Parameters:
-----------
AQ : numpy.matrix or similar object
A 3x3 matrix (usually Hermitian or real) representing the Cartesian tensor
to be converted. AQ must be a quantum object with attribute "data".
Returns:
--------
dict
A dictionary containing the spherical tensor components:
- "rank0": complex
The rank-0 (isotropic) component T(0,0).
- "rank1": list of complex
The rank-1 (antisymmetric) components [T(1,1), T(1,0), T(1,-1)].
- "rank2": list of complex
The rank-2 (symmetric traceless) components [T(2,2), T(2,1), T(2,0), T(2,-1), T(2,-2)].
Reference:
----------
1. Pascal P. Man, "Cartesian and Spherical Tensors in NMR Hamiltonians",
Concepts in Magnetic Resonance Part A, 2014. https://doi.org/10.1002/cmr.a.21289
(Equations 275 to 281 are particularly relevant)
2. Tensors and Rotations in NMR, LEONARD J. MUELLER, https://doi.org/10.1002/cmr.a.20224
"""
A = AQ.data
Sptensor = {}
# Isotropic (rank 0)
Sptensor["rank0"] = (-1/np.sqrt(3)) * (A[0][0] + A[1][1] + A[2][2]) # T(0,0)
# Anti-Symmetric (rank 1)
AANTI_1 = (-1.0/2.0) * (A[2][0] - A[0][2] - 1j *(A[2][1] - A[1][2])) # T(1,-1)
AANTI_2 = (-1.0/np.sqrt(2)) * 1j * (A[0][1] - A[1][0]) # T(1,0)
AANTI_3 = (-1.0/2.0) * (A[2][0] - A[0][2] + 1j *(A[2][1] - A[1][2])) # T(1,1)
Sptensor["rank1"] = [AANTI_3,AANTI_2,AANTI_1]
# Symmetric (rank 2)
SYMM_1 = (1.0/2.0) * (A[0][0] - A[1][1] - 1j *(A[0][1] + A[1][0])) # T(2,-2)
SYMM_2 = (1.0/2.0) * (A[0][2] + A[2][0] - 1j *(A[1][2] + A[2][1])) # T(2,-1)
SYMM_3 = (1.0/np.sqrt(6)) * (3 * A[2][2] - (A[0][0] + A[1][1] + A[2][2])) # T(2,0)
SYMM_4 = (-1.0/2.0) * (A[0][2] + A[2][0] + 1j *(A[1][2] + A[2][1])) # T(2,1)
SYMM_5 = (1.0/2.0) * (A[0][0] - A[1][1] + 1j *(A[0][1] + A[1][0])) # T(2,2)
Sptensor["rank2"] = [SYMM_5,SYMM_4,SYMM_3,SYMM_2,SYMM_1]
return Sptensor
[docs]
def SphericalTensorsToMatrix(Sptensor):
"""
Reconstructs a 3x3 complex Cartesian matrix from its spherical tensor components.
This function performs the inverse operation of `MatrixToSphericalTensors`. It takes
a dictionary containing spherical tensor components of ranks 0 (isotropic), 1
(antisymmetric), and 2 (symmetric traceless), and reconstructs the corresponding
Cartesian second-rank tensor as a 3x3 complex NumPy array.
Parameters:
-----------
Sptensor : dict
Dictionary containing spherical tensor components with the following keys:
- 'rank0': complex
Scalar representing the isotropic component T(0,0).
- 'rank1': list of 3 complex numbers
Antisymmetric components [T(1,1), T(1,0), T(1,-1)].
- 'rank2': list of 5 complex numbers
Symmetric traceless components [T(2,2), T(2,1), T(2,0), T(2,-1), T(2,-2)].
Returns:
--------
QunObj
A custom object (assumed from context) wrapping a 3x3 complex NumPy array
that represents the reconstructed Cartesian tensor.
Notes:
------
- The spherical to Cartesian transformation follows standard NMR tensor decomposition
conventions, particularly those described in:
- This function assumes `QunObj` is a class or wrapper that accepts a 3x3 complex
NumPy array. Ensure `QunObj` is defined in your codebase or environment.
See Also:
---------
MatrixToSphericalTensors : Function that performs the forward decomposition from a
Cartesian tensor to spherical tensor components.
Reference:
----------
1. Tensors and Rotations in NMR, LEONARD J. MUELLER, https://doi.org/10.1002/cmr.a.20224
"""
T0 = Sptensor["rank0"]
T11, T10, T1m1 = Sptensor["rank1"]
T22, T21, T20, T2m1, T2m2 = Sptensor["rank2"]
# Spherical tensor Basis
TB00 = (-1/np.sqrt(3) ) * np.eye(3)
TB10 = (-1 / np.sqrt(2)) * np.array([[0, 1j, 0], [-1j, 0, 0], [0, 0, 0]])
TB11 = 0.5 * np.array([[0, 0, -1], [0, 0, -1j], [1, 1j, 0]])
TB1m1 = 0.5 * np.array([[0, 0, -1], [0, 0, 1j], [1, -1j, 0]])
TB20 = (1.0 / np.sqrt(6)) * np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 2]])
TB21 = - 0.5 * np.array([[0, 0, 1], [0, 0, 1j], [1, 1j, 0]])
TB2m1 = 0.5 * np.array([[0, 0, 1], [0, 0, -1j], [1, -1j, 0]])
TB22 = 0.5 * np.array([[1, 1j, 0], [1j, -1, 0], [0, 0, 0]])
TB2m2 = 0.5 * np.array([[1, -1j, 0], [-1j, -1, 0], [0, 0, 0]])
A = np.zeros((3, 3), dtype=complex)
# Rank 0 (isotropic)
A = A + T0 * TB00
# Rank 1 (antisymmetric)
A = A + T1m1 * TB1m1
A = A + T10 * TB10
A = A + T11 * TB11
# Rank 2 (symmetric traceless)
A = A + T2m2 * TB2m2
A = A + T2m1 * TB2m1
A = A + T20 * TB20
A = A + T21 * TB21
A = A + T22 * TB22
return QunObj(A)