Octopus
dielectric_function.F90
Go to the documentation of this file.
1!! Copyright (C) 2008 X. Andrade
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
33 use batch_oct_m
35 use global_oct_m
36 use io_oct_m
39 use math_oct_m
42 use parser_oct_m
44 use space_oct_m
46 use unit_oct_m
48
49 implicit none
50
51 private
53
54contains
55
56 subroutine dielectric_function_main() bind(c)
57 integer :: ierr
58
59 ! Initialize stuff
61
62 call getopt_init(ierr)
63 if (ierr == 0) call getopt_dielectric_function()
64 call getopt_end()
65
66 call parser_init()
67
68 call messages_init()
69
70 call io_init()
72
74
76
78 call io_end()
79 call messages_end()
80
81 call parser_end()
82 call global_end()
83
84 contains
85
87
88 integer :: in_file, out_file, ref_file, ii, jj, kk
89 integer :: time_steps, time_steps_ref, energy_steps, istart, iend, ntiter
90 real(real64) :: dt, dt_ref, tt, ww, norm_Aext
91 real(real64), allocatable :: vecpot(:, :), Aext(:), Eind_real(:, :), Eind_imag(:, :)
92 complex(real64), allocatable :: dielectric(:), chi(:), invdielectric(:)
93 real(real64), allocatable :: vecpot_ref(:, :)
94 type(spectrum_t) :: spectrum
95 type(block_t) :: blk
96 type(space_t) :: space
97 type(lattice_vectors_t) :: latt
98 type(batch_t) :: vecpotb, Eind_realb, Eind_imagb
99 character(len=120) :: header
100 real(real64) :: start_time
101 character(len=MAX_PATH_LEN) :: ref_filename
102 complex(real64),allocatable :: Eind(:)
103
104 call spectrum_init(spectrum, global_namespace)
105
108
109 safe_allocate(aext(1:space%dim))
110 safe_allocate(eind(1:space%dim))
111
112 if (parse_block(global_namespace, 'GaugeVectorField', blk) == 0) then
113
114 do ii = 1, space%dim
115 call parse_block_float(blk, 0, ii - 1, aext(ii))
116 end do
117
118 call parse_block_end(blk)
119
120 else
121
122 message(1) = "Cannot find the GaugeVectorField in the input file"
123 call messages_fatal(1)
124
125 end if
126
127 if(space%dim > 1) then
128 message(1) = "This program assumes that the gauge field is along a "
129 message(2) = "direction for which the dielectric tensor has no off-diagonal terms."
130 message(3) = "If this is not the case the dielectric function and the"
131 message(4) = "susceptibility will be wrong."
132 call messages_warning(4)
133 end if
134
135 start_time = spectrum%start_time
136 call parse_variable(global_namespace, 'GaugeFieldDelay', start_time, spectrum%start_time)
137
138 in_file = io_open('td.general/gauge_field', global_namespace, action='read', status='old')
139
140 ! Get the number of iterations and the time-step
141 call io_skip_header(in_file)
142 call spectrum_count_time_steps(global_namespace, in_file, time_steps, dt)
143
144 ! Fix the correct time at which the kick was applied.
145 ! This guaranties that the first time has exactly a zero vector potential
146 ! If we do not do this, we can get some artifacts for transient absorption.
147 spectrum%start_time = ceiling(spectrum%start_time/dt)*dt
148
149 if (parse_is_defined(global_namespace, 'TransientAbsorptionReference')) then
150 !%Variable TransientAbsorptionReference
151 !%Type string
152 !%Default "."
153 !%Section Utilities::oct-propagation_spectrum
154 !%Description
155 !% In case of delayed kick, the calculation of the transient absorption requires
156 !% to substract a reference calculation, containing the gauge-field without the kick
157 !% This reference must be computed using GaugeFieldPropagate=yes and to have
158 !% TDOutput = gauge_field.
159 !% This variables defined the directory in which the reference gauge_field field is,
160 !% relative to the current folder
161 !%End
162
163 call parse_variable(global_namespace, 'TransientAbsorptionReference', '.', ref_filename)
164 ref_file = io_open(trim(ref_filename)//'/gauge_field', global_namespace, action='read', status='old')
165 call io_skip_header(ref_file)
166 call spectrum_count_time_steps(global_namespace, ref_file, time_steps_ref, dt_ref)
167 if (time_steps_ref < time_steps) then
168 message(1) = "The reference calculation does not contain enought time steps"
169 call messages_fatal(1)
170 end if
171
172 if (.not. is_close(dt_ref, dt)) then
173 message(1) = "The time step of the reference calculation is different from the current calculation"
174 call messages_fatal(1)
175 end if
176
177 end if
178
179 ! Add one as zero is included in the time signal
180 time_steps = time_steps + 1
181
182 safe_allocate(vecpot(1:time_steps, 1:space%dim*3))
183
184 call io_skip_header(in_file)
185
186 do ii = 1, time_steps
187 read(in_file, *) jj, tt, (vecpot(ii, kk), kk = 1, space%dim*3)
188 end do
189
190 call io_close(in_file)
191
192 !We remove the reference
193 if (parse_is_defined(global_namespace, 'TransientAbsorptionReference')) then
194 time_steps_ref = time_steps_ref + 1
195 safe_allocate(vecpot_ref(1:time_steps_ref, 1:space%dim*3))
196 call io_skip_header(ref_file)
197 do ii = 1, time_steps_ref
198 read(ref_file, *) jj, tt, (vecpot_ref(ii, kk), kk = 1, space%dim*3)
199 end do
200 call io_close(ref_file)
201 do ii = 1, time_steps
202 do kk = 1, space%dim*3
203 vecpot(ii, kk) = vecpot(ii, kk) - vecpot_ref(ii, kk)
204 end do
205 end do
206 end if
207
208 write(message(1), '(a, i7, a)') "Info: Read ", time_steps, " steps from file '"// &
209 trim(io_workpath('td.general/gauge_field', global_namespace))//"'"
210 call messages_info(1)
211
212
213 ! Find out the iteration numbers corresponding to the time limits.
214 ! Max time correspond to time_steps-1, as we start from 0.
215 call spectrum_fix_time_limits(spectrum, time_steps-1, dt, istart, iend, ntiter)
216
217 ! We need to fix istart because the damping starts are (istart-1)*dt, which needs to be spectrum%start_time
218 istart = istart + 1
219
220 energy_steps = spectrum_nenergy_steps(spectrum)
221
222 norm_aext = norm2(aext(1:space%dim))
223 if (norm_aext <= tiny(1.0_real64)) then
224 message(1) = "GaugeVectorField norm is zero (or underflow-level); cannot normalize dielectric response."
225 call messages_fatal(1)
226 end if
227
228 safe_allocate(eind_real(1:energy_steps, 1:space%dim))
229 safe_allocate(eind_imag(1:energy_steps, 1:space%dim))
230
231 ! We select dA/dt = E
232 call batch_init(vecpotb, 1, 1, space%dim, vecpot(:, space%dim+1:space%dim*2))
233 call batch_init(eind_realb, 1, 1, space%dim, eind_real)
234 call batch_init(eind_imagb, 1, 1, space%dim, eind_imag)
235
236 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart, iend, spectrum%start_time, dt, vecpotb)
237
238 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
239 istart, iend, spectrum%start_time, dt, vecpotb, spectrum%min_energy, &
240 spectrum%max_energy, spectrum%energy_step, eind_realb)
241
242 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
243 istart, iend, spectrum%start_time, dt, vecpotb, spectrum%min_energy, &
244 spectrum%max_energy, spectrum%energy_step, eind_imagb)
245
246
247 call vecpotb%end()
248 call eind_realb%end()
249 call eind_imagb%end()
250
251 safe_allocate(invdielectric(1:energy_steps))
252 safe_allocate(dielectric(1:energy_steps))
253 safe_allocate(chi(1:energy_steps))
254
255 do kk = 1, energy_steps
256 ww = (kk-1)*spectrum%energy_step + spectrum%min_energy
257
258 ! We compute 1/\epsilon(\omega), see Eq. (4) in Bertsch et al. PRB 62, 7998
259 ! More precisely, we have \epsilon^{-1}_{\alpha\beta} = \frac{E_{tot,\alpha}}{E_{ext,\beta}}
260
261 ! Here we can only assume that the Gauge field is along an axis without off-diagonal terms
262 ! Else, we need several calulations
263 eind = cmplx(eind_real(kk, 1:space%dim), eind_imag(kk, 1:space%dim), real64)
264 invdielectric(kk) = dot_product(aext, aext + eind) /norm_aext**2
265
266 dielectric(kk) = m_one / invdielectric(kk)
267
268 chi(kk) = (dielectric(kk) - m_one)*latt%rcell_volume/(m_four*m_pi)
269 end do
270
271 out_file = io_open('td.general/inverse_dielectric_function', global_namespace, action='write')
272 write(header, '(7a15)') '# energy', 'Re', 'Im'
273
274 write(out_file,'(a)') trim(header)
275 do kk = 1, energy_steps
276 ww = (kk-1)*spectrum%energy_step + spectrum%min_energy
277 write(out_file, '(e15.6)', advance='no') ww
278 write(out_file, '(2e15.6)', advance='no') real(invdielectric(kk), real64), aimag(invdielectric(kk))
279 write(out_file, '()')
280 end do
281 call io_close(out_file)
282
283 out_file = io_open('td.general/dielectric_function', global_namespace, action='write')
284 write(out_file,'(a)') trim(header)
285 do kk = 1, energy_steps
286 ww = (kk-1)*spectrum%energy_step + spectrum%min_energy
287 write(out_file, '(e15.6)', advance='no') ww
288 write(out_file, '(2e15.6)', advance='no') real(dielectric(kk), real64), aimag(dielectric(kk))
289 write(out_file, '()')
290 end do
291 call io_close(out_file)
292
293 out_file = io_open('td.general/chi', global_namespace, action='write')
294 write(out_file,'(a)') trim(header)
295 do kk = 1, energy_steps
296 ww = (kk-1)*spectrum%energy_step + spectrum%min_energy
297 write(out_file, '(e15.6)', advance='no') ww
298 write(out_file, '(2e15.6)', advance='no') real(chi(kk), real64), aimag(chi(kk))
299 write(out_file, '()')
300 end do
301 call io_close(out_file)
302
303 safe_deallocate_a(dielectric)
304 safe_deallocate_a(invdielectric)
305 safe_deallocate_a(chi)
306 safe_deallocate_a(vecpot)
307 safe_deallocate_a(vecpot_ref)
308 safe_deallocate_a(aext)
309 safe_deallocate_a(eind)
310 safe_deallocate_a(eind_real)
311 safe_deallocate_a(eind_imag)
312
313 end subroutine dielectric_function_compute
314 end subroutine dielectric_function_main
316
317!! Local Variables:
318!! mode: f90
319!! coding: utf-8
320!! End:
subroutine dielectric_function_compute()
initialize a batch with existing memory
Definition: batch.F90:294
This module implements batches of mesh functions.
Definition: batch.F90:133
subroutine, public getopt_init(ierr)
Initializes the getopt machinery. Must be called before attempting to parse the options....
subroutine, public getopt_end
A utility used to obtain the dielectric function from a kick calculation using the gauge field approa...
subroutine, public dielectric_function_main()
subroutine, public global_end()
Finalise parser varinfo file, and MPI.
Definition: global.F90:493
real(real64), parameter, public m_four
Definition: global.F90:202
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:196
type(mpi_comm), parameter, public serial_dummy_comm
Alias MPI_COMM_UNDEFINED for the specific use case of initialising Octopus utilities with no MPI supp...
Definition: global.F90:293
subroutine, public init_octopus_globals(comm)
Initialise Octopus-specific global constants and files. This routine performs no initialisation calls...
Definition: global.F90:431
real(real64), parameter, public m_one
Definition: global.F90:199
Definition: io.F90:114
subroutine, public io_init(defaults)
If the argument defaults is present and set to true, then the routine will not try to read anything f...
Definition: io.F90:163
subroutine, public io_close(iunit, grp)
Definition: io.F90:465
subroutine, public io_skip_header(iunit)
Definition: io.F90:644
subroutine, public io_end()
Definition: io.F90:269
character(len=max_path_len) function, public io_workpath(path, namespace)
construct path name from given name and namespace
Definition: io.F90:316
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:400
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public messages_end()
Definition: messages.F90:271
subroutine, public messages_init(output_dir)
Definition: messages.F90:218
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:523
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:408
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:592
type(namespace_t), public global_namespace
Definition: namespace.F90:133
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:461
subroutine, public parser_init()
Initialise the Octopus parser.
Definition: parser.F90:408
subroutine, public parser_end()
End the Octopus parser.
Definition: parser.F90:440
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:621
/* To use the profiling module, call profiling_in and profiling_out with the label of the region as a...
Definition: profiling.F90:143
subroutine, public profiling_end(namespace)
Definition: profiling.F90:476
subroutine, public profiling_init(namespace)
Create profiling subdirectory.
Definition: profiling.F90:285
subroutine, public spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
Definition: spectrum.F90:2536
subroutine, public spectrum_fourier_transform(method, transform, noise, time_start, time_end, t0, time_step, time_function, energy_start, energy_end, energy_step, energy_function)
Computes the sine, cosine, (or "exponential") Fourier transform of the real function given in the tim...
Definition: spectrum.F90:2666
subroutine, public spectrum_init(spectrum, namespace, default_energy_step, default_max_energy)
Definition: spectrum.F90:218
subroutine, public spectrum_signal_damp(damp_type, damp_factor, time_start, time_end, t0, time_step, time_function)
Definition: spectrum.F90:2580
integer, parameter, public spectrum_transform_cos
Definition: spectrum.F90:171
integer, parameter, public spectrum_transform_sin
Definition: spectrum.F90:171
subroutine, public spectrum_count_time_steps(namespace, iunit, time_steps, dt)
Definition: spectrum.F90:2401
pure integer function, public spectrum_nenergy_steps(spectrum)
Definition: spectrum.F90:2977
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
This module defines the unit system, used for input and output.
subroutine, public unit_system_init(namespace)