Coverage for gpaw/test/response/test_iron_sf_pawALDA.py: 70%
84 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
1import pytest
3import numpy as np
5from gpaw import GPAW
6from gpaw.mpi import world
7from gpaw.response import ResponseGroundStateAdapter, ResponseContext
8from gpaw.response.chiks import ChiKSCalculator, SelfEnhancementCalculator
9from gpaw.response.frequencies import ComplexFrequencyDescriptor
10from gpaw.response.dyson import DysonSolver
11from gpaw.response.susceptibility import (spectral_decomposition,
12 read_eigenmode_lineshapes)
13from gpaw.response.pair_functions import read_pair_function
15from gpaw.test import findpeak
16from gpaw.test.gpwfile import response_band_cutoff
19@pytest.mark.kspair
20@pytest.mark.response
21def test_response_iron_sf_pawALDA(in_tmp_dir, gpw_files, scalapack):
22 # ---------- Inputs ---------- #
24 # Magnetic response calculation
25 q_qc = [[0.0, 0.0, 0.0], [0.0, 0.0, 1. / 4.]] # Two q-points along G-N
26 frq_w = np.linspace(-1.0, 3.0, 161)
27 ecut = 100
28 eta = 0.5
29 rshewmin = 1e-8
31 if world.size > 1:
32 nblocks = 2
33 else:
34 nblocks = 1
36 # ---------- Script ---------- #
38 context = ResponseContext(txt='iron_susceptibility.txt')
39 calc = GPAW(gpw_files['fe_pw'], parallel=dict(domain=1))
40 nbands = response_band_cutoff['fe_pw']
41 gs = ResponseGroundStateAdapter(calc)
43 calc_args = (gs,)
44 calc_kwargs = dict(context=context,
45 nbands=nbands,
46 ecut=ecut,
47 gammacentered=True,
48 bandsummation='double',
49 nblocks=nblocks)
50 chiks_calc = ChiKSCalculator(*calc_args, **calc_kwargs)
51 xi_calc = SelfEnhancementCalculator(*calc_args,
52 rshewmin=rshewmin,
53 **calc_kwargs)
54 dyson_solver = DysonSolver(context)
56 for q, q_c in enumerate(q_qc):
57 # Calculate χ_KS^+- and Ξ^++
58 zd = ComplexFrequencyDescriptor.from_array(frq_w + 1j * eta)
59 chiks = chiks_calc.calculate('+-', q_c, zd)
60 xi = xi_calc.calculate('+-', q_c, zd)
62 # Distribute frequencies and invert dyson equation
63 chiks = chiks.copy_with_global_frequency_distribution()
64 xi = xi.copy_with_global_frequency_distribution()
65 chi = dyson_solver(chiks, xi)
67 # plot_inverse_enhancement(xi)
69 # Write macroscopic component and acoustic magnon mode
70 chi.write_macroscopic_component(f'iron_chiM_q{q}.csv')
71 Amaj, _ = spectral_decomposition(chi)
72 Amaj.write_eigenmode_lineshapes(f'iron_Amaj_q{q}.csv')
74 context.write_timer()
76 # plot_magnons()
78 refs_q = [
79 # (wpeak, Ipeak, Apeak)
80 (0.001, 0.476, 3.104),
81 (0.165, 0.428, 2.816)]
83 world.barrier() # wait for csv-file written above ...
84 for q, refs in enumerate(refs_q):
85 w_w, chiM_w, a_w = extract_data(q)
86 wpeak1, Ipeak = findpeak(w_w, -chiM_w.imag / np.pi)
87 wpeak2, Apeak = findpeak(w_w, a_w)
89 assert wpeak1 == pytest.approx(wpeak2, abs=0.002) # eV
90 assert wpeak1 == pytest.approx(refs[0], abs=0.01) # eV
91 assert Ipeak == pytest.approx(refs[1], abs=0.01) # a.u.
92 assert Apeak == pytest.approx(refs[2], abs=0.05) # a.u.
95def extract_data(q):
96 w1_w, chiM_w = read_pair_function(f'iron_chiM_q{q}.csv')
97 w2_w, a_wm = read_eigenmode_lineshapes(f'iron_Amaj_q{q}.csv')
98 assert np.allclose(w1_w, w2_w)
99 return w1_w, chiM_w, a_wm[:, 0]
102def plot_inverse_enhancement(xi):
103 import matplotlib.pyplot as plt
104 from ase.units import Ha
105 invenh_mywM, _ = np.linalg.eig(xi.array)
106 invenh_wM = xi.blocks1d.all_gather(invenh_mywM)
107 omega_w = xi.zd.omega_w * Ha
109 for M in range(invenh_wM.shape[1]):
110 plt.subplot(1, 2, 1)
111 plt.scatter(omega_w, invenh_wM[:, M].real)
112 plt.subplot(1, 2, 2)
113 plt.scatter(omega_w, invenh_wM[:, M].imag)
114 plt.subplot(1, 2, 1)
115 plt.axhline(1., c='0.5')
116 if world.rank == 0:
117 plt.show()
120def plot_magnons():
121 import matplotlib.pyplot as plt
122 for q in range(2):
123 w_w, chiM_w, a_w = extract_data(q)
124 plt.subplot(1, 2, 1)
125 plt.plot(w_w, - chiM_w.imag / np.pi, label=f'{q}')
126 plt.subplot(1, 2, 2)
127 plt.plot(w_w, a_w, label=f'{q}')
128 plt.legend(title='q')
129 if world.rank == 0:
130 plt.show()