Coverage for gpaw/test/elph/test_ramancalculator.py: 100%

58 statements  

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

1import numpy as np 

2import pytest 

3 

4from ase.utils.filecache import MultiFileJSONCache 

5from gpaw import GPAW 

6from gpaw.lcao.dipoletransition import get_momentum_transitions 

7from gpaw.elph import ResonantRamanCalculator 

8from gpaw.mpi import world 

9 

10 

11def get_random_g(nk, nb): 

12 g_sqklnn = np.zeros((1, 1, 4, 3, 4, 4), dtype=complex) 

13 rng = np.random.default_rng() 

14 tmp = rng.random((4, 4)) + 1j * rng.random((4, 4)) 

15 # make hermitian 

16 for i in range(4): 

17 for j in range(i + 1, 4): 

18 tmp[i, j] = tmp[j, i].conj() 

19 g_sqklnn[0, 0, 0, 2] = tmp 

20 return g_sqklnn 

21 

22 

23@pytest.mark.old_gpaw_only # calc.initialize_positions(atoms) not implemented! 

24@pytest.mark.serial 

25def test_ramancalculator(gpw_files, in_tmp_dir): 

26 """Test of ResonantRamanCalculator object""" 

27 calc = GPAW(gpw_files['bcc_li_lcao']) 

28 atoms = calc.atoms 

29 # Initialize calculator if necessary 

30 if not hasattr(calc.wfs, 'C_nM'): 

31 calc.initialize_positions(atoms) 

32 # need to fiddle with some occupation numnbers as this exampe is 

33 # not properly converged 

34 for kpt in calc.wfs.kpt_u: 

35 kpt.f_n[0] = kpt.weight 

36 

37 # prepare some required data 

38 wph_w = np.array([0., 0., 0.1]) 

39 get_momentum_transitions(calc.wfs) 

40 if world.rank == 0: 

41 g_sqklnn = get_random_g(4, 4) 

42 np.save("gsqklnn.npy", g_sqklnn) 

43 

44 rrc = ResonantRamanCalculator(calc, wph_w) 

45 assert rrc.mom_skvnm == pytest.approx(np.transpose(rrc.mom_skvnm, 

46 (0, 1, 2, 4, 3)).conj()) 

47 # Force momentum matrix elements to be the same in all directions 

48 # else R^ab won't be R^{ba*} 

49 # This is a bit of a dirty hack I guess. Ideally we need a test systm with 

50 # equivalent axes but no degenerate bands... so yeah 

51 rrc.mom_skvnm[0, :, 1] = rrc.mom_skvnm[0, :, 0] 

52 rrc.mom_skvnm[0, :, 2] = rrc.mom_skvnm[0, :, 0] 

53 

54 # check reading of file cache 

55 check_cache = MultiFileJSONCache("Rlab") 

56 assert check_cache["phonon_frequencies"] == pytest.approx(wph_w) 

57 assert check_cache["frequency_grid"] is None 

58 

59 rrc.calculate_raman_tensor(1.0) 

60 for i in range(3): 

61 for j in range(3): 

62 R_l = check_cache[f"{'xyz'[i]}{'xyz'[j]}"] 

63 assert R_l is not None 

64 assert R_l[0] == pytest.approx(0.0 + 1j * 0.) 

65 assert R_l[1] == pytest.approx(0.0 + 1j * 0.) 

66 

67 if j > i: 

68 # need to make sure momentum matrix is perfectly hermitian too 

69 Rother_l = check_cache[f"{'xyz'[j]}{'xyz'[i]}"] 

70 print(i, j, R_l[2], Rother_l[2]) 

71 assert R_l[2].real == pytest.approx(Rother_l[2].real) 

72 assert R_l[2].imag == pytest.approx(Rother_l[2].imag) 

73 

74 # check proper kpt dependence. If we half all the weights, 

75 # the total intensity should be half as well 

76 for kpt in calc.wfs.kpt_u: 

77 kpt.weight /= 2 

78 kpt.f_n /= 2 # because f_n = kpt.f_n / kpt.weight 

79 

80 for i in range(3): 

81 for j in range(3): 

82 R_l = check_cache[f"{'xyz'[i]}{'xyz'[j]}"] 

83 R_l_half = rrc.calculate(1.0, i, j) 

84 assert 2. * R_l_half[2].real == pytest.approx(R_l[2].real) 

85 assert 2. * R_l_half[2].imag == pytest.approx(R_l[2].imag)