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