Source code for magnumnp.field_terms.spintorque

#
# This file is part of the magnum.np distribution
# (https://gitlab.com/magnum.np/magnum.np).
# Copyright (c) 2023 magnum.np team.
#
# 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, version 3.
#
# 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 <http://www.gnu.org/licenses/>.
#

from magnumnp.common import timedmethod, constants
import torch

__all__ = ["SpinOrbitTorque", "SpinTorqueZhangLi", "SpinTorqueSlonczewski"]

#TODO: generalize interface (ZhangLi uses state.j, SOT uses material["je"]
[docs] class SpinOrbitTorque(object): r""" General spin torque contributions can be described by the following field .. math:: \vec{h}^\text{sot} = -\frac{j_e \hbar}{2 e \mu_0 M_s} \left[\eta_\text{damp} \, \vec{m} \times \vec{p} + \eta_\text{field} \, \vec{p} \right], with the current density :math:`j_e`, the reduced Planck constant :math:`\hbar`, the elementary charge :math:`e`, and the polarization of the electrons :math:`\vec{p}`. :math:`\eta_\text{damp}` and :math:`\eta_\text{field}` are material parameters which describe the amplitude of damping- and field-like torque. In case of Spin-Orbit-Torqe (SOT) :math:`\eta_\text{field}` and :math:`\eta_\text{damp}` are constant material parameters. """ @timedmethod @torch.compile def h(self, state): p = state.material["p"].expand_as(state.m) h = state.material["eta_damp"] * torch.linalg.cross(state.m, p) + state.material["eta_field"] * p h *= -state.material["je"] * constants.hbar / (2. * constants.e * state.material["Ms"] * constants.mu_0 * state.material["d"]) return h.nan_to_num(posinf=0, neginf=0) def E(self, state): raise NotImplemented()
[docs] class SpinTorqueZhangLi(object): r""" Zhang Lie spin torque contributions can be described by the following field .. math:: \vec{h}^\text{stt,zl} = \frac{b}{\gamma} \left[\vec{m} \times (\vec{j}_e \cdot \nabla) \vec{m} + \xi \; (\vec{j}_e \cdot \nabla) \vec{m} \right], with the reduced gyromagnetic ratio :math:`\gamma`, the degree of nonadiabacity :math:`\xi`. :math:`b` is the polarization rate of the conducting electrons and can be written as .. math:: b = \frac{\beta \mu_B}{e M_s (1+\xi^2)}, with the Bohr magneton :math:`\mu_B`, and the dimensionless polarization rate :math:`\beta`. """ @timedmethod @torch.compile def h(self, state): dim = [i for i in range(3) if state.mesh.n[i] > 1] dx = [state.mesh.dx[i] for i in range(3) if state.mesh.n[i] > 1] j = state.j # (state.t) TODO: allow time-dependent j jgradm = torch.einsum('...a,...ba-> ...b', j[...,dim], torch.stack(torch.gradient(state.m, spacing=dx, dim=dim), dim=-1)) # matmult return state.material["b"] / constants.gamma * (torch.linalg.cross(state.m, jgradm) + state.material["xi"] * jgradm) def E(self, state): raise NotImplemented()
[docs] class SpinTorqueSlonczewski(object): r""" Slonczewski spin torque contributions can be described by the following field: .. math:: \vec{h}^\text{stt,slonczewski} = \beta \left[ \epsilon (\vec{m} \times \vec{p}_\text{p}) + \epsilon' \vec{p}_\text{p} \right], with the polarization vector of the conducting electrons :math:`\vec{p}_\text{p}` and the secondary spin torque efficiency :math:`\epsilon'`. The :math:`\beta` is given by current density :math:`J`, the thickness of the fixed layer :math:`d` (default using the thickness of the mesh), the reduced Planck constant :math:`\hbar`, the elementary charge :math:`e`, the permeability of free space :math:`\mu_0`, .. math:: \beta = \frac{\hbar J} {e M_s d \mu_0}, The :math:`\epsilon` is computed by assuming both the fixed layer and free layer have the same spin polarization :math:`P` and the spin diffusion length :math:`\Lambda`: across the spacer layer .. math:: \epsilon = \frac{P \Lambda^2} {(\Lambda^2 + 1) + (\Lambda^2 - 1) \vec{m} \cdot \vec{p}_\text{p}}. """ @timedmethod @torch.compile def h(self, state): mp = state.material["mp"] Lambda = state.material["Lambda"] # use thickness of mesh if not provided if state.material["d"] is None: d = state.mesh.dx[2] else: d = state.material["d"] epsilon = state.material["P"] * Lambda**2 / ((Lambda**2 + 1) + ((Lambda**2 - 1) * (state.m*mp).sum(axis = 3, keepdim=True))) mxp = torch.linalg.cross(state.m, mp) h = epsilon * mxp + state.material["epsilon_prime"] * mp h *= constants.hbar * state.material["J"] / (constants.mu_0 * state.material["Ms"] * constants.e * d) return h.nan_to_num(posinf=0, neginf=0) def E(self, state): raise NotImplemented()