soprano.nmr.utils#
Utility functions for NMR-related properties
- soprano.nmr.utils._J_constant(Kij, gi, gj)[source]#
J coupling constants for pairs ij, with reduced constant Kij and gyromagnetic ratios gi and gj
- Return type:
FloatOrArray
- soprano.nmr.utils._anisotropy(haeb_evals, reduced=False)[source]#
Calculate anisotropy given eigenvalues sorted with Haeberlen convention
- Return type:
FloatOrArray
- soprano.nmr.utils._dip_constant(Rij, gi, gj)[source]#
Dipolar constants for pairs ij, with distances Rij and gyromagnetic ratios gi and gj
- Return type:
FloatOrArray
- soprano.nmr.utils._dip_tensor(d, r, rotation_axis=None)[source]#
Full dipolar tensor given a constant and a connecting vector
- soprano.nmr.utils._ensure_tensor_format(tensors)[source]#
Ensure tensors are in 3x3 format, converting from flattened 1x9 if necessary.
- Parameters:
tensors (np.ndarray) – Tensor array, either (N, 3, 3) or (N, 9)
- Returns:
Tensors in (N, 3, 3) format
- Return type:
np.ndarray
- soprano.nmr.utils._equivalent_euler(euler_angles, passive=False)[source]#
Find the equivalent Euler angles for a given set of Euler angles.
This set should be correct for NMR tensors, according to TensorView for MATLAB: [6]
- Parameters:
euler_angles (ndarray)
passive (bool)
- Return type:
ndarray
- soprano.nmr.utils._equivalent_relative_euler(euler_angles, passive=False)[source]#
Returns a list of 16 equivalent relative Euler angles for a given set of Euler angles that corresponds to the relative orientation of two NMR tensors. See TensorView for MATLAB: [6]
- Parameters:
euler_angles (ndarray)
passive (bool)
- Return type:
ndarray
- soprano.nmr.utils._evals_sort(evals, convention='i', return_indices=False)[source]#
Sort a list of eigenvalue triplets by various conventions
The sorting conventions are: - i: increasing order - d: decreasing order - h: Haeberlen order - n: NQR order (absolute values)
- Parameters:
evals (np.ndarray) – Array of eigenvalue triplets to sort.
convention (str) – The sorting convention to use (‘i’, ‘d’, ‘h’, ‘n’).
return_indices (bool) – Whether to return the sorting indices.
Returns – Union[np.ndarray, tuple[np.ndarray, np.ndarray]]: Sorted eigenvalues, and optionally the sorting indices.
- Return type:
ndarray | tuple[ndarray, ndarray]
- soprano.nmr.utils._evecs_2_quat(evecs)[source]#
Convert a set of eigenvectors to a Quaternion expressing the rotation of the tensor’s PAS with respect to the Cartesian axes
- soprano.nmr.utils._get_tensor_array(s, tensor_tag)[source]#
Get tensor array from structure, ensuring 3x3 format.
- Parameters:
s (Atoms) – The structure
tensor_tag (str) – Name of the tensor array
- Returns:
Tensor array in (N, 3, 3) format
- Return type:
np.ndarray
- Raises:
RuntimeError – If tensor array not found
- soprano.nmr.utils._gradients_to_list(gradients, elements)[source]#
Convert gradients input to a list with one value per element in elements.
Parameters: gradients (Union[float, dict[str, float], list[float]]): The gradients input, which can be a float, a dictionary, or a list. elements (list[str]): The list of elements.
Returns: Optional[list[Optional[float]]]: A list of gradients corresponding to the elements, or None if gradients is None.
Raises: ValueError: If the gradients input is not a float, dictionary, or list, or if the length of the gradients list does not match the length of elements.
- Parameters:
gradients (float | dict[str, float] | list[float])
elements (list[str])
- Return type:
list[float]
- soprano.nmr.utils._handle_euler_edge_cases(euler_angles, eigenvalues, original_tensor, convention='zyz', passive=False, eps=1e-06)[source]#
Handle edge cases in the Euler angle conventions for degenerate tensors.
- Parameters:
euler_angles (np.ndarray) – Euler angles in radians
eigenvalues (np.ndarray) – Eigenvalues of the tensor
original_tensor (np.ndarray) – Original symmetric tensor
convention (str, optional) – Euler angle convention. Defaults to “zyz”.
eps (float, optional) – Tolerance for degeneracy. Defaults to 1e-6.
passive (bool)
- soprano.nmr.utils._matrix_to_euler(R, convention='zyz', passive=False)[source]#
Convert an NMR tensor eigenframe matrix to NMR-canonical Euler angles (in radians).
NMR-specific function. This function is designed for use with NMR tensor eigenframes, where eigenvector signs are physically arbitrary. It applies
_normalise_euler_angles()after extracting angles from scipy, which restricts β to [0, π/2] by exploiting the sign freedom of eigenvectors. This transformation does not preserve a general rotation matrix: for arbitrary rotations with β > π/2 the returned angles reconstruct a different matrix. Do not use this function for general rotation matrices.SciPy’s upper-case convention strings denote intrinsic rotations; all input convention strings are converted to upper case so the behaviour is always intrinsic.
- Parameters:
R (list[list[float]] | ndarray) – Rotation matrix (3×3), typically the eigenvector matrix of an NMR tensor. Array-like inputs are accepted. If
det(R) < 0, the last column is negated before proceeding. For eigenvector matrices this is valid because eigenvector signs are arbitrary; for general improper rotations it is not the nearest proper rotation in a metric sense.convention (str) – Euler-angle convention, e.g.
"zyz"or"zxz". Converted to upper case internally. Defaults to"zyz".passive (bool) – If
True, return the passive (alias) angles, i.e. those describing the rotation of the coordinate frame rather than the object. Defaults toFalse.
- Returns:
NMR-canonical Euler angles in radians, shape
(3,).- Return type:
np.ndarray
- soprano.nmr.utils._normalise_euler_angles(euler_angles, passive=False, eps=1e-06)[source]#
Normalise Euler angles to standard ranges for NMR as defined in: TensorView for MATLAB [6]
- Parameters:
euler_angles (np.ndarray) – Euler angles in radians
passive (bool, optional) – Whether the angles are passive rotations. Defaults to False.
eps (float, optional) – Tolerance for degeneracy. Defaults to 1e-6.
- Return type:
ndarray
- soprano.nmr.utils._references_to_list(references, elements)[source]#
Convert references input to a list with one value per element in elements.
Parameters: references (Union[None, dict[str, float], list[float]]): The references input, which can be None, a dictionary, or a list. elements (list[str]): The list of elements.
Returns: Optional[list[Optional[float]]]: A list of references corresponding to the elements, or None if references is None.
Raises: ValueError: If the references input is not None, a dictionary, or a list, or if the length of the references list does not match the length of elements.
- Parameters:
references (None | dict[str, float] | list[float])
elements (list[str])
- Return type:
list[float | None]
- soprano.nmr.utils._skew(evals)[source]#
Calculate skew
\[\kappa = 3 (\sigma_{iso} - \sigma_{22}) / \Omega\]where \(\Omega\) is the span of the tensor.
Note that for chemical shift tensors (\(\delta\)), the sign is reversed.
- Return type:
FloatOrArray
- soprano.nmr.utils._span(evals)[source]#
Calculate span
\[\Omega = \sigma_{33} - \sigma_{11}\]where \(\sigma_{33}\) is the largest, and \(\sigma_{11}\) is the smallest eigenvalue.
- Return type:
FloatOrArray
- soprano.nmr.utils._split_species(species)[source]#
Validate the species string and extract the isotope number and element.
- Parameters:
species (str) – The species string to validate. e.g. ‘13C’ or ‘1H’.
- Returns:
A tuple containing the isotope number (int), and element symbol (str, such as ‘C’ or ‘H’).
- Return type:
tuple
- soprano.nmr.utils._test_euler_rotation(euler_angles, eigenvalues, eigenvecs, convention='zyz', passive=False, eps=1e-06)[source]#
Test that the Euler angles correctly rotate the tensor.
We compare the tensor rotated by the Euler angles to that you get by rotating the tensor with the rotation matrix corresponding to the Euler angles. i.e.
PAS = np.diag(eigenvalues) R = Rotation.from_euler(convention, euler_angles).as_matrix() A_rot = np.dot(R, np.dot(PAS, R.T))
B_rot = np.dot(eigenvecs, np.dot(PAS, eigenvecs.T))
- Parameters:
euler_angles (np.ndarray) – Euler angles in radians
eigenvalues (np.ndarray) – Eigenvalues of the tensor
eigenvecs (np.ndarray) – Eigenvectors of the tensor
convention (str, optional) – Euler angle convention. Defaults to “zyz”.
passive (bool, optional) – Whether the angles are passive rotations. Defaults to False.
eps (float, optional) – Tolerance for degeneracy. Defaults to 1e-6.
- Returns:
True if the Euler angles correctly rotate the tensor. False otherwise.
- Return type:
bool
- soprano.nmr.utils._tryallanglestest(euler_angles, pas1, pasv2, arel1, convention, eps=0.001)[source]#
For relative Euler angles from tensor A to B, if B is axially symmetric, we need to try all equivalent Euler angles of the symmetric tensor to find the conventional one.
Go through the 4 equivalent passive angles since we’re using the trick of calculating the A relative angles in the frame of B by calculating the B relative angles in the frame of A with the passive convention.
Credit: function adapted from TensorView for MATLAB: [6]
- Parameters:
euler_angles (ndarray)
pas1 (ndarray)
pasv2 (ndarray)
arel1 (ndarray)
convention (str)
eps (float)
- Return type:
ndarray