# -*- coding: utf-8 -*-
"""
This module contains the class :class:`Bfield` which provides methods to represent
and imitate a realistic DC magnetic field.
The main intended purpose of this class is to be part of the :class:`System.System`
in order to include the effect of a megnetic field in dynamics simulations.
"""
import numpy as np
from scipy.constants import c,h,hbar,pi,g,physical_constants
from scipy.constants import k as k_B
from scipy.constants import u as u_mass
import warnings
#%%
[docs]
class Bfield:
def __init__(self,**kwargs):
"""Class defines a magnetic field configuration and methods to turn on
a certain field strength and direction conveniently. When initializing
a new system via `system=System()` a magnetic field instance with zero
field strength is directly included in this System via `system.Bfield`.
Example
-------
>>> B1 = Bfield() # initialize Bfield instance
>>> B1.turnon(strength=5e-4,direction=[0,0,1],angle=60)
>>> print(B1) # print properties
>>> B1.reset() # reset magnetic field to zero.
Parameters
----------
**kwargs
Optional keyword arguments for directly turn on a certain magnetic
field by using these keyword arguments within the the method
:func:`turnon` (further information).
"""
if kwargs: self.turnon(**kwargs)
else: self.reset()
self.mu_B = physical_constants['Bohr magneton'][0]
[docs]
def turnon(self,strength=5e-4,direction=[0,0,1],angle=None,remix_strength=None):
"""Turn on a magnetic field with a certain strength and direction.
Parameters
----------
strength : float or np.ndarray, optional
Strength in Tesla. The default is 5e-4.
direction : list or np.ndarray with shape (3,), optional
Direction of the magnetic field vector. Doesn't have to be given
as normalized array. The default is [0,0,1].
angle : float or np.ndarray, optional
Angle in degrees at which the magnetic field vector is pointing with
respect to the `direction` argument. The default is None.
remix_strength : float, optional
measure of the magnetic field strength (i.e. the magnetic remixing
matrix is multiplied by 10^remix_strength). Reasonable values are
between 6 and 9. The default is None.
"""
if np.any(strength >= 10e-4):
print('WARNING: linear Zeeman shifts are only a good approx for B<10G.')
self.strength = strength
self.direction = np.array(direction) / np.expand_dims(np.linalg.norm(direction,axis=-1),axis=-1)
if np.all(angle != None):
self.angle = angle
self.axisforangle = self.direction
angle = angle/360*2*pi
v1 = self.direction
v_perp = np.cross(v1,np.array([0,1,0]))
if np.all(v_perp == 0.0):
v_perp = np.cross(v1, np.array([1,0,0]))
self.direction = np.tensordot(np.cos(angle), v1, axes=0) \
+ np.tensordot(np.sin(angle), v_perp, axes=0)
[docs]
def turnon_earth(self,vertical='z',towardsNorthPole='x'):
"""Turn on the magnetic field of the earth at Germany with a strength
of approximately 48 uT. The vertical component is 44 uT and the horizontal
component directing towards the North Pole is 20 uT.
Parameters
----------
vertical : str, optional
vertical axis. Supported values are 'x', 'y' or 'z'.
The default is 'z'.
towardsNorthPole : str, optional
horizontal axis directing towards the North Pole. Supported values
are 'x', 'y' or 'z'.The default is 'x'.
"""
axes = {'x' : 0, 'y' : 1, 'z' : 2}
vec = np.zeros(3)
vec[axes[vertical]] = 44e-6
vec[axes[towardsNorthPole]] = 20e-6
self.turnon(strength=np.linalg.norm(vec),direction=vec)
[docs]
def reset(self):
"""Reset the magnetic field to default which is a magnetic field
strength 0.0 and the direction [0.,0.,1.]"""
self.strength, self.direction = 0.0, np.array([0.,0.,1.])
if 'angle' in self.__dict__: del self.angle, self.axisforangle
self._remix_matrix = np.array([[],[]])
[docs]
def get_remix_matrix(self,grs,remix_strength=None):
"""return a matrix to remix all adjacent ground hyperfine levels
by a magnetic field with certain field strength. The default is False.
Parameters
----------
grs : :class:`~Levelsystem.ElectronicGrState`
for which the matrix is to be build.
remix_strength : float
measure of the magnetic field strength (i.e. the magnetic remixing
matrix is multiplied by 10^remix_strength). Reasonable values are
between 6 and 9.
Returns
-------
array
magnetic remixing matrix.
"""
#must be updated!? not only grstates can mix!
# maybe use OBEs muMat for Bfield strength
matr = np.zeros((grs.N,grs.N))
for i in range(grs.N):
for j in range(grs.N):
if grs[i].is_lossstate or grs[j].is_lossstate:
if grs[i].is_lossstate == grs[j].is_lossstate:
matr[i,j] = 1
elif grs[i].is_equal_without_mF(grs[j]) and abs(grs[i].mF-grs[j].mF) <= 1:
matr[i,j] = 1
self._remix_matrix = 10**(remix_strength)*matr
return self._remix_matrix #if remix_strength ==None: estimate it with strength & if strength=0 return empty matrix?
def __str__(self):
return str(self.__dict__)
[docs]
def Bfield_vec(self):
"""Returns the magnetic field vector with its three components in T.
Returns
-------
np.ndarray(3)
magnetic field vector.
"""
return np.tensordot(self.strength,self.direction,axes=0)
@property
def Bvec_sphbasis(self):
"""returns the magnetic field vector in the spherical basis."""
strength, direction = self.strength, np.array(self.direction)
ex,ey,ez = direction.T / np.linalg.norm(direction,axis=-1)
eps = np.array([+(ex - 1j*ey)/np.sqrt(2), ez, -(ex + 1j*ey)/np.sqrt(2)])
eps = np.array([ -eps[2], +eps[1], -eps[0] ])
if type(strength) == np.ndarray: strength = strength[:,None,None]
if type(ex) == np.ndarray: eps = (eps.T)[None,:]
self._Bvec_sphbasis = eps*strength
return self._Bvec_sphbasis
if __name__ == '__main__':
B1 = Bfield() # initialize Bfield instance
B1.turnon(strength=5e-4,direction=[0,0,1],angle=60)
print(B1) # print properties
B1.reset() # reset magnetic field to zero.