def test_composition(self): nu, nv, nw, n_atm = 2, 3, 4, 2 np.random.seed(13) c = 0.7 A_r = occupational.composition(nu, nv, nw, n_atm, value=c) delta = c * (1 + A_r) sigma = 2 * delta - 1 np.testing.assert_array_almost_equal(sigma, (2 * (A_r > 0) - 1)) np.random.seed(13) u = np.random.rand(nu, nv, nw, n_atm) np.testing.assert_array_almost_equal(delta, u.flatten() <= c) c = np.array([0.6, 0.4]) A_r = occupational.composition(nu, nv, nw, n_atm, value=c) delta = (c * (1 + A_r.reshape(nu, nv, nw, n_atm))).flatten() sigma = 2 * delta - 1 np.testing.assert_array_almost_equal(sigma, (2 * (A_r > 0) - 1))
def test_transform(self): nu, nv, nw, n_atm = 2, 3, 4, 2 np.random.seed(13) c = 0.7 A_r = occupational.composition(nu, nv, nw, n_atm, value=c) H = np.random.randint(0, 4 * nu, size=(16)) K = np.random.randint(0, 5 * nv, size=(16)) L = np.random.randint(0, 6 * nw, size=(16)) A_k, i_dft = occupational.transform(A_r, H, K, L, nu, nv, nw, n_atm) A_r = A_r.reshape(nu, nv, nw, n_atm) A_k = A_k.reshape(nu, nv, nw, n_atm) n_uvw = nu * nv * nw np.testing.assert_array_almost_equal(A_k[0,0,0,:], \ np.mean(A_r, axis=(0,1,2))*n_uvw) w = i_dft % nw v = i_dft // nw % nv u = i_dft // nw // nv % nu np.testing.assert_array_equal(u, np.mod(H, nu)) np.testing.assert_array_equal(v, np.mod(K, nv)) np.testing.assert_array_equal(w, np.mod(L, nw))
def test_transform(self): nu, nv, nw, n_atm = 2, 3, 4, 2 np.random.seed(13) c = 0.1 Ux, Uy, Uz = displacive.expansion(nu, nv, nw, n_atm, value=c) c = 0.7 A_r = occupational.composition(nu, nv, nw, n_atm, value=c) H = np.random.randint(0, 4 * nu, size=(16)) K = np.random.randint(0, 5 * nv, size=(16)) L = np.random.randint(0, 6 * nw, size=(16)) p = 2 U_r = displacive.products(Ux, Uy, Uz, p) n_prod = U_r.shape[0] // (nu * nv * nw * n_atm) U_k, A_k, i_dft = nonmagnetic.transform(U_r, A_r, H, K, L, nu, nv, nw, n_atm) A_r = np.tile(A_r, n_prod) U_r = U_r.reshape(n_prod, nu, nv, nw, n_atm) A_r = A_r.reshape(n_prod, nu, nv, nw, n_atm) U_k = U_k.reshape(n_prod, nu, nv, nw, n_atm) A_k = A_k.reshape(n_prod, nu, nv, nw, n_atm) n_uvw = nu * nv * nw V_r = U_r * A_r np.testing.assert_array_almost_equal(U_k[:,0,0,0,:], \ np.mean(U_r, axis=(1,2,3))*n_uvw) np.testing.assert_array_almost_equal(A_k[:,0,0,0,:], \ np.mean(V_r, axis=(1,2,3))*n_uvw) w = i_dft % nw v = i_dft // nw % nv u = i_dft // nw // nv % nu np.testing.assert_array_equal(u, np.mod(H, nu)) np.testing.assert_array_equal(v, np.mod(K, nv)) np.testing.assert_array_equal(w, np.mod(L, nw))
def test_disordered(self): folder = os.path.abspath(os.path.join(directory, '..', 'data')) uc_dict = crystal.unitcell(folder=folder, filename='CaTiOSiO4.cif', tol=1e-4) u = uc_dict['u'] v = uc_dict['v'] w = uc_dict['w'] occ = uc_dict['occupancy'] disp = uc_dict['displacement'] mom = uc_dict['moment'] atm = uc_dict['atom'] n_atm = uc_dict['n_atom'] nu, nv, nw = 2, 3, 4 constants = crystal.parameters(folder=folder, filename='CaTiOSiO4.cif') A = crystal.cartesian(*constants) C = crystal.cartesian_moment(*constants) D = crystal.cartesian_displacement(*constants) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) U11, U22, U33, U23, U13, U12 = disp.T U = np.row_stack(displacive.cartesian(U11, U22, U33, U23, U13, U12, D)) Ux, Uy, Uz = displacive.expansion(nu, nv, nw, n_atm, U) A_r = occupational.composition(nu, nv, nw, n_atm, occ) delta = (occ * (1 + A_r.reshape(nu, nv, nw, n_atm))).flatten() mu1, mu2, mu3 = mom.T mu = np.row_stack(magnetic.cartesian(mu1, mu2, mu3, C)) Sx, Sy, Sz = magnetic.spin(nu, nv, nw, n_atm, mu) crystal.disordered(delta, Ux, Uy, Uz, Sx, Sy, Sz, rx, ry, rz, nu, nv, nw, atm, A, folder + '/disordered_CaTiOSiO4.cif', folder=folder, filename='CaTiOSiO4.cif', ulim=[0, nu], vlim=[0, nv], wlim=[0, nw]) UC_dict = crystal.unitcell(folder=folder, filename='disordered_CaTiOSiO4.cif', tol=1e-4) Atm = UC_dict['atom'] np.testing.assert_array_equal(atms == Atm, True) os.remove(folder + '/disordered_CaTiOSiO4.cif') uc_dict = crystal.unitcell(folder=folder, filename='CuMnO2.mcif', tol=1e-4) u = uc_dict['u'] v = uc_dict['v'] w = uc_dict['w'] occ = uc_dict['occupancy'] disp = uc_dict['displacement'] mom = uc_dict['moment'] atm = uc_dict['atom'] n_atm = uc_dict['n_atom'] nu, nv, nw = 2, 3, 4 constants = crystal.parameters(folder=folder, filename='CuMnO2.mcif') A = crystal.cartesian(*constants) C = crystal.cartesian_moment(*constants) D = crystal.cartesian_displacement(*constants) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) Uiso = disp.flatten() Ux, Uy, Uz = displacive.expansion(nu, nv, nw, n_atm, Uiso) A_r = occupational.composition(nu, nv, nw, n_atm, occ) delta = (occ * (1 + A_r.reshape(nu, nv, nw, n_atm))).flatten() mu1, mu2, mu3 = mom.T mu = np.row_stack(magnetic.cartesian(mu1, mu2, mu3, C)) Sx, Sy, Sz = magnetic.spin(nu, nv, nw, n_atm, mu) crystal.disordered(delta, Ux, Uy, Uz, Sx, Sy, Sz, rx, ry, rz, nu, nv, nw, atm, A, folder + '/disordered_CuMnO2.mcif', folder=folder, filename='CuMnO2.mcif', ulim=[0, nu], vlim=[0, nv], wlim=[0, nw]) UC_dict = crystal.unitcell(folder=folder, filename='disordered_CuMnO2.mcif', tol=1e-4) Atm = UC_dict['atom'] np.testing.assert_array_equal(atms == Atm, True) os.remove(folder + '/disordered_CuMnO2.mcif')
def test_occupational(self): a, b, c, alpha, beta, gamma = 5, 6, 7, np.pi / 2, np.pi / 3, np.pi / 4 inv_constants = crystal.reciprocal(a, b, c, alpha, beta, gamma) a_, b_, c_, alpha_, beta_, gamma_ = inv_constants h_range, nh = [-1, 1], 5 k_range, nk = [0, 2], 11 l_range, nl = [-1, 0], 5 nu, nv, nw, n_atm = 2, 5, 4, 2 u = np.array([0.2, 0.1]) v = np.array([0.3, 0.4]) w = np.array([0.4, 0.5]) atm = np.array(['Fe', 'Mn']) occupancy = np.array([0.75, 0.5]) U11 = np.array([0.5, 0.3]) U22 = np.array([0.6, 0.4]) U33 = np.array([0.4, 0.6]) U23 = np.array([0.05, -0.03]) U13 = np.array([-0.04, 0.02]) U12 = np.array([0.03, -0.02]) twins = np.eye(3).reshape(1, 3, 3) variants = np.array([1.0]) W = np.eye(3) T = space.debye_waller(h_range, k_range, l_range, nh, nk, nl, U11, U22, U33, U23, U13, U12, a_, b_, c_) A = crystal.cartesian(a, b, c, alpha, beta, gamma) B = crystal.cartesian(a_, b_, c_, alpha_, beta_, gamma_) R = crystal.cartesian_rotation(a, b, c, alpha, beta, gamma) D = crystal.cartesian_displacement(a, b, c, alpha, beta, gamma) A_r = occupational.composition(nu, nv, nw, n_atm, value=occupancy) index_parameters = space.mapping(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) h, k, l, H, K, L, indices, inverses, operators = index_parameters Qh, Qk, Ql = crystal.vector(h, k, l, B) Qx, Qy, Qz = crystal.transform(Qh, Qk, Ql, R) Qx_norm, Qy_norm, Qz_norm, Q = space.unit(Qx, Qy, Qz) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) phase_factor = scattering.phase(Qx, Qy, Qz, ux, uy, uz) scattering_length = scattering.length(atm, Q.size) A_k, i_dft = occupational.transform(A_r, H, K, L, nu, nv, nw, n_atm) factors = space.prefactors(scattering_length, phase_factor, occupancy) factors *= T I_ref = occupational.intensity(A_k, i_dft, factors) reduced_params = space.reduced(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) indices, reverses, symops, Nu, Nv, Nw = reduced_params symop = symmetry.laue_id(symops) I = monocrystal.occupational(A_r, occupancy, U11, U22, U33, U23, U13, U12, ux, uy, uz, atm, h_range, k_range, l_range, indices, symop, W, B, R, D, twins, variants, nh, nk, nl, nu, nv, nw, Nu, Nv, Nw) np.testing.assert_array_almost_equal(I, I_ref)
def test_intensity(self): a, b, c, alpha, beta, gamma = 5, 6, 7, np.pi / 2, np.pi / 3, np.pi / 4 inv_constants = crystal.reciprocal(a, b, c, alpha, beta, gamma) a_, b_, c_, alpha_, beta_, gamma_ = inv_constants h_range, nh = [-1, 1], 5 k_range, nk = [0, 2], 11 l_range, nl = [-1, 0], 5 nu, nv, nw, n_atm = 2, 5, 4, 2 u = np.array([0.2, 0.1]) v = np.array([0.3, 0.4]) w = np.array([0.4, 0.5]) atm = np.array(['Fe', 'Mn']) occupancy = np.array([0.75, 0.5]) U11 = np.array([0.5, 0.3]) U22 = np.array([0.6, 0.4]) U33 = np.array([0.4, 0.6]) U23 = np.array([0.05, -0.03]) U13 = np.array([-0.04, 0.02]) U12 = np.array([0.03, -0.02]) T = space.debye_waller(h_range, k_range, l_range, nh, nk, nl, U11, U22, U33, U23, U13, U12, a_, b_, c_) A = crystal.cartesian(a, b, c, alpha, beta, gamma) B = crystal.cartesian(a_, b_, c_, alpha_, beta_, gamma_) R = crystal.cartesian_rotation(a, b, c, alpha, beta, gamma) A_r = occupational.composition(nu, nv, nw, n_atm, value=occupancy) index_parameters = space.mapping(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) h, k, l, H, K, L, indices, inverses, operators = index_parameters Qh, Qk, Ql = crystal.vector(h, k, l, B) Qx, Qy, Qz = crystal.transform(Qh, Qk, Ql, R) Qx_norm, Qy_norm, Qz_norm, Q = space.unit(Qx, Qy, Qz) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) phase_factor = scattering.phase(Qx, Qy, Qz, ux, uy, uz) scattering_length = scattering.length(atm, Q.size) A_k, i_dft = occupational.transform(A_r, H, K, L, nu, nv, nw, n_atm) factors = space.prefactors(scattering_length, phase_factor, occupancy) factors *= T I = occupational.intensity(A_k, i_dft, factors) n_hkl = Q.size n_xyz = nu * nv * nw * n_atm i, j = np.triu_indices(n_xyz, 1) k, l = np.mod(i, n_atm), np.mod(j, n_atm) m = np.arange(n_xyz) n = np.mod(m, n_atm) rx_ij = rx[j] - rx[i] ry_ij = ry[j] - ry[i] rz_ij = rz[j] - rz[i] bc = scattering.length(atm, 1) T = T.reshape(n_hkl, n_atm) A_i, A_j, A_m = A_r[i], A_r[j], A_r[m] c_k, c_l, c_n = occupancy[k], occupancy[l], occupancy[n] b_k, b_l, b_n = bc[k], bc[l], bc[n] T_k, T_l, T_n = T[:, k], T[:, l], T[:, n] I_ref = ((c_n**2*(b_n*b_n.conj()).real*A_m**2*T_n**2).sum(axis=1)\ + 2*(c_k*c_l*(b_k*b_l.conj()).real*A_i*A_j*T_k*T_l*\ np.cos(Qx[:,np.newaxis]*rx_ij+\ Qy[:,np.newaxis]*ry_ij+\ Qz[:,np.newaxis]*rz_ij)).sum(axis=1))/n_xyz np.testing.assert_array_almost_equal(I, I_ref)
def test_structure(self): a, b, c, alpha, beta, gamma = 5, 6, 7, np.pi / 2, np.pi / 3, np.pi / 4 inv_constants = crystal.reciprocal(a, b, c, alpha, beta, gamma) a_, b_, c_, alpha_, beta_, gamma_ = inv_constants h_range, nh = [-1, 1], 5 k_range, nk = [0, 2], 11 l_range, nl = [-1, 0], 5 nu, nv, nw, n_atm = 2, 5, 4, 2 u = np.array([0.2, 0.1]) v = np.array([0.3, 0.4]) w = np.array([0.4, 0.5]) atm = np.array(['Fe', 'Mn']) occupancy = np.array([0.75, 0.5]) U11 = np.array([0.5, 0.3]) U22 = np.array([0.6, 0.4]) U33 = np.array([0.4, 0.6]) U23 = np.array([0.05, -0.03]) U13 = np.array([-0.04, 0.02]) U12 = np.array([0.03, -0.02]) T = space.debye_waller(h_range, k_range, l_range, nh, nk, nl, U11, U22, U33, U23, U13, U12, a_, b_, c_) A = crystal.cartesian(a, b, c, alpha, beta, gamma) B = crystal.cartesian(a_, b_, c_, alpha_, beta_, gamma_) R = crystal.cartesian_rotation(a, b, c, alpha, beta, gamma) A_r = occupational.composition(nu, nv, nw, n_atm, value=occupancy) index_parameters = space.mapping(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) h, k, l, H, K, L, indices, inverses, operators = index_parameters Qh, Qk, Ql = crystal.vector(h, k, l, B) Qx, Qy, Qz = crystal.transform(Qh, Qk, Ql, R) Qx_norm, Qy_norm, Qz_norm, Q = space.unit(Qx, Qy, Qz) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) phase_factor = scattering.phase(Qx, Qy, Qz, ux, uy, uz) scattering_length = scattering.length(atm, Q.size) A_k, i_dft = occupational.transform(A_r, H, K, L, nu, nv, nw, n_atm) factors = space.prefactors(scattering_length, phase_factor, occupancy) factors *= T F, prod = occupational.structure(A_k, i_dft, factors) n_hkl = Q.size n_xyz = nu * nv * nw * n_atm m = np.arange(n_xyz) n = np.mod(m, n_atm) rx_m = rx[m] ry_m = ry[m] rz_m = rz[m] bc = scattering.length(atm, 1) T = T.reshape(n_hkl, n_atm) A_m = A_r[m] c_n = occupancy[n] b_n = bc[n] T_n = T[:, n] prod_ref = (c_n*b_n*A_m*T_n*np.exp(1j*(Qx[:,np.newaxis]*rx_m+\ Qy[:,np.newaxis]*ry_m+\ Qz[:,np.newaxis]*rz_m))) F_ref = prod_ref.sum(axis=1) prod_ref = prod_ref.reshape(n_hkl, nu * nv * nw, n_atm).sum(axis=1).flatten() np.testing.assert_array_almost_equal(F, F_ref) np.testing.assert_array_almost_equal(prod, prod_ref)
def random_occupancies(self, nu, nv, nw, n_atm, occupancy): return occupational.composition(nu, nv, nw, n_atm, occupancy)
def test_intensity(self): a, b, c, alpha, beta, gamma = 5, 6, 7, np.pi / 2, np.pi / 3, np.pi / 4 inv_constants = crystal.reciprocal(a, b, c, alpha, beta, gamma) a_, b_, c_, alpha_, beta_, gamma_ = inv_constants h_range, nh = [-1, 1], 5 k_range, nk = [0, 2], 11 l_range, nl = [-1, 0], 5 nu, nv, nw, n_atm = 2, 5, 4, 2 u = np.array([0.2, 0.1]) v = np.array([0.3, 0.4]) w = np.array([0.4, 0.5]) atm = np.array(['Fe', 'Mn']) occupancy = np.array([0.75, 0.5]) U11 = np.array([0.5, 0.3]) U22 = np.array([0.6, 0.4]) U33 = np.array([0.4, 0.6]) U23 = np.array([0.05, -0.03]) U13 = np.array([-0.04, 0.02]) U12 = np.array([0.03, -0.02]) A = crystal.cartesian(a, b, c, alpha, beta, gamma) B = crystal.cartesian(a_, b_, c_, alpha_, beta_, gamma_) R = crystal.cartesian_rotation(a, b, c, alpha, beta, gamma) U = np.row_stack((U11, U22, U33, U23, U13, U12)) Ux, Uy, Uz = displacive.expansion(nu, nv, nw, n_atm, value=U) A_r = occupational.composition(nu, nv, nw, n_atm, value=occupancy) index_parameters = space.mapping(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) h, k, l, H, K, L, indices, inverses, operators = index_parameters Qh, Qk, Ql = crystal.vector(h, k, l, B) Qx, Qy, Qz = crystal.transform(Qh, Qk, Ql, R) Qx_norm, Qy_norm, Qz_norm, Q = space.unit(Qx, Qy, Qz) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) phase_factor = scattering.phase(Qx, Qy, Qz, ux, uy, uz) scattering_length = scattering.length(atm, Q.size) p = 3 coeffs = displacive.coefficients(p) H_nuc, K_nuc, L_nuc, cond = space.condition(H, K, L, nu, nv, nw, centering='P') U_r = displacive.products(Ux, Uy, Uz, p) Q_k = displacive.products(Qx, Qy, Qz, p) U_k, A_k, i_dft = nonmagnetic.transform(U_r, A_r, H, K, L, nu, nv, nw, n_atm) factors = space.prefactors(scattering_length, phase_factor, occupancy) I, F_nuc = nonmagnetic.intensity(U_k, A_k, Q_k, coeffs, cond, p, i_dft, factors, subtract=False) n_hkl = Q.size n_xyz = nu * nv * nw * n_atm i, j = np.triu_indices(n_xyz, 1) k, l = np.mod(i, n_atm), np.mod(j, n_atm) m = np.arange(n_xyz) n = np.mod(m, n_atm) rx_ij = rx[j] - rx[i] ry_ij = ry[j] - ry[i] rz_ij = rz[j] - rz[i] bc = scattering.length(atm, 1) U_r = U_r.reshape(coeffs.shape[0], n_xyz) Q_k = Q_k.reshape(coeffs.shape[0], n_hkl) U_i, U_j, U_m = U_r[:, i], U_r[:, j], U_r[:, m] A_i, A_j, A_m = A_r[i], A_r[j], A_r[m] c_k, c_l, c_n = occupancy[k], occupancy[l], occupancy[n] b_k, b_l, b_n = bc[k], bc[l], bc[n] exp_iQ_dot_V_m = np.dot(coeffs * (U_m + A_m * U_m).T, Q_k).T exp_iQ_dot_V_i = np.dot(coeffs * (U_i + A_i * U_i).T, Q_k).T exp_iQ_dot_V_j = np.dot(coeffs * (U_j + A_j * U_j).T, Q_k).T I_ref = ((c_n**2*(b_n*b_n.conj()).real*\ (exp_iQ_dot_V_m*exp_iQ_dot_V_m.conj()).real).sum(axis=1)\ + 2*(c_k*c_l*(b_k*b_l.conj()).real* ((exp_iQ_dot_V_i*exp_iQ_dot_V_j.conj()*\ np.cos(Qx[:,np.newaxis]*rx_ij+\ Qy[:,np.newaxis]*ry_ij+\ Qz[:,np.newaxis]*rz_ij)).real+ (exp_iQ_dot_V_i*exp_iQ_dot_V_j.conj()*\ np.sin(Qx[:,np.newaxis]*rx_ij+\ Qy[:,np.newaxis]*ry_ij+\ Qz[:,np.newaxis]*rz_ij)).imag )).sum(axis=1))/n_xyz np.testing.assert_array_almost_equal(I, I_ref)
def test_structure(self): a, b, c, alpha, beta, gamma = 5, 6, 7, np.pi / 2, np.pi / 3, np.pi / 4 inv_constants = crystal.reciprocal(a, b, c, alpha, beta, gamma) a_, b_, c_, alpha_, beta_, gamma_ = inv_constants h_range, nh = [-1, 1], 5 k_range, nk = [0, 2], 11 l_range, nl = [-1, 0], 5 nu, nv, nw, n_atm = 2, 5, 4, 2 u = np.array([0.2, 0.1]) v = np.array([0.3, 0.4]) w = np.array([0.4, 0.5]) atm = np.array(['Fe', 'Mn']) occupancy = np.array([0.75, 0.5]) U11 = np.array([0.5, 0.3]) U22 = np.array([0.6, 0.4]) U33 = np.array([0.4, 0.6]) U23 = np.array([0.05, -0.03]) U13 = np.array([-0.04, 0.02]) U12 = np.array([0.03, -0.02]) A = crystal.cartesian(a, b, c, alpha, beta, gamma) B = crystal.cartesian(a_, b_, c_, alpha_, beta_, gamma_) R = crystal.cartesian_rotation(a, b, c, alpha, beta, gamma) U = np.row_stack((U11, U22, U33, U23, U13, U12)) Ux, Uy, Uz = displacive.expansion(nu, nv, nw, n_atm, value=U) A_r = occupational.composition(nu, nv, nw, n_atm, value=occupancy) index_parameters = space.mapping(h_range, k_range, l_range, nh, nk, nl, nu, nv, nw) h, k, l, H, K, L, indices, inverses, operators = index_parameters Qh, Qk, Ql = crystal.vector(h, k, l, B) Qx, Qy, Qz = crystal.transform(Qh, Qk, Ql, R) Qx_norm, Qy_norm, Qz_norm, Q = space.unit(Qx, Qy, Qz) ux, uy, uz = crystal.transform(u, v, w, A) ix, iy, iz = space.cell(nu, nv, nw, A) rx, ry, rz, atms = space.real(ux, uy, uz, ix, iy, iz, atm) phase_factor = scattering.phase(Qx, Qy, Qz, ux, uy, uz) scattering_length = scattering.length(atm, Q.size) p = 3 coeffs = displacive.coefficients(p) H_nuc, K_nuc, L_nuc, cond = space.condition(H, K, L, nu, nv, nw, centering='P') U_r = displacive.products(Ux, Uy, Uz, p) Q_k = displacive.products(Qx, Qy, Qz, p) U_k, A_k, i_dft = nonmagnetic.transform(U_r, A_r, H, K, L, nu, nv, nw, n_atm) factors = space.prefactors(scattering_length, phase_factor, occupancy) F, F_nuc, \ prod, prod_nuc, \ V_k, V_k_nuc, \ even, bragg = nonmagnetic.structure(U_k, A_k, Q_k, coeffs, cond, p, i_dft, factors) n_hkl = Q.size n_xyz = nu * nv * nw * n_atm m = np.arange(n_xyz) n = np.mod(m, n_atm) rx_m = rx[m] ry_m = ry[m] rz_m = rz[m] bc = scattering.length(atm, 1) U_r = U_r.reshape(coeffs.shape[0], n_xyz) Q_k = Q_k.reshape(coeffs.shape[0], n_hkl) U_m = U_r[:, m] A_m = A_r[m] c_n = occupancy[n] b_n = bc[n] exp_iQ_dot_V_m = np.dot(coeffs * (U_m + A_m * U_m).T, Q_k).T prod_ref = (c_n*b_n*exp_iQ_dot_V_m*np.exp(1j*(Qx[:,np.newaxis]*rx_m+\ Qy[:,np.newaxis]*ry_m+\ Qz[:,np.newaxis]*rz_m))) F_ref = prod_ref.sum(axis=1) prod_ref = prod_ref.reshape(n_hkl, nu * nv * nw, n_atm).sum(axis=1).flatten() np.testing.assert_array_almost_equal(F, F_ref) np.testing.assert_array_almost_equal(prod, prod_ref)