Coverage for gpaw/test/fdtd/test_ed_inducedfield.py: 98%
66 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-12 00:18 +0000
1import numpy as np
2import pytest
3from gpaw import GPAW
4from gpaw.inducedfield.inducedfield_base import BaseInducedField
5from gpaw.inducedfield.inducedfield_fdtd import (
6 FDTDInducedField, calculate_hybrid_induced_field)
7from gpaw.inducedfield.inducedfield_tddft import TDDFTInducedField
8from gpaw.tddft import TDDFT, DipoleMomentWriter
11@pytest.mark.old_gpaw_only
12def test_fdtd_ed_inducedfield(in_tmp_dir, gpw_files):
13 do_print_values = 0 # Use this for printing the reference values
15 # Accuracy
16 energy_eps = 0.0005
17 poisson_eps = 1e-12
18 density_eps = 1e-6
20 # load gpw file
21 gs_calc = GPAW(gpw_files['na2_isolated'])
22 energy = gs_calc.get_potential_energy()
24 # Test ground state
25 assert energy == pytest.approx(
26 -0.631881,
27 abs=energy_eps * gs_calc.get_number_of_electrons())
29 # Test floating point arithmetic errors
30 assert gs_calc.hamiltonian.poisson.shift_indices_1 == pytest.approx(
31 [4, 4, 10], abs=0)
32 assert gs_calc.hamiltonian.poisson.shift_indices_2 == pytest.approx(
33 [8, 8, 16], abs=0)
35 # Initialize TDDFT and FDTD
36 kick = [0.0, 0.0, 1.0e-3]
37 time_step = 10.0
38 iterations = 10
40 td_calc = TDDFT(gpw_files['na2_isolated'])
41 DipoleMomentWriter(td_calc, 'dm.dat')
43 # Attach InducedFields to the calculation
44 frequencies = [2.05, 4.0]
45 width = 0.15
46 cl_ind = FDTDInducedField(paw=td_calc,
47 frequencies=frequencies,
48 width=width)
49 qm_ind = TDDFTInducedField(paw=td_calc,
50 frequencies=frequencies,
51 width=width)
53 # Propagate TDDFT and FDTD
54 td_calc.absorption_kick(kick_strength=kick)
55 td_calc.propagate(time_step, iterations // 2)
56 td_calc.write('td.gpw', 'all')
57 cl_ind.write('cl.ind')
58 qm_ind.write('qm.ind')
60 # Restart
61 td_calc = TDDFT('td.gpw')
62 DipoleMomentWriter(td_calc, 'dm.dat')
63 cl_ind = FDTDInducedField(filename='cl.ind',
64 paw=td_calc)
65 qm_ind = TDDFTInducedField(filename='qm.ind',
66 paw=td_calc)
67 td_calc.propagate(time_step, iterations // 2)
68 td_calc.write('td.gpw', 'all')
69 cl_ind.write('cl.ind')
70 qm_ind.write('qm.ind')
72 # Test
73 ref_cl_dipole_moment = [5.25374117e-14, 5.75811267e-14, 3.08349334e-02]
74 ref_qm_dipole_moment = [1.78620337e-11, -1.57782578e-11, 5.21368300e-01]
76 tol = 1e-4
77 assert td_calc.hamiltonian.poisson.get_classical_dipole_moment() == (
78 pytest.approx(ref_cl_dipole_moment, abs=tol))
79 assert td_calc.hamiltonian.poisson.get_quantum_dipole_moment() == (
80 pytest.approx(ref_qm_dipole_moment, abs=tol))
82 # Calculate induced fields
83 td_calc = TDDFT('td.gpw')
85 # Classical subsystem
86 cl_ind = FDTDInducedField(filename='cl.ind', paw=td_calc)
87 cl_ind.calculate_induced_field(gridrefinement=2)
88 cl_ind.write('cl_field.ind', mode='all')
90 # Quantum subsystem
91 qm_ind = TDDFTInducedField(filename='qm.ind', paw=td_calc)
92 qm_ind.calculate_induced_field(gridrefinement=2)
93 qm_ind.write('qm_field.ind', mode='all')
95 # Total system, interpolate/extrapolate to a grid with spacing h
96 tot_ind = calculate_hybrid_induced_field(cl_ind, qm_ind, h=0.4)
97 tot_ind.write('tot_field.ind', mode='all')
99 # Test induced fields
100 ref_values = [72404.467117024149,
101 0.520770766296,
102 0.520770766299,
103 0.830247064075,
104 72416.234345610734,
105 0.517294132489,
106 0.517294132492,
107 0.824704513888,
108 2451.767847927681,
109 0.088037476748,
110 0.088037476316,
111 0.123334033914,
112 2454.462292798476,
113 0.087537484422,
114 0.087537483971,
115 0.122592730690,
116 76582.089818637178,
117 0.589941751987,
118 0.589941751804,
119 0.869526245360,
120 76592.175846021099,
121 0.586223386358,
122 0.586223386102,
123 0.864478308364]
125 for fname in ['cl_field.ind', 'qm_field.ind', 'tot_field.ind']:
126 ind = BaseInducedField(filename=fname,
127 readmode='field')
128 # Estimate tolerance (worst case error accumulation)
129 tol = (iterations * ind.fieldgd.integrate(ind.fieldgd.zeros() + 1.0) *
130 max(density_eps, np.sqrt(poisson_eps)))
131 if do_print_values:
132 print('tol = %.12f' % tol)
133 for w in range(len(frequencies)):
134 val = ind.fieldgd.integrate(ind.Ffe_wg[w])
135 assert val == pytest.approx(ref_values.pop(0), abs=tol)
136 for v in range(3):
137 val = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[w][v]))
138 assert val == pytest.approx(ref_values.pop(0), abs=tol)