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

1from typing import Callable, Collection, NamedTuple, Tuple, Union 

2 

3import numpy as np 

4import pytest 

5 

6from gpaw import GPAW 

7from gpaw.directmin.etdm_lcao import LCAOETDM 

8from gpaw.typing import RNG 

9 

10 

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 """ 

20 

21 class NiterCheck(NamedTuple): 

22 assertion: str 

23 func: Callable[[int], bool] 

24 

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) 

28 

29 def check_niter(niter: int, check: NiterCheck) -> None: 

30 assert check.func(niter), f'failed {check.assertion} (niter = {niter})' 

31 

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() 

37 

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) 

41 

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)] 

50 

51 f2 = np.array([[-1.11463, -1.23723, 0.0], 

52 [1.35791, 0.00827, 0.0], 

53 [-0.34423, 1.33207, 0.0]]) 

54 

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') 

62 

63 assert f2 == pytest.approx(f, abs=abs_force_tol) 

64 

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() 

71 

72 check_niter(niter, is_approx_3) 

73 assert f2 == pytest.approx(f3, abs=abs_force_tol) 

74 

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)