Coverage for gpaw/test/noncollinear/test_spin_dir_constraint.py: 100%

40 statements  

« prev     ^ index     » next       coverage.py v7.7.1, created at 2025-07-09 00:21 +0000

1import numpy as np 

2import pytest 

3 

4from ase import Atoms 

5 

6from gpaw.mpi import world 

7from gpaw.new.constraints import SpinDirectionConstraint 

8from gpaw.new.ase_interface import GPAW 

9 

10 

11@pytest.mark.soc 

12@pytest.mark.skipif(world.size > 1, reason='Gamma-point calculation.') 

13def test_spin_dir_constraint_H(): 

14 

15 c = 2.5 # Å 

16 atom = Atoms('H', scaled_positions=[[0.5, 0.5, 0.5]], 

17 cell=[c, c, c], pbc=False) 

18 

19 # Constrain spin to point along x direction 

20 constraint = SpinDirectionConstraint({0: [1.0, 0.0, 0.0]}, 2.0) 

21 

22 # Initialize spin along [1 1 1] 

23 calc = GPAW( 

24 mode={'name': 'pw', 'ecut': 400}, xc='LDA', 

25 nbands=1, symmetry='off', 

26 soc=True, magmoms=np.array([[1, 1, 1]]) / np.sqrt(3), 

27 parallel={'domain': 1, 'band': 1}, 

28 extensions=[constraint]) 

29 

30 atom.calc = calc 

31 atom.get_potential_energy() 

32 

33 # Assert that spin points along x 

34 smm_v = calc.dft.density.calculate_magnetic_moments()[0] 

35 assert smm_v[0] == pytest.approx(1., abs=1e-3) 

36 assert smm_v[1] == pytest.approx(0., abs=1e-3) 

37 assert smm_v[2] == pytest.approx(0., abs=1e-3) 

38 

39 

40@pytest.mark.soc 

41@pytest.mark.skipif(world.size > 1, reason='Unit test with no' 

42 ' parallelization.') 

43def test_spin_dir_constraint_derivative(): 

44 

45 rng = np.random.default_rng(seed=23) 

46 

47 # Generate random data simulating a setup with s and p orbitals. 

48 M_vii = rng.random([3, 4, 4], dtype=np.float64) 

49 # Make Hermitian 

50 M_vii = (M_vii + np.transpose(M_vii, (0, 2, 1))) / 2 

51 l_j = [0, 1] 

52 

53 # Initialize constraint 

54 constraint = SpinDirectionConstraint({0: [0, 0, 1]}, 2.0) 

55 

56 # Generate some radial inner products 

57 N0_q = np.zeros(len(l_j) * (len(l_j) + 1) // 2) 

58 N0_q[0] = 0.8 

59 N0_q[2] = 0.6 

60 

61 eL, V_vii = constraint.calculate(M_vii, 0, l_j, N0_q) 

62 assert eL == 0., 'Do not calculate constraining field energy unless stated' 

63 

64 # Check that the spin constraint Hamiltonian is calculated correctly by 

65 # comparing it with an energy derivative w.r.t. a density matrix element 

66 # calculated through finite difference. 

67 

68 diff = 1e-5 

69 

70 M1_vii = M_vii.copy() 

71 M1_vii[0, 2, 2] += diff / 2 

72 eL1, _ = constraint.calculate(M1_vii, 0, l_j, N0_q, return_energy=True) 

73 

74 M2_vii = M_vii.copy() 

75 M2_vii[0, 2, 2] -= diff / 2 

76 eL2, _ = constraint.calculate(M2_vii, 0, l_j, N0_q, return_energy=True) 

77 

78 assert (eL1 - eL2) / diff == pytest.approx(V_vii[0, 2, 2], abs=1e-8)