Octopus
spectrum.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
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
21module spectrum_oct_m
22 use batch_oct_m
23 use iso_c_binding
25 use debug_oct_m
26 use fft_oct_m
27 use global_oct_m
28 use io_oct_m
29 use kick_oct_m
30 use, intrinsic :: iso_fortran_env
32 use math_oct_m
36 use parser_oct_m
37 use pcm_oct_m
39 use string_oct_m
40 use types_oct_m
41 use unit_oct_m
44
45 implicit none
46
47 private
48 public :: &
49 spectrum_t, &
70
71 integer, public, parameter :: &
72 SPECTRUM_DAMP_NONE = 0, &
77
78 integer, public, parameter :: &
79 SPECTRUM_TRANSFORM_LAPLACE = 1, &
82
83 integer, public, parameter :: &
84 SPECTRUM_ABSORPTION = 1, &
86 spectrum_p_power = 3, &
88
89 integer, public, parameter :: &
90 SPECTRUM_FOURIER = 1, &
92
93 type spectrum_t
94 real(real64) :: start_time
95 real(real64) :: end_time
96 real(real64) :: energy_step
97 real(real64) :: min_energy
98 real(real64) :: max_energy
99 integer :: damp
100 integer :: transform
101 real(real64) :: damp_factor
102 integer :: spectype
103 integer :: method
104 real(real64) :: noise
105 logical, private :: sigma_diag
106 end type spectrum_t
107
110 integer :: niter_
111 real(real64) :: time_step_, energy_step_
112 complex(real64), allocatable :: func_(:),func_ar_(:,:),pos_(:,:),tret_(:), funcw_(:)
113 type(fft_t), save :: fft_handler
114 integer :: is_, ie_, default
115
117 module procedure spectrum_read_header_line
118 module procedure spectrum_read_header_integer
119 end interface spectrum_read_header
120
121contains
122
123 ! ---------------------------------------------------------
124 subroutine spectrum_init(spectrum, namespace, default_energy_step, default_max_energy)
125 type(spectrum_t), intent(inout) :: spectrum
126 type(namespace_t), intent(in) :: namespace
127 real(real64), optional, intent(in) :: default_energy_step
128 real(real64), optional, intent(in) :: default_max_energy
129
130 real(real64) :: fdefault
131
132 push_sub(spectrum_init)
133
134 call messages_print_with_emphasis(msg="Spectrum Options", namespace=namespace)
135
136 !%Variable PropagationSpectrumType
137 !%Type integer
138 !%Default AbsorptionSpectrum
139 !%Section Utilities::oct-propagation_spectrum
140 !%Description
141 !% Type of spectrum to calculate.
142 !%Option AbsorptionSpectrum 1
143 !% Photoabsorption spectrum.
144 !%Option EnergyLossSpectrum 2
145 !% Dynamic structure factor (also known as energy-loss function or spectrum).
146 !%Option DipolePower 3
147 !% Power spectrum of the dipole moment.
148 !%Option RotatoryStrength 4
149 !% Rotatory strength spectrum.
150 !%End
151
152 call parse_variable(namespace, 'PropagationSpectrumType', spectrum_absorption, spectrum%spectype)
153
154 if (.not. varinfo_valid_option('PropagationSpectrumType', spectrum%spectype)) then
155 call messages_input_error(namespace, 'PropagationSpectrumType')
156 end if
157 call messages_print_var_option('PropagationSpectrumType', spectrum%spectype, namespace=namespace)
158
159 !%Variable SpectrumMethod
160 !%Type integer
161 !%Default fourier
162 !%Section Utilities::oct-propagation_spectrum
163 !%Description
164 !% Decides which method is used to obtain the spectrum.
165 !%Option fourier 1
166 !% The standard Fourier transform. Further specified by <tt>PropagationSpectrumTransform</tt>.
167 !%Option compressed_sensing 2
168 !% (Experimental) Uses the compressed sensing technique.
169 !%End
170 call parse_variable(namespace, 'SpectrumMethod', spectrum_fourier, spectrum%method)
171 if (.not. varinfo_valid_option('SpectrumMethod', spectrum%method)) then
172 call messages_input_error(namespace, 'SpectrumMethod')
173 end if
174 call messages_print_var_option('SpectrumMethod', spectrum%method, namespace=namespace)
175
176 if (spectrum%method == spectrum_compressed_sensing) then
177 call messages_experimental('compressed sensing', namespace=namespace)
179 !%Variable SpectrumSignalNoise
180 !%Type float
181 !%Default 0.0
182 !%Section Utilities::oct-propagation_spectrum
183 !%Description
184 !% For compressed sensing, the signal to process, the
185 !% time-dependent dipole in this case, is assumed to have some
186 !% noise that is given by this dimensionless quantity.
187 !%End
188 call parse_variable(namespace, 'SpectrumSignalNoise', 0.0_real64, spectrum%noise)
189 call messages_print_var_value('SpectrumSignalNoise', spectrum%noise, namespace=namespace)
190 end if
193 !%Variable PropagationSpectrumDampMode
194 !%Type integer
195 !%Section Utilities::oct-propagation_spectrum
196 !%Description
197 !% Decides which damping/filtering is to be applied in order to
198 !% calculate spectra by calculating a Fourier transform. The
199 !% default is polynomial damping, except when <tt>SpectrumMethod = compressed_sensing</tt>.
200 !% In that case the default is none.
201 !%Option none 0
202 !% No filtering at all.
203 !%Option exponential 1
204 !% Exponential filtering, corresponding to a Lorentzian-shaped spectrum.
205 !%Option polynomial 2
206 !% Third-order polynomial damping.
207 !%Option gaussian 3
208 !% Gaussian damping.
209 !%End
211 if (spectrum%method == spectrum_compressed_sensing) default = spectrum_damp_none
212
213 call parse_variable(namespace, 'PropagationSpectrumDampMode', default, spectrum%damp)
214
215 if (.not. varinfo_valid_option('PropagationSpectrumDampMode', spectrum%damp)) then
216 call messages_input_error(namespace, 'PropagationSpectrumDampMode')
217 end if
218 call messages_print_var_option('PropagationSpectrumDampMode', spectrum%damp, namespace=namespace)
220 if (spectrum%method == spectrum_compressed_sensing .and. spectrum%damp /= spectrum_damp_none) then
221 message(1) = 'Using damping with compressed sensing, this is not required'
222 message(2) = 'and can introduce noise in the spectra.'
223 call messages_warning(2, namespace=namespace)
224 end if
225
226 !%Variable PropagationSpectrumTransform
227 !%Type integer
228 !%Default sine
229 !%Section Utilities::oct-propagation_spectrum
230 !%Description
231 !% Decides which transform to perform, if <tt>SpectrumMethod = fourier</tt>.
232 !%Option sine 2
233 !% Sine transform: <math>\int dt \sin(wt) f(t)</math>. Produces the imaginary part of the polarizability.
234 !%Option cosine 3
235 !% Cosine transform: <math>\int dt \cos(wt) f(t)</math>. Produces the real part of the polarizability.
236 !%Option laplace 1
237 !% Real exponential transform: <math>\int dt e^{-wt} f(t)</math>. Produces the real part of the polarizability at imaginary
238 !% frequencies, <i>e.g.</i> for Van der Waals <math>C_6</math> coefficients.
239 !% This is the only allowed choice for complex scaling.
240 !%End
241 call parse_variable(namespace, 'PropagationSpectrumTransform', spectrum_transform_sin, spectrum%transform)
242 if (.not. varinfo_valid_option('PropagationSpectrumTransform', spectrum%transform)) then
243 call messages_input_error(namespace, 'PropagationSpectrumTransform')
244 end if
245 call messages_print_var_option('PropagationSpectrumTransform', spectrum%transform, namespace=namespace)
246
247 !%Variable PropagationSpectrumStartTime
248 !%Type float
249 !%Default 0.0
250 !%Section Utilities::oct-propagation_spectrum
251 !%Description
252 !% Processing is done for the given function in a time-window that starts at the
253 !% value of this variable.
254 !%End
255 call parse_variable(namespace, 'PropagationSpectrumStartTime', m_zero, spectrum%start_time, units_inp%time)
256 call messages_print_var_value('PropagationSpectrumStartTime', spectrum%start_time, unit = units_out%time, namespace=namespace)
257
258 !%Variable PropagationSpectrumEndTime
259 !%Type float
260 !%Default -1.0 au
261 !%Section Utilities::oct-propagation_spectrum
262 !%Description
263 !% Processing is done for the given function in a time-window that ends at the
264 !% value of this variable. If set to a negative value, the maximum value from
265 !% the corresponding multipole file will used.
266 !%End
267 call parse_variable(namespace, 'PropagationSpectrumEndTime', -m_one, spectrum%end_time, units_inp%time)
268 call messages_print_var_value('PropagationSpectrumEndTime', spectrum%end_time, unit = units_out%time, namespace=namespace)
269
270 !%Variable PropagationSpectrumEnergyStep
271 !%Type float
272 !%Default 0.01 eV
273 !%Section Utilities::oct-propagation_spectrum
274 !%Description
275 !% Sampling rate for the spectrum. If you supply a number equal or smaller than zero, then
276 !% the sampling rate will be <math>2 \pi / T</math>, where <math>T</math> is the total propagation time.
277 !%End
278 fdefault = 0.01_real64/(m_two*p_ry)
279 if (present(default_energy_step)) fdefault = default_energy_step
280 call parse_variable(namespace, 'PropagationSpectrumEnergyStep', fdefault, spectrum%energy_step, units_inp%energy)
281 call messages_print_var_value('PropagationSpectrumEnergyStep', spectrum%energy_step, unit = units_out%energy, &
282 namespace=namespace)
283
284 !%Variable PropagationSpectrumMinEnergy
285 !%Type float
286 !%Default 0
287 !%Section Utilities::oct-propagation_spectrum
288 !%Description
289 !% The Fourier transform is calculated for energies larger than this value.
290 !%End
291 call parse_variable(namespace, 'PropagationSpectrumMinEnergy', m_zero, spectrum%min_energy, units_inp%energy)
292 call messages_print_var_value('PropagationSpectrumMinEnergy', spectrum%min_energy, unit = units_out%energy, &
293 namespace=namespace)
294
295
296 !%Variable PropagationSpectrumMaxEnergy
297 !%Type float
298 !%Default 20 eV
299 !%Section Utilities::oct-propagation_spectrum
300 !%Description
301 !% The Fourier transform is calculated for energies smaller than this value.
302 !%End
303 fdefault = 20.0_real64/(m_two*p_ry)
304 if (present(default_max_energy)) fdefault = default_max_energy
305 call parse_variable(namespace, 'PropagationSpectrumMaxEnergy', fdefault, spectrum%max_energy, units_inp%energy)
306 call messages_print_var_value('PropagationSpectrumMaxEnergy', spectrum%max_energy, unit = units_out%energy, &
307 namespace=namespace)
308
309 !%Variable PropagationSpectrumDampFactor
310 !%Type float
311 !%Default -1.0
312 !%Section Utilities::oct-propagation_spectrum
313 !%Description
314 !% If <tt>PropagationSpectrumDampMode = exponential, gaussian</tt>, the damping parameter of the exponential
315 !% is fixed through this variable.
316 !% Default value ensure that the damping function adquires a 0.0001 value at the end of the propagation time.
317 !%End
318 call parse_variable(namespace, 'PropagationSpectrumDampFactor', -m_one, spectrum%damp_factor, units_inp%time**(-1))
319
320 call messages_print_var_value('PropagationSpectrumDampFactor', spectrum%damp_factor, unit = units_out%time**(-1), &
321 namespace=namespace)
322
323 !%Variable PropagationSpectrumSigmaDiagonalization
324 !%Type logical
325 !%Default .false.
326 !%Section Utilities::oct-propagation_spectrum
327 !%Description
328 !% If <tt>PropagationSpectrumSigmaDiagonalization = yes</tt>, the polarizability tensor is diagonalizied.
329 !% This variable is only used if the cross_section_tensor is computed.
330 !%End
331 call parse_variable(namespace, 'PropagationSpectrumSigmaDiagonalization', .false., spectrum%sigma_diag)
332 call messages_print_var_value('PropagationSpectrumSigmaDiagonalization', spectrum%sigma_diag, namespace=namespace)
333
334 call messages_print_with_emphasis(namespace=namespace)
335
336 pop_sub(spectrum_init)
337 end subroutine spectrum_init
338
339
340 ! ---------------------------------------------------------
341 subroutine spectrum_cross_section_tensor(spectrum, namespace, out_file, in_file)
342 type(spectrum_t), intent(inout) :: spectrum
343 type(namespace_t), intent(in) :: namespace
344 integer, intent(in) :: out_file
345 integer, contiguous, intent(in) :: in_file(:)
346
347 integer :: nspin, energy_steps, ie, is, equiv_axes, n_files, trash
348 real(real64), allocatable :: sigma(:, :, :, :), sigmap(:, :, :, :), sigmau(:, :, :), &
349 sigmav(:, :, :), sigmaw(:, :, :), ip(:, :)
350 real(real64) :: dw, dump
351 type(kick_t) :: kick
352
354
355 n_files = size(in_file)
356 equiv_axes = 3 - n_files + 1
357
358 call spectrum_cross_section_info(namespace, in_file(1), nspin, kick, energy_steps, dw)
359 ! on subsequent calls, do not overwrite energy_steps and dw
360 call io_skip_header(in_file(1))
361
362 safe_allocate(sigma(1:3, 1:3, 1:energy_steps, 1:nspin))
363 safe_allocate(sigmap(1:3, 1:3, 1:energy_steps, 1:nspin))
364 safe_allocate(sigmau(1:3, 1:energy_steps, 1:nspin))
365 safe_allocate(sigmav(1:3, 1:energy_steps, 1:nspin))
366 safe_allocate(sigmaw(1:3, 1:energy_steps, 1:nspin))
367 safe_allocate( ip(1:3, 1:3))
368
369 select case (equiv_axes)
370
371 case (3)
372
373 do ie = 1, energy_steps
374 read(in_file(1), *) dump, (sigmau(1:3, ie, is), is = 1, nspin)
375 end do
376
377 ! The first row of sigma is the vector that we have just read, but properly projected...
378 do is = 1, nspin
379 do ie = 1, energy_steps
380 sigmap(1, 1, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 1))
381 sigmap(1, 2, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 2))
382 sigmap(1, 3, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 3))
383 end do
384 end do
385
386 ! The diagonal parts are also equal:
387 sigmap(2, 2, :, :) = sigmap(1, 1, :, :)
388 sigmap(3, 3, :, :) = sigmap(1, 1, :, :)
389
390 ! The (2,1) term and (3,1) term are equal by symmetry:
391 sigmap(2, 1, :, :) = sigmap(1, 2, :, :)
392 sigmap(3, 1, :, :) = sigmap(1, 3, :, :)
393
394 ! But for the (2,3) term we need the wprime vector....
395 do is = 1, nspin
396 do ie = 1, energy_steps
397 sigmap(2, 3, ie, is) = sum(sigmau(1:3, ie, is) * kick%wprime(1:3))
398 sigmap(3, 2, ie, is) = sigmap(2, 3, ie, is)
399 end do
400 end do
401
402 case (2)
403
404 call spectrum_cross_section_info(namespace, in_file(2), ie, kick, trash, dump)
405 call io_skip_header(in_file(2))
406
407 do ie = 1, energy_steps
408 read(in_file(1), *) dump, (sigmau(1:3, ie, is), is = 1, nspin)
409 read(in_file(2), *) dump, (sigmaw(1:3, ie, is), is = 1, nspin)
410 end do
411
412 ! The first row of sigma is the vector that we have just read, but properly projected...
413 do is = 1, nspin
414 do ie = 1, energy_steps
415 sigmap(1, 1, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 1))
416 sigmap(1, 2, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 2))
417 sigmap(1, 3, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 3))
418 end do
419 end do
420
421 ! The third row of sigma is also the vector that we have just read, but properly projected...
422 do is = 1, nspin
423 do ie = 1, energy_steps
424 sigmap(3, 1, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 1))
425 sigmap(3, 2, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 2))
426 sigmap(3, 3, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 3))
427 end do
428 end do
429
430 ! The diagonal (2,2) is equal by symmetry to (1,1)
431 sigmap(2, 2, :, :) = sigmap(1, 1, :, :)
432
433 ! The (2,1) term and (1,2) term are equal; (2,3) and (3,2), also.
434 sigmap(2, 1, :, :) = sigmap(1, 2, :, :)
435 sigmap(2, 3, :, :) = sigmap(3, 2, :, :)
437 case default
438
439 call spectrum_cross_section_info(namespace, in_file(2), ie, kick, trash, dump)
440 call spectrum_cross_section_info(namespace, in_file(3), ie, kick, trash, dump)
441 call io_skip_header(in_file(2))
442 call io_skip_header(in_file(3))
443
444 do ie = 1, energy_steps
445 read(in_file(1), *) dump, (sigmau(1:3, ie, is), is = 1, nspin)
446 read(in_file(2), *) dump, (sigmav(1:3, ie, is), is = 1, nspin)
447 read(in_file(3), *) dump, (sigmaw(1:3, ie, is), is = 1, nspin)
448 end do
449
450 do is = 1, nspin
451 do ie = 1, energy_steps
452 sigmap(1, 1, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 1))
453 sigmap(1, 2, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 2))
454 sigmap(1, 3, ie, is) = sum(sigmau(1:3, ie, is) * kick%pol(1:3, 3))
455 end do
456 end do
457 do is = 1, nspin
458 do ie = 1, energy_steps
459 sigmap(2, 1, ie, is) = sum(sigmav(1:3, ie, is) * kick%pol(1:3, 1))
460 sigmap(2, 2, ie, is) = sum(sigmav(1:3, ie, is) * kick%pol(1:3, 2))
461 sigmap(2, 3, ie, is) = sum(sigmav(1:3, ie, is) * kick%pol(1:3, 3))
462 end do
463 end do
464 do is = 1, nspin
465 do ie = 1, energy_steps
466 sigmap(3, 1, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 1))
467 sigmap(3, 2, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 2))
468 sigmap(3, 3, ie, is) = sum(sigmaw(1:3, ie, is) * kick%pol(1:3, 3))
469 end do
470 end do
471
472 end select
473
474 ! And now, perform the necessary transformation.
475 ip(1:3, 1:3) = kick%pol(1:3, 1:3)
476 call lalg_inverse(3, ip, 'dir')
477 do is = 1, nspin
478 do ie = 1, energy_steps
479 sigma(:, :, ie, is) = matmul(transpose(ip), matmul(sigmap(:, :, ie, is), ip))
480 end do
481 end do
482
483 ! Finally, write down the result
484 call spectrum_cross_section_tensor_write(out_file, sigma, nspin, spectrum%energy_step, &
485 spectrum%min_energy, energy_steps, kick)
486
487 ! Diagonalize sigma tensor
488 if (spectrum%sigma_diag) then
489 call spectrum_sigma_diagonalize(namespace, sigma, nspin, spectrum%energy_step, spectrum%min_energy, energy_steps, kick)
490 end if
491
492 safe_deallocate_a(sigma)
493 safe_deallocate_a(sigmap)
494 safe_deallocate_a(sigmau)
495 safe_deallocate_a(sigmav)
496 safe_deallocate_a(sigmaw)
497 safe_deallocate_a(ip)
498
500 end subroutine spectrum_cross_section_tensor
501
502
503 ! ---------------------------------------------------------
504 subroutine spectrum_cross_section_tensor_write(out_file, sigma, nspin, energy_step, min_energy, energy_steps, kick)
505 integer, intent(in) :: out_file
506 real(real64), contiguous, intent(in) :: sigma(:, :, :, :)
507 integer, intent(in) :: nspin
508 real(real64), intent(in) :: energy_step, min_energy
509 integer, intent(in) :: energy_steps
510 type(kick_t), optional, intent(in) :: kick
511
512 integer :: is, idir, jdir, ie, ii
513 real(real64) :: average, anisotropy
514 real(real64), allocatable :: pp(:,:), pp2(:,:), ip(:,:)
515 logical :: spins_singlet, spins_triplet
516 character(len=20) :: header_string
517
519
520 spins_singlet = .true.
521 spins_triplet = .false.
522 if (present(kick)) then
523 write(out_file, '(a15,i2)') '# nspin ', nspin
524 call kick_write(kick, out_file)
525 select case (kick_get_type(kick))
526 case (kick_spin_mode)
527 spins_triplet = .true.
528 spins_singlet = .false.
530 spins_triplet = .true.
531 end select
532 end if
533
534 write(out_file, '(a1, a20)', advance = 'no') '#', str_center("Energy", 20)
535 write(out_file, '(a20)', advance = 'no') str_center("(1/3)*Tr[sigma]", 20)
536 write(out_file, '(a20)', advance = 'no') str_center("Anisotropy[sigma]", 20)
537 if (spins_triplet .and. spins_singlet) then
538 write(out_file, '(a20)', advance = 'no') str_center("(1/3)*Tr[sigma-]", 20)
539 end if
540 do is = 1, nspin
541 do idir = 1, 3
542 do jdir = 1, 3
543 write(header_string,'(a6,i1,a1,i1,a1,i1,a1)') 'sigma(', idir, ',', jdir, ',', is, ')'
544 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
545 end do
546 end do
547 end do
548 write(out_file, '(1x)')
549 write(out_file, '(a1,a20)', advance = 'no') '#', str_center('[' // trim(units_abbrev(units_out%energy)) // ']', 20)
550 if (spins_triplet .and. spins_singlet) then
551 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
552 end if
553 do ii = 1, 2 + nspin * 9
554 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
555 end do
556 write(out_file, '(1x)')
557
558 ! The anisotropy (Delta alpha) of a second-rank symmetric tensor alpha (such
559 ! as the cross section) is defined as:
560 !
561 ! (Delta alpha)^2 = (1/3) * (3 * Tr(alpha^2) - (Tr(a))^2)
562 !
563 ! The reason for this definition is that it is identically equal to:
564 !
565 ! (Delta alpha)^2 = (1/3) * ( (alpha_1-alpha_2)^2 + (alpha_1-alpha_3)^2 + (alpha_2-alpha_3)^2)
566 !
567 ! where {alpha_1, alpha_2, alpha_3} are the eigenvalues of alpha. An "isotropic" tensor
568 ! is characterized by having three equal eigenvalues, which leads to zero anisotropy. The
569 ! more different that the eigenvalues are, the larger the anisotropy is.
570
571 safe_allocate(pp(1:3, 1:3))
572 if (spins_triplet .and. spins_singlet) then
573 safe_allocate(pp2(1:3, 1:3))
574 end if
575 safe_allocate(ip(1:3, 1:3))
576
577 do ie = 1, energy_steps
578
579 pp(:, :) = sigma(:, :, ie, 1)
580 if (nspin >= 2) then
581 if (spins_singlet .and. spins_triplet) then
582 pp2(:, :) = pp(:, :) - sigma(:, :, ie, 2)
583 pp(:, :) = pp(:, :) + sigma(:, :, ie, 2)
584 elseif (spins_triplet .and. .not. spins_singlet) then
585 pp(:, :) = pp(:, :) - sigma(:, :, ie, 2)
586 elseif (spins_singlet .and. .not. spins_triplet) then
587 pp(:, :) = pp(:, :) + sigma(:, :, ie, 2)
588 end if
589 end if
590
591 average = m_third * (pp(1, 1) + pp(2, 2) + pp(3, 3))
592 ip = matmul(pp, pp)
593 anisotropy = m_third * (m_three * ( ip(1, 1) + ip(2, 2) + ip(3, 3)) - (m_three * average)**2)
594
595 ! Note that the cross-section elements do not have to be transformed to the proper units, since
596 ! they have been read from the "cross_section_vector.x", where they are already in the proper units.
597 write(out_file,'(3e20.8)', advance = 'no') units_from_atomic(units_out%energy, ((ie - 1) * energy_step + min_energy)), &
598 average, sqrt(max(anisotropy, m_zero))
600 if (spins_singlet .and. spins_triplet) then
601 average = m_third * (pp2(1, 1) + pp2(2, 2) + pp2(3, 3))
602 write(out_file,'(1e20.8)', advance = 'no') average
603 end if
604
605 do is = 1, nspin
606 write(out_file,'(9e20.8)', advance = 'no') sigma(1:3, 1:3, ie, is)
607 end do
608 write(out_file, '(1x)')
609 end do
610
611 safe_deallocate_a(pp)
612 if (spins_triplet .and. spins_singlet) then
613 safe_deallocate_a(pp2)
614 end if
615 safe_deallocate_a(ip)
618
619
620 ! ---------------------------------------------------------
621 subroutine spectrum_cross_section(spectrum, namespace, in_file, out_file, ref_file)
622 type(spectrum_t), intent(inout) :: spectrum
623 type(namespace_t), intent(in) :: namespace
624 integer, intent(in) :: in_file
625 integer, intent(in) :: out_file
626 integer, optional, intent(in) :: ref_file
627
628 character(len=20) :: header_string
629 integer :: nspin, ref_nspin, lmax, ref_lmax, time_steps, &
630 ref_time_steps, istart, iend, ntiter, it, ii, isp, no_e, ie, idir, nrho
631 real(real64) :: dt, ref_dt, energy, ewsum, polsum
632 type(kick_t) :: kick, ref_kick
633 real(real64), allocatable :: dipole(:, :, :), ref_dipole(:, :, :), sigma(:, :, :), sf(:, :)
634 type(unit_system_t) :: file_units, ref_file_units
635 type(batch_t) :: dipoleb, sigmab
636
637 type(pcm_min_t) :: pcm
638
639 push_sub(spectrum_cross_section)
640
641 ! This function gives us back the unit connected to the "multipoles" file, the header information,
642 ! the number of time steps, and the time step.
643 call spectrum_mult_info(namespace, in_file, nspin, kick, time_steps, dt, file_units, lmax=lmax)
644
645 if (present(ref_file)) then
646 call spectrum_mult_info(namespace, ref_file, ref_nspin, ref_kick, &
647 ref_time_steps, ref_dt, ref_file_units, lmax = ref_lmax)
648 if ((nspin /= ref_nspin) .or. &
649 (time_steps /= ref_time_steps) .or. &
650 (.not.(abs(dt-ref_dt)< 1e-10_real64)) .or. &
651 (lmax /= ref_lmax)) then
652 write(message(1),'(a)') 'The multipoles and reference multipoles files do not match.'
653 call messages_fatal(1, namespace=namespace)
654 end if
655 end if
656
657 ! Now we cannot process files that do not contain the dipole, or that contain more than the dipole.
658 if (lmax /= 1) then
659 message(1) = 'Multipoles file should contain the dipole -- and only the dipole.'
660 call messages_fatal(1, namespace=namespace)
661 end if
662
663 if (kick%function_mode /= kick_function_dipole) then
664 message(1) = "Kick function must have been dipole to run this utility."
665 call messages_fatal(1, namespace=namespace)
666 end if
667
668 if (kick%pol_dir < 1) then
669 message(1) = "Kick polarization direction is not set. Probably no kick was used."
670 call messages_fatal(1, namespace=namespace)
671 end if
672
673 ! Find out the iteration numbers corresponding to the time limits.
674 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
675
676 safe_allocate(dipole(0:time_steps, 1:3, 1:nspin))
677 call spectrum_read_dipole(namespace, in_file, dipole)
678
679 if (present(ref_file)) then
680 safe_allocate(ref_dipole(0:time_steps, 1:3, 1:nspin))
681 call spectrum_read_dipole(namespace, ref_file, ref_dipole)
682 end if
683
684 ! parsing and re-printing to output useful PCM data
685 call pcm_min_input_parsing_for_spectrum(pcm, namespace)
686
687 ! adding the dipole generated by the PCM polarization charges due solute
688 if (pcm%localf) then
689 call spectrum_add_pcm_dipole(namespace, dipole, time_steps, nspin)
690 end if
691
692 ! Now subtract the initial dipole.
693 if (present(ref_file)) then
694 dipole = dipole - ref_dipole
695 else
696 do it = 1, time_steps
697 dipole(it, :, :) = dipole(it, :, :) - dipole(0, :, :)
698 end do
699 dipole(0, :, :) = m_zero
700 end if
701
702 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
703
704 ! Get the number of energy steps.
705 no_e = spectrum_nenergy_steps(spectrum)
706 safe_allocate(sigma(1:no_e, 1:3, 1:nspin))
707
708 if (pcm%localf) then
709
710 ! for numerical reasons, we cannot add the difference (d(t)-d(t0)) of PCM dipoles here -- although it would look cleaner
711
712 ! in the PCM local field case \sigma(\omega) \propto \Im{\alpha(\omega)\epsilon(\omega)} not just \propto \Im{\alpha(\omega)}
713 ! since the dielectric function is complex as well, we need to compute both the real and imaginary part of the polarizability
714 call spectrum_times_pcm_epsilon(spectrum, pcm, dipole, sigma, nspin, istart, iend, kick%time, dt, no_e)
715
716 write(out_file,'(a59)') "# Cross-section spectrum contains full local field effects."
717
718 else
719
720 call batch_init(dipoleb, 3, 1, nspin, dipole)
721 call batch_init(sigmab, 3, 1, nspin, sigma)
722
723 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart + 1, iend + 1, kick%time, dt, dipoleb)
724 call spectrum_fourier_transform(spectrum%method, spectrum%transform, spectrum%noise, &
725 istart + 1, iend + 1, kick%time, dt, dipoleb, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, sigmab)
726
727 call dipoleb%end()
728 call sigmab%end()
729
730 end if
731
732 if (pcm%run_pcm) then
733 call spectrum_over_pcm_refraction_index(spectrum, pcm, sigma, nspin, no_e)
734 end if
735
736
737 safe_deallocate_a(dipole)
738 if (present(ref_file)) then
739 safe_deallocate_a(ref_dipole)
740 end if
741
742 safe_allocate(sf(1:no_e, nspin))
743
744 if (abs(kick%delta_strength) < 1e-12_real64) kick%delta_strength = m_one
745 do ie = 1, no_e
746 energy = (ie-1) * spectrum%energy_step + spectrum%min_energy
747 do isp = 1, nspin
748 sf(ie, isp) = sum(sigma(ie, 1:3, isp)*kick%pol(1:3, kick%pol_dir))
749 end do
750 sf(ie, 1:nspin) = -sf(ie, 1:nspin) * (energy * m_two) / (m_pi * kick%delta_strength)
751 sigma(ie, 1:3, 1:nspin) = -sigma(ie, 1:3, 1:nspin)*(m_four*m_pi*energy/p_c)/kick%delta_strength
752 end do
753
754 ! The formulae below are only correct in this particular case.
755 if (kick_get_type(kick) == kick_density_mode .and. spectrum%transform == spectrum_transform_sin) then
756 ! Only the density components (not the spinor off-diagonal ones) carry the charge
757 nrho = min(nspin, 2)
758 ewsum = sum(sf(1, 1:nrho))
759 polsum = m_zero
760
761 do ie = 2, no_e
762 energy = (ie-1) * spectrum%energy_step + spectrum%min_energy
763 ewsum = ewsum + sum(sf(ie, 1:nrho))
764 polsum = polsum + sum(sf(ie, 1:nrho)) / energy**2
765 end do
766
767 ewsum = ewsum * spectrum%energy_step
768 polsum = polsum * spectrum%energy_step
769 end if
770
771 write(out_file, '(a15,i2)') '# nspin ', nspin
772 call kick_write(kick, out_file)
773 write(out_file, '(a)') '#%'
774 write(out_file, '(a,i8)') '# Number of time steps = ', time_steps
775 call spectrum_write_info(spectrum, out_file)
776 write(out_file, '(a)') '#%'
777 if (kick_get_type(kick) == kick_density_mode .and. spectrum%transform == spectrum_transform_sin) then
778 write(out_file, '(a,f16.6)') '# Electronic sum rule = ', ewsum
779 write(out_file, '(a,f16.6,1x,a)') '# Static polarizability (from sum rule) = ', &
780 units_from_atomic(units_out%length**3, polsum), trim(units_abbrev(units_out%length))
781 write(out_file, '(a)') '#%'
782 end if
783
784 write(out_file, '(a1,a20)', advance = 'no') '#', str_center("Energy", 20)
785 do isp = 1, nspin
786 do idir = 1, 3
787 write(header_string,'(a6,i1,a8,i1,a1)') 'sigma(', idir, ', nspin=', isp, ')'
788 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
789 end do
790 end do
791 do isp = 1, nspin
792 write(header_string,'(a18,i1,a1)') 'StrengthFunction(', isp, ')'
793 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
794 end do
795 write(out_file, '(1x)')
796 write(out_file, '(a1,a20)', advance = 'no') '#', str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20)
797 do ii = 1, nspin * 3
798 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
799 end do
800 do isp = 1, nspin
801 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(unit_one/units_out%energy)) // ']', 20)
802 end do
803 write(out_file, '(1x)')
804
805 do ie = 1, no_e
806 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy, &
807 (ie-1) * spectrum%energy_step + spectrum%min_energy)
808 do isp = 1, nspin
809 write(out_file,'(3e20.8)', advance = 'no') (units_from_atomic(units_out%length**2, sigma(ie, idir, isp)), &
810 idir = 1, 3)
811 end do
812 do isp = 1, nspin
813 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(unit_one/units_out%energy, sf(ie, isp))
814 end do
815 write(out_file, '(1x)')
816 end do
817
818 safe_deallocate_a(sigma)
820 end subroutine spectrum_cross_section
821
822 ! ---------------------------------------------------------
823
824 subroutine spectrum_read_dipole(namespace, in_file, dipole)
825 type(namespace_t), intent(in) :: namespace
826 integer, intent(in) :: in_file
827 real(real64), intent(out) :: dipole(0:, :, :)
828
829 integer :: nspin, lmax, time_steps, trash, it, idir, ispin
830 real(real64) :: dt, dump
831 type(kick_t) :: kick
832 type(unit_system_t) :: file_units
833
834 push_sub(spectrum_read_dipole)
835
836 ! This function gives us back the unit connected to the "multipoles" file, the header information,
837 ! the number of time steps, and the time step.
838 call spectrum_mult_info(namespace, in_file, nspin, kick, time_steps, dt, file_units, lmax = lmax)
839
840 ! Read the dipole.
841 call io_skip_header(in_file)
842
843 do it = 0, time_steps
844 dipole(it, :, :) = m_zero
845 read(in_file, *) trash, dump, (dump, (dipole(it, idir, ispin), idir = 1, kick%dim), ispin = 1, nspin)
846 end do
847 dipole(:,:,:) = units_to_atomic(file_units%length, dipole(:,:,:))
848
849 pop_sub(spectrum_read_dipole)
850
851 end subroutine spectrum_read_dipole
852
853 ! ---------------------------------------------------------
854
855 subroutine spectrum_add_pcm_dipole(namespace, dipole, time_steps, nspin)
856 type(namespace_t), intent(in) :: namespace
857 real(real64), intent(inout) :: dipole(0:, :, :)
858 integer, intent(in) :: time_steps
859 integer, intent(in) :: nspin
860
861 type(pcm_t) :: pcm
862 real(real64) :: dipole_pcm(1:3)
863 integer :: ia, it
864
865 ! unit io variables
866 integer :: asc_unit_test
867 integer :: cavity_unit
868 integer :: asc_vs_t_unit, asc_vs_t_unit_check
869 integer :: dipole_vs_t_unit_check, dipole_vs_t_unit_check1
870 integer :: iocheck
871 integer :: aux_int
872 real(real64) :: aux_float, aux_float1, aux_vec(1:3)
873 character(len=23) :: asc_vs_t_unit_format
874 character(len=16) :: asc_vs_t_unit_format_tail
875
877
878 ! reading PCM cavity from standard output file in two steps
879
880 ! first step - counting tesserae
881 asc_unit_test = io_open(pcm_dir//'ASC_e.dat', namespace, action='read')
882 pcm%n_tesserae = 0
883 iocheck = 1
884 do while(iocheck >= 0)
885 read(asc_unit_test,*,iostat=iocheck) aux_vec(1:3), aux_float, aux_int
886 if (iocheck >= 0) pcm%n_tesserae = pcm%n_tesserae + 1
887 end do
888 call io_close(asc_unit_test)
889
890 ! intermezzo - allocating PCM tessellation and polarization charges arrays
891 safe_allocate(pcm%tess(1:pcm%n_tesserae))
892 safe_allocate(pcm%q_e(1:pcm%n_tesserae))
893 safe_allocate(pcm%q_e_in(1:pcm%n_tesserae)) ! with auxiliary role
894
895 ! second step - reading of PCM tessellation arrays from standard output file
896 ! writing the cavity to debug-purpose file
897 asc_unit_test = io_open(pcm_dir//'ASC_e.dat', namespace, action='read')
898 cavity_unit = io_open(pcm_dir//'cavity_check.xyz', namespace, action='write')
899 write(cavity_unit,'(I3)') pcm%n_tesserae
900 write(cavity_unit,*)
901 do ia = 1, pcm%n_tesserae
902 read(asc_unit_test,*) pcm%tess(ia)%point(1:3), aux_float, aux_int
903 write(cavity_unit,'(A1,3(1X,F14.8))') 'H', pcm%tess(ia)%point(1:3)
904 end do
905 call io_close(asc_unit_test)
906 call io_close(cavity_unit)
907
908 write (asc_vs_t_unit_format_tail,'(I5,A11)') pcm%n_tesserae,'(1X,F14.8))'
909 write (asc_vs_t_unit_format,'(A)') '(F14.8,'//trim(adjustl(asc_vs_t_unit_format_tail))
910
911 ! Now, summary: * read the time-dependent PCM polarization charges due to solute electrons, pcm%q_e
912 ! * compute the real-time dipole generated by pcm%q_e, dipole_pcm
913 ! * add it to the real-time molecular dipole
914 ! * write the total dipole and its PCM contribution to debug-purpose files
915 ! N.B. we assume nuclei fixed in time
916
917 ! opening time-dependent PCM charges standard and debug-purpose file
918 asc_vs_t_unit = io_open(pcm_dir//'ASC_e_vs_t.dat', namespace, action='read', form='formatted')
919 asc_vs_t_unit_check = io_open(pcm_dir//'ASC_e_vs_t_check.dat', namespace, action='write', form='formatted')
920
921 ! opening time-dependent PCM and total dipole debug-purpose files
922 dipole_vs_t_unit_check = io_open(pcm_dir//'dipole_e_vs_t_check.dat', namespace, action='write', form='formatted')
923 dipole_vs_t_unit_check1 = io_open(pcm_dir//'dipole_e_vs_t_check1.dat', namespace, action='write', form='formatted')
924
925 ! reading PCM charges for the zeroth-iteration - not used - pcm%q_e_in is only auxiliary here
926 read(asc_vs_t_unit,trim(adjustl(asc_vs_t_unit_format))) aux_float1, ( pcm%q_e_in(ia) , ia=1,pcm%n_tesserae)
927
928 do it = 1, time_steps
929
930 ! reading real-time PCM charges due to electrons per timestep
931 read(asc_vs_t_unit,trim(adjustl(asc_vs_t_unit_format))) aux_float, ( pcm%q_e(ia) , ia=1,pcm%n_tesserae)
932
933 ! computing real-time PCM dipole per timestep
934 call pcm_dipole(dipole_pcm(1:3), -pcm%q_e(1:pcm%n_tesserae), pcm%tess, pcm%n_tesserae)
935
936 ! adding PCM dipole to the molecular dipole per timestep
937 dipole(it, 1, 1:nspin) = dipole(it, 1, 1:nspin) + dipole_pcm(1)
938 dipole(it, 2, 1:nspin) = dipole(it, 2, 1:nspin) + dipole_pcm(2)
939 dipole(it, 3, 1:nspin) = dipole(it, 3, 1:nspin) + dipole_pcm(3)
940
941 ! since we always have a kick for the optical spectrum in Octopus
942 ! the first-iteration dipole should be equal to the zeroth-iteration one
943 ! in any case, made them equal by hand
944 if (it == 1) then
945 dipole(0, 1, 1:nspin) = dipole(1, 1, 1:nspin)
946 dipole(0, 2, 1:nspin) = dipole(1, 2, 1:nspin)
947 dipole(0, 3, 1:nspin) = dipole(1, 3, 1:nspin)
948 end if
949
950 ! writing real-time PCM charges and dipole, and the total dipole for debug purposes
951 write(asc_vs_t_unit_check,trim(adjustl(asc_vs_t_unit_format))) aux_float, (pcm%q_e(ia), ia=1,pcm%n_tesserae)
952 write(dipole_vs_t_unit_check,'(F14.8,3(1X,F14.8))') aux_float, dipole_pcm
953 write(dipole_vs_t_unit_check1,'(F14.8,3(1X,F14.8))') aux_float, dipole(it,:,1)
954
955 end do
956
957 ! closing PCM and debug files
958 call io_close(asc_vs_t_unit)
959 call io_close(asc_vs_t_unit_check)
960 call io_close(dipole_vs_t_unit_check)
961 call io_close(dipole_vs_t_unit_check1)
962
963 ! deallocating PCM arrays
964 safe_deallocate_a(pcm%tess)
965 safe_deallocate_a(pcm%q_e)
966 safe_deallocate_a(pcm%q_e_in)
967
969
970 end subroutine spectrum_add_pcm_dipole
971
972 ! ---------------------------------------------------------
973
974 subroutine spectrum_times_pcm_epsilon(spectrum, pcm, dipole, sigma, nspin, istart, iend, kick_time, dt, no_e)
975 type(spectrum_t), intent(in) :: spectrum
976 type(pcm_min_t) , intent(in) :: pcm
977 real(real64), allocatable, intent(inout) :: sigma(:, :, :)
978 real(real64), allocatable, intent(in) :: dipole(:, :, :)
979 integer, intent(in) :: nspin
980 real(real64), intent(in) :: kick_time
981 integer, intent(in) :: istart, iend
982 real(real64), intent(in) :: dt
983 integer, intent(in) :: no_e
984
985 real(real64), allocatable :: sigmap(:, :, :)
986 type(batch_t) :: dipoleb, sigmab
987
988 integer :: ie
989
990 complex(real64), allocatable :: eps(:)
991
993
994 ! imaginary part of the polarizability
995
996 call batch_init(dipoleb, 3, 1, nspin, dipole)
997 call batch_init(sigmab, 3, 1, nspin, sigma)
998
999 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart + 1, iend + 1, kick_time, dt, dipoleb)
1000 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
1001 istart + 1, iend + 1, kick_time, dt, dipoleb, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, sigmab)
1002
1003 call dipoleb%end()
1004 call sigmab%end()
1005
1006 ! real part of the polarizability
1007
1008 safe_allocate(sigmap(1:no_e, 1:3, 1:nspin))
1009
1010 call batch_init(dipoleb, 3, 1, nspin, dipole)
1011 call batch_init(sigmab, 3, 1, nspin, sigmap)
1012
1013 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart + 1, iend + 1, kick_time, dt, dipoleb)
1014 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
1015 istart + 1, iend + 1, kick_time, dt, dipoleb, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, sigmab)
1016
1017 call dipoleb%end()
1018 call sigmab%end()
1019
1020 safe_allocate(eps(1:no_e))
1021
1022 ! multiplying by the dielectric function and taking the imaginary part of the product
1023
1024 do ie = 1, no_e
1025 call pcm_eps(pcm, eps(ie), (ie-1)*spectrum%energy_step + spectrum%min_energy)
1026 sigma(ie, 1:3, 1:nspin) = sigma(ie, 1:3, 1:nspin) * real(eps(ie), real64) + sigmap(ie, 1:3, 1:nspin) *aimag(eps(ie))
1027 end do
1028
1029 safe_deallocate_a(sigmap)
1030 safe_deallocate_a(eps)
1031
1033
1034 end subroutine spectrum_times_pcm_epsilon
1035
1036 ! ---------------------------------------------------------
1037
1038 subroutine spectrum_over_pcm_refraction_index(spectrum, pcm, sigma, nspin, no_e)
1039 type(spectrum_t), intent(in) :: spectrum
1040 type(pcm_min_t) , intent(in) :: pcm
1041 real(real64), allocatable, intent(inout) :: sigma(:, :, :)
1042 integer, intent(in) :: nspin
1043 integer, intent(in) :: no_e
1044
1045 integer :: ie
1046
1047 complex(real64), allocatable :: eps(:)
1048
1050
1051 safe_allocate(eps(1:no_e))
1052
1053 ! dividing by the refraction index - n(\omega)=\sqrt{\frac{|\epsilon(\omega)|+\Re[\epsilon(\omega)]}{2}}
1054
1055 do ie = 1, no_e
1056 call pcm_eps(pcm, eps(ie), (ie-1)*spectrum%energy_step + spectrum%min_energy)
1057 sigma(ie, 1:3, 1:nspin) = sigma(ie, 1:3, 1:nspin) / sqrt(0.5_real64 * (abs(eps(ie)) + real(eps(ie), real64)))
1058 end do
1059
1060 safe_deallocate_a(eps)
1061
1063
1065
1066 ! ---------------------------------------------------------
1067 subroutine spectrum_dipole_power(spectrum, namespace, in_file, out_file)
1068 type(spectrum_t), intent(inout) :: spectrum
1069 type(namespace_t), intent(in) :: namespace
1070 integer, intent(in) :: in_file
1071 integer, intent(in) :: out_file
1072
1073 character(len=20) :: header_string
1074 integer :: nspin, lmax, time_steps, istart, iend, ntiter, it, ii, isp, no_e, ie, idir
1075 real(real64) :: dt
1076 real(real64), allocatable :: dipole(:, :, :), transform_cos(:, :, :), transform_sin(:, :, :), power(:, :, :)
1077 type(unit_system_t) :: file_units
1078 type(batch_t) :: dipoleb, transformb_cos, transformb_sin
1079 type(kick_t) :: kick
1080
1081 push_sub(spectrum_dipole_power)
1082
1083 ! This function gives us back the unit connected to the "multipoles" file, the header information,
1084 ! the number of time steps, and the time step.
1085 call spectrum_mult_info(namespace, in_file, nspin, kick, time_steps, dt, file_units, lmax=lmax)
1086
1087 ! Now we cannot process files that do not contain the dipole, or that contain more than the dipole.
1088 if (lmax /= 1) then
1089 message(1) = 'Multipoles file should contain the dipole -- and only the dipole.'
1090 call messages_fatal(1, namespace=namespace)
1091 end if
1092
1093 ! Find out the iteration numbers corresponding to the time limits.
1094 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1095
1096 safe_allocate(dipole(0:time_steps, 1:3, 1:nspin))
1097 call spectrum_read_dipole(namespace, in_file, dipole)
1098
1099 ! Now subtract the initial dipole.
1100 do it = 1, time_steps
1101 dipole(it, :, :) = dipole(it, :, :) - dipole(0, :, :)
1102 end do
1103 dipole(0, :, :) = m_zero
1104
1105 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
1106
1107 ! Get the number of energy steps.
1108 no_e = spectrum_nenergy_steps(spectrum)
1109 safe_allocate(transform_cos(1:no_e, 1:3, 1:nspin))
1110 safe_allocate(transform_sin(1:no_e, 1:3, 1:nspin))
1111 safe_allocate(power(1:no_e, 1:3, 1:nspin))
1112
1113
1114 call batch_init(dipoleb, 3, 1, nspin, dipole)
1115 call batch_init(transformb_cos, 3, 1, nspin, transform_cos)
1116 call batch_init(transformb_sin, 3, 1, nspin, transform_sin)
1117
1118 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart + 1, iend + 1, spectrum%start_time, dt, dipoleb)
1119
1120 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
1121 istart + 1, iend + 1, spectrum%start_time, dt, dipoleb, spectrum%min_energy, &
1122 spectrum%max_energy, spectrum%energy_step, transformb_cos)
1123 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
1124 istart + 1, iend + 1, spectrum%start_time, dt, dipoleb, spectrum%min_energy, &
1125 spectrum%max_energy, spectrum%energy_step, transformb_sin)
1126
1127 do ie = 1, no_e
1128 power(ie, :, :) = (transform_sin(ie, :, :)**2 + transform_cos(ie, :, :)**2)
1129 end do
1130
1131 call dipoleb%end()
1132 call transformb_cos%end()
1133 call transformb_sin%end()
1134
1135 safe_deallocate_a(dipole)
1136 safe_deallocate_a(transform_sin)
1137 safe_deallocate_a(transform_cos)
1138
1139 write(out_file, '(a15,i2)') '# nspin ', nspin
1140 write(out_file, '(a)') '#%'
1141 write(out_file, '(a,i8)') '# Number of time steps = ', time_steps
1142 call spectrum_write_info(spectrum, out_file)
1143 write(out_file, '(a)') '#%'
1144
1145 write(out_file, '(a1,a20,1x)', advance = 'no') '#', str_center("Energy", 20)
1146 do isp = 1, nspin
1147 do idir = 1, 3
1148 write(header_string,'(a6,i1,a8,i1,a1)') 'power(', idir, ', nspin=', isp, ')'
1149 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
1150 end do
1151 end do
1152 write(out_file, '(1x)')
1153 write(out_file, '(a1,a20)', advance = 'no') '#', str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20)
1154 do ii = 1, nspin * 3
1155 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
1156 end do
1157 write(out_file, '(1x)')
1158
1159 do ie = 1, no_e
1160 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy, &
1161 (ie-1) * spectrum%energy_step + spectrum%min_energy)
1162 do isp = 1, nspin
1163 write(out_file,'(3e20.8)', advance = 'no') (units_from_atomic(units_out%length**2, power(ie, idir, isp)), &
1164 idir = 1, 3)
1165 end do
1166 write(out_file, '(1x)')
1167 end do
1168
1169 safe_deallocate_a(power)
1170
1171 pop_sub(spectrum_dipole_power)
1172 end subroutine spectrum_dipole_power
1173
1174 ! ---------------------------------------------------------
1175 subroutine spectrum_dyn_structure_factor(spectrum, namespace, in_file_sin, in_file_cos, out_file)
1176 type(spectrum_t), intent(inout) :: spectrum
1177 type(namespace_t), intent(in) :: namespace
1178 integer, intent(in) :: in_file_sin, in_file_cos
1179 integer, intent(in) :: out_file
1180
1181 character(len=20) :: header_string
1182 integer :: time_steps, time_steps_sin, time_steps_cos
1183 integer :: istart, iend, ntiter, it, jj, ii, no_e, ie, trash
1184 real(real64) :: dt, dt_sin, dt_cos
1185 real(real64) :: dump, dummy1, dummy2, dummy3, dummy4, energy, fsum
1186 type(kick_t) :: kick
1187 complex(real64) :: xx
1188 complex(real64), allocatable :: ftchd(:), chi(:), damp(:)
1189 type(unit_system_t) :: file_units
1190 character(len=100) :: line
1191
1193
1194 safe_allocate(kick%qvector(1:3, 1:1))
1195
1196 ! Read information from ftchds.sin file
1197
1198 rewind(in_file_sin)
1199
1200 ! skip two lines
1201 read(in_file_sin, *)
1202 read(in_file_sin, *)
1203 read(in_file_sin, '(15x,i2)') kick%qkick_mode
1204 read(in_file_sin, '(10x,3f9.5)') kick%qvector
1205 read(in_file_sin, '(15x,f18.12)') kick%delta_strength
1206
1207 ! skip two lines
1208 read(in_file_sin, *)
1209 read(in_file_sin, '(a)') line
1210 call io_skip_header(in_file_sin)
1211 call io_skip_header(in_file_cos)
1212
1213 ! Figure out the units of the file
1214 ii = index(line, 'eV')
1215 if (ii /= 0) then
1216 call unit_system_get(file_units, units_eva)
1217 else
1218 call unit_system_get(file_units, units_atomic)
1219 end if
1220
1221 ! get time_steps and dt, and make sure that dt is the same in the two files
1222 call spectrum_count_time_steps(namespace, in_file_sin, time_steps_sin, dt_sin)
1223 call spectrum_count_time_steps(namespace, in_file_cos, time_steps_cos, dt_cos)
1224
1225 if (.not. is_close(dt_sin, dt_cos)) then
1226 message(1) = "dt is different in ftchds.cos and ftchds.sin!"
1227 call messages_fatal(1, namespace=namespace)
1228 end if
1229
1230 time_steps = min(time_steps_sin, time_steps_cos)
1231 dt = units_to_atomic(file_units%time, dt_cos) ! units_out is OK
1232
1233 ! Find out the iteration numbers corresponding to the time limits.
1234 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1235
1236 ! Read the f-transformed charge density.
1237 call io_skip_header(in_file_sin)
1238 call io_skip_header(in_file_cos)
1239
1240 safe_allocate(ftchd(0:time_steps))
1241 do it = 0, time_steps
1242 read(in_file_sin, *) trash, dump, dummy1, dummy2
1243 read(in_file_cos, *) trash, dump, dummy3, dummy4
1244 ftchd(it) = cmplx(dummy3-dummy2, dummy4+dummy1, real64)
1245 end do
1246
1247 ! Now subtract the initial value.
1248 do it = 1, time_steps
1249 ftchd(it) = ftchd(it) - ftchd(0)
1250 end do
1251 ftchd(0) = m_zero
1252
1253 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
1254
1255 ! Get the number of energy steps.
1256 no_e = spectrum_nenergy_steps(spectrum)
1257
1258 safe_allocate(chi(1:no_e))
1259 chi = m_zero
1260
1261 ! Gets the damp function
1262 safe_allocate(damp(istart:iend))
1263 do it = istart, iend
1264 jj = it - istart
1265 select case (spectrum%damp)
1266 case (spectrum_damp_none)
1267 damp(it) = m_one
1269 damp(it)= exp(-jj * dt * spectrum%damp_factor)
1271 damp(it) = m_one - m_three * (real(jj, real64) / ntiter)**2 &
1272 + m_two * (real(jj, real64) / ntiter)**3
1274 damp(it)= exp(-(jj * dt)**2 * spectrum%damp_factor**2)
1275 end select
1276 end do
1277
1278 ! Fourier transformation from time to frequency
1279 if (abs(kick%delta_strength) < 1.d-12) kick%delta_strength = m_one
1280 do ie = 1, no_e
1281 energy = (ie-1) * spectrum%energy_step + spectrum%min_energy
1282 do it = istart, iend
1283 jj = it - istart
1284
1285 xx = exp(m_zi * energy * jj * dt)
1286 chi(ie) = chi(ie) + xx * damp(it) * ftchd(it)
1287
1288 end do
1289 chi(ie) = chi(ie) * dt / kick%delta_strength / m_pi
1290 end do
1291
1292 ! Test f-sum rule
1293 fsum = m_zero
1294 do ie = 1, no_e
1295 energy = (ie-1) * spectrum%energy_step + spectrum%min_energy
1296 fsum = fsum + energy * aimag(chi(ie))
1297 end do
1298 fsum = spectrum%energy_step * fsum * 2/sum(kick%qvector(:,1)**2)
1299
1300 write(out_file, '(a)') '#%'
1301 write(out_file, '(a,i8)') '# Number of time steps = ', time_steps
1302 call spectrum_write_info(spectrum, out_file)
1303 write(out_file, '(a,3f9.5)') '# qvector : ', kick%qvector
1304 write(out_file, '(a,f10.4)') '# F-sum rule : ', fsum
1305 write(out_file, '(a)') '#%'
1306
1307 write(out_file, '(a1,a20)', advance = 'no') '#', str_center("Energy", 20)
1308 write(header_string,'(a3)') 'chi'
1309 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
1310 write(out_file, '(1x)')
1311 write(out_file, '(a1,a20)', advance = 'no') '#', str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20)
1312 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%energy)) // '**(-1)]', 20)
1313 write(out_file, '(1x)')
1314
1315 do ie = 1, no_e
1316 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy, &
1317 (ie-1) * spectrum%energy_step + spectrum%min_energy)
1318 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy**(-1), aimag(chi(ie)))
1319 write(out_file, '(1x)')
1320 end do
1321
1322 safe_deallocate_a(ftchd)
1323 safe_deallocate_a(chi)
1325
1326 end subroutine spectrum_dyn_structure_factor
1327
1328
1329 ! ---------------------------------------------------------
1330 subroutine spectrum_rotatory_strength(spectrum, namespace, in_file, out_file)
1331 type(spectrum_t), intent(inout) :: spectrum
1332 type(namespace_t), intent(in) :: namespace
1333 integer, intent(in) :: in_file
1334 integer, intent(in) :: out_file
1335
1336 integer :: istart, iend, ntiter, ie, idir, time_steps, no_e, nspin, trash, it
1337 real(real64) :: dump, dt, energy
1338 type(kick_t) :: kick
1339 complex(real64) :: sum1, sum2, sp
1340 real(real64), allocatable :: angular(:, :), resp(:), imsp(:)
1341 type(batch_t) :: angularb, respb, imspb
1342 type(unit_system_t) :: file_units
1343
1345
1346 call spectrum_mult_info(namespace, in_file, nspin, kick, time_steps, dt, file_units)
1347 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1348
1349 if (kick%dim /= 3) then
1350 message(1) = "Rotatory strength can only be computed for 3D systems."
1351 call messages_fatal(1, namespace=namespace)
1352 end if
1353
1354 ! load angular momentum from file
1355 safe_allocate(angular(0:time_steps, 1:3))
1356 call io_skip_header(in_file)
1357 do ie = 0, time_steps
1358 read(in_file, *) trash, dump, (angular(ie, idir), idir = 1, 3)
1359 end do
1360
1361 ! subtract static dipole
1362 do idir = 1, 3
1363 angular(:, idir) = angular(:, idir) - angular(0, idir)
1364 end do
1365
1366 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
1367
1368 no_e = spectrum_nenergy_steps(spectrum)
1369
1370 do it = istart, iend
1371 angular(it, 1) = sum(angular(it, 1:3)*kick%pol(1:3, kick%pol_dir))
1372 end do
1373
1374 safe_allocate(resp(1:no_e))
1375 safe_allocate(imsp(1:no_e))
1376
1377 call batch_init(angularb, angular(:, 1))
1378 call batch_init(respb, resp)
1379 call batch_init(imspb, imsp)
1380
1381 call spectrum_signal_damp(spectrum%damp, spectrum%damp_factor, istart + 1, iend + 1, kick%time, dt, angularb)
1382
1383 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
1384 istart + 1, iend + 1, kick%time, dt, angularb, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, respb)
1385 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
1386 istart + 1, iend + 1, kick%time, dt, angularb, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, imspb)
1387
1388 call angularb%end()
1389 call respb%end()
1390 call imspb%end()
1391
1392 sum1 = m_z0
1393 sum2 = m_z0
1394 if (abs(kick%delta_strength) < 1.d-12) kick%delta_strength = m_one
1395 do ie = 1, no_e
1396 energy = (ie-1) * spectrum%energy_step + spectrum%min_energy
1397
1398 sp = cmplx(resp(ie), imsp(ie), real64)
1399
1400 sp = sp*m_zi/(m_two*p_c*kick%delta_strength)
1401
1402 sum1 = sum1 + spectrum%energy_step*sp
1403 sum2 = sum2 + spectrum%energy_step*sp*energy**2
1404
1405 resp(ie) = real(sp, real64)
1406 imsp(ie) = aimag(sp)
1407 end do
1408
1409 safe_deallocate_a(angular)
1410
1411 ! print some info
1412 write(message(1), '(a,i8)') 'Number of time steps = ', ntiter
1413 write(message(2), '(a,i4)') 'PropagationSpectrumDampMode = ', spectrum%damp
1414 write(message(3), '(a,f10.4)') 'PropagationSpectrumDampFactor = ', units_from_atomic(units_out%time**(-1), spectrum%damp_factor)
1415 write(message(4), '(a,f10.4)') 'PropagationSpectrumStartTime = ', units_from_atomic(units_out%time, spectrum%start_time)
1416 write(message(5), '(a,f10.4)') 'PropagationSpectrumEndTime = ', units_from_atomic(units_out%time, spectrum%end_time)
1417 write(message(6), '(a,f10.4)') 'PropagationSpectrumMaxEnergy = ', units_from_atomic(units_inp%energy, spectrum%max_energy)
1418 write(message(7),'(a,f10.4)') 'PropagationSpectrumEnergyStep = ', units_from_atomic(units_inp%energy, spectrum%energy_step)
1419 message(8) = ""
1420 write(message(9), '(a,5e15.6,5e15.6)') 'R(0) sum rule = ', sum1
1421 write(message(10),'(a,5e15.6,5e15.6)') 'R(2) sum rule = ', sum2
1422 call messages_info(10, namespace=namespace)
1423
1424
1425 ! Output to file
1426 write(out_file, '(a15,i2)') '# nspin ', nspin
1427 call kick_write(kick, out_file)
1428 write(out_file, '(a1,a20,a20,a20)') '#', str_center("Energy", 20), str_center("R", 20), str_center("Re[beta]", 20)
1429 write(out_file, '(a1,a20,a20,a20)') '#', str_center('[' // trim(units_abbrev(units_out%energy)) // ']', 20), &
1430 str_center('[' // trim(units_abbrev(units_out%length**3)) // ']', 20), &
1431 str_center('[' // trim(units_abbrev(units_out%length**4)) // ']', 20)
1432 write(out_file, '(a,5e15.6,5e15.6)') '# R(0) sum rule = ', sum1
1433 write(out_file, '(a,5e15.6,5e15.6)') '# R(2) sum rule = ', sum2
1434 do ie = 1, no_e
1435 write(out_file,'(e20.8,e20.8,e20.8)') units_from_atomic(units_out%energy, (ie-1)*spectrum%energy_step+spectrum%min_energy), &
1436 units_from_atomic(units_out%length**3, imsp(ie)/m_pi), &
1437 units_from_atomic(units_out%length**4, resp(ie)*p_c/(m_three*max((ie-1),1)*spectrum%energy_step))
1438 end do
1439
1440 safe_deallocate_a(resp)
1441 safe_deallocate_a(imsp)
1442
1444 end subroutine spectrum_rotatory_strength
1445 ! ---------------------------------------------------------
1446
1447
1448 ! ---------------------------------------------------------
1449 subroutine spectrum_hsfunction_init(dt, is, ie, niter, acc)
1450 real(real64), intent(in) :: dt
1451 integer, intent(in) :: is, ie, niter
1452 complex(real64), contiguous, intent(in) :: acc(:)
1453
1454 integer :: nn(3), j, optimize_parity(3)
1455 logical :: optimize(3)
1456
1457 push_sub(spectrum_hsfunction_init)
1458
1459 is_ = is
1460 ie_ = ie
1461 time_step_ = dt
1462 niter_ = niter
1463 energy_step_ = (m_two * m_pi) / (niter * time_step_)
1464 safe_allocate(func_(0:niter))
1465 safe_allocate(funcw_(0:niter))
1466 func_ = m_z0
1467 func_ = acc
1468 nn(1:3) = (/ niter, 1, 1 /)
1469 optimize(1:3) = .false.
1470 optimize_parity(1:3) = -1
1471
1472 call fft_init(fft_handler, nn(1:3), 1, fft_complex, fftlib_fftw, optimize, optimize_parity)
1473 call zfft_forward(fft_handler, func_(0:niter-1), funcw_(0:niter-1))
1474 do j = 0, niter - 1
1475 funcw_(j) = -abs(funcw_(j))**2 * dt**2
1476 end do
1477
1479 end subroutine spectrum_hsfunction_init
1480 ! ---------------------------------------------------------
1481
1482
1483 ! ---------------------------------------------------------
1484 subroutine spectrum_hsfunction_end
1485
1486 push_sub(spectrum_hsfunction_end)
1487
1488 call fft_end(fft_handler)
1489
1490 safe_deallocate_a(func_)
1491 safe_deallocate_a(funcw_)
1493 end subroutine spectrum_hsfunction_end
1494 ! ---------------------------------------------------------
1495
1496
1497 ! ---------------------------------------------------------
1498 subroutine spectrum_hsfunction_min(namespace, aa, bb, omega_min, func_min)
1499 type(namespace_t), intent(in) :: namespace
1500 real(real64), intent(in) :: aa, bb
1501 real(real64), intent(out) :: omega_min, func_min
1502
1503 integer :: ierr, ie
1504 real(real64) :: xx, hsval, minhsval, ww, xa, xb, hxa, hxb
1505
1506 push_sub(spectrum_hsfunction_min)
1507
1508 ! xx should be an initial guess for the minimum. So we do a quick search
1509 ! that we refine later calling 1dminimize.
1510 !xx = omega
1511 !call hsfunction(xx, minhsval)
1512
1513 ierr = 0
1514
1515 ie = int(aa/energy_step_)
1516 ww = ie * energy_step_
1517 if (ww < aa) then
1518 ie = ie + 1
1519 ww = ie * energy_step_
1520 end if
1521 xx = ie * energy_step_
1522 minhsval = real(funcw_(ie), real64)
1523 do while(ww <= bb)
1524 hsval = real(funcw_(ie), real64)
1525 if (hsval < minhsval) then
1526 minhsval = hsval
1527 xx = ww
1528 end if
1529 ie = ie + 1
1530 ww = ie * energy_step_
1531 end do
1532
1533 ! Around xx, we call some GSL sophisticated search algorithm to find the minimum.
1534 ! First, we get the value of the function at the extremes of the interval
1535 xa = max(xx-energy_step_, aa)
1536 xb = min(xx+energy_step_, bb)
1537 call hsfunction(xa, hxa)
1538 call hsfunction(xb, hxb)
1539
1540 if (hxa <= minhsval) then
1541 xx = xa
1542 minhsval = hxa
1543 elseif (hxb <= minhsval) then
1544 xx = xb
1545 minhsval = hxb
1546 else
1547 call loct_1dminimize(xa, xb, xx, hsfunction, ierr)
1548 end if
1549
1550 if (ierr /= 0) then
1551 write(message(1),'(a,f14.6,a)') 'spectrum_hsfunction_min: The maximum at', xx,' was not properly converged.'
1552 write(message(2),'(a,i12)') 'Error code: ', ierr
1553 call messages_warning(2, namespace=namespace)
1554 end if
1555 call hsfunction(xx, hsval)
1556 omega_min = xx
1557 func_min = hsval
1558
1560 end subroutine spectrum_hsfunction_min
1561 ! ---------------------------------------------------------
1562
1563
1564 ! ---------------------------------------------------------
1565 subroutine hsfunction(omega, power)
1566 real(real64), intent(in) :: omega
1567 real(real64), intent(out) :: power
1568
1569 complex(real64) :: cc, ez1, ez, zz
1570 integer :: jj,dir
1571
1572 push_sub(hsfunction)
1573
1574 zz = m_zi * omega * time_step_
1575 ez = exp(zz)
1576
1577 if (allocated(func_ar_)) then
1578 power = m_zero
1579 do dir = 1, 3
1580 ez1 = exp((is_ - 1) * zz)
1581 cc = m_z0
1582 do jj = is_, ie_
1583 ! This would be easier, but slower.
1584 !cc = cc + exp(M_zI * omega * jj * time_step_) * func_(jj)
1585 ez1 = ez1 * ez
1586 cc = cc + ez1 * func_ar_(dir,jj) &
1587 *exp(-m_zi * omega * tret_(jj)) !integrate over the retarded time
1588 end do
1589 power = power - abs(cc)**2 * time_step_**2
1590! pp(dir) = cc * time_step_
1591 end do
1592! power = - sum(abs(zcross_product(vv_, pp))**2)
1593 else
1594 cc = m_z0
1595 ez1 = exp((is_ - 1) * zz)
1596 do jj = is_, ie_
1597 ez1 = ez1 * ez
1598 cc = cc + ez1 * func_(jj)
1599 end do
1600 power = -abs(cc)**2 * time_step_**2
1601 end if
1602
1603
1604 pop_sub(hsfunction)
1605 end subroutine hsfunction
1606 ! ---------------------------------------------------------
1607
1608 ! ---------------------------------------------------------
1609 subroutine spectrum_hsfunction_ar_init(dt, is, ie, niter, acc, pos,tret)
1610 real(real64), intent(in) :: dt
1611 integer, intent(in) :: is, ie, niter
1612 complex(real64), contiguous, intent(in) :: acc(:,:),pos(:,:),tret(:)
1613
1615
1616 is_ = is
1617 ie_ = ie
1618 time_step_ = dt
1619 safe_allocate(func_ar_(1:3, 0:niter))
1620 safe_allocate(pos_(1:3, 0:niter))
1621 safe_allocate(tret_(0:niter))
1622 func_ar_ = acc
1623 pos_= pos
1624 tret_=tret
1625
1626
1628 end subroutine spectrum_hsfunction_ar_init
1629 ! ---------------------------------------------------------
1630
1631
1632 ! ---------------------------------------------------------
1633 ! FIXME: why is this never called?
1635
1637
1638 safe_deallocate_a(func_ar_)
1639 safe_deallocate_a(pos_)
1640 safe_deallocate_a(tret_)
1641
1643 end subroutine spectrum_hsfunction_ar_end
1644 ! ---------------------------------------------------------
1645
1646 ! ---------------------------------------------------------
1647 subroutine spectrum_hs_ar_from_acc(spectrum, namespace, out_file, vec, w0)
1648 type(spectrum_t), intent(inout) :: spectrum
1649 type(namespace_t), intent(in) :: namespace
1650 character(len=*), intent(in) :: out_file
1651 real(real64), contiguous, intent(in) :: vec(:)
1652 real(real64), optional, intent(in) :: w0
1653
1654 integer :: istep, trash, iunit, nspin, time_steps, istart, iend, ntiter, lmax, ierr, jj, idir, ispin
1655 real(real64) :: dt, dump, aa(3)
1656 complex(real64) :: nn(3)
1657 type(kick_t) :: kick
1658 real(real64), allocatable :: dd(:,:)
1659 complex(real64), allocatable :: acc(:,:),pp(:,:),pos(:,:),tret(:)
1660 real(real64) :: vv(3)
1661 type(unit_system_t) :: file_units
1662
1663 push_sub(spectrum_hs_ar_from_acc)
1664
1665 call spectrum_tdfile_info(namespace, 'acceleration', iunit, time_steps, dt)
1666 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1667
1668 ! load dipole from file
1669 safe_allocate(acc(1:3, 0:time_steps))
1670 safe_allocate(pp(1:3, 0:time_steps))
1671 safe_allocate(pos(1:3, 0:time_steps))
1672 safe_allocate(tret(0:time_steps))
1673
1674 acc = m_zero
1675 pos = m_zero
1676 pp = m_zero
1677 nn = m_zero
1678 tret = m_zero
1679
1680 call io_skip_header(iunit)
1681 do istep = 0, time_steps-1
1682 aa = m_zero
1683 read(iunit, '(28x,e20.12)', advance = 'no', iostat = ierr) aa(1)
1684 jj = 2
1685 do while((ierr == 0) .and. (jj <= 3))
1686 read(iunit, '(e20.12)', advance = 'no', iostat = ierr) aa(jj)
1687 jj = jj+1
1688 end do
1689
1690! read(iunit, *) trash, dump, aa
1691
1692 acc(:,istep) = units_to_atomic(units_out%acceleration, aa(:))
1693! write (*,*) istep, Real(acc(:,istep))
1694 end do
1695 close(iunit)
1696
1697
1698 ! Try to get the trajectory from multipole file
1699
1700 iunit = io_open('multipoles', namespace, action='read', status='old', die=.false.)
1701 if (iunit == -1) then
1702 iunit = io_open('td.general/multipoles', namespace, action='read', status='old')
1703 end if
1704 call spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax=lmax)
1705 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1706
1707 call io_skip_header(iunit)
1708! write (*,*)
1709
1710 safe_allocate(dd(1:3, 1:nspin))
1711 do istep = 0, time_steps-1
1712 dd = m_zero
1713 read(iunit, *) trash, dump, (dump, (dd(idir, ispin), idir = 1, kick%dim), ispin = 1, nspin)
1714 pos(1:3, istep) = -sum(dd(1:3, 1:min(nspin, 2)),2)
1715 pos(:,istep) = units_to_atomic(units_out%length, pos(:,istep))
1716 end do
1717 safe_deallocate_a(dd)
1718 pos(:,0) = pos(:,1)
1719 call io_close(iunit)
1720
1721! write (*,*)
1722
1723 ! normalize vector and set to global var
1724! vv = vec / sqrt(sum(vec(:)**2))
1725 vv(1:3) = vec(1:3)
1726
1727 pp(:,0) = m_zero
1728 do istep = 0, time_steps - 1
1729 nn(:) = vv(:)-pos(:,istep)
1730 nn(:) = nn(:)/norm2(abs(nn(:)))
1731 tret(istep) = dot_product(vv(:), real(pos(:,istep), real64))/p_c
1732 pp(:,istep) = zcross_product(nn, zcross_product(nn, acc(:,istep)))
1733! write (*,*) istep, Real(PP(:,istep)),"acc", Real(acc(:,istep))
1734 end do
1735
1736 call spectrum_hsfunction_ar_init(dt, istart, iend, time_steps, pp, pos, tret)
1737 call spectrum_hs(spectrum, namespace, out_file, 'a', w0)
1739
1740 safe_deallocate_a(acc)
1741 safe_deallocate_a(pp)
1742 safe_deallocate_a(pos)
1743 safe_deallocate_a(tret)
1744
1746 end subroutine spectrum_hs_ar_from_acc
1747 ! ---------------------------------------------------------
1748
1749
1750 ! ---------------------------------------------------------
1751 subroutine spectrum_hs_ar_from_mult(spectrum, namespace, out_file, vec, w0)
1752 type(spectrum_t), intent(inout) :: spectrum
1753 type(namespace_t), intent(in) :: namespace
1754 character(len=*), intent(in) :: out_file
1755 real(real64), contiguous, intent(in) :: vec(:)
1756 real(real64), optional, intent(in) :: w0
1757
1758 integer :: istep, trash, iunit, nspin, time_steps, istart, iend, ntiter, lmax, idir, ispin
1759 real(real64) :: dt, dump
1760 type(kick_t) :: kick
1761 real(real64), allocatable :: dd(:,:)
1762 complex(real64), allocatable :: dipole(:,:), ddipole(:,:), pp(:,:), tret(:)
1763 complex(real64) :: vv(3)
1764 type(unit_system_t) :: file_units
1765
1766 push_sub(spectrum_hs_ar_from_mult)
1767
1768
1769 iunit = io_open('multipoles', namespace, action='read', status='old', die=.false.)
1770 if (iunit == -1) then
1771 iunit = io_open('td.general/multipoles', namespace, action='read', status='old')
1772 end if
1773 call spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax=lmax)
1774 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1775
1776 call io_skip_header(iunit)
1777
1778 ! load dipole from file
1779 safe_allocate(dipole(1:3, 0:time_steps))
1780 safe_allocate(ddipole(1:3, 0:time_steps))
1781 safe_allocate(pp(1:3, 0:time_steps))
1782 safe_allocate(tret(0:time_steps))
1783 safe_allocate(dd(1:3, 1:nspin))
1784
1785 dipole = m_z0
1786 ddipole = m_z0
1787 pp = m_z0
1788 tret= m_zero
1789
1790 do istep = 1, time_steps
1791 dd = m_zero
1792 read(iunit, *) trash, dump, (dump, (dd(idir, ispin), idir = 1, kick%dim), ispin = 1, nspin)
1793 dipole(1:3, istep) = -sum(dd(1:3, 1:min(nspin, 2)),2)
1794 dipole(:,istep) = units_to_atomic(units_out%length, dipole(:,istep))
1795 end do
1796 safe_deallocate_a(dd)
1797 dipole(:,0) = dipole(:,1)
1798 call io_close(iunit)
1799
1800 ! we now calculate the acceleration.
1801 ddipole(:,0) = m_zero
1802 do istep = 1, time_steps - 1
1803 ddipole(:,istep) = (dipole(:,istep - 1) + dipole(:,istep + 1) - m_two * dipole(:,istep)) / dt**2
1804 end do
1805 call interpolate(dt*(/ -3, -2, -1 /), &
1806 ddipole(1,time_steps - 3:time_steps - 1), &
1807 m_zero, &
1808 ddipole(1,time_steps))
1809 call interpolate(dt*(/ -3, -2, -1 /), &
1810 ddipole(2,time_steps - 3:time_steps - 1), &
1811 m_zero, &
1812 ddipole(2,time_steps))
1813 call interpolate(dt*(/ -3, -2, -1 /), &
1814 ddipole(3,time_steps - 3:time_steps - 1), &
1815 m_zero, &
1816 ddipole(3,time_steps))
1817
1818 ! normalize vector and set to global var
1819 vv(1:3) = vec(1:3) / norm2(vec(1:3))
1820
1821 pp(:,0) = m_zero
1822 do istep = 1, time_steps - 1
1823! write (*,*) istep, istep*dt, Real(ddipole(1,istep)), Real(ddipole(2,istep))
1824 tret(istep) = dot_product(vv(:), dipole(:,istep))/p_c
1825 pp(:,istep) = zcross_product(vv, zcross_product(vv, ddipole(:,istep - 1)))
1826! PP(istep) = sum(abs(dipole(:,istep))**2)
1827! write(*,*) istep, PP(istep)
1828
1829 end do
1830
1831
1832 call spectrum_hsfunction_ar_init(dt, istart, iend, time_steps, pp, dipole,tret)
1833 call spectrum_hs(spectrum, namespace, out_file, 'a', w0)
1835
1836 safe_deallocate_a(dipole)
1837 safe_deallocate_a(ddipole)
1838 safe_deallocate_a(pp)
1839 safe_deallocate_a(tret)
1840
1841
1843 end subroutine spectrum_hs_ar_from_mult
1844 ! ---------------------------------------------------------
1845
1847 ! ---------------------------------------------------------
1848 subroutine spectrum_hs_from_mult(spectrum, namespace, out_file, pol, vec, w0)
1849 type(spectrum_t), intent(inout) :: spectrum
1850 type(namespace_t), intent(in) :: namespace
1851 character(len=*), intent(in) :: out_file
1852 character, intent(in) :: pol
1853 real(real64), contiguous, intent(in) :: vec(:)
1854 real(real64), optional, intent(in) :: w0
1855
1856 integer :: istep, trash, iunit, nspin, time_steps, istart, iend, ntiter, lmax, no_e, ie, idir, ispin, nrho
1857 real(real64) :: dt, dump, vv(3)
1858 type(kick_t) :: kick
1859 real(real64), allocatable :: dd(:,:)
1860 real(real64), allocatable :: sps(:), spc(:), racc(:)
1861 complex(real64), allocatable :: dipole(:), ddipole(:)
1862 type(batch_t) :: acc_batch, sps_batch, spc_batch
1863 type(unit_system_t) :: file_units
1864
1865 push_sub(spectrum_hs_from_mult)
1866
1867 iunit = io_open('multipoles', namespace, action='read', status='old', die=.false.)
1868 if (iunit == -1) then
1869 iunit = io_open('td.general/multipoles', namespace, action='read', status='old')
1870 end if
1871 call spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax=lmax)
1872 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1873
1874 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
1875
1876 call io_skip_header(iunit)
1877
1878 ! load dipole from file
1879 safe_allocate(dipole(0:time_steps))
1880 safe_allocate(ddipole(0:time_steps))
1881 safe_allocate(dd(1:3, 1:nspin))
1882
1883 vv(1:3) = vec(1:3) / norm2(vec(1:3))
1884
1885 ! Only the density components (not the spinor off-diagonal ones) carry the charge
1886 nrho = min(nspin, 2)
1887
1888 do istep = 1, time_steps
1889 dd = m_zero
1890 read(iunit, *) trash, dump, (dump, (dd(idir, ispin), idir = 1, kick%dim), ispin = 1, nspin)
1891 select case (pol)
1892 case ('x')
1893 dipole(istep) = -sum(dd(1, 1:nrho))
1894 case ('y')
1895 dipole(istep) = -sum(dd(2, 1:nrho))
1896 case ('z')
1897 dipole(istep) = sum(dd(3, 1:nrho))
1898 case ('+')
1899 dipole(istep) = -sum(cmplx(dd(1, 1:nrho), dd(2, 1:nrho), real64)) / sqrt(m_two)
1900 case ('-')
1901 dipole(istep) = -sum(cmplx(dd(1, 1:nrho), -dd(2, 1:nrho), real64)) / sqrt(m_two)
1902 case ('v')
1903 dipole(istep) = -sum(vv(1)*dd(1, 1:nrho) + vv(2)*dd(2, 1:nrho) + vv(3)*dd(3, 1:nrho))
1904 end select
1905 dipole(istep) = units_to_atomic(units_out%length, dipole(istep))
1906 end do
1907 safe_deallocate_a(dd)
1908 dipole(0) = dipole(1)
1909 call io_close(iunit)
1910
1911 ! we now calculate the acceleration.
1912 ddipole(0) = m_zero
1913 do istep = 1, time_steps - 1
1914 ddipole(istep) = (dipole(istep - 1) + dipole(istep + 1) - m_two * dipole(istep)) / dt**2
1915 end do
1916 call interpolate( dt*(/ -3, -2, -1 /), &
1917 ddipole(time_steps - 3:time_steps - 1), &
1918 m_zero, &
1919 ddipole(time_steps))
1920
1921 if (present(w0)) then
1922
1923 call spectrum_hsfunction_init(dt, istart, iend, time_steps, ddipole)
1924 call spectrum_hs(spectrum, namespace, out_file, pol, w0)
1926
1927 else
1928
1929 safe_allocate(racc(0:time_steps))
1930 racc = real(ddipole, real64)
1931
1932 no_e = spectrum_nenergy_steps(spectrum)
1933 safe_allocate(sps(1:no_e))
1934 safe_allocate(spc(1:no_e))
1935 sps = m_zero
1936 spc = m_zero
1937
1938 call batch_init(acc_batch, racc)
1939 call batch_init(sps_batch, sps)
1940 call batch_init(spc_batch, spc)
1941
1942 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
1943 istart + 1, iend + 1, m_zero, dt, acc_batch, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, spc_batch)
1944 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
1945 istart + 1, iend + 1, m_zero, dt, acc_batch, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, sps_batch)
1946
1947 do ie = 1, no_e
1948 sps(ie) = (sps(ie)**2 + spc(ie)**2)
1949 end do
1950
1951 call spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sps)
1952
1953 call acc_batch%end()
1954 call sps_batch%end()
1955 call spc_batch%end()
1956
1957 safe_deallocate_a(racc)
1958
1959 end if
1960
1961 safe_deallocate_a(dipole)
1962 safe_deallocate_a(ddipole)
1963
1964 pop_sub(spectrum_hs_from_mult)
1965 end subroutine spectrum_hs_from_mult
1966 ! ---------------------------------------------------------
1967
1968
1969 ! ---------------------------------------------------------
1970 subroutine spectrum_hs_from_acc(spectrum, namespace, out_file, pol, vec, w0)
1971 type(spectrum_t), intent(inout) :: spectrum
1972 type(namespace_t), intent(in) :: namespace
1973 character(len=*), intent(in) :: out_file
1974 character, intent(in) :: pol
1975 real(real64), contiguous, intent(in) :: vec(:)
1976 real(real64), optional, intent(in) :: w0
1977
1978 integer :: istep, jj, iunit, time_steps, istart, iend, ntiter, ierr, no_e, ie
1979 real(real64) :: dt, aa(3), vv(3)
1980 complex(real64), allocatable :: acc(:)
1981 real(real64), allocatable :: racc(:), sps(:), spc(:)
1982 type(batch_t) :: acc_batch, sps_batch, spc_batch
1983
1984 push_sub(spectrum_hs_from_acc)
1985
1986 call spectrum_tdfile_info(namespace, 'acceleration', iunit, time_steps, dt)
1987 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
1988
1989 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt*time_steps)
1990
1991 ! load dipole from file
1992 safe_allocate(acc(0:time_steps))
1993 acc = m_zero
1994 vv = vec / norm2(vec(:))
1995 call io_skip_header(iunit)
1996
1997 do istep = 1, time_steps
1998 aa = m_zero
1999 read(iunit, '(28x,e20.12)', advance = 'no', iostat = ierr) aa(1)
2000 jj = 2
2001 do while((ierr == 0) .and. (jj <= 3))
2002 read(iunit, '(e20.12)', advance = 'no', iostat = ierr) aa(jj)
2003 jj = jj + 1
2004 end do
2005 select case (pol)
2006 case ('x')
2007 acc(istep) = aa(1)
2008 case ('y')
2009 acc(istep) = aa(2)
2010 case ('z')
2011 acc(istep) = aa(3)
2012 case ('+')
2013 acc(istep) = cmplx(aa(1), aa(2), real64) / sqrt(m_two)
2014 case ('-')
2015 acc(istep) = cmplx(aa(1), -aa(2), real64) / sqrt(m_two)
2016 case ('v')
2017 acc(istep) = vv(1)*aa(1) + vv(2)*aa(2) + vv(3)*aa(3)
2018 end select
2019 acc(istep) = units_to_atomic(units_out%acceleration, acc(istep))
2020 end do
2021 close(iunit)
2022
2023 if (present(w0)) then
2024
2025 call spectrum_hsfunction_init(dt, istart, iend, time_steps, acc)
2026 call spectrum_hs(spectrum, namespace, out_file, pol, w0)
2028
2029 else
2030
2031 safe_allocate(racc(0:time_steps))
2032 racc = real(acc, real64)
2033
2034 no_e = spectrum_nenergy_steps(spectrum)
2035 safe_allocate(sps(1:no_e))
2036 safe_allocate(spc(1:no_e))
2037 sps = m_zero
2038 spc = m_zero
2039
2040 call batch_init(acc_batch, racc)
2041 call batch_init(sps_batch, sps)
2042 call batch_init(spc_batch, spc)
2043
2044 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
2045 istart + 1, iend + 1, m_zero, dt, acc_batch, spectrum%min_energy, &
2046 spectrum%max_energy, spectrum%energy_step, spc_batch)
2047 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
2048 istart + 1, iend + 1, m_zero, dt, acc_batch, spectrum%min_energy, &
2049 spectrum%max_energy, spectrum%energy_step, sps_batch)
2050
2051 do ie = 1, no_e
2052 sps(ie) = (sps(ie)**2 + spc(ie)**2)
2053 end do
2054
2055 call spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sps)
2056
2057 call acc_batch%end()
2058 call sps_batch%end()
2059 call spc_batch%end()
2060
2061 safe_deallocate_a(racc)
2062
2063 end if
2064
2065 safe_deallocate_a(acc)
2066 pop_sub(spectrum_hs_from_acc)
2067 end subroutine spectrum_hs_from_acc
2068 ! ---------------------------------------------------------
2069
2070 ! ---------------------------------------------------------
2071 subroutine spectrum_hs_from_current(spectrum, namespace, out_file, pol, vec, w0)
2072 type(spectrum_t), intent(inout) :: spectrum
2073 type(namespace_t), intent(in) :: namespace
2074 character(len=*), intent(in) :: out_file
2075 character, intent(in) :: pol
2076 real(real64), contiguous, intent(in) :: vec(:)
2077 real(real64), optional, intent(in) :: w0
2078
2079 integer :: istep, jj, iunit, time_steps, istart, iend, ntiter, ierr, no_e, ie
2080 real(real64) :: dt, cc(3), vv(3)
2081 complex(real64), allocatable :: cur(:)
2082 real(real64), allocatable :: rcur(:), sps(:), spc(:)
2083 type(batch_t) :: cur_batch, sps_batch, spc_batch
2084
2085 push_sub(spectrum_hs_from_current)
2086
2087 call spectrum_tdfile_info(namespace, 'total_current', iunit, time_steps, dt)
2088 call spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
2089
2090 if (spectrum%energy_step <= m_zero) spectrum%energy_step = m_two * m_pi / (dt * time_steps)
2091
2092 ! load dipole from file
2093 safe_allocate(cur(0:time_steps))
2094 cur = m_zero
2095 vv = vec / norm2(vec(:))
2096 call io_skip_header(iunit)
2097
2098 do istep = 1, time_steps
2099 cc = m_zero
2100 read(iunit, '(28x,e20.12)', advance = 'no', iostat = ierr) cc(1)
2101 jj = 2
2102 do while((ierr == 0) .and. (jj <= 3))
2103 read(iunit, '(e20.12)', advance = 'no', iostat = ierr) cc(jj)
2104 jj = jj + 1
2105 end do
2106 select case (pol)
2107 case ('x')
2108 cur(istep) = cc(1)
2109 case ('y')
2110 cur(istep) = cc(2)
2111 case ('z')
2112 cur(istep) = cc(3)
2113 case ('+')
2114 cur(istep) = cmplx(cc(1), cc(2), real64) / sqrt(m_two)
2115 case ('-')
2116 cur(istep) = cmplx(cc(1), -cc(2), real64) / sqrt(m_two)
2117 case ('v')
2118 cur(istep) = vv(1)*cc(1) + vv(2)*cc(2) + vv(3)*cc(3)
2119 end select
2120 cur(istep) = units_to_atomic(units_out%velocity, cur(istep))
2121 end do
2122 close(iunit)
2123
2124 if (present(w0)) then
2125
2126 call spectrum_hsfunction_init(dt, istart, iend, time_steps, cur)
2127 call spectrum_hs(spectrum, namespace, out_file, pol, w0)
2129
2130 else
2131
2132 safe_allocate(rcur(0:time_steps))
2133 rcur = real(cur, real64)
2134
2135 no_e = spectrum_nenergy_steps(spectrum)
2136 safe_allocate(sps(1:no_e))
2137 safe_allocate(spc(1:no_e))
2138 sps = m_zero
2139 spc = m_zero
2140
2141 call batch_init(cur_batch, rcur)
2142 call batch_init(sps_batch, sps)
2143 call batch_init(spc_batch, spc)
2144
2145 call spectrum_fourier_transform(spectrum%method, spectrum_transform_cos, spectrum%noise, &
2146 istart + 1, iend + 1, m_zero, dt, cur_batch, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, spc_batch)
2147 call spectrum_fourier_transform(spectrum%method, spectrum_transform_sin, spectrum%noise, &
2148 istart + 1, iend + 1, m_zero, dt, cur_batch, spectrum%min_energy, spectrum%max_energy, spectrum%energy_step, sps_batch)
2149
2150 do ie = 1, no_e
2151 sps(ie) = (sps(ie)**2 + spc(ie)**2) * ((ie-1) * spectrum%energy_step + spectrum%min_energy)**2
2152 end do
2153
2154 call spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sps)
2155
2156 call cur_batch%end()
2157 call sps_batch%end()
2158 call spc_batch%end()
2159
2160 safe_deallocate_a(rcur)
2161
2162 end if
2163
2164 safe_deallocate_a(cur)
2167
2168
2169 ! ---------------------------------------------------------
2170 subroutine spectrum_hs(spectrum, namespace, out_file, pol, w0)
2171 type(spectrum_t), intent(inout) :: spectrum
2172 type(namespace_t), intent(in) :: namespace
2173 character(len=*), intent(in) :: out_file
2174 character, intent(in) :: pol
2175 real(real64), optional, intent(in) :: w0
2176
2177 integer :: iunit, no_e, ie
2178 real(real64) :: omega, hsval, xx
2179 real(real64), allocatable :: sp(:)
2180
2181 push_sub(spectrum_hs)
2182
2183 if (present(w0)) then
2184
2185 iunit = io_open(trim(out_file) // "." // trim(pol), namespace, action='write')
2186 write(iunit, '(a1,a20,a20)') '#', str_center("w", 20), str_center("H(w)", 20)
2187 write(iunit, '(a1,a20,a20)') '#', &
2188 str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20), &
2189 str_center('[('//trim(units_abbrev(units_out%length))//'/' &
2190 //trim(units_abbrev(units_out%time**2)), 20)
2191
2192 ! output
2193 omega = w0
2194 do while(omega <= spectrum%max_energy)
2195 call spectrum_hsfunction_min(namespace, omega - w0, omega + w0, xx, hsval)
2196
2197 write(iunit, '(1x,2e20.8)') units_from_atomic(units_out%energy, xx), &
2198 units_from_atomic((units_out%length / units_out%time)**2, -hsval)
2199
2200 ! 2 * w0 because we assume that there are only odd peaks.
2201 omega = omega + 2 * w0
2202 end do
2203 call io_close(iunit)
2204
2205 else
2206 no_e = spectrum_nenergy_steps(spectrum)
2207 safe_allocate(sp(1:no_e))
2208 sp = m_zero
2209
2210 do ie = 1, no_e
2211 call hsfunction((ie-1) * spectrum%energy_step + spectrum%min_energy, sp(ie))
2212 sp(ie) = -sp(ie)
2213 end do
2214
2215 call spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sp)
2216
2217 safe_deallocate_a(sp)
2218
2219 end if
2220
2221 pop_sub(spectrum_hs)
2222 end subroutine spectrum_hs
2223 ! ---------------------------------------------------------
2224
2225
2226 subroutine spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sp)
2227 type(spectrum_t), intent(inout) :: spectrum
2228 type(namespace_t), intent(in) :: namespace
2229 character(len=*), intent(in) :: out_file
2230 character, intent(in) :: pol
2231 integer, intent(in) :: no_e
2232 real(real64), contiguous, intent(in) :: sp(:)
2233
2234 integer :: iunit, ie
2235
2236 push_sub(spectrum_hs_output)
2237
2238 ! output
2239 if (trim(out_file) /= '-') then
2240 iunit = io_open(trim(out_file) // "." // trim(pol), namespace, action='write')
2241 write(iunit, '(a1,a20,a20)') '#', str_center("w", 20), str_center("H(w)", 20)
2242
2243 write(iunit, '(a1,a20,a20)') &
2244 '#', str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20), &
2245 str_center('[('//trim(units_abbrev(units_out%length))//'/' &
2246 //trim(units_abbrev(units_out%time**2)), 20)
2247
2248 do ie = 1, no_e
2249 write(iunit, '(2e15.6)') units_from_atomic(units_out%energy, (ie-1) * spectrum%energy_step + spectrum%min_energy), &
2250 units_from_atomic((units_out%length / units_out%time)**2, sp(ie))
2251 end do
2252
2253 call io_close(iunit)
2254 end if
2255
2256 pop_sub(spectrum_hs_output)
2257 end subroutine spectrum_hs_output
2258
2259
2260 ! ---------------------------------------------------------
2261 subroutine spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax)
2262 type(namespace_t), intent(in) :: namespace
2263 integer, intent(in) :: iunit
2264 integer, intent(out) :: nspin
2265 type(kick_t), intent(out) :: kick
2266 integer, intent(out) :: time_steps
2267 real(real64), intent(out) :: dt
2268 type(unit_system_t), intent(out) :: file_units
2269 integer, optional, intent(out) :: lmax
2270
2271 integer :: ii
2272 character(len=100) :: line
2273
2274 push_sub(spectrum_mult_info)
2275
2276 assert(iunit /= -1)
2277
2278 rewind(iunit)
2279 call spectrum_read_header(namespace, iunit, line, "header separator")
2280 call spectrum_read_header(namespace, iunit, line, "header title")
2281 call spectrum_read_header(namespace, iunit, nspin, "number of spin components")
2282 if (present(lmax)) then
2283 call spectrum_read_header(namespace, iunit, lmax, "maximum multipole order")
2284 end if
2285 call kick_read(kick, iunit, namespace)
2286 call spectrum_read_header(namespace, iunit, line, "multipoles column labels")
2287 call spectrum_read_header(namespace, iunit, line, "multipoles units")
2288 call io_skip_header(iunit)
2289
2290 ! Figure out the units of the file
2291 ii = index(line,'eV')
2292 if (ii /= 0) then
2293 call unit_system_get(file_units, units_eva)
2294 else
2295 call unit_system_get(file_units, units_atomic)
2296 end if
2297
2298 call spectrum_count_time_steps(namespace, iunit, time_steps, dt)
2299 dt = units_to_atomic(file_units%time, dt) ! units_out is OK
2300
2301 pop_sub(spectrum_mult_info)
2302 end subroutine spectrum_mult_info
2303 ! ---------------------------------------------------------
2304
2305
2306 ! ---------------------------------------------------------
2307 subroutine spectrum_count_time_steps(namespace, iunit, time_steps, dt)
2308 type(namespace_t), intent(in) :: namespace
2309 integer, intent(in) :: iunit
2310 integer, intent(out) :: time_steps
2311 real(real64), intent(out) :: dt
2312
2313 real(real64) :: t1, t2, dummy
2314 integer :: trash, ierr
2315 character(len=200) :: line
2316
2317 push_sub(count_time_steps)
2318
2319 ! count number of time_steps
2320 time_steps = 0
2322 t2 = m_zero
2323 do
2324 read(iunit, '(a)', iostat = ierr) line
2325 if (ierr == iostat_end) exit
2326 if (ierr /= 0) then
2327 message(1) = "Could not read multipoles time-step data."
2328 call messages_fatal(1, namespace=namespace)
2329 end if
2330 if (len_trim(line) == 0 .or. line(1:1) == "#") cycle
2331 read(line, *, iostat = ierr) trash, dummy
2332 if (ierr /= 0) then
2333 message(1) = "Could not parse multipoles time-step line:"
2334 write(message(2), '(a)') trim(line)
2335 call messages_fatal(2, namespace=namespace)
2336 end if
2337 time_steps = time_steps + 1
2338 if (time_steps == 1) t1 = dummy
2339 if (time_steps == 2) t2 = dummy
2340 end do
2341 dt = (t2 - t1)
2342 time_steps = time_steps - 1
2343
2344 if (time_steps < 3) then
2345 message(1) = "Empty file?"
2346 call messages_fatal(1, namespace=namespace)
2347 end if
2348
2349 pop_sub(count_time_steps)
2350 end subroutine spectrum_count_time_steps
2351 ! ---------------------------------------------------------
2352
2353
2354 ! ---------------------------------------------------------
2355 subroutine spectrum_cross_section_info(namespace, iunit, nspin, kick, energy_steps, dw)
2356 type(namespace_t), intent(in) :: namespace
2357 integer, intent(in) :: iunit
2358 integer, intent(out) :: nspin
2359 type(kick_t), intent(out) :: kick
2360 integer, intent(out) :: energy_steps
2361 real(real64), intent(out) :: dw
2362
2363 real(real64) :: dummy, e1, e2
2364
2366
2367 ! read in number of spin components
2368 call spectrum_find_cross_section_header(namespace, iunit)
2369 call spectrum_read_header(namespace, iunit, nspin, "number of spin components")
2370 call kick_read(kick, iunit, namespace)
2371 call io_skip_header(iunit)
2372
2373 ! count number of time_steps
2374 energy_steps = 0
2375 do
2376 read(iunit, *, end=100) dummy
2377 energy_steps = energy_steps + 1
2378 if (energy_steps == 1) e1 = dummy
2379 if (energy_steps == 2) e2 = dummy
2380 end do
2381100 continue
2382 dw = units_to_atomic(units_out%energy, e2 - e1)
2383
2384 if (energy_steps < 3) then
2385 message(1) = "Empty multipole file?"
2386 call messages_fatal(1, namespace=namespace)
2387 end if
2388
2390 end subroutine spectrum_cross_section_info
2391
2392
2393 ! ---------------------------------------------------------
2394 subroutine spectrum_tdfile_info(namespace, fname, iunit, time_steps, dt)
2395 type(namespace_t), intent(in) :: namespace
2396 character(len=*), intent(in) :: fname
2397 integer, intent(out) :: iunit, time_steps
2398 real(real64), intent(out) :: dt
2399
2400 integer :: trash
2401 real(real64) :: t1, t2, dummy
2402 character(len=256) :: filename
2403
2404 push_sub(spectrum_tdfile_info)
2405
2406 ! open files
2407 filename = trim('td.general/')//trim(fname)
2408 iunit = io_open(filename, namespace, action='read', status='old', die=.false.)
2409
2410 if (iunit == -1) then
2411 filename = trim('./')//trim(fname)
2412 iunit = io_open(filename, namespace, action='read', status='old')
2413 end if
2414
2415
2416 ! read in dipole
2417 call io_skip_header(iunit)
2418
2419 ! count number of time_steps
2420 time_steps = 0
2421 do
2422 read(iunit, *, end=100) trash, dummy
2423 time_steps = time_steps + 1
2424 if (time_steps == 1) t1 = dummy
2425 if (time_steps == 2) t2 = dummy
2426 end do
2427100 continue
2428 dt = units_to_atomic(units_out%time, t2 - t1) ! units_out is OK
2429 time_steps = time_steps - 1
2430
2431 if (time_steps < 3) then
2432 message(1) = "Empty file?"
2433 call messages_fatal(1, namespace=namespace)
2434 end if
2435
2436 rewind(iunit)
2437 pop_sub(spectrum_tdfile_info)
2438 end subroutine spectrum_tdfile_info
2439
2440
2441 ! ---------------------------------------------------------
2442 subroutine spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
2443 type(spectrum_t), intent(inout) :: spectrum
2444 integer, intent(in) :: time_steps
2445 real(real64), intent(in) :: dt
2446 integer, intent(out) :: istart, iend, ntiter
2447
2448 real(real64) :: ts, te, dummy
2449
2451
2452 ts = m_zero
2453 te = time_steps * dt
2454
2455 if (spectrum%start_time < ts) spectrum%start_time = ts
2456 if (spectrum%start_time > te) spectrum%start_time = te
2457 if (spectrum%end_time > te .or. spectrum%end_time <= m_zero) spectrum%end_time = te
2458 if (spectrum%end_time < ts) spectrum%end_time = ts
2459
2460 if (spectrum%end_time < spectrum%start_time) then
2461 dummy = spectrum%end_time ! swap
2462 spectrum%end_time = spectrum%start_time
2463 spectrum%start_time = dummy
2464 end if
2465 istart = nint(spectrum%start_time / dt)
2466 iend = nint(spectrum%end_time / dt)
2467 ntiter = iend - istart + 1
2468
2469 ! Get default damp factor
2470 if (spectrum%damp /= spectrum_damp_none .and. spectrum%damp /= spectrum_damp_polynomial &
2471 .and. is_close(spectrum%damp_factor, -m_one)) then
2472 select case (spectrum%damp)
2474 spectrum%damp_factor = -log(0.0001_real64)/(spectrum%end_time-spectrum%start_time)
2476 spectrum%damp_factor = sqrt(-log(0.0001_real64)/(spectrum%end_time-spectrum%start_time)**2)
2477 end select
2478 end if
2479
2480
2482 end subroutine spectrum_fix_time_limits
2483
2484 ! -------------------------------------------------------
2485
2486 subroutine spectrum_signal_damp(damp_type, damp_factor, time_start, time_end, t0, time_step, time_function)
2487 integer, intent(in) :: damp_type
2488 real(real64), intent(in) :: damp_factor
2489 integer, intent(in) :: time_start
2490 integer, intent(in) :: time_end
2491 real(real64), intent(in) :: t0
2492 real(real64), intent(in) :: time_step
2493 type(batch_t), intent(inout) :: time_function
2494
2495 integer :: itime, ii
2496 real(real64) :: time
2497 real(real64), allocatable :: weight(:)
2498
2499 push_sub(signal_damp)
2500
2501 assert(time_function%status() == batch_not_packed)
2502
2503 safe_allocate(weight(time_start:time_end))
2504
2505 do itime = time_start, time_end
2506 time = time_step*(itime-1)
2507
2508 ! Gets the damp function
2509 select case (damp_type)
2510 case (spectrum_damp_none)
2511 weight(itime) = m_one
2513 if (time < t0) then
2514 weight(itime) = m_one
2515 else
2516 weight(itime) = exp(-(time - t0)*damp_factor)
2517 end if
2519 if (time < t0) then
2520 weight(itime) = m_one
2521 else
2522 weight(itime) = m_one - m_three*((time - t0) / (time_step * (time_end - 1) - t0))**2 + &
2523 m_two * ((time - t0) / (time_step * (time_end - 1) - t0))**3
2524 end if
2526 if (time < t0) then
2527 weight(itime) = m_one
2528 else
2529 weight(itime) = exp(-(time - t0)**2*damp_factor**2)
2530 end if
2531 case (spectrum_damp_sin)
2532 if (time < t0) then
2533 weight(itime) = m_one
2534 else
2535 weight(itime) = sin(-(time - t0)*m_pi/(time_end+t0))
2536 end if
2537 end select
2538 end do
2539
2540 if (time_function%type() == type_cmplx) then
2541 do ii = 1, time_function%nst_linear
2542 do itime = time_start, time_end
2543 time_function%zff_linear(itime, ii) = weight(itime)*time_function%zff_linear(itime, ii)
2544 end do
2545 end do
2546 else
2547 do ii = 1, time_function%nst_linear
2548 do itime = time_start, time_end
2549 time_function%dff_linear(itime, ii) = weight(itime)*time_function%dff_linear(itime, ii)
2550 end do
2551 end do
2552 end if
2553
2554 safe_deallocate_a(weight)
2555
2556 pop_sub(signal_damp)
2557
2558 end subroutine spectrum_signal_damp
2559 ! -------------------------------------------------------
2560
2561 ! -------------------------------------------------------
2571 subroutine spectrum_fourier_transform(method, transform, noise, time_start, time_end, t0, time_step, time_function, &
2572 energy_start, energy_end, energy_step, energy_function)
2573 integer, intent(in) :: method
2574 integer, intent(in) :: transform
2575 real(real64), intent(in) :: noise
2576 integer, intent(in) :: time_start
2577 integer, intent(in) :: time_end
2578 real(real64), intent(in) :: t0
2579 real(real64), intent(in) :: time_step
2580 type(batch_t), intent(in) :: time_function
2581 real(real64), intent(in) :: energy_start
2582 real(real64), intent(in) :: energy_end
2583 real(real64), intent(in) :: energy_step
2584 type(batch_t), intent(inout) :: energy_function
2585
2586 integer :: itime, ienergy, ii, energy_steps
2587 real(real64) :: energy, sinz, cosz
2588 complex(real64) :: ez, eidt
2589 type(compressed_sensing_t) :: cs
2590
2591 push_sub(fourier_transform)
2592
2593 assert(time_function%nst_linear == energy_function%nst_linear)
2594 assert(time_function%status() == energy_function%status())
2595 assert(time_function%status() == batch_not_packed)
2596 assert(time_function%type() == type_float)
2597 assert(energy_function%type() == type_float)
2598
2599 energy_steps = nint((energy_end-energy_start) / energy_step) + 1
2600
2601 select case (method)
2602
2603 case (spectrum_fourier)
2604
2605 do ienergy = 1, energy_steps
2606
2607 energy = energy_step*(ienergy - 1) + energy_start
2608
2609 do ii = 1, energy_function%nst_linear
2610 energy_function%dff_linear(ienergy, ii) = m_zero
2611 end do
2612
2613 select case (transform)
2614
2615 ! The sine and cosine transforms are computed as the real and imaginary part of the exponential.
2616 ! One can compute the exponential by successive multiplications, instead of calling the sine or
2617 ! cosine function at each time step.
2619
2620 eidt = exp(m_zi * energy * time_step)
2621 ez = exp(m_zi * energy * ((time_start-1)*time_step - t0))
2622 sinz = aimag(ez)
2623 do itime = time_start, time_end
2624 do ii = 1, time_function%nst_linear
2625 energy_function%dff_linear(ienergy, ii) = &
2626 energy_function%dff_linear(ienergy, ii) + &
2627 time_function%dff_linear(itime, ii) * sinz
2628 end do
2629 ez = ez * eidt
2630 sinz = aimag(ez)
2631 end do
2632
2634
2635 eidt = exp(m_zi * energy * time_step)
2636 ez = exp(m_zi * energy * ( (time_start-1)*time_step - t0))
2637 cosz = real(ez, real64)
2638 do itime = time_start, time_end
2639 do ii = 1, time_function%nst_linear
2640 energy_function%dff_linear(ienergy, ii) = &
2641 energy_function%dff_linear(ienergy, ii) + &
2642 time_function%dff_linear(itime, ii) * cosz
2643 end do
2644 ez = ez * eidt
2645 cosz = real(ez, real64)
2646 end do
2647
2649
2650 eidt = exp(-energy * time_step)
2651 ez = exp(-energy * ((time_start - 1) * time_step - t0))
2652 do itime = time_start, time_end
2653 do ii = 1, time_function%nst_linear
2654 energy_function%dff_linear(ienergy, ii) = &
2655 energy_function%dff_linear(ienergy, ii) + &
2656 real( time_function%dff_linear(itime, ii) * ez, real64)
2657 end do
2658 ez = ez * eidt
2659 end do
2660 end select
2661
2662 ! The total sum must be multiplied by time_step in order to get the integral.
2663 do ii = 1, time_function%nst_linear
2664 energy_function%dff_linear(ienergy, ii) = &
2665 energy_function%dff_linear(ienergy, ii) * time_step
2666 end do
2667
2668
2669 end do
2670
2672
2673 call compressed_sensing_init(cs, transform, &
2674 time_end - time_start + 1, time_step, time_step*(time_start - 1) - t0, &
2675 energy_steps, energy_step, energy_start, noise)
2676
2677 do ii = 1, time_function%nst_linear
2678 call compressed_sensing_spectral_analysis(cs, time_function%dff_linear(:, ii), &
2679 energy_function%dff_linear(:, ii))
2680 end do
2681
2682 call compressed_sensing_end(cs)
2683
2684 end select
2685
2686 pop_sub(fourier_transform)
2687
2688 end subroutine spectrum_fourier_transform
2689
2690 ! ---------------------------------------------------------
2691 subroutine spectrum_sigma_diagonalize(namespace, sigma, nspin, energy_step, min_energy, energy_steps, kick)
2692 type(namespace_t), intent(in) :: namespace
2693 real(real64), contiguous, intent(in) :: sigma(:, :, :, :)
2694 integer, intent(in) :: nspin
2695 real(real64), intent(in) :: energy_step, min_energy
2696 integer, intent(in) :: energy_steps
2697 type(kick_t), optional, intent(in) :: kick
2698
2699 integer :: is, idir, jdir, ie, info, out_file, out_file_t
2700 real(real64), allocatable :: work(:,:)
2701 complex(real64), allocatable :: w(:)
2702 character(len=20) :: header_string
2703 logical :: spins_singlet, spins_triplet, symmetrize
2704 real(real64), allocatable :: pp(:,:), pp2(:,:)
2705
2707
2708
2709 !%Variable PropagationSpectrumSymmetrizeSigma
2710 !%Type logical
2711 !%Default .false.
2712 !%Section Utilities::oct-propagation_spectrum
2713 !%Description
2714 !% The polarizablity tensor has to be real and symmetric. Due to numerical accuracy,
2715 !% that is not extricly conserved when computing it from different time-propations.
2716 !% If <tt>PropagationSpectrumSymmetrizeSigma = yes</tt>, the polarizability tensor is
2717 !% symmetrized before its diagonalizied.
2718 !% This variable is only used if the cross_section_tensor is computed.
2719 !%End
2720 call parse_variable(namespace, 'PropagationSpectrumSymmetrizeSigma', .false., symmetrize)
2721 call messages_print_var_value('PropagationSpectrumSymmetrizeSigma', symmetrize, namespace=namespace)
2722
2723 spins_singlet = .true.
2724 spins_triplet = .false.
2725 if (present(kick)) then
2726 select case (kick_get_type(kick))
2727 case (kick_spin_mode)
2728 spins_triplet = .true.
2729 spins_singlet = .false.
2730 case (kick_spin_density_mode)
2731 spins_triplet = .true.
2732 end select
2733 end if
2734
2735 if (spins_singlet .and. spins_triplet) then
2736 out_file = io_open('cross_section_diagonal-sigma_s', namespace, action='write')
2737 out_file_t = io_open('cross_section_diagonal-sigma_t', namespace, action='write')
2738 else
2739 out_file = io_open('cross_section_diagonal-sigma', namespace, action='write')
2740 end if
2741
2742 is = 1
2743 write(out_file, '(a1, a20)', advance = 'no') '#', str_center("Energy", 20)
2744 do idir = 1, 3
2745 write(out_file, '(a20)', advance = 'no') str_center("Real part", 20)
2746 if (.not. symmetrize) write(out_file, '(a20)', advance = 'no') str_center("Imaginary part", 20)
2747 do jdir = 1, 3
2748 write(header_string,'(a7,i1,a1,i1,a1,i1,a1)') 'vector(', idir, ',', jdir, ',', is, ')'
2749 write(out_file, '(a20)', advance = 'no') str_center(trim(header_string), 20)
2750 end do
2751 end do
2752 write(out_file, '(1x)')
2753 write(out_file, '(a1,a20)', advance = 'no') '#', str_center('[' // trim(units_abbrev(units_out%energy)) // ']', 20)
2754
2755 do idir = 1, 3
2756 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
2757 if (.not. symmetrize) then
2758 write(out_file, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
2759 end if
2760 do jdir = 1, 3
2761 write(out_file, '(a20)', advance = 'no') str_center('[ - ]', 20)
2762 end do
2763 end do
2764 write(out_file, '(1x)')
2765
2766 if (spins_singlet .and. spins_triplet) then
2767 is = 2
2768 write(out_file_t, '(a1, a20)', advance = 'no') '#', str_center("Energy", 20)
2769 do idir = 1, 3
2770 write(out_file_t, '(a20)', advance = 'no') str_center("Real part", 20)
2771 if (.not. symmetrize) write(out_file_t, '(a20)', advance = 'no') str_center("Imaginary part", 20)
2772 do jdir = 1, 3
2773 write(header_string,'(a7,i1,a1,i1,a1,i1,a1)') 'vector(', idir, ',', jdir, ',', is, ')'
2774 write(out_file_t, '(a20)', advance = 'no') str_center(trim(header_string), 20)
2775 end do
2776 end do
2777 write(out_file_t, '(1x)')
2778 write(out_file_t, '(a1,a20)', advance = 'no') '#', str_center('[' // trim(units_abbrev(units_out%energy)) // ']', 20)
2779
2780 do idir = 1, 3
2781 write(out_file_t, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
2782 if (.not. symmetrize) then
2783 write(out_file_t, '(a20)', advance = 'no') str_center('[' // trim(units_abbrev(units_out%length**2)) // ']', 20)
2784 end if
2785 do jdir = 1, 3
2786 write(out_file_t, '(a20)', advance = 'no') str_center('[ - ]', 20)
2787 end do
2788 end do
2789 write(out_file_t, '(1x)')
2790 end if
2791
2792 safe_allocate(pp(1:3, 1:3))
2793 if (spins_triplet .and. spins_singlet) then
2794 safe_allocate(pp2(1:3, 1:3))
2795 end if
2796 safe_allocate(w(1:3))
2797 safe_allocate(work(1:3, 1:3))
2798 do ie = 1, energy_steps
2799
2800 pp(:, :) = sigma(:, :, ie, 1)
2801 if (nspin >= 2) then
2802 if (spins_singlet .and. spins_triplet) then
2803 pp2(:, :) = pp(:, :) - sigma(:, :, ie, 2)
2804 pp(:, :) = pp(:, :) + sigma(:, :, ie, 2)
2805 elseif (spins_triplet .and. .not. spins_singlet) then
2806 pp(:, :) = pp(:, :) - sigma(:, :, ie, 2)
2807 elseif (spins_singlet .and. .not. spins_triplet) then
2808 pp(:, :) = pp(:, :) + sigma(:, :, ie, 2)
2809 end if
2810 end if
2811
2812 if (symmetrize) then
2813 do idir = 1, 3
2814 do jdir = idir + 1, 3
2815 pp(idir, jdir) = (pp(idir, jdir) + pp(jdir, idir)) / m_two
2816 pp(jdir, idir) = pp(idir, jdir)
2817 end do
2818 end do
2819 end if
2820
2821 work(1:3, 1:3) = pp(1:3, 1:3)
2822 call lalg_eigensolve_nonh(3, work, w, err_code = info, sort_eigenvectors = .true.)
2823 ! Note that the cross-section elements do not have to be transformed to the proper units, since
2824 ! they have been read from the "cross_section_vector.x", where they are already in the proper units.
2825
2826 write(out_file,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy, ((ie-1) * energy_step + min_energy))
2827 do idir = 3, 1, -1
2828 if (symmetrize) then
2829 write(out_file,'(2e20.8)', advance = 'no') real(w(idir), real64)
2830 else
2831 write(out_file,'(2e20.8)', advance = 'no') w(idir)
2832 end if
2833
2834 do jdir = 1, 3
2835 write(out_file,'(e20.8)', advance = 'no') work(jdir, idir)
2836 end do
2837 end do
2838 write(out_file, '(1x)')
2839
2840 if (spins_singlet .and. spins_triplet) then
2841 if (symmetrize) then
2842 do idir = 1, 3
2843 do jdir = idir + 1, 3
2844 pp2(idir, jdir) = (pp2(idir, jdir) + pp2(jdir, idir)) / m_two
2845 pp2(jdir, idir) = pp2(idir, jdir)
2846 end do
2847 end do
2848 end if
2849 work(1:3, 1:3) = -pp2(1:3, 1:3)
2850 call lalg_eigensolve_nonh(3, work, w, err_code = info, sort_eigenvectors = .true.)
2851 ! Note that the cross-section elements do not have to be transformed to the proper units, since
2852 ! they have been read from the "cross_section_vector.x", where they are already in the proper units.
2853
2854 write(out_file_t,'(e20.8)', advance = 'no') units_from_atomic(units_out%energy, (ie * energy_step + min_energy))
2855 do idir = 3, 1, -1
2856 if (symmetrize) then
2857 write(out_file_t,'(2e20.8)', advance = 'no') real(w(idir), real64)
2858 else
2859 write(out_file_t,'(2e20.8)', advance = 'no') w(idir)
2860 end if
2861
2862 do jdir = 1, 3
2863 write(out_file_t,'(e20.8)', advance = 'no') work(jdir, idir)
2864 end do
2865 end do
2866 write(out_file_t, '(1x)')
2867 end if
2868 end do
2869
2870 call io_close(out_file)
2871
2872 safe_deallocate_a(pp)
2873 if (spins_triplet .and. spins_singlet) then
2874 safe_deallocate_a(pp2)
2875 call io_close(out_file_t)
2876 end if
2877 safe_deallocate_a(w)
2878 safe_deallocate_a(work)
2879
2881 end subroutine spectrum_sigma_diagonalize
2882
2883 pure integer function spectrum_nenergy_steps(spectrum) result(no_e)
2884 type(spectrum_t), intent(in) :: spectrum
2885
2886 no_e = nint((spectrum%max_energy-spectrum%min_energy) / spectrum%energy_step) + 1
2887 end function spectrum_nenergy_steps
2888
2889 subroutine spectrum_write_info(spectrum, out_file)
2890 type(spectrum_t), intent(in) :: spectrum
2891 integer, intent(in) :: out_file
2892
2893 push_sub(spectrum_write_info)
2894
2895 write(out_file, '(a,i4)') '# PropagationSpectrumDampMode = ', spectrum%damp
2896 write(out_file, '(a,f10.4)') '# PropagationSpectrumDampFactor = ', units_from_atomic(units_out%time**(-1), &
2897 spectrum%damp_factor)
2898 write(out_file, '(a,f10.4)') '# PropagationSpectrumStartTime = ', units_from_atomic(units_out%time, spectrum%start_time)
2899 write(out_file, '(a,f10.4)') '# PropagationSpectrumEndTime = ', units_from_atomic(units_out%time, spectrum%end_time)
2900 write(out_file, '(a,f10.4)') '# PropagationSpectrumMinEnergy = ', units_from_atomic(units_out%energy, spectrum%min_energy)
2901 write(out_file, '(a,f10.4)') '# PropagationSpectrumMaxEnergy = ', units_from_atomic(units_out%energy, spectrum%max_energy)
2902 write(out_file, '(a,f10.4)') '# PropagationSpectrumEnergyStep = ', units_from_atomic(units_out%energy, spectrum%energy_step)
2903
2904 pop_sub(spectrum_write_info)
2905 end subroutine spectrum_write_info
2906
2907 ! ---------------------------------------------------------
2909 subroutine spectrum_read_header_line(namespace, iunit, line, context)
2910 type(namespace_t), intent(in) :: namespace
2911 integer, intent(in) :: iunit
2912 character(len=*), intent(out) :: line
2913 character(len=*), intent(in) :: context
2914
2915 integer :: ierr
2916
2918
2919 read(iunit, '(a)', iostat = ierr) line
2920 if (ierr /= 0) then
2921 write(message(1), '(3a)') "Could not read ", trim(context), " from multipoles header."
2922 call messages_fatal(1, namespace=namespace)
2923 end if
2924
2926 end subroutine spectrum_read_header_line
2927
2928
2929 ! ---------------------------------------------------------
2931 subroutine spectrum_read_header_integer(namespace, iunit, value, context)
2932 type(namespace_t), intent(in) :: namespace
2933 integer, intent(in) :: iunit
2934 integer, intent(out) :: value
2935 character(len=*), intent(in) :: context
2936
2937 integer :: ierr
2938 character(len=200) :: line
2939
2941
2942 call spectrum_read_header(namespace, iunit, line, context)
2943 ! see the routine td_write_multipole_r to understand this
2944 if (len_trim(line) < 16) then
2945 ierr = 1
2946 else
2947 read(line(16:), *, iostat = ierr) value
2948 end if
2949 if (ierr /= 0) then
2950 write(message(1), '(3a)') "Could not read ", trim(context), " from multipoles header line:"
2951 write(message(2), '(a)') trim(line)
2952 call messages_fatal(2, namespace=namespace)
2953 end if
2954
2956 end subroutine spectrum_read_header_integer
2957
2958
2959 ! ---------------------------------------------------------
2961 subroutine spectrum_find_cross_section_header(namespace, iunit)
2962 type(namespace_t), intent(in) :: namespace
2963 integer, intent(in) :: iunit
2964
2965 integer :: ierr
2966 character(len=200) :: line
2967
2969
2970 rewind(iunit)
2971 do
2972 read(iunit, '(a)', iostat = ierr) line
2973 if (ierr == iostat_end) then
2974 message(1) = "Could not find cross-section header in spectrum file."
2975 call messages_fatal(1, namespace=namespace)
2976 end if
2977 if (ierr /= 0) then
2978 message(1) = "Could not read spectrum file while looking for cross-section header."
2979 call messages_fatal(1, namespace=namespace)
2980 end if
2981 if (index(adjustl(line), "# nspin") == 1) then
2982 backspace(iunit)
2983 exit
2984 end if
2985 end do
2986
2989
2990
2991end module spectrum_oct_m
2992
2993!! Local Variables:
2994!! mode: f90
2995!! coding: utf-8
2996!! End:
subroutine optimize()
subroutine info()
Definition: em_resp.F90:1099
initialize a batch with existing memory
Definition: batch.F90:296
This is the common interface to a simple-minded polynomical interpolation procedure (simple use of th...
Definition: math.F90:189
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:182
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
This module implements batches of mesh functions.
Definition: batch.F90:135
integer, parameter spectrum_transform_cos
integer, parameter spectrum_transform_sin
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:120
subroutine, public fft_end(this)
Definition: fft.F90:854
subroutine, public fft_init(this, nn, dim, type, library, optimize, optimize_parity, comm, mpi_grp, use_aligned, howmany, nthreads, single)
Definition: fft.F90:452
integer, parameter, public fft_complex
Definition: fft.F90:178
integer, parameter, public fftlib_fftw
Definition: fft.F90:183
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_four
Definition: global.F90:204
real(real64), parameter, public p_ry
Definition: global.F90:239
real(real64), parameter, public m_third
Definition: global.F90:207
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:198
character(len= *), parameter, public pcm_dir
Definition: global.F90:288
complex(real64), parameter, public m_z0
Definition: global.F90:210
complex(real64), parameter, public m_zi
Definition: global.F90:214
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:242
real(real64), parameter, public m_one
Definition: global.F90:201
real(real64), parameter, public m_three
Definition: global.F90:203
Definition: io.F90:116
subroutine, public io_close(iunit, grp)
Definition: io.F90:467
subroutine, public io_skip_header(iunit)
Definition: io.F90:646
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:402
subroutine, public kick_read(kick, iunit, namespace)
Definition: kick.F90:823
integer, parameter, public kick_spin_mode
Definition: kick.F90:165
pure integer function, public kick_get_type(kick)
Definition: kick.F90:1377
subroutine, public kick_write(kick, iunit, out)
Definition: kick.F90:895
integer, parameter, public kick_density_mode
Definition: kick.F90:165
integer, parameter, public kick_function_dipole
Definition: kick.F90:160
integer, parameter, public kick_spin_density_mode
Definition: kick.F90:165
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
pure complex(real64) function, dimension(1:3), public zcross_product(a, b)
Definition: math.F90:1718
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
character(len=512), private msg
Definition: messages.F90:167
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
real(real64), dimension(:,:), allocatable sigma
S_E matrix.
Definition: pcm.F90:269
subroutine, public pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
Computes the dipole moment mu_pcm due to a distribution of charges q_pcm.
Definition: pcm.F90:3235
subroutine, public pcm_eps(pcm, eps, omega)
Definition: pcm.F90:3255
subroutine, public pcm_min_input_parsing_for_spectrum(pcm, namespace)
Definition: pcm.F90:3279
subroutine, public spectrum_hsfunction_min(namespace, aa, bb, omega_min, func_min)
Definition: spectrum.F90:1594
subroutine spectrum_tdfile_info(namespace, fname, iunit, time_steps, dt)
Definition: spectrum.F90:2490
subroutine spectrum_hsfunction_ar_end
Definition: spectrum.F90:1730
subroutine spectrum_hsfunction_ar_init(dt, is, ie, niter, acc, pos, tret)
Definition: spectrum.F90:1705
subroutine spectrum_read_header_line(namespace, iunit, line, context)
Read a required multipoles or spectrum header line.
Definition: spectrum.F90:3005
subroutine, public spectrum_cross_section(spectrum, namespace, in_file, out_file, ref_file)
Definition: spectrum.F90:717
subroutine spectrum_times_pcm_epsilon(spectrum, pcm, dipole, sigma, nspin, istart, iend, kick_time, dt, no_e)
Definition: spectrum.F90:1070
subroutine, public spectrum_hs_ar_from_acc(spectrum, namespace, out_file, vec, w0)
Definition: spectrum.F90:1743
integer, parameter, public spectrum_damp_lorentzian
Definition: spectrum.F90:166
subroutine, public spectrum_fix_time_limits(spectrum, time_steps, dt, istart, iend, ntiter)
Definition: spectrum.F90:2538
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:2668
integer, parameter, public spectrum_transform_laplace
Definition: spectrum.F90:173
subroutine spectrum_find_cross_section_header(namespace, iunit)
Position a spectrum file at the cross-section metadata header.
Definition: spectrum.F90:3057
subroutine, public spectrum_cross_section_tensor(spectrum, namespace, out_file, in_file)
Definition: spectrum.F90:437
subroutine, public spectrum_hsfunction_init(dt, is, ie, niter, acc)
Definition: spectrum.F90:1545
subroutine, public spectrum_hsfunction_end
Definition: spectrum.F90:1580
subroutine spectrum_read_dipole(namespace, in_file, dipole)
Definition: spectrum.F90:920
integer, parameter, public spectrum_damp_sin
Definition: spectrum.F90:166
subroutine spectrum_sigma_diagonalize(namespace, sigma, nspin, energy_step, min_energy, energy_steps, kick)
Definition: spectrum.F90:2787
subroutine spectrum_cross_section_info(namespace, iunit, nspin, kick, energy_steps, dw)
Definition: spectrum.F90:2451
subroutine, public spectrum_dyn_structure_factor(spectrum, namespace, in_file_sin, in_file_cos, out_file)
Definition: spectrum.F90:1271
integer, parameter, public spectrum_damp_gaussian
Definition: spectrum.F90:166
subroutine, public spectrum_init(spectrum, namespace, default_energy_step, default_max_energy)
Definition: spectrum.F90:220
subroutine, public spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax)
Definition: spectrum.F90:2357
integer, parameter, public spectrum_fourier
Definition: spectrum.F90:184
subroutine, public spectrum_dipole_power(spectrum, namespace, in_file, out_file)
Definition: spectrum.F90:1163
subroutine spectrum_add_pcm_dipole(namespace, dipole, time_steps, nspin)
Definition: spectrum.F90:951
subroutine, public spectrum_signal_damp(damp_type, damp_factor, time_start, time_end, t0, time_step, time_function)
Definition: spectrum.F90:2582
subroutine, public spectrum_hs_from_acc(spectrum, namespace, out_file, pol, vec, w0)
Definition: spectrum.F90:2066
integer, parameter, public spectrum_energyloss
Definition: spectrum.F90:178
subroutine spectrum_over_pcm_refraction_index(spectrum, pcm, sigma, nspin, no_e)
Definition: spectrum.F90:1134
subroutine, public spectrum_hs_from_current(spectrum, namespace, out_file, pol, vec, w0)
Definition: spectrum.F90:2167
subroutine spectrum_cross_section_tensor_write(out_file, sigma, nspin, energy_step, min_energy, energy_steps, kick)
Definition: spectrum.F90:600
subroutine spectrum_read_header_integer(namespace, iunit, value, context)
Read a required integer value from a fixed-label header line.
Definition: spectrum.F90:3027
subroutine spectrum_write_info(spectrum, out_file)
Definition: spectrum.F90:2985
subroutine spectrum_hs_output(spectrum, namespace, out_file, pol, no_e, sp)
Definition: spectrum.F90:2322
integer, parameter, public spectrum_damp_polynomial
Definition: spectrum.F90:166
subroutine hsfunction(omega, power)
Definition: spectrum.F90:1661
integer, parameter, public spectrum_rotatory
Definition: spectrum.F90:178
subroutine spectrum_hs(spectrum, namespace, out_file, pol, w0)
Definition: spectrum.F90:2266
integer, parameter, public spectrum_damp_none
Definition: spectrum.F90:166
integer, parameter, public spectrum_transform_cos
Definition: spectrum.F90:173
integer, parameter, public spectrum_transform_sin
Definition: spectrum.F90:173
subroutine, public spectrum_count_time_steps(namespace, iunit, time_steps, dt)
Definition: spectrum.F90:2403
subroutine, public spectrum_rotatory_strength(spectrum, namespace, in_file, out_file)
Definition: spectrum.F90:1426
pure integer function, public spectrum_nenergy_steps(spectrum)
Definition: spectrum.F90:2979
subroutine, public spectrum_hs_from_mult(spectrum, namespace, out_file, pol, vec, w0)
Definition: spectrum.F90:1944
integer, parameter, public spectrum_compressed_sensing
Definition: spectrum.F90:184
subroutine, public spectrum_hs_ar_from_mult(spectrum, namespace, out_file, vec, w0)
Definition: spectrum.F90:1847
integer, parameter, public spectrum_p_power
Definition: spectrum.F90:178
character(len=80) function, public str_center(s_in, l_in)
puts space around string, so that it is centered
Definition: string.F90:176
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:225
This module defines the unit system, used for input and output.
integer, parameter, public units_atomic
type(unit_system_t), public units_out
subroutine, public unit_system_get(uu, cc)
integer, parameter, public units_eva
type(unit_system_t), public units_inp
the units systems for reading and writing
type(unit_t), public unit_one
some special units required for particular quantities
Class defining batches of mesh functions.
Definition: batch.F90:164
int true(void)