Line data Source code
1 : !!****m* ABINIT/m_rttddft_tdef
2 : !! NAME
3 : !! m_rttddft_tdef
4 : !!
5 : !! FUNCTION
6 : !! Contains definition of the tdef type
7 : !! related to time-dependent electric field
8 : !!
9 : !! COPYRIGHT
10 : !! Copyright (C) 2021-2026 ABINIT group (FBrieuc)
11 : !! This file is distributed under the terms of the
12 : !! GNU General Public License, see ~abinit/COPYING
13 : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : !!
15 : !! SOURCE
16 :
17 : #if defined HAVE_CONFIG_H
18 : #include "config.h"
19 : #endif
20 :
21 : #include "abi_common.h"
22 :
23 : module m_rttddft_tdef
24 :
25 : use defs_basis
26 : use defs_abitypes, only: MPI_type
27 :
28 : use m_dtset, only: dataset_type
29 : use m_errors, only: msg_hndl
30 : use m_initylmg, only: initylmg
31 : use m_profiling_abi, only: abimem_record
32 : use m_xmpi, only: xmpi_bcast
33 :
34 : implicit none
35 :
36 : private
37 : !!***
38 :
39 : !! NAME
40 : !! tdef_type: Time Dependent Electric Field type
41 : !! Object containing the TD Electric field
42 : !! for RT-TDDFT runs
43 : !!
44 : !! SOURCE
45 : type,public :: tdef_type
46 :
47 : integer :: ef_type !type of TD electric feld (Dirac or sin^2 pulse)
48 : real(dp) :: efield(3) !TD external elec. field perturbation
49 : real(dp) :: ef_ezero(3) !E_0 = |E_0|*polarization
50 : real(dp) :: vecpot(3) !total vector potential
51 : real(dp) :: vecpot_ext(3) !external vector potential
52 : real(dp) :: vecpot_ind(3,2) !induced vector potential at t and t-dt
53 : real(dp) :: vecpot_red(3) !total vector potential in reduced coord. (in reciprocal space)
54 : real(dp) :: ef_tzero !time at which elec field is switched on
55 : real(dp) :: ef_omega !angular freq. of TD elec field
56 : real(dp) :: ef_tau !time width of the pulse
57 : real(dp) :: ef_sin_a !useful constant for sin^2 pulse
58 : real(dp) :: ef_sin_b !useful constant for sin^2 pulse
59 : real(dp), allocatable :: kpa(:,:) ! contains kpts + A
60 : ! (in reduced coordinates in reciprocal space)
61 : logical :: induced_vecpot ! Add the vector potential induced by the current density
62 : ! in the Hamiltonian
63 :
64 : contains
65 :
66 : procedure :: init => tdef_init
67 : procedure :: update => tdef_update
68 : procedure :: restart => tdef_restart
69 :
70 : end type tdef_type
71 : !!***
72 :
73 : contains
74 : !!***
75 :
76 : !!****f* m_rttddft/tdef_init
77 : !!
78 : !! NAME
79 : !! tdef_init
80 : !!
81 : !! FUNCTION
82 : !! Update value of electric field and vector potential at time t
83 : !!
84 : !! INPUTS
85 : !! [tdef = tdef structure to update]
86 : !! td_ef_type = type of electric field (Dirac or sin^2 pulse)
87 : !! td_ef_pol = polarization
88 : !! td_ef_ezero = Amplitude (E_0 = |E_0|*polarization)
89 : !! td_ef_tzero = time at which the pulse is switched on
90 : !! td_ef_lambda = wavelength (for sin^2 pulse)
91 : !! td_ef_tau = time width of the pulse (for finite-width delta kick or sin^2 pulse)
92 : !! time = propagation time
93 : !! nkpt = number of kpoints
94 : !! kpts = kpoints array
95 : !!
96 : !! OUTPUT
97 : !! [tdef = updated tdef structure]
98 : !!
99 : !! SOURCE
100 50 : subroutine tdef_init(tdef,td_ef_type,td_ef_pol,td_ef_ezero,td_ef_tzero,td_ef_lambda,td_ef_tau,td_ef_induced_vecpot,nkpt,kpts)
101 :
102 : !Arguments ------------------------------------
103 : !scalars
104 : class(tdef_type), intent(inout) :: tdef
105 : integer, intent(in) :: td_ef_type, td_ef_induced_vecpot, nkpt
106 : real(dp), intent(in) :: td_ef_ezero, td_ef_tzero, td_ef_lambda, td_ef_tau
107 : !arrays
108 : real(dp), intent(in) :: kpts(:,:)
109 :
110 : !Local variables-------------------------------
111 : real(dp), intent(in) :: td_ef_pol(3)
112 :
113 : ! ***********************************************************************
114 :
115 50 : if (td_ef_type > 1 .or. td_ef_type < 0) then
116 0 : ABI_ERROR("Wrong value of td_ef_type")
117 : end if
118 :
119 50 : tdef%ef_type = td_ef_type
120 200 : tdef%ef_ezero = td_ef_pol*td_ef_ezero
121 50 : tdef%ef_tau = td_ef_tau
122 50 : tdef%ef_omega = 2.0_dp*pi*Speed_Light/td_ef_lambda !2*pi*f=2*pi*c/lambda
123 50 : tdef%ef_tzero = td_ef_tzero
124 50 : tdef%ef_sin_a = 2.0_dp*pi/td_ef_tau + tdef%ef_omega
125 50 : tdef%ef_sin_b = 2.0_dp*pi/td_ef_tau - tdef%ef_omega
126 50 : if (td_ef_induced_vecpot == 0) then
127 48 : tdef%induced_vecpot = .false.
128 2 : else if (td_ef_induced_vecpot == 1) then
129 2 : tdef%induced_vecpot = .true.
130 : else
131 0 : ABI_ERROR("Wrong value of td_ef_induced_vecpot")
132 : end if
133 :
134 200 : tdef%efield = zero
135 200 : tdef%vecpot = zero
136 200 : tdef%vecpot_ext = zero
137 450 : tdef%vecpot_ind = zero
138 200 : tdef%vecpot_red = zero
139 :
140 150 : ABI_MALLOC(tdef%kpa,(3,nkpt))
141 3732 : tdef%kpa = kpts
142 :
143 50 : end subroutine tdef_init
144 : !!***
145 :
146 : !!****f* m_rttddft/tdef_update
147 : !!
148 : !! NAME
149 : !! tdef_update
150 : !!
151 : !! FUNCTION
152 : !! Update value of electric field and vector potential at time t
153 : !!
154 : !! INPUTS
155 : !! [tdef = tdef structure to update]
156 : !! dtset = dataset structure
157 : !! mpi_enreg = MPI communicators structure
158 : !! time = propagation time
159 : !! rprimd = cell vectors (direct space)
160 : !! gprimd = cell vectors (reciprocal space)
161 : !! kg = kpoints in reciprocal space
162 : !! mpsang = 1+maximum angular momentum for nonlocal pseudopotential (required by initylmg)
163 : !! npwarr = array holding npw for each k point
164 : !! ylm = real spherical harmonics for each G and k point
165 : !! ylmgr = gradient of real spherical harmonics for each G and k point
166 : !! current = total current density
167 : !!
168 : !! OUTPUT
169 : !! [tdef = updated tdef structure]
170 : !!
171 : !! SOURCE
172 1795 : subroutine tdef_update(tdef,dtset,mpi_enreg,time,rprimd,gprimd,kg,mpsang,npwarr,ylm,ylmgr,current,update_vecpot_ind)
173 :
174 : !Arguments ------------------------------------
175 : !scalars
176 : class(tdef_type), intent(inout) :: tdef
177 : type(dataset_type), intent(inout) :: dtset
178 : type(MPI_type), intent(inout) :: mpi_enreg
179 : real(dp), intent(in) :: time
180 : real(dp), intent(in) :: rprimd(3,3)
181 : real(dp), intent(in) :: gprimd(3,3)
182 : integer, intent(in) :: kg(:,:)
183 : integer, intent(in) :: mpsang
184 : integer, intent(in) :: npwarr(:)
185 : real(dp), intent(in) :: current(:,:)
186 : real(dp), intent(out) :: ylm(:,:)
187 : real(dp), intent(out) :: ylmgr(:,:,:)
188 : logical, optional, intent(in) :: update_vecpot_ind
189 :
190 : !Local variables-------------------------------
191 : character(len=500) :: msg
192 : integer :: i
193 : logical :: lvecpot_ind
194 : real(dp) :: tmp(3), expt
195 :
196 : ! ***********************************************************************
197 :
198 : ! Update potential vector if time-dependent electric field perturbation is present
199 2916 : select case (tdef%ef_type)
200 : !No external field
201 : case (0)
202 : !Dirac pulse: vector potential is just an Heaviside function
203 : case (1)
204 1121 : if (abs(time-tdef%ef_tzero)<tol16) then
205 44 : tdef%efield(:) = tdef%ef_ezero(:)
206 : else
207 4440 : tdef%efield(:) = zero
208 : end if
209 1121 : if (time >= tdef%ef_tzero) then
210 4324 : tdef%vecpot_ext(:) = -tdef%ef_ezero(:)
211 : end if
212 : !"Finite" delta-kick pulse: Vector potential is a finite width sigmoid function
213 : case (2)
214 0 : expt = exp(-(time-tdef%ef_tzero)/tdef%ef_tau)
215 0 : tdef%efield(:) = tdef%ef_ezero(:)/tdef%ef_tau * expt/(1+expt)**2
216 0 : tdef%vecpot_ext(:) = -tdef%ef_ezero(:)/(1+expt)**2
217 : !Pulse with sin^2 shape:
218 : !E(t) = E0*cos(w*(t-t0))*sin^2(pi*(t-t0)/tau)
219 : !A(t) = -(E0/2w)*sin(w*(t-t0))+E0/(4*(2pi/tau+w))*sin((2pi/tau+w)*(t-t0))+E0/(4(2pi/tau-w))*sin((2pi/tau-w)*(t-t0))
220 : ! case(2)
221 : ! if (time >= tdef%ef_tzero+tdef%ef_tau) then
222 : ! tdef%efield(:) = zero
223 : ! else if (time >= tdef%ef_tzero) then
224 : ! t = time-tdef%ef_tzero
225 : ! tdef%efield(:) = tdef%ef_ezero*cos(tdef%ef_omega*t)*sin(pi*t/tdef%ef_tau)**2
226 : ! tdef%vecpot_ext(:) = tdef%ef_ezero*(-sin(tdef%ef_omega*t)/(two*tdef%ef_omega) &
227 : ! & +sin(tdef%ef_sin_a*t)/(four*tdef%ef_sin_a) &
228 : ! & +sin(tdef%ef_sin_b*t)/(four*tdef%ef_sin_b))
229 : ! end if
230 : case default
231 0 : write(msg,"(a)") "Unknown electric field type - check the value of td_ef_type"
232 1795 : ABI_ERROR(msg)
233 : end select
234 :
235 1795 : lvecpot_ind = .true.
236 1795 : if (present(update_vecpot_ind)) lvecpot_ind = update_vecpot_ind
237 :
238 : !Induced vector potential
239 : !Should deal with sppol?! How?
240 : !d^2A_ind/dt^2 = 4piJ(t)
241 : !A_ind(t+dt) = 2*A_ind(t) - A_ind(t-dt) + 4*pi*dt**2*J(t)
242 1795 : if (tdef%induced_vecpot) then
243 102 : if (lvecpot_ind) then
244 404 : tmp = tdef%vecpot_ind(:,2) ! t - 2dt
245 404 : tdef%vecpot_ind(:,2) = tdef%vecpot_ind(:,1) ! t - dt
246 404 : tdef%vecpot_ind(:,1) = 2*tdef%vecpot_ind(:,2) - tmp(:) + four*pi*(dtset%dtele**2)*current(:,1) ! t
247 : end if
248 408 : tdef%vecpot = tdef%vecpot_ext + tdef%vecpot_ind(:,1)
249 : else
250 6772 : tdef%vecpot = tdef%vecpot_ext
251 : end if
252 :
253 7180 : tdef%vecpot_red = matmul(transpose(rprimd),tdef%vecpot)
254 :
255 1795 : if (tdef%ef_type /= 0) then
256 : !Update the k+A grid used in cprojs
257 : !Divide by 2pi here seems necessary
258 4484 : do i = 1,3
259 112100 : tdef%kpa(i,:) = dtset%kptns(i,:) + tdef%vecpot_red(i)/(two*pi)
260 : end do
261 : ! update the spherical harmonics (computed at k+G+A)
262 : call initylmg(gprimd,kg,tdef%kpa,dtset%mkmem,mpi_enreg,mpsang,dtset%mpw,dtset%nband, &
263 1121 : & dtset%nkpt,npwarr,dtset%nsppol,0,rprimd,ylm,ylmgr)
264 : end if
265 :
266 1795 : end subroutine tdef_update
267 : !!***
268 :
269 : !!****f* m_rttddft/tdef_restart
270 : !!
271 : !! NAME
272 : !! tdef_restart
273 : !!
274 : !! FUNCTION
275 : !! Update some values for restart of calculation with TD electric field
276 : !! Essentially needed if we account for induced vector potential
277 : !!
278 : !! INPUTS
279 : !! [tdef = tdef structure to update]
280 : !! mpi_enreg = MPI communicators structure
281 : !! restart_unit = unit of restart file to read
282 : !!
283 : !! OUTPUT
284 : !! [tdef = updated tdef structure]
285 : !!
286 : !! SOURCE
287 20 : subroutine tdef_restart(tdef,mpi_enreg,restart_unit)
288 :
289 : !Arguments ------------------------------------
290 : !scalars
291 : class(tdef_type), intent(inout) :: tdef
292 : type(MPI_type), intent(inout) :: mpi_enreg
293 : integer, intent(in) :: restart_unit
294 :
295 : !Local variables-------------------------------
296 : integer :: ierr
297 :
298 : ! ***********************************************************************
299 :
300 20 : if (tdef%induced_vecpot) then
301 1 : if (mpi_enreg%me == 0) then
302 1 : read(restart_unit,*) tdef%vecpot_ind(:,2)
303 1 : read(restart_unit,*) tdef%vecpot_ind(:,1)
304 : end if
305 : end if
306 : !Send to all procs
307 20 : call xmpi_bcast(tdef%vecpot_ind,0,mpi_enreg%comm_world,ierr)
308 :
309 20 : end subroutine tdef_restart
310 : !!***
311 :
312 0 : end module m_rttddft_tdef
313 : !!***
|