Source code for magnopy._local_rf

# ================================== LICENSE ===================================
# Magnopy - Python package for magnons.
# Copyright (C) 2023-2025 Magnopy Team
#
# e-mail: anry@uv.es, web: magnopy.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# ================================ END LICENSE =================================


import numpy as np

# Save local scope at this moment
old_dir = set(dir())
old_dir.add("old_dir")


[docs] def span_local_rf(direction_vector, hybridize=False): r""" Span local right-handed reference frame based on the direction vector. Parameters ---------- direction_vector : (3, ) |array-like|_ Direction of the z axis of the local reference frame. hybridize : bool, default False * If ``hybridize == True``, then returns ``p_alpha, z_alpha``. * If ``hybridize == False``, then returns ``x_alpha, y_alpha, z_alpha``. Returns ------- x_alpha : (3, ) :numpy:`ndarray` y_alpha : (3, ) :numpy:`ndarray` p_alpha : (3, ) :numpy:`ndarray` ``p_alpha = x_alpha + 1j * y_alpha``. z_alpha : (3, ) :numpy:`ndarray` See Also -------- span_local_rfs Examples -------- Two special cases are handled as .. doctest:: >>> import magnopy >>> x, y, z = magnopy.span_local_rf([0, 0, 1]) >>> x array([1., 0., 0.]) >>> y array([0., 1., 0.]) >>> z array([0., 0., 1.]) >>> p, z = magnopy.span_local_rf([0, 0, 1], hybridize=True) >>> p array([1.+0.j, 0.+1.j, 0.+0.j]) >>> z array([0., 0., 1.]) .. doctest:: >>> import magnopy >>> x, y, z = magnopy.span_local_rf([0, 0, -1]) >>> x array([ 0., -1., 0.]) >>> y array([-1., 0., 0.]) >>> z array([ 0., 0., -1.]) >>> p, z = magnopy.span_local_rf([0, 0, -1], hybridize=True) >>> p array([ 0.-1.j, -1.+0.j, 0.+0.j]) >>> z array([ 0., 0., -1.]) For the arbitrary direction the global reference frame is rotated as a whole .. doctest:: >>> import magnopy >>> x, y, z = magnopy.span_local_rf([1, 1, 1]) >>> x array([ 0.78867513, -0.21132487, -0.57735027]) >>> y array([-0.21132487, 0.78867513, -0.57735027]) >>> z array([0.57735027, 0.57735027, 0.57735027]) >>> p, z = magnopy.span_local_rf([1, 1, 1], hybridize=True) >>> p array([ 0.78867513-0.21132487j, -0.21132487+0.78867513j, -0.57735027-0.57735027j]) >>> z array([0.57735027, 0.57735027, 0.57735027]) """ direction_vector = np.array(direction_vector, dtype=float) if np.allclose(direction_vector, np.zeros(3)): raise ValueError("Zero vector.") direction_vector /= np.linalg.norm(direction_vector) if np.allclose(direction_vector, [0, 0, 1]): x_alpha = np.array([1, 0, 0], dtype=float) y_alpha = np.array([0, 1, 0], dtype=float) elif np.allclose(direction_vector, [0, 0, -1]): x_alpha = np.array([0, -1, 0], dtype=float) y_alpha = np.array([-1, 0, 0], dtype=float) else: z_dir = [0, 0, 1] sin_rot_angle = np.linalg.norm(np.cross(z_dir, direction_vector)) cos_rot_angle = np.dot(z_dir, direction_vector) # direction_vector and z_dir are unit vectors ux, uy, uz = np.cross(z_dir, direction_vector) / sin_rot_angle x_alpha = np.array( [ ux**2 * (1 - cos_rot_angle) + cos_rot_angle, ux * uy * (1 - cos_rot_angle) + uz * sin_rot_angle, ux * uz * (1 - cos_rot_angle) - uy * sin_rot_angle, ] ) y_alpha = np.array( [ ux * uy * (1 - cos_rot_angle) - uz * sin_rot_angle, uy**2 * (1 - cos_rot_angle) + cos_rot_angle, uy * uz * (1 - cos_rot_angle) + ux * sin_rot_angle, ] ) if hybridize: return x_alpha + 1j * y_alpha, direction_vector return x_alpha, y_alpha, direction_vector
[docs] def span_local_rfs(directional_vectors, hybridize=False): r""" Span a series of local right-handed reference frames based on a series of the direction vectors. Parameters ---------- direction_vectors : (M, 3) |array-like|_ Direction of the z axis of the local reference frames. hybridize : bool, default False * If ``hybridize == True``, then returns ``p_alphas, z_alphas``. * If ``hybridize == False``, then returns ``x_alphas, y_alphas, z_alphas``. Returns ------- x_alphas : (M, 3) :numpy:`ndarray` y_alphas : (M, 3) :numpy:`ndarray` p_alphas : (M, 3) :numpy:`ndarray` ``p_alpha = x_alpha + 1j * y_alpha``. z_alphas : (M, 3) :numpy:`ndarray` See Also -------- span_local_rf Examples -------- .. doctest:: >>> import magnopy >>> x, y, z = magnopy.span_local_rfs([[0, 0, 1], [0, 0, -1], [1, 1, 1]]) >>> x array([[ 1. , 0. , 0. ], [ 0. , -1. , 0. ], [ 0.78867513, -0.21132487, -0.57735027]]) >>> y array([[ 0. , 1. , 0. ], [-1. , 0. , 0. ], [-0.21132487, 0.78867513, -0.57735027]]) >>> z array([[ 0. , 0. , 1. ], [ 0. , 0. , -1. ], [ 0.57735027, 0.57735027, 0.57735027]]) """ results = [] for directional_vector in directional_vectors: results.append( span_local_rf(direction_vector=directional_vector, hybridize=hybridize) ) results = np.array(results) if hybridize: return results[:, 0], results[:, 1] return results[:, 0], results[:, 1], results[:, 2]
# Populate __all__ with objects defined in this file __all__ = list(set(dir()) - old_dir) # Remove all semi-private objects __all__ = [i for i in __all__ if not i.startswith("_")] del old_dir