Coverage for gpaw/test/directopt/test_directmin_lcao.py: 100%
48 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
1from typing import Callable, Collection, NamedTuple, Tuple, Union
3import numpy as np
4import pytest
6from gpaw import GPAW
7from gpaw.directmin.etdm_lcao import LCAOETDM
8from gpaw.typing import RNG
11@pytest.mark.old_gpaw_only
12@pytest.mark.do
13def test_directmin_lcao(in_tmp_dir, gpw_files):
14 """
15 test exponential transformation
16 direct minimization method for KS-DFT in LCAO
17 :param in_tmp_dir:
18 :return:
19 """
21 class NiterCheck(NamedTuple):
22 assertion: str
23 func: Callable[[int], bool]
25 is_approx_3 = NiterCheck('niter ~ 3',
26 lambda niter: niter == pytest.approx(3, abs=1))
27 is_le_12 = NiterCheck('niter <= 12', lambda niter: niter <= 12)
29 def check_niter(niter: int, check: NiterCheck) -> None:
30 assert check.func(niter), f'failed {check.assertion} (niter = {niter})'
32 calc = GPAW(gpw_files['h2o_do_lcao'])
33 H2O = calc.atoms
34 H2O.calc = calc
35 e = H2O.get_potential_energy()
36 f = H2O.get_forces()
38 target_pot_en = -13.643156256566218
39 abs_force_tol, abs_en_tol = 1e-2, 1.0e-4
40 assert e == pytest.approx(target_pot_en, abs=abs_en_tol)
42 lcaoetdm_kwargs = dict(representation='u-invar',
43 matrix_exp='egdecomp-u-invar',
44 need_init_orbs=False,
45 linesearch_algo={'name': 'max-step'})
46 lcaoetdm_rand_and_niter_checks: Collection[
47 Tuple[Union[RNG, None], NiterCheck]
48 ] = [(None, is_approx_3),
49 (np.random.default_rng(8), is_le_12)]
51 f2 = np.array([[-1.11463, -1.23723, 0.0],
52 [1.35791, 0.00827, 0.0],
53 [-0.34423, 1.33207, 0.0]])
55 for use_rho in [0, 1]:
56 if use_rho:
57 for kpt in calc.wfs.kpt_u:
58 kpt.rho_MM = calc.wfs.calculate_density_matrix(kpt.f_n,
59 kpt.C_nM)
60 f = H2O.get_forces()
61 H2O.calc.results.pop('forces')
63 assert f2 == pytest.approx(f, abs=abs_force_tol)
65 calc.write('h2o.gpw', mode='all')
66 from gpaw import restart
67 H2O, calc = restart('h2o.gpw', txt='-')
68 H2O.positions += 1.0e-6
69 f3 = H2O.get_forces()
70 niter = calc.get_number_of_iterations()
72 check_niter(niter, is_approx_3)
73 assert f2 == pytest.approx(f3, abs=abs_force_tol)
75 # Test for various randomization options
76 for randomize, check in lcaoetdm_rand_and_niter_checks:
77 calc.set(eigensolver=LCAOETDM(randomizeorbitals=randomize,
78 **lcaoetdm_kwargs))
79 e = H2O.get_potential_energy()
80 niter = calc.get_number_of_iterations()
81 check_niter(niter, check)
82 assert e == pytest.approx(target_pot_en, abs=abs_en_tol)