Coverage for gpaw/test/test_inducedfield_td.py: 100%
60 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-09 00:21 +0000
1import pytest
2import numpy as np
3from ase import Atoms
5from gpaw import GPAW
6from gpaw.tddft import TDDFT, DipoleMomentWriter
7from gpaw.inducedfield.inducedfield_base import BaseInducedField
8from gpaw.inducedfield.inducedfield_tddft import TDDFTInducedField
9from gpaw.poisson import PoissonSolver
12@pytest.mark.ci
13def test_inducedfield_td(in_tmp_dir):
14 poisson_eps = 1e-12
15 density_eps = 1e-6
17 # PoissonSolver
18 poissonsolver = PoissonSolver('fd', eps=poisson_eps)
20 # Na2 cluster
21 atoms = Atoms(symbols='Na2',
22 positions=[(0, 0, 0), (3.0, 0, 0)],
23 pbc=False)
24 atoms.center(vacuum=3.0)
26 # Standard ground state calculation
27 calc = GPAW(mode='fd', nbands=2,
28 h=0.6,
29 setups={'Na': '1'},
30 poissonsolver=poissonsolver,
31 symmetry={'point_group': False},
32 convergence={'density': density_eps})
33 atoms.calc = calc
34 _ = atoms.get_potential_energy()
35 calc.write('na2_gs.gpw', mode='all')
37 # Standard time-propagation initialization
38 time_step = 10.0
39 iterations = 20
40 kick_strength = [1.0e-3, 1.0e-3, 0.0]
41 td_calc = TDDFT('na2_gs.gpw')
42 DipoleMomentWriter(td_calc, 'na2_td_dm.dat')
44 # Create and attach InducedField object
45 frequencies = [1.0, 2.08] # Frequencies of interest in eV
46 folding = 'Gauss' # Folding function
47 width = 0.1 # Line width for folding in eV
48 ind = TDDFTInducedField(paw=td_calc,
49 frequencies=frequencies,
50 folding=folding,
51 width=width,
52 restart_file='na2_td.ind')
54 # Propagate as usual
55 td_calc.absorption_kick(kick_strength=kick_strength)
56 td_calc.propagate(time_step, iterations // 2)
58 # Save TDDFT and InducedField objects
59 td_calc.write('na2_td.gpw', mode='all')
60 ind.write('na2_td.ind')
61 ind.paw = None
63 # Restart and continue
64 td_calc = TDDFT('na2_td.gpw')
65 DipoleMomentWriter(td_calc, 'na2_td_dm.dat')
67 # Load and attach InducedField object
68 ind = TDDFTInducedField(filename='na2_td.ind',
69 paw=td_calc,
70 restart_file='na2_td.ind')
72 # Continue propagation as usual
73 td_calc.propagate(time_step, iterations // 2)
75 # Calculate induced electric field
76 ind.calculate_induced_field(gridrefinement=2,
77 from_density='comp',
78 poissonsolver=poissonsolver,
79 extend_N_cd=3 * np.ones((3, 2), int),
80 deextend=True)
82 # Save
83 ind.write('na2_td_field.ind', 'all')
84 ind.paw = None
85 td_calc = None
86 ind = None
88 # Read data (test also field data I/O)
89 ind = BaseInducedField(filename='na2_td_field.ind',
90 readmode='field')
92 # Estimate tolerance (worst case error accumulation)
93 tol = (iterations * ind.fieldgd.integrate(ind.fieldgd.zeros() + 1.0) *
94 max(density_eps, np.sqrt(poisson_eps)))
95 # tol = 0.038905993684
96 # print('tol = %.12f' % tol)
98 # Test
99 val1 = ind.fieldgd.integrate(ind.Ffe_wg[0])
100 val2 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][0]))
101 val3 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][1]))
102 val4 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][2]))
103 val5 = ind.fieldgd.integrate(ind.Ffe_wg[1])
104 val6 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][0]))
105 val7 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][1]))
106 val8 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][2]))
108 assert val1 == pytest.approx(1926.232999117403, abs=tol)
109 assert val2 == pytest.approx(0.427606450419, abs=tol)
110 assert val3 == pytest.approx(0.565823985683, abs=tol)
111 assert val4 == pytest.approx(0.372493489423, abs=tol)
112 assert val5 == pytest.approx(1945.618902611449, abs=tol)
113 assert val6 == pytest.approx(0.423899965987, abs=tol)
114 assert val7 == pytest.approx(0.560882533828, abs=tol)
115 assert val8 == pytest.approx(0.369203021329, abs=tol)