def test_icommensurate(self): p = np.array([[0.,0.,0.]]) fc = np.array([[0.,1.j,1.]],dtype=np.complex) k = np.array([0.,0.,0.0]) phi= np.array([0.,]) mu = np.array([0.5,0.,0.]) sc = np.array([1,1,1],dtype=np.int32) latpar = np.diag([2.,2.,2.]) r = 10. #all atoms, i.e. 1 atom nnn = 1 rc=10. nangles=4 c,d,l = lfclib.Fields('i', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,nangles) # N.B.: this rotates with the opposite angle with respect to the # rotate function! np.testing.assert_array_almost_equal(d, np.array([[0,0,-0.92740095], [0,-0.92740095,0], [0,0,0.92740095], [0,0.92740095,0]])) # we have one dipole so Lorentz opposite to dipolar np.testing.assert_array_almost_equal(l, np.array([[0,0,0.92740095E-3], [0,0.92740095E-3,0], [0,0,-0.92740095E-3], [0,-0.92740095E-3,0]]))
def test_null_by_symmetry(self): p = np.array([[0.,0.,0.]]) fc = np.array([[0.,0.,1.]],dtype=np.complex) k = np.array([0.,0.,0.0]) phi= np.array([0.,]) mu = np.array([0.5,0.5,0.5]) sc = np.array([10,10,10],dtype=np.int32) latpar = np.diag([2.,2.,2.]) r = 10. nnn = 2 rc=10. #### simple tests with phase c,d,l = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) np.testing.assert_array_almost_equal(d, np.zeros(3)) # this works with a large grid but then unit testing is slow! # by the way, 1.9098593 is the ratio between cube and sphere # volumes. #np.testing.assert_array_almost_equal(l, np.array([0.,0.,0.92740095/1.9098593])) # # the comparison done below is with the unconverged results that # is obtained in the 10x10x10 supercell np.testing.assert_array_almost_equal(l, np.array([0.,0.,0.46741]),decimal=4) # (2 magnetic_constant/3)⋅1bohr_magneton = ((2 ⋅ magnetic_constant) ∕ 3) ⋅ (1 ⋅ bohr_magneton) # ≈ 7.769376E-27((g⋅m^3) ∕ (A⋅s^2)) # ≈ 7.769376 T⋅Å^3 # np.testing.assert_array_almost_equal(c, np.array([0,0,7.769376]))
def test_one_over_r_cube(self): p = np.array([[0., 0., 0.]]) fc = np.array([[0., 0., 1.]], dtype=np.complex) k = np.array([0., 0., 0.]) phi = np.array([ 0., ]) mu = np.array([0.5, 0.5, 0.5]) sc = np.array([1, 1, 1], dtype=np.int32) latpar = np.diag([2., 2., 2.]) r = 10. nnn = 0 rc = 1. c, d, l = lfcext.Fields('s', p, fc, k, phi, mu, sc, latpar, r, nnn, rc) # zero hyperfine field since zero nnn np.testing.assert_array_equal(c, np.zeros(3)) # this is 0.3333333333⋅magnetic_constant⋅(1 bohr_magneton/(4/3⋅pi⋅(10 angstrom)^3))=9.2740095E-4 tesla np.testing.assert_array_almost_equal(l, np.array([0, 0, 9.2740095E-4])) mu = np.array([0.5, 0., 0.]) c, d, l = lfcext.Fields('s', p, fc, k, phi, mu, sc, latpar, r, nnn, rc) # (1/(4pi))magnetic_constant⋅(1 bohr_magneton/(1 angstrom^3)) = 0.92740095 tesla np.testing.assert_array_almost_equal(d, np.array([0, 0, -0.92740095])) mu2 = np.array([0.654, 0., 0.]) c, d2, l = lfcext.Fields('s', p, fc, k, phi, mu2, sc, latpar, r, nnn, rc) # ratios must be like 1/r^3 np.testing.assert_array_almost_equal( d2, np.array([0, 0, -0.92740095]) * (1. / (np.linalg.norm(mu2 * 2.))**3))
def test_rotate1(self): p = np.array([[0., 0., 0.]]) fc = np.array([[0., 0., 1.]], dtype=np.complex) k = np.array([0., 0., 0.]) phi = np.array([ 0., ]) mu = np.array([0.5, 0.5, 0.5]) sc = np.array([1, 1, 1], dtype=np.int32) latpar = np.diag([2., 2., 2.]) r = 10. nnn = 0 rc = 1. nangles = 10 axis = np.array([0, 0, 1.]) # rotation with axis parallel to local moment c, d, l = lfcext.Fields('r', p, fc, k, phi, mu, sc, latpar, r, nnn, rc, nangles, axis) # this tests that nothing changes since we are rotating with an # axis parallel to the moment direction np.testing.assert_array_almost_equal(np.diff(d, axis=0), np.zeros([9, 3])) mu = np.array([0.5, 0., 0.]) axis = np.array([1., 0., 0.]) nangles = 4 c, d, l = lfcext.Fields('r', p, fc, k, phi, mu, sc, latpar, r, nnn, rc, nangles, axis) np.testing.assert_array_almost_equal( d, np.array([[0, 0, -0.92740095], [0, 0.92740095, 0], [0, 0, 0.92740095], [0, -0.92740095, 0]]))
def test_rotation_of_cart_coord(self): p = np.array([[0.1, 0.2, 0.3]]) fc = np.array([[0.2, 0.4, 1.]], dtype=np.complex) k = np.array([0.2, 0.3, 0.4]) phi = np.array([ 0., ]) mu = np.array([0.5, 0.5, 0.5]) sc = np.array([6, 6, 6], dtype=np.int32) latpar = np.array([[5.7369999886, 0.0, 0.0], [2.2372645948, 8.3929280278, 0.0], [1.9062265066, 0.8564261924, 10.7293797745]]) r = 100000. #sum everything nnn = 4 rc = 6. c, d, l = lfcext.Fields('s', p, fc, k, phi, mu, sc, latpar, r, nnn, rc) #now rotate lattice system and recalculate rmat = rotation_matrix([3., 4., 5.], 1.86) mrmat = rotation_matrix([3., 4., 5.], -1.86) rlatpar = np.zeros_like(latpar) rlatpar[0, :] = np.dot(rmat, latpar[0, :]) rlatpar[1, :] = np.dot(rmat, latpar[1, :]) rlatpar[2, :] = np.dot(rmat, latpar[2, :]) rfc = np.zeros_like(fc) rfc[0] = np.dot(rmat, fc[0]) cr, dr, lr = lfcext.Fields('s', p, rfc, k, phi, mu, sc, rlatpar, r, nnn, rc) np.testing.assert_array_almost_equal(c, np.dot(mrmat, cr)) np.testing.assert_array_almost_equal(d, np.dot(mrmat, dr)) np.testing.assert_array_almost_equal(l, np.dot(mrmat, lr))
def test_phase(self): p = np.array([[0.,0.,0.]]) fc = np.array([[0.,0.,1.]],dtype=np.complex) k = np.array([0.,0.,0.0]) phi= np.array([0.,]) mu = np.array([0.5,0.4,0.3]) sc = np.array([10,10,10],dtype=np.int32) latpar = np.diag([2.,2.,2.]) r = 10. nnn = 1 rc=10. #### simple tests with phase refc,refd,refl = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) refcr,refdr,reflr = lfclib.Fields('r', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,10,np.array([0,1.,0])) phi= np.array([0.25,]) c,d,l = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) np.testing.assert_array_almost_equal(c, np.zeros(3)) np.testing.assert_array_almost_equal(d, np.zeros(3)) np.testing.assert_array_almost_equal(l, np.zeros(3)) c,d,l = lfclib.Fields('r', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,10,np.array([0,1.,0])) np.testing.assert_array_almost_equal(c, np.zeros([10,3])) np.testing.assert_array_almost_equal(d, np.zeros([10,3])) np.testing.assert_array_almost_equal(l, np.zeros([10,3])) phi= np.array([0.5,]) c,d,l = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) np.testing.assert_array_almost_equal(c, -refc) np.testing.assert_array_almost_equal(d, -refd) np.testing.assert_array_almost_equal(l, -refl) c,d,l = lfclib.Fields('r', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,10,np.array([0,1.,0])) np.testing.assert_array_almost_equal(c, -refcr) np.testing.assert_array_almost_equal(d, -refdr) np.testing.assert_array_almost_equal(l, -reflr) #### Check spin density dephased ## ## depending on the phase different magnetic structures are ## obtained. With k=0. only the size is modulated. ## If k = 0.25 one can obtain orders like (for example) ## + 0 - 0 or + + - - p = np.array([[0.,0.,0.]]) fc = np.array([[0.,0.,1.j]],dtype=np.complex) k = np.array([0.,0.,0.0]) phi= np.array([0.125,]) mu = np.array([0.5,0.4,0.]) sc = np.array([10,10,10],dtype=np.int32) latpar = np.diag([2.,2.,2.]) r = 10. nnn = 1 rc=10. refc,refd,refl = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) # no use the equivalent order without phase phi= np.array([0.,]) #pi/4 is sqrt(2)/2 fc = np.array([[0.,0.,np.sqrt(2.)/2.]],dtype=np.complex) c,d,l = lfclib.Fields('s', p,fc,k,phi,mu,sc,latpar,r,nnn,rc) np.testing.assert_array_almost_equal(c, refc) np.testing.assert_array_almost_equal(d, refd) np.testing.assert_array_almost_equal(l, refl) #### now test incommensurate function p = np.array([[0.,0.,0.]]) fc = np.array([[0.,1.j,1.]],dtype=np.complex) k = np.array([0.1,0.,0.0]) phi= np.array([0.125,]) mu = np.array([0.5,0.4,0.1]) sc = np.array([20,20,20],dtype=np.int32) latpar = np.diag([2.,2.,2.]) r = 20. nnn = 1 rc=5. refc,refd,refl = lfclib.Fields('i', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,8) # no use the equivalent order without phase phi= np.array([0.,]) c,d,l = lfclib.Fields('i', p,fc,k,phi,mu,sc,latpar,r,nnn,rc,8) # shifted by one angle (that is the phase) np.testing.assert_array_almost_equal(np.take(c,range(1,9),mode='wrap',axis=0), refc) np.testing.assert_array_almost_equal(np.take(l,range(1,9),mode='wrap',axis=0), refl) np.testing.assert_array_almost_equal(np.take(d,range(1,9),mode='wrap',axis=0), refd)
def locfield(sample, ctype, supercellsize, radius, nnn=2, rcont=10.0, nangles=None, axis=None): """ Evaluates local fields at the muon site. This function gives access to three types of calculations specfified with the option `ctype`: * 'sum': magnetic moments are just summed up to the Lorentz sphere * 'rotate': magnetic moments are rotate `nangles` times around the `axis` axis. * 'incommensurate': this function is particulary useful for incommensurate structures. It performs the sum with the method discussed in PRB XX XXXXXX :param sample: the sample object :param str ctype: calculation type. Can be 'sum', 'rotate' or 'incommensurate' (or abbreviations 's', 'r', 'i'). :param list supercellsize: the size of the supercell along the lattice coordinates. :param float radius: the radius of the sphere used to evaluate the dipolar tensor. :param int nnn: number of local moments nearest neighbours of the muon considered for the contact hyperfine field estimation. Default 2. :param float rcont: maximum radius used to search for local moments close to the muon in the contact hyperfine field estimation in Angstrom. Default 10 Angstrom. :param int nangles: for 'rotate' and 'incommensurate' simulations, a nangles number of estimation will perfomed on local moments incrementally rotated by 360/nangles. :param list axis: for 'rotate' simulations, axis used to perform the rotation. In 'incommensurate' simulations the axis is defined as the perpendicular vector to the real and the imaginary parts of the fourier componts (warnings will be printed if this vector is not well defined). :return: a list of :py:class:`~LocalFields` containing the local field components for each muon site defined in the sample. :rtype: list :raises: TypeError, ValueError """ # check sample is a Sample object if not isinstance(sample, Sample): raise TypeError("sample must be a Sample instance.") if not isstr(ctype): raise TypeError("ctype must be a of type str") # validate input if ctype != 's' and ctype != 'sum' and \ ctype != 'r' and ctype != 'rotate' and \ ctype != 'i' and ctype != 'incommmensurate': raise ValueError("Invalid calculation type.") # if 'i', nangles must be defined if ctype == 'i' or ctype == 'incommmensurate' or \ ctype == 'r' or ctype == 'rotate': if nangles is None: raise ValueError("Number of angles must be specified.") try: nangles = int(nangles) except: raise ValueError("Cannot convert number of angles to int.") if ctype == 'r' or ctype == 'rotate': if axis is None: raise ValueError("Axis for rotation must be specified.") try: axis = np.array(axis) axis = axis / np.linalg.norm(axis) except: raise ValueError("Cannot convert axis for rotation to np.ndarray.") try: sc = np.array(supercellsize, dtype=np.int32) except: raise TypeError("Cannot convert supercellsize to NumPy array.") if (np.min(sc) <= 0): raise ValueError("Supercellsize must be strictly positive.") if sc.shape != (3, ): raise ValueError("Propagation vector has the wrong shape.") try: r = float(radius) # Lorentz radius (in A) except: raise TypeError("Cannot convert radius to float.") try: nnn = int(nnn) except: raise TypeError("Cannot convert nnn to int.") if nnn < 0: raise ValueError("nnn must be positive.") rc = 0 try: rc = float(rcont) except: raise TypeError("Cannot convert rcont to float.") if rc < 0: raise ValueError("rcont must be positive.") # check current status is ok sample._check_lattice() sample._check_magdefs() # Remove non magnetic atoms from list unitcell = sample._cell positions = unitcell.get_scaled_positions() latpar = unitcell.get_cell() ufc = sample.mm.fc magnetic_atoms = [] for i, e in enumerate(ufc): if not np.allclose(e, np.zeros(3, dtype=np.complex)): magnetic_atoms.append(i) p = positions[magnetic_atoms, :] fc = ufc[magnetic_atoms, :] phi = sample.mm.phi[magnetic_atoms] # phase in magnetic order definition k = sample.mm.k res = [] # if is outside for (minimal) sake of performances for mu in sample.muons: if ctype == 's' or ctype == 'sum': res.append( LocalFields(*lfcext.Fields(ctype, p, fc, k, phi, mu, sc, latpar, r, nnn, rc))) elif ctype == 'i' or ctype == 'incommensurate': res.append( LocalFields(*lfcext.Fields(ctype, p, fc, k, phi, mu, sc, latpar, r, nnn, rc, nangles))) elif ctype == 'r' or ctype == 'rotate': res.append( LocalFields(*lfcext.Fields(ctype, p, fc, k, phi, mu, sc, latpar, r, nnn, rc, nangles, axis))) return res