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
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
1import numpy as np
2import pytest
4from ase import Atoms
6from gpaw.mpi import world
7from gpaw.new.constraints import SpinDirectionConstraint
8from gpaw.new.ase_interface import GPAW
11@pytest.mark.soc
12@pytest.mark.skipif(world.size > 1, reason='Gamma-point calculation.')
13def test_spin_dir_constraint_H():
15 c = 2.5 # Å
16 atom = Atoms('H', scaled_positions=[[0.5, 0.5, 0.5]],
17 cell=[c, c, c], pbc=False)
19 # Constrain spin to point along x direction
20 constraint = SpinDirectionConstraint({0: [1.0, 0.0, 0.0]}, 2.0)
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])
30 atom.calc = calc
31 atom.get_potential_energy()
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)
40@pytest.mark.soc
41@pytest.mark.skipif(world.size > 1, reason='Unit test with no'
42 ' parallelization.')
43def test_spin_dir_constraint_derivative():
45 rng = np.random.default_rng(seed=23)
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]
53 # Initialize constraint
54 constraint = SpinDirectionConstraint({0: [0, 0, 1]}, 2.0)
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
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'
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.
68 diff = 1e-5
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)
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)
78 assert (eL1 - eL2) / diff == pytest.approx(V_vii[0, 2, 2], abs=1e-8)