def sundials_rhs(self, t, y, ydot): self.t = t # already synchronized when call this funciton # self.spin[:]=y[:] self.compute_effective_field(t) if self.update_j_fun is not None: clib.compute_stt_field(self.spin, self.field_stt, self._jx * self.update_j_fun(t), self._jy * self.update_j_fun(t), self.mesh.dx * self.mesh.unit_length, self.mesh.dy * self.mesh.unit_length, self.mesh.nx, self.mesh.ny, self.mesh.nz, self.xperiodic, self.yperiodic) else: clib.compute_stt_field(self.spin, self.field_stt, self._jx, self._jy, self.mesh.dx * self.mesh.unit_length, self.mesh.dy * self.mesh.unit_length, self.mesh.neighbours, self.n) clib.compute_llg_stt_rhs(ydot, self.spin, self.field, self.field_stt, self.alpha, self.beta, self.u0 * self.p / self.Ms_const, self.gamma, self.n)
def sundials_rhs(self, t, y, ydot): self.t = t # already synchronized when call this funciton # self.spin[:]=y[:] self.compute_effective_field(t) if self.update_j_fun is not None: clib.compute_stt_field(self.spin, self.field_stt, self._jx * self.update_j_fun(t), self._jy * self.update_j_fun(t), self._jz * self.update_j_fun(t), self.mesh.dx * self.mesh.unit_length, self.mesh.dy * self.mesh.unit_length, self.mesh.dz * self.mesh.unit_length, self.mesh.neighbours, self.n ) else: clib.compute_stt_field(self.spin, self.field_stt, self._jx, self._jy, self._jz, self.mesh.dx * self.mesh.unit_length, self.mesh.dy * self.mesh.unit_length, self.mesh.dz * self.mesh.unit_length, self.mesh.neighbours, self.n ) clib.compute_llg_stt_rhs(ydot, self.spin, self.field, self.field_stt, self._alpha, self.beta, self.u0 * self.p / self.Ms_const, self.gamma, self.n)
def test_sst_field_1d(): """ This is a direct test of the STT C library We create a 1-D 4 spins system along the x direction with the following components: s_x s_y s_z spin [[ 0. 4. 8. ] i = 0 [ 0.8 5. 9. ] i = 1 [ 2. 6. 10. ] i = 2 [ 2.1 7. 11. ]] i = 3 Most of the STT parameters are set to zero, so the field is reduced to the calculation of: H_STT = j \cdot \nabla S = ( jx * d S_x / dx + jy * d S_x / dy , jx * d S_y / dx + jy * d S_y / dy , 0) Therefore, the x component of the field for the 1th spin, for example, would be: H_STTx (i=1) = jx * d S_x (i=1) / dx + 0 = [ S_x (i=2) - S_x (i=0) ] / 2 * dx = ( 2 - 0 ) / 2 = 1 since jx = dx = 1 and the derivatives along y are zero (1D spin chain) The first test is the spin chain without PBC and the second test is using PBCs, so the neighbours matrix changes ** Without PBC: At the extremes, the derivative has a different discretisation (using only the right or left neighbour and centered at the spin) which, for the 0th spin, for instance, is H_STTx (i=0) = jx * d S_x (i=0) / dx + 0 = [ S_x (i=1) - S_x (i=0) ] / dx = ( 0.8 - 0 ) = 0.8 For further details, see: fidimag/atomistic/lib/stt.c With PBC: The derivatives at the extremes are performed with the periodic neighbour, e.g. for the 0th spin, the NN at -x is the 3th spin """ # The system is 1d with 4 spins. nx, ny, nz = 4, 1, 1 n = nx * ny * nz dx, dy, dz = 1, 1, 1 # NO PBCs ----------------------------------------------------------------- # We can manually construct the neighbours matrix, # the neighbours order is [-x, +x, -y, +y, -z, +z] # Since there are no PBCs, for the 0th spin, i.e. ngbs[0], # the left (-x) NN is -1 and for the 3th spin, the +x NN is -1 # Also, since it is a 1D chain, there are no NNs in y or z ngbs = [[-1, 1, -1, -1, -1, -1], [0, 2, -1, -1, -1, -1], [1, 3, -1, -1, -1, -1], [2, -1, -1, -1, -1, -1], ] ngbs = np.array(ngbs, dtype=np.int32) nxyz = nx * ny * nz * 3 # The spin values to get the matrix: # # [[ 0. 4. 8. ] # [ 1 5. 9. ] # [ 2. 6. 10. ] # [ 3 7. 11. ]] spin = np.array([1.0 * i for i in range(nxyz)]).reshape((-1, 3), order='F').flatten() field = np.zeros(nxyz) jx = np.zeros(nxyz) jy = np.zeros(nxyz) jz = np.zeros(nxyz) jx[:] = 1 jy[:] = 2 # Modify the x components of the spins to get the values # specified in the problem description spin[3 * 1] = 0.8 spin[3 * 2] = 2 spin[3 * 3] = 2.1 # print spin.reshape(-1, 3) clib.compute_stt_field(spin, field, jx, jy, jz, dx, dy, dz, ngbs, n ) # print field assert field[3 * 0] == 0.8 assert field[3 * 1] == 1 assert field[3 * 2] == 0.65 assert abs(field[3 * 3] - 0.1) < 1e-16 # PBCs -------------------------------------------------------------------- # Now we make PBCs in the x direction so the -x NN for # the 0th spin is the 3rd spin, and the opposite way for the 3rd spin ngbs = [[3, 1, -1, -1, -1, -1], [0, 2, -1, -1, -1, -1], [1, 3, -1, -1, -1, -1], [2, 0, -1, -1, -1, -1], ] ngbs = np.array(ngbs, dtype=np.int32) clib.compute_stt_field(spin, field, jx, jy, jz, dx, dy, dz, ngbs, n ) # print field assert field[3 * 0] == -0.65 assert field[3 * 3] == -1
def test_sst_field_1d(): """ This is a direct test of the STT C library We create a 1-D 4 spins system along the x direction with the following components: s_x s_y s_z spin [[ 0. 4. 8. ] i = 0 [ 0.8 5. 9. ] i = 1 [ 2. 6. 10. ] i = 2 [ 2.1 7. 11. ]] i = 3 Most of the STT parameters are set to zero, so the field is reduced to the calculation of: H_STT = j \cdot \nabla S = ( jx * d S_x / dx + jy * d S_x / dy , jx * d S_y / dx + jy * d S_y / dy , 0) Therefore, the x component of the field for the 1th spin, for example, would be: H_STTx (i=1) = jx * d S_x (i=1) / dx + 0 = [ S_x (i=2) - S_x (i=0) ] / 2 * dx = ( 2 - 0 ) / 2 = 1 since jx = dx = 1 and the derivatives along y are zero (1D spin chain) The first test is the spin chain without PBC and the second test is using PBCs, so the neighbours matrix changes ** Without PBC: At the extremes, the derivative has a different discretisation (using only the right or left neighbour and centered at the spin) which, for the 0th spin, for instance, is H_STTx (i=0) = jx * d S_x (i=0) / dx + 0 = [ S_x (i=1) - S_x (i=0) ] / dx = ( 0.8 - 0 ) = 0.8 For further details, see: fidimag/atomistic/lib/stt.c With PBC: The derivatives at the extremes are performed with the periodic neighbour, e.g. for the 0th spin, the NN at -x is the 3th spin """ # The system is 1d with 4 spins. nx, ny, nz = 4, 1, 1 n = nx * ny * nz dx, dy = 1, 1 # NO PBCs ----------------------------------------------------------------- # We can manually construct the neighbours matrix, # the neighbours order is [-x, +x, -y, +y, -z, +z] # Since there are no PBCs, for the 0th spin, i.e. ngbs[0], # the left (-x) NN is -1 and for the 3th spin, the +x NN is -1 # Also, since it is a 1D chain, there are no NNs in y or z ngbs = [[-1, 1, -1, -1, -1, -1], [0, 2, -1, -1, -1, -1], [1, 3, -1, -1, -1, -1], [2, -1, -1, -1, -1, -1], ] ngbs = np.array(ngbs, dtype=np.int32) nxyz = nx * ny * nz * 3 # The spin values to get the matrix: # # [[ 0. 4. 8. ] # [ 1 5. 9. ] # [ 2. 6. 10. ] # [ 3 7. 11. ]] spin = np.array([1.0 * i for i in range(nxyz)]).reshape((-1, 3), order='F').flatten() field = np.zeros(nxyz) jx = np.zeros(nxyz) jy = np.zeros(nxyz) jx[:] = 1 jy[:] = 2 # Modify the x components of the spins to get the values # specified in the problem description spin[3 * 1] = 0.8 spin[3 * 2] = 2 spin[3 * 3] = 2.1 # print spin.reshape(-1, 3) clib.compute_stt_field(spin, field, jx, jy, dx, dy, ngbs, n ) # print field assert field[3 * 0] == 0.8 assert field[3 * 1] == 1 assert field[3 * 2] == 0.65 assert abs(field[3 * 3] - 0.1) < 1e-16 # PBCs -------------------------------------------------------------------- # Now we make PBCs in the x direction so the -x NN for # the 0th spin is the 3rd spin, and the opposite way for the 3rd spin ngbs = [[3, 1, -1, -1, -1, -1], [0, 2, -1, -1, -1, -1], [1, 3, -1, -1, -1, -1], [2, 0, -1, -1, -1, -1], ] ngbs = np.array(ngbs, dtype=np.int32) clib.compute_stt_field(spin, field, jx, jy, dx, dy, ngbs, n ) # print field assert field[3 * 0] == -0.65 assert field[3 * 3] == -1