Coverage for gpaw/test/test_reuse_wfs_celldisp.py: 97%

35 statements  

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

1import numpy as np 

2from ase.build import molecule 

3 

4from gpaw import GPAW, Mixer 

5from gpaw.mpi import world 

6 

7# Place one atom next to cell boundary, then check that reuse_wfs 

8# works correctly when atom is subsequently displaced across the 

9# boundary, i.e., that the kpoint phases of the PAW correction 

10# are handled correctly when unprojecting/reprojecting the wavefunctions. 

11 

12 

13def test_reuse_wfs_celldisp(in_tmp_dir): 

14 def check(reuse): 

15 atoms = molecule('H2') 

16 atoms.pbc = 1 

17 atoms.center(vacuum=1.5) 

18 atoms.positions -= atoms.positions[1] 

19 dz = 1e-2 

20 atoms.positions[:, 2] += dz 

21 

22 calc = GPAW(mode='pw', 

23 txt=f'gpaw-{reuse}.txt', 

24 nbands=1, 

25 eigensolver='davidson', 

26 experimental=dict( 

27 reuse_wfs_method='paw' if reuse else None), 

28 kpts=[[-0.3, 0.4, 0.2]], 

29 symmetry='off', 

30 mixer=Mixer(0.7, 5, 50.0)) 

31 atoms.calc = calc 

32 

33 for ctx in calc.icalculate(atoms): 

34 if ctx.niter == 2: 

35 # logerr1 = np.log10(calc.wfs.eigensolver.error) 

36 logerr1 = np.log10(ctx.wfs.eigensolver.error) 

37 

38 atoms.positions[:, 2] -= 2 * dz 

39 

40 if not reuse and not calc.old: 

41 calc.dft.ibzwfs.move_wave_functions = lambda *args: None 

42 

43 for ctx in calc.icalculate(atoms, system_changes=['positions']): 

44 if ctx.niter == 2: 

45 logerr2 = np.log10(ctx.wfs.eigensolver.error) 

46 break 

47 

48 if world.rank == 0: 

49 print(f'reuse={bool(reuse)}') 

50 print('logerr1', logerr1) 

51 print('logerr2', logerr2) 

52 gain = logerr2 - logerr1 

53 print('gain', gain) 

54 return logerr2 

55 

56 noreuse_logerr = check(0) 

57 reuse_logerr = check(1) 

58 # Ref values: logerr=-4.8 without reuse_wfs and -6.1 with reuse_wfs 

59 assert reuse_logerr < -6.0, reuse_logerr 

60 assert reuse_logerr < noreuse_logerr - 1.2, (reuse_logerr, noreuse_logerr)