Octopus
oscillator_strength.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
22 use debug_oct_m
23 use global_oct_m
24 use io_oct_m
25 use kick_oct_m
26 use, intrinsic :: iso_fortran_env
31 use parser_oct_m
34 use string_oct_m
35 use unit_oct_m
37
38 implicit none
39
40 integer, parameter :: &
41 SINE_TRANSFORM = 1, &
43
45 integer :: n_multipoles
46 integer, allocatable :: l(:), m(:)
47 real(real64), allocatable :: weight(:)
48 end type local_operator_t
49
50 integer :: observable(2)
51 type(unit_system_t) :: units
52 real(real64), allocatable :: ot(:)
53 type(kick_t) :: kick
54 integer :: time_steps
55 real(real64) :: total_time
56 integer :: mode
57 real(real64) :: dt
58
59contains
60
61 ! ---------------------------------------------------------
62 subroutine ft(omega, power)
63 real(real64), intent(in) :: omega
64 real(real64), intent(out) :: power
65
66 integer :: j
67 real(real64) :: x
68 power = m_zero
69
70 push_sub(ft)
71
72 select case (mode)
73
74 case (sine_transform)
75
76 do j = 0, time_steps
77 x = sin(omega*j*dt)
78 power = power + x*ot(j)
79 end do
80 power = power*dt / (dt*time_steps)
81
82 case (cosine_transform)
83
84 do j = 0, time_steps
85 x = cos(omega*j*dt)
86 power = power + x*ot(j)
87 end do
88 power = power*dt / (dt*time_steps)
89
90 end select
91
92 pop_sub(ft)
93 end subroutine ft
94
95
96 ! ---------------------------------------------------------
97 subroutine ft2(omega, power)
98 real(real64), intent(in) :: omega
99 real(real64), intent(out) :: power
100
101 integer :: j
102 real(real64) :: x
103 power = m_zero
104
105 push_sub(ft2)
106
107 select case (mode)
108
109 case (sine_transform)
110
111 do j = 0, time_steps
112 x = sin(omega*j*dt)
113 power = power + x*ot(j)
114 end do
115 ! The function should be *minus* the sine Fourier transform, since this
116 ! is the function to be minimized.
117 power = - (power*dt / (dt*time_steps))**2
118
119 case (cosine_transform)
120
121 do j = 0, time_steps
122 x = cos(omega*j*dt)
123 power = power + x*ot(j)
124 end do
125 power = - (power*dt / (dt*time_steps))**2
126
127 end select
128
129 pop_sub(ft2)
130 end subroutine ft2
131
132
133 ! ---------------------------------------------------------
134 subroutine local_operator_copy(o, i)
135 type(local_operator_t), intent(inout) :: o
136 type(local_operator_t), intent(inout) :: i
138 integer :: j
141
142 o%n_multipoles = i%n_multipoles
143 safe_allocate( o%l(1:o%n_multipoles))
144 safe_allocate( o%m(1:o%n_multipoles))
145 safe_allocate(o%weight(1:o%n_multipoles))
147 do j = 1, o%n_multipoles
148 o%l(j) = i%l(j)
149 o%m(j) = i%m(j)
150 o%weight(j) = i%weight(j)
151 end do
152
153 pop_sub(local_operator_copy)
154 end subroutine local_operator_copy
156 ! ---------------------------------------------------------
157 subroutine read_resonances_file(order, ffile, namespace, search_interval, final_time, nfrequencies)
158 integer, intent(inout) :: order
159 character(len=*), intent(in) :: ffile
160 type(namespace_t), intent(in):: namespace
161 real(real64), intent(inout) :: search_interval
162 real(real64), intent(in) :: final_time
163 integer, intent(in) :: nfrequencies
164
165 real(real64) :: dummy, leftbound, rightbound, w, power, dw
166 integer :: iunit, nresonances, ios, i, j, k, npairs, nspin, order_in_file, nw_subtracted, ierr
167 logical :: file_exists
168 real(real64), allocatable :: wij(:), omega(:), c0i(:)
169
170 push_sub(read_resonances_file)
171
172 if (order /= 2) then
173 write(message(1),'(a)') 'The run mode #3 is only compatible with the analysis of the'
174 write(message(2),'(a)') 'second-order response.'
175 call messages_fatal(2)
176 end if
177
178 ! First, let us check that the file "ot" exists.
179 inquire(file="ot", exist = file_exists)
180 if (.not. file_exists) then
181 write(message(1),'(a)') "Could not find 'ot' file."
182 call messages_fatal(1)
183 end if
184
185 ! Now, we should find out which units the file "ot" has.
186 call unit_system_from_file(units, "ot", namespace, ierr)
187 if (ierr /= 0) then
188 write(message(1),'(a)') "Could not retrieve units in the 'ot' file."
189 call messages_fatal(1)
190 end if
191
192 mode = cosine_transform
193
194 iunit = io_open(trim(ffile), namespace, action='read', status='old', die=.false.)
195 if (iunit == 0) then
196 write(message(1),'(a)') 'Could not open '//trim(ffile)//' file.'
197 call messages_fatal(1)
198 end if
199
200 call io_skip_header(iunit)
201 ! Count the number of resonances
202 nresonances = 0
203 do
204 read(iunit, *, iostat = ios) dummy, dummy
205 if (ios /= 0) exit
206 nresonances = nresonances + 1
207 end do
208
209 npairs = (nresonances*(nresonances-1))/2
210
211 safe_allocate(omega(1:nresonances))
212 safe_allocate( c0i(1:nresonances))
213 safe_allocate(wij(1:npairs))
214
215 call io_skip_header(iunit)
216 do i = 1, nresonances
217 read(iunit, *) omega(i), c0i(i)
218 end do
219
220 k = 1
221 do i = 1, nresonances
222 do j = i + 1, nresonances
223 wij(k) = omega(j) - omega(i)
224 k = k + 1
225 end do
226 end do
228 if (search_interval > m_zero) then
229 search_interval = units_to_atomic(units%energy, search_interval)
230 else
231 search_interval = m_half
232 end if
233
234 call read_ot(namespace, nspin, order_in_file, nw_subtracted)
235
236 if (order_in_file /= order) then
237 write(message(1), '(a)') 'The ot file should contain the second-order response in this run mode.'
238 call messages_fatal(1)
239 end if
240
241 if (final_time > m_zero) then
242 total_time = units_to_atomic(units%time, final_time)
243 if (total_time > dt*time_steps) then
244 total_time = dt*time_steps
245 write(message(1), '(a)') 'The requested total time to process is larger than the time available in the input file.'
246 write(message(2), '(a,f8.4,a)') 'The time has been adjusted to ', &
247 units_from_atomic(units%time, total_time), units_abbrev(units%time)
248 call messages_warning(2, namespace=namespace)
249 end if
250 time_steps = int(total_time / dt)
251 total_time = time_steps * dt
252 else
253 total_time = dt*time_steps
254 end if
255
256 dw = (rightbound-leftbound) / (nfrequencies - 1)
257
258 ! First, subtract zero resonance...
259 w = m_zero
260 call resonance_second_order(w, power, nw_subtracted, leftbound, rightbound, m_zero, m_zero)
261 call modify_ot(time_steps, dt, order, ot, w, power)
262 nw_subtracted = nw_subtracted + 1
263
264 ! Then, get all the others...
265 k = 1
266 do i = 1, nresonances
267 do j = i + 1, nresonances
268 leftbound = wij(k) - search_interval
269 rightbound = wij(k) + search_interval
270 call find_resonance(wij(k), leftbound, rightbound, nfrequencies)
271 call resonance_second_order(wij(k), power, nw_subtracted, leftbound, rightbound, c0i(i), c0i(j))
272 call modify_ot(time_steps, dt, order, ot, wij(k), power)
273 nw_subtracted = nw_subtracted + 1
274 k = k + 1
275 end do
276 end do
277
278 safe_deallocate_a(wij)
279 safe_deallocate_a(c0i)
280 safe_deallocate_a(omega)
281 call io_close(iunit)
282
283 pop_sub(read_resonances_file)
284 end subroutine read_resonances_file
285 ! ---------------------------------------------------------
286
287
288 ! ---------------------------------------------------------
289 subroutine analyze_signal(order, omega, search_interval, final_time, nresonances, nfrequencies, &
290 damping, namespace)
291 integer, intent(inout) :: order
292 real(real64), intent(inout) :: omega
293 real(real64), intent(inout) :: search_interval
294 real(real64), intent(inout) :: final_time
295 integer, intent(inout) :: nresonances
296 integer, intent(inout) :: nfrequencies
297 real(real64), intent(in) :: damping
298 type(namespace_t), intent(in) :: namespace
299
300 real(real64) :: leftbound, rightbound, dw, power
301 real(real64), allocatable :: w(:), c0I2(:)
302 integer :: nspin, i, ierr, order_in_file, nw_subtracted
303 logical :: file_exists
304
305 push_sub(analyze_signal)
306
307 ! First, let us check that the file "ot" exists.
308 inquire(file="ot", exist = file_exists)
309 if (.not. file_exists) then
310 write(message(1),'(a)') "Could not find 'ot' file."
311 call messages_fatal(1)
312 end if
313
314 ! Now, we should find out which units the file "ot" has.
315 call unit_system_from_file(units, "ot", namespace, ierr)
316 if (ierr /= 0) then
317 write(message(1),'(a)') "Could not retrieve units in the 'ot' file."
318 call messages_fatal(1)
319 end if
320
321 if (omega > m_zero) then
322 omega = units_to_atomic(units%energy, omega)
323 else
324 omega = m_half
325 end if
326
327 if (search_interval > m_zero) then
328 search_interval = units_to_atomic(units%energy, search_interval)
329 else
330 search_interval = m_half
331 end if
332
333 leftbound = omega - search_interval
334 rightbound = omega + search_interval
335
336 call read_ot(namespace, nspin, order_in_file, nw_subtracted)
337
338 if (order_in_file /= order) then
339 write(message(1), '(a)') 'Internal error in analyze_signal'
340 call messages_fatal(1, namespace=namespace)
341 end if
342
343 if (mod(order, 2) == 1) then
344 mode = sine_transform
345 else
346 mode = cosine_transform
347 end if
348
349 if (final_time > m_zero) then
350 total_time = units_to_atomic(units%time, final_time)
351 if (total_time > dt*time_steps) then
352 total_time = dt*time_steps
353 write(message(1), '(a)') 'The requested total time to process is larger than the time available in the input file.'
354 write(message(2), '(a,f8.4,a)') 'The time has been adjusted to ', &
355 units_from_atomic(units%time, total_time), units_abbrev(units%time)
356 call messages_warning(2, namespace=namespace)
357 end if
358 time_steps = int(total_time / dt)
359 total_time = time_steps * dt
360 else
361 total_time = dt*time_steps
362 end if
363
364 dw = (rightbound-leftbound) / (nfrequencies - 1)
365
366 safe_allocate( w(1:nresonances))
367 safe_allocate(c0i2(1:nresonances))
368 w = m_zero
369 c0i2 = m_zero
370
371 i = 1
372 do
373 if (nw_subtracted >= nresonances) exit
374
375 if (mode == cosine_transform .and. nw_subtracted == 0) then
376 omega = m_zero
377 else
378 call find_resonance(omega, leftbound, rightbound, nfrequencies)
379 end if
380
381 select case (order)
382 case (1)
383 call resonance_first_order(omega, power, nw_subtracted, dw, leftbound, rightbound)
384 case (2)
385 call resonance_second_order(omega, power, nw_subtracted, leftbound, rightbound, m_zero, m_zero)
386 end select
387
388 w(i) = omega
389 c0i2(i) = power
390
391 call modify_ot(time_steps, dt, order, ot, omega, power)
392
393 nw_subtracted = nw_subtracted + 1
394 i = i + 1
395 end do
396
397 select case (order)
398 case (1)
399 call write_polarizability(namespace, nfrequencies, nresonances, dw, w, c0i2, damping)
400 end select
401
402 safe_deallocate_a(ot)
403 safe_deallocate_a(w)
404 safe_deallocate_a(c0i2)
405
406 pop_sub(analyze_signal)
407 end subroutine analyze_signal
408 ! ---------------------------------------------------------
409
410
411 ! ---------------------------------------------------------
415 subroutine write_polarizability(namespace, nfrequencies, nresonances, dw, w, c0I2, gamma)
416 type(namespace_t), intent(in) :: namespace
417 integer, intent(in) :: nfrequencies, nresonances
418 real(real64), intent(in) :: dw
419 real(real64), intent(in) :: w(nresonances), c0I2(nresonances)
420 real(real64), intent(in) :: gamma
421
422 integer :: iunit, i, j
423 real(real64) :: e
424 complex(real64) :: pol
425
426 push_sub(write_polarizability)
427
428 iunit = io_open('polarizability', namespace, action = 'write', status='replace', die=.false.)
429 write(iunit, '(a)') '# Polarizability file. Generated using the SOS formula with the following data:'
430 write(iunit, '(a)') '#'
431
432 do i = 1, nresonances
433 write(iunit, '(a1,3e20.12)') '#', w(i), sqrt(abs(c0i2(i))), c0i2(i)
434 end do
435
436 write(iunit, '(a10,f12.6)') '# Gamma = ', gamma
437 write(iunit, '(a)') '#'
438
439 do i = 1, nfrequencies
440 e = (i - 1) * dw
441 pol = m_z0
442 do j = 1, nresonances
443 pol = pol + c0i2(j) * (m_one / (w(j) - e - m_zi * gamma) + m_one/(w(j) + e + m_zi * gamma))
444 end do
445 write(iunit, '(3e20.12)') e, pol
446 end do
447
448 call io_close(iunit)
449
450 pop_sub(write_polarizability)
451 end subroutine write_polarizability
452 ! ---------------------------------------------------------
453
454
455 ! ---------------------------------------------------------
456 ! \todo This subroutine should be simplified.
457 subroutine find_resonance(omega, leftbound, rightbound, nfrequencies)
458 real(real64), intent(inout) :: omega
459 real(real64), intent(in) :: leftbound, rightbound
460 integer, intent(in) :: nfrequencies
461
462 integer :: i, ierr
463 real(real64) :: dw, w, aw, min_aw, min_w, omega_orig, min_w1, min_w2
464 real(real64), allocatable :: warray(:), tarray(:)
465
466 push_sub(find_resonance)
467
468 safe_allocate(warray(1:nfrequencies))
469 safe_allocate(tarray(1:nfrequencies))
470
471 warray = m_zero
472 tarray = m_zero
473 dw = (rightbound-leftbound) / (nfrequencies - 1)
474 do i = 1, nfrequencies
475 w = leftbound + (i-1)*dw
476 warray(i) = w
477 call ft2(w, aw)
478 tarray(i) = aw
479 end do
480
481 min_w = omega
482 min_aw = m_zero
483 do i = 1, nfrequencies
484 w = leftbound + (i-1)*dw
485 if (tarray(i) < min_aw) then
486 min_aw = tarray(i)
487 min_w = w
488 end if
489 end do
490
491 omega_orig = omega
492 omega = min_w
493 min_w1 = min_w - 2*dw
494 min_w2 = min_w + 2*dw
495 call loct_1dminimize(min_w1, min_w2, omega, ft2, ierr)
496
497 if (ierr /= 0) then
498 write(message(1),'(a)') 'Could not find a maximum.'
499 write(message(2),'(a)')
500 write(message(3), '(a,f12.8,a,f12.8,a)') ' Search interval = [', &
501 units_from_atomic(units%energy, leftbound), ',', units_from_atomic(units%energy, rightbound), ']'
502 write(message(4), '(a,f12.4,a)') ' Search discretization = ', &
503 units_from_atomic(units%energy, dw), ' '//trim(units_abbrev(units%energy))
504 call messages_fatal(4)
505 end if
506
507 safe_deallocate_a(warray)
508 safe_deallocate_a(tarray)
509
510 pop_sub(find_resonance)
511 end subroutine find_resonance
512 ! ---------------------------------------------------------
513
514
515 ! ---------------------------------------------------------
516 subroutine resonance_first_order(omega, power, nw_subtracted, dw, leftbound, rightbound)
517 real(real64), intent(in) :: omega
518 real(real64), intent(out) :: power
519 integer, intent(in) :: nw_subtracted
520 real(real64), intent(in) :: dw, leftbound, rightbound
521
522 push_sub(resonance_first_order)
523
524 call ft(omega, power)
525
526 select case (mode)
527 case (sine_transform)
528 power = power / (m_one - sin(m_two*omega*total_time)/(m_two*omega*total_time))
529 case (cosine_transform)
530 call messages_not_implemented("resonance first order cosine transform")
531 end select
532
533 write(message(1), '(a)') '******************************************************************'
534 write(message(2), '(a,i3)') 'Resonance #', nw_subtracted + 1
535 write(message(3), '(a,f12.8,a,f12.8,a)') 'omega = ', units_from_atomic(units_out%energy, omega), &
536 ' '//trim(units_abbrev(units_out%energy))//' = ', omega, ' Ha'
537 write(message(4), '(a,f12.8,a,f12.8,a)') 'C(omega) = ', units_from_atomic(units_out%length**2, power), &
538 ' '//trim(units_abbrev(units_out%length**2))//' =', power, ' b^2'
539 write(message(5), '(a,f12.8,a,f12.8,a)') '<0|P|I> = ', units_from_atomic(units_out%length, sqrt(abs(power))), &
540 ' '//trim(units_abbrev(units_out%length))//' = ', sqrt(abs(power)),' b'
541 write(message(6), '(a,f12.8)') 'f[O->I] = ', m_two*omega*power
542 write(message(7), '(a)')
543 write(message(8), '(a,f12.8,a,f12.8,a)') ' Search interval = [', units_from_atomic(units_out%energy, leftbound), ',', &
544 units_from_atomic(units_out%energy, rightbound), ']'
545 write(message(9), '(a,f12.4,a)') ' Search discretization = ', units_from_atomic(units_out%energy, dw), &
546 ' '//trim(units_abbrev(units_out%energy))
547 write(message(10), '(a)') '******************************************************************'
548 write(message(11), '(a)')
549 call messages_info(11)
551 pop_sub(resonance_first_order)
552
553 end subroutine resonance_first_order
554 ! ---------------------------------------------------------
555
556
557 ! ---------------------------------------------------------
558 subroutine resonance_second_order(omega, power, nw_subtracted, leftbound, rightbound, c01, c02)
559 real(real64), intent(in) :: omega
560 real(real64), intent(out) :: power
561 integer, intent(in) :: nw_subtracted
562 real(real64), intent(in) :: leftbound, rightbound
563 real(real64), intent(in) :: c01, c02
564
565 push_sub(resonance_second_order)
566
567 call ft(omega, power)
568 select case (mode)
569 case (sine_transform)
570 power = power / (m_one - sin(m_two*omega*total_time)/(m_two*omega*total_time))
571 case (cosine_transform)
572 ! WARNING: there is some difference between the omega=0 case and the rest.
573 if (abs(omega) > m_epsilon) then
574 power = power / (m_one + sin(m_two*omega*total_time)/(m_two*omega*total_time))
575 else
576 power = power / m_two
577 end if
578 end select
579
580 write(message(1), '(a)') '******************************************************************'
581 write(message(2), '(a,i3)') 'Resonance #', nw_subtracted + 1
582 write(message(3), '(a,f12.8,a,f12.8,a)') 'omega = ', units_from_atomic(units_out%energy, omega), &
583 ' '//trim(units_abbrev(units_out%energy))//' = ', omega, ' Ha'
584 write(message(4), '(a,f12.8,a,f12.8,a)') 'C(omega) = ', units_from_atomic(units_out%length**3, power), &
585 ' '//trim(units_abbrev(units_out%length**3))//' = ', power, ' b^3'
586 call messages_info(4)
587
588 if (abs(c01*c02) > m_epsilon) then
589 write(message(1), '(a,f12.8)') ' C(omega)/(C0i*C0j) = ', power / (c01 * c02)
590 call messages_info(1)
591 end if
592
593 write(message(1), '(a)')
594 write(message(2), '(a,f12.8,a,f12.8,a)') ' Search interval = [', units_from_atomic(units_out%energy, leftbound), ',', &
595 units_from_atomic(units_out%energy, rightbound), ']'
596 write(message(3), '(a)') '******************************************************************'
597 write(message(4), '(a)')
598 call messages_info(4)
599
601 end subroutine resonance_second_order
602 ! ---------------------------------------------------------
603
604
605 ! ---------------------------------------------------------
606 subroutine generate_signal(namespace, order, observable)
607 type(namespace_t), intent(in) :: namespace
608 integer, intent(in) :: order
609 integer, intent(in) :: observable(2)
610
611 logical :: file_exists
612 integer :: i, j, nspin, time_steps, lmax, nfiles, k, add_lm, l, m, max_add_lm
613 integer, allocatable :: iunit(:)
614 real(real64) :: dt, lambda, dump, o0
615 type(unit_t) :: mp_unit
616 real(real64), allocatable :: q(:), mu(:), qq(:, :), c(:)
617 character(len=20) :: filename
618 type(kick_t) :: kick
619 type(unit_system_t) :: units
620 real(real64), allocatable :: multipole(:, :, :), ot(:), dipole(:, :)
621 type(local_operator_t) :: kick_operator
622 type(local_operator_t) :: obs
623
624 push_sub(generate_signal)
625
626 ! Find out how many files do we have
627 nfiles = 0
628 do
629 write(filename,'(a11,i1)') 'multipoles.', nfiles+1
630 inquire(file=trim(filename), exist = file_exists)
631 if (.not. file_exists) exit
632 nfiles = nfiles + 1
633 end do
634
635 ! WARNING: Check that order is smaller or equal to nfiles
636 if (nfiles == 0) then
637 write(message(1),'(a)') 'No multipoles.x file was found'
638 call messages_fatal(1, namespace=namespace)
639 end if
640 if (order > nfiles) then
641 write(message(1),'(a)') 'The order that you ask for is higher than the number'
642 write(message(2),'(a)') 'of multipoles.x file that you supply.'
643 call messages_fatal(2, namespace=namespace)
644 end if
645
646 ! Open the files.
647 safe_allocate(iunit(1:nfiles))
648 do j = 1, nfiles
649 write(filename,'(a11,i1)') 'multipoles.', j
650 iunit(j) = io_open(trim(filename), namespace, action='read', status='old', die=.false.)
651 end do
652
653 safe_allocate( q(1:nfiles))
654 safe_allocate(mu(1:nfiles))
655 safe_allocate(qq(1:nfiles, 1:nfiles))
656 safe_allocate( c(1:nfiles))
657
658 c = m_zero
659 c(order) = m_one
660
661 ! Get the basic info from the first file
662 call spectrum_mult_info(namespace, iunit(1), nspin, kick, time_steps, dt, units, lmax=lmax)
663
664 ! Sets the kick operator...
665 if (kick%n_multipoles > 0) then
666 kick_operator%n_multipoles = kick%n_multipoles
667 safe_allocate( kick_operator%l(1:kick_operator%n_multipoles))
668 safe_allocate( kick_operator%m(1:kick_operator%n_multipoles))
669 safe_allocate(kick_operator%weight(1:kick_operator%n_multipoles))
670 do i = 1, kick_operator%n_multipoles
671 kick_operator%l(i) = kick%l(i)
672 kick_operator%m(i) = kick%m(i)
673 kick_operator%weight(i) = kick%weight(i)
674 end do
675 else
676 kick_operator%n_multipoles = 3
677 safe_allocate( kick_operator%l(1:kick_operator%n_multipoles))
678 safe_allocate( kick_operator%m(1:kick_operator%n_multipoles))
679 safe_allocate(kick_operator%weight(1:kick_operator%n_multipoles))
680 kick_operator%l(1:3) = 1
681 kick_operator%m(1) = -1
682 kick_operator%m(2) = 0
683 kick_operator%m(3) = 1
684 ! WARNING: not sure if m = -1 => y, and m = 1 => x. What is the convention?
685 kick_operator%weight(1) = -sqrt((m_four*m_pi)/m_three) * kick%pol(2, kick%pol_dir)
686 kick_operator%weight(2) = sqrt((m_four*m_pi)/m_three) * kick%pol(3, kick%pol_dir)
687 kick_operator%weight(3) = -sqrt((m_four*m_pi)/m_three) * kick%pol(1, kick%pol_dir)
688 end if
689
690 ! Sets the observation operator
691 select case (observable(1))
692 case (-1)
693 ! This means that the "observation operator" should be equal
694 ! to the "perturbation operator", i.e., the kick.
695 call local_operator_copy(obs, kick_operator)
696 case (0)
697 ! This means that the observable is the dipole operator; observable(2) determines
698 ! if it is x, y or z.
699 obs%n_multipoles = 1
700 safe_allocate(obs%l(1:1))
701 safe_allocate(obs%m(1:1))
702 safe_allocate(obs%weight(1:1))
703 obs%l(1) = 1
704 select case (observable(2))
705 case (1)
706 obs%m(1) = -1
707 obs%weight(1) = -sqrt((m_four*m_pi)/m_three)
708 case (2)
709 obs%m(1) = 1
710 obs%weight(1) = sqrt((m_four*m_pi)/m_three)
711 case (3)
712 obs%m(1) = 0
713 obs%weight(1) = -sqrt((m_four*m_pi)/m_three)
714 end select
715 case default
716 ! This means that the observation operator is (l,m) = (observable(1), observable(2))
717 obs%n_multipoles = 1
718 safe_allocate(obs%l(1:1))
719 safe_allocate(obs%m(1:1))
720 safe_allocate(obs%weight(1:1))
721 obs%weight(1) = m_one
722 obs%l(1) = observable(1)
723 obs%m(1) = observable(2)
724 end select
725
726 lambda = abs(kick%delta_strength)
727 q(1) = kick%delta_strength / lambda
728
729 do j = 2, nfiles
730 call spectrum_mult_info(namespace, iunit(j), nspin, kick, time_steps, dt, units, lmax=lmax)
731 q(j) = kick%delta_strength / lambda
732 end do
733
734 do i = 1, nfiles
735 do j = 1, nfiles
736 qq(i, j) = q(j)**i
737 end do
738 end do
739
740 call lalg_inverse(nfiles, qq, 'dir')
741
742 mu = matmul(qq, c)
743
744 if (kick%n_multipoles > 0) then
745 lmax = maxval(kick%l(1:obs%n_multipoles))
746 max_add_lm = (lmax+1)**2-1
747 safe_allocate(multipole(1:max_add_lm, 0:time_steps, 1:nspin))
748 ! The units have nothing to do with the perturbing kick??
749 mp_unit = units%length**kick%l(1)
750 else
751 max_add_lm = 3
752 safe_allocate(multipole(1:3, 0:time_steps, 1:nspin))
753 mp_unit = units%length
754 end if
755 safe_allocate(ot(0:time_steps))
756 multipole = m_zero
757 ot = m_zero
758 o0 = m_zero
759
760 safe_allocate(dipole(1:3, 1:nspin))
761
762 do j = 1, nfiles
763 call io_skip_header(iunit(j))
764
765 do i = 0, time_steps
766 select case (nspin)
767 case (1)
768 read(iunit(j), *) k, dump, dump, (multipole(add_lm, i, 1), add_lm = 1, max_add_lm)
769 case (2)
770 read(iunit(j), *) k, dump, dump, (multipole(add_lm, i, 1), add_lm = 1, max_add_lm), &
771 dump, (multipole(add_lm, i, 2), add_lm = 1, max_add_lm)
772 case (4)
773 read(iunit(j), *) k, dump, dump, (multipole(add_lm, i, 1), add_lm = 1, max_add_lm), &
774 dump, (multipole(add_lm, i, 2), add_lm = 1, max_add_lm), &
775 dump, (multipole(add_lm, i, 3), add_lm = 1, max_add_lm), &
776 dump, (multipole(add_lm, i, 4), add_lm = 1, max_add_lm)
777 end select
778 multipole(1:max_add_lm, i, :) = units_to_atomic(mp_unit, multipole(1:max_add_lm, i, :))
779
780 ! The dipole is treated differently in the multipoles file: first of all,
781 ! the program should have printed *minus* the dipole operator.
782 dipole(1:3, 1:nspin) = - multipole(1:3, i, 1:nspin)
783 ! And then it contains the "cartesian" dipole, opposed to the spherical dipole:
784 multipole(1, i, 1:nspin) = -sqrt(m_three/(m_four*m_pi)) * dipole(2, 1:nspin)
785 multipole(2, i, 1:nspin) = sqrt(m_three/(m_four*m_pi)) * dipole(3, 1:nspin)
786 multipole(3, i, 1:nspin) = -sqrt(m_three/(m_four*m_pi)) * dipole(1, 1:nspin)
787
788 dump = m_zero
789 do k = 1, obs%n_multipoles
790 add_lm = 1
791 l = 1
792 lcycle: do
793 do m = -l, l
794 if (l == obs%l(k) .and. m == obs%m(k)) exit lcycle
795 add_lm = add_lm + 1
796 end do
797 l = l + 1
798 end do lcycle
799 ! Warning: it should not add the nspin components?
800 dump = dump + obs%weight(k) * sum(multipole(add_lm, i, 1:nspin))
801 end do
802
803 if (i == 0) o0 = dump
804 ot(i) = ot(i) + mu(j)*(dump - o0)
805 end do
806
807 end do
808
809 ot = ot / lambda**order
810
811 call write_ot(namespace, nspin, time_steps, dt, kick, order, ot(0:time_steps), observable)
812
813 ! Close files and exit.
814 do j = 1, nfiles
815 call io_close(iunit(j))
816 end do
817 safe_deallocate_a(iunit)
818 safe_deallocate_a(q)
819 safe_deallocate_a(mu)
820 safe_deallocate_a(qq)
821 safe_deallocate_a(c)
822 safe_deallocate_a(ot)
823 safe_deallocate_a(multipole)
824 safe_deallocate_a(dipole)
825
826 pop_sub(generate_signal)
827 end subroutine generate_signal
828 ! ---------------------------------------------------------
829
830
831 ! ---------------------------------------------------------
832 subroutine modify_ot(time_steps, dt, order, ot, omega, power)
833 integer, intent(in) :: time_steps
834 real(real64), intent(in) :: dt
835 integer, intent(in) :: order
836 real(real64), intent(inout) :: ot(0:time_steps)
837 real(real64), intent(in) :: omega
838 real(real64), intent(in) :: power
839
840 integer :: i
841
842 push_sub(modify_ot)
843
844 select case (mod(order, 2))
845 case (1)
846 do i = 0, time_steps
847 ot(i) = ot(i) - m_two * power * sin(omega*i*dt)
848 end do
849 case (0)
850 if (abs(omega) <= m_epsilon) then
851 do i = 0, time_steps
852 ot(i) = ot(i) - power * cos(omega*i*dt)
853 end do
854 else
855 do i = 0, time_steps
856 ot(i) = ot(i) - m_two * power * cos(omega*i*dt)
857 end do
858 end if
859 end select
860
861 pop_sub(modify_ot)
862 end subroutine modify_ot
863 ! ---------------------------------------------------------
864
865
866 ! ---------------------------------------------------------
867 subroutine write_ot(namespace, nspin, time_steps, dt, kick, order, ot, observable)
868 type(namespace_t), intent(in) :: namespace
869 integer, intent(in) :: nspin, time_steps
870 real(real64), intent(in) :: dt
871 type(kick_t), intent(in) :: kick
872 integer, intent(in) :: order
873 real(real64), intent(in) :: ot(0:time_steps)
874 integer, intent(in) :: observable(2)
875
876 integer :: iunit, i
877 character(len=20) :: header_string
878 type(unit_t) :: ot_unit
879
880 push_sub(write_ot)
881
882 iunit = io_open('ot', namespace, action='write', status='replace')
883
884 write(iunit, '(a15,i2)') '# nspin ', nspin
885 write(iunit, '(a15,i2)') '# Order ', order
886 write(iunit, '(a28,i2)') '# Frequencies subtracted = ', 0
887 select case (observable(1))
888 case (-1)
889 write(iunit,'(a)') '# Observable operator = kick operator'
890 if (kick%n_multipoles > 0) then
891 ot_unit = units_out%length**kick%l(1)
892 else
893 ot_unit = units_out%length
894 end if
895 case (0)
896 select case (observable(2))
897 case (1)
898 write(iunit,'(a)') '# O = x'
899 case (2)
900 write(iunit,'(a)') '# O = y'
901 case (3)
902 write(iunit,'(a)') '# O = z'
903 end select
904 ot_unit = units_out%length
905 case default
906 ot_unit = units_out%length**observable(1)
907 write(iunit, '(a12,i1,a1,i2,a1)') '# (l, m) = (', observable(1),',',observable(2),')'
908 end select
909 call kick_write(kick, iunit)
910
911 ! Units
912 write(iunit,'(a1)', advance = 'no') '#'
913 write(iunit,'(a20)', advance = 'no') str_center('t', 19)
914 write(iunit,'(a20)', advance = 'yes') str_center('<O>(t)', 20)
915 write(iunit,'(a1)', advance = 'no') '#'
916 write(header_string, '(a)') '['//trim(units_abbrev(units_out%time))//']'
917 write(iunit,'(a20)', advance = 'no') str_center(trim(header_string), 19)
918 write(header_string, '(a)') '['//trim(units_abbrev(units_out%length))//']'
919 write(iunit,'(a20)', advance = 'yes') str_center(trim(header_string), 20)
920
921 do i = 0, time_steps
922 write(iunit, '(2e20.8)') units_from_atomic(units_out%time, i*dt), units_from_atomic(ot_unit, ot(i))
923 end do
924
925 call io_close(iunit)
926 pop_sub(write_ot)
927 end subroutine write_ot
928
929
930 ! ---------------------------------------------------------
931 subroutine read_ot(namespace, nspin, order, nw_subtracted)
932 type(namespace_t), intent(in) :: namespace
933 integer, intent(out) :: nspin
934 integer, intent(out) :: order
935 integer, intent(out) :: nw_subtracted
936
937 integer :: iunit, i, ierr
938 character(len=100) :: line
939 character(len=12) :: dummychar
940 real(real64) :: dummy, t1, t2
941 type(unit_t) :: ot_unit
942
943 push_sub(read_ot)
944
945 iunit = io_open('ot', namespace, action='read', status='old')
946 if (iunit == 0) then
947 write(message(1),'(a)') 'A file called ot should be present and was not found.'
948 call messages_fatal(1, namespace=namespace)
949 end if
950
951 read(iunit, '(15x,i2)') nspin
952 read(iunit, '(15x,i2)') order
953 read(iunit, '(28x,i2)') nw_subtracted
954 read(iunit, '(a)') line
955
956 i = index(line, 'Observable')
957 if (index(line, 'Observable') /= 0) then
958 observable(1) = -1
959 elseif (index(line, '# O =') /= 0) then
960 observable(1) = 0
961 if (index(line,'x') /= 0) then
962 observable(2) = 1
963 elseif (index(line,'y') /= 0) then
964 observable(2) = 2
965 elseif (index(line,'z') /= 0) then
966 observable(2) = 3
967 end if
968 elseif (index(line, '# (l, m) = ') /= 0) then
969 read(line,'(a12,i1,a1,i2,a1)') dummychar(1:12), observable(1), dummychar(1:1), observable(2), dummychar(1:1)
970 else
971 write(message(1),'(a)') 'Problem reading "ot" file: could not figure out the shape'
972 write(message(2),'(a)') 'of the observation operator.'
973 call messages_fatal(2, namespace=namespace)
974 end if
975
976 call kick_read(kick, iunit, namespace)
977 read(iunit, '(a)') line
978 read(iunit, '(a)') line
979 call io_skip_header(iunit)
980
981 ! Figure out about the units of the file
982 call unit_system_from_file(units, "ot", namespace, ierr)
983 if (ierr /= 0) then
984 write(message(1), '(a)') 'Could not figure out the units in file "ot".'
985 call messages_fatal(1, namespace=namespace)
986 end if
987
988 select case (observable(1))
989 case (-1)
990 if (kick%n_multipoles > 0) then
991 ot_unit = units_out%length**kick%l(1)
992 else
993 ot_unit = units_out%length
994 end if
995 case (0)
996 ot_unit = units_out%length
997 case default
998 ot_unit = units_out%length**observable(1)
999 end select
1000
1001 ! count number of time_steps
1002 time_steps = 0
1003 do
1004 read(iunit, *, end=100) dummy
1005 time_steps = time_steps + 1
1006 if (time_steps == 1) t1 = dummy
1007 if (time_steps == 2) t2 = dummy
1008 end do
1009100 continue
1010 dt = units_to_atomic(units%time, (t2 - t1)) ! units_out is OK
1011
1012 call io_skip_header(iunit)
1013
1014 safe_allocate(ot(0:time_steps))
1015
1016 do i = 0, time_steps-1
1017 read(iunit, *) dummy, ot(i)
1018 ot(i) = units_to_atomic(ot_unit, ot(i))
1019 end do
1020
1021 pop_sub(read_ot)
1022 end subroutine read_ot
1023
1025 ! ---------------------------------------------------------
1026 subroutine print_omega_file(namespace, omega, search_interval, final_time, nfrequencies)
1027 type(namespace_t), intent(in) :: namespace
1028 real(real64), intent(inout) :: omega
1029 real(real64), intent(inout) :: search_interval
1030 real(real64), intent(inout) :: final_time
1031 integer, intent(inout) :: nfrequencies
1032
1033 integer :: iunit, i, ierr, nspin, order, nw_subtracted
1034 logical :: file_exists
1035 character(len=20) :: header_string
1036 real(real64), allocatable :: warray(:), tarray(:)
1037 real(real64) :: leftbound, rightbound, dw, w, aw
1038
1039 push_sub(print_omega_file)
1040
1041 ! First, let us check that the file "ot" exists.
1042 inquire(file="ot", exist = file_exists)
1043 if (.not. file_exists) then
1044 write(message(1),'(a)') "Could not find 'ot' file."
1045 call messages_fatal(1, namespace=namespace)
1046 end if
1047
1048 ! Now, we should find out which units the file "ot" has.
1049 call unit_system_from_file(units, "ot", namespace, ierr)
1050 if (ierr /= 0) then
1051 write(message(1),'(a)') "Could not retrieve units in the 'ot' file."
1052 call messages_fatal(1, namespace=namespace)
1053 end if
1054
1055 if (omega > m_zero) then
1056 omega = units_to_atomic(units%energy, omega)
1057 else
1058 omega = m_half
1059 end if
1060
1061 if (search_interval > m_zero) then
1062 search_interval = units_to_atomic(units%energy, search_interval)
1063 else
1064 search_interval = m_half
1065 end if
1066
1067 leftbound = omega - search_interval
1068 rightbound = omega + search_interval
1069
1070 safe_allocate(warray(1:nfrequencies))
1071 safe_allocate(tarray(1:nfrequencies))
1072
1073 call read_ot(namespace, nspin, order, nw_subtracted)
1074
1075 if (mod(order, 2) == 1) then
1077 else
1079 end if
1080
1081 if (final_time > m_zero) then
1082 total_time = units_to_atomic(units%time, final_time)
1083 if (total_time > dt*time_steps) then
1085 write(message(1), '(a)') 'The requested total time to process is larger than the time available in the input file.'
1086 write(message(2), '(a,f8.4,a)') 'The time has been adjusted to ', &
1087 units_from_atomic(units_out%time, total_time), trim(units_abbrev(units_out%time))
1088 call messages_warning(2, namespace=namespace)
1089 end if
1090 time_steps = int(total_time / dt)
1092 else
1094 end if
1095
1096 warray = m_zero
1097 tarray = m_zero
1098 dw = (rightbound-leftbound) / (nfrequencies - 1)
1099 do i = 1, nfrequencies
1100 w = leftbound + (i-1)*dw
1101 warray(i) = w
1102 call ft(w, aw)
1103 tarray(i) = aw
1104 end do
1105
1106 iunit = io_open('omega', namespace, action='write', status='replace')
1107 write(iunit, '(a15,i2)') '# nspin ', nspin
1108 call kick_write(kick, iunit)
1109 write(iunit, '(a)') '#%'
1110 write(iunit, '(a1,a20)', advance = 'no') '#', str_center("omega", 20)
1111 write(header_string,'(a)') 'F(omega)'
1112 write(iunit, '(a20)', advance = 'yes') str_center(trim(header_string), 20)
1113 write(iunit, '(a1,a20)', advance = 'no') '#', str_center('['//trim(units_abbrev(units_out%energy)) // ']', 20)
1114 ! Here we should print the units of the transform.
1115 write(iunit, '(a)', advance = 'yes')
1116
1117 do i = 1, nfrequencies
1118 write(iunit,'(2e20.8)') units_from_atomic(units_out%energy, warray(i)), &
1119 tarray(i)
1120 end do
1121
1122 safe_deallocate_a(warray)
1123 safe_deallocate_a(tarray)
1124
1125 pop_sub(print_omega_file)
1126 end subroutine print_omega_file
1127 ! ---------------------------------------------------------
1128
1130
1131! ---------------------------------------------------------
1132! ---------------------------------------------------------
1133! ---------------------------------------------------------
1134program oscillator_strength
1136 use global_oct_m
1137 use io_oct_m
1138 use messages_oct_m
1140
1141 implicit none
1142
1143 integer :: run_mode, order, nfrequencies, ierr, nresonances
1144 real(real64) :: omega, search_interval, final_time, damping
1145 integer, parameter :: &
1146 ANALYZE_NTHORDER_SIGNAL = 1, &
1147 generate_nthorder_signal = 2, &
1148 read_resonances_from_file = 3, &
1149 generate_omega_file = 4
1150 character(len=100) :: ffile
1151
1152 ! Reads the information passed through the command line options (if available).
1153 call getopt_init(ierr)
1154 if (ierr /= 0) then
1155 message(1) = "Your Fortran compiler doesn't support command-line arguments;"
1156 message(2) = "the oct-oscillator-strength command is not available."
1157 call messages_fatal(2)
1158 end if
1159
1160 ! Set the default values
1161 run_mode = analyze_nthorder_signal
1162 omega = - m_one
1163 search_interval = - m_one
1164 order = 1
1165 nfrequencies = 1000
1166 final_time = - m_one
1167 nresonances = 1
1168 observable(1) = -1
1169 observable(2) = 0
1170 ffile = ""
1171 damping = 0.1_real64/27.2114_real64 ! This is the usual damping factor used in the literature.
1172
1173 ! Get the parameters from the command line.
1174 call getopt_oscillator_strength(run_mode, omega, search_interval, &
1175 order, nresonances, nfrequencies, final_time, &
1176 observable(1), observable(2), damping, ffile)
1177 call getopt_end()
1178
1179 ! Initialize stuff
1181 call parser_init()
1182 call io_init(defaults = .true.)
1183
1184 select case (run_mode)
1185 case (generate_nthorder_signal)
1186 call generate_signal(global_namespace, order, observable)
1187 case (analyze_nthorder_signal)
1188 call analyze_signal(order, omega, search_interval, final_time, nresonances, nfrequencies, damping, &
1189 global_namespace)
1190 case (read_resonances_from_file)
1191 call read_resonances_file(order, ffile, global_namespace, search_interval, final_time, nfrequencies)
1192 case (generate_omega_file)
1193 call print_omega_file(global_namespace, omega, search_interval, final_time, nfrequencies)
1194 case default
1195 end select
1196
1197 call io_end()
1198 call parser_end()
1199 call global_end()
1200
1201end program oscillator_strength
1202! ---------------------------------------------------------
1203
1204!! Local Variables:
1205!! mode: f90
1206!! coding: utf-8
1207!! End:
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
subroutine, public getopt_init(ierr)
Initializes the getopt machinery. Must be called before attempting to parse the options....
subroutine, public getopt_end
real(real64), parameter, public m_two
Definition: global.F90:189
subroutine, public global_end()
Finalise parser varinfo file, and MPI.
Definition: global.F90:381
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_four
Definition: global.F90:191
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
type(mpi_comm), parameter, public serial_dummy_comm
Alias MPI_COMM_UNDEFINED for the specific use case of initialising Octopus utilities with no MPI supp...
Definition: global.F90:264
subroutine, public init_octopus_globals(comm)
Initialise Octopus-specific global constants and files. This routine performs no initialisation calls...
Definition: global.F90:353
complex(real64), parameter, public m_z0
Definition: global.F90:197
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public m_epsilon
Definition: global.F90:203
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public m_one
Definition: global.F90:188
real(real64), parameter, public m_three
Definition: global.F90:190
Definition: io.F90:114
subroutine, public io_init(defaults)
If the argument defaults is present and set to true, then the routine will not try to read anything f...
Definition: io.F90:166
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
subroutine, public io_skip_header(iunit)
Definition: io.F90:679
subroutine, public io_end()
Definition: io.F90:265
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
subroutine, public kick_read(kick, iunit, namespace)
Definition: kick.F90:819
subroutine, public kick_write(kick, iunit, out)
Definition: kick.F90:891
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1125
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:543
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine ft(omega, power)
integer, dimension(2) observable
subroutine write_ot(namespace, nspin, time_steps, dt, kick, order, ot, observable)
subroutine generate_signal(namespace, order, observable)
subroutine ft2(omega, power)
subroutine read_ot(namespace, nspin, order, nw_subtracted)
subroutine resonance_first_order(omega, power, nw_subtracted, dw, leftbound, rightbound)
integer, parameter cosine_transform
subroutine resonance_second_order(omega, power, nw_subtracted, leftbound, rightbound, c01, c02)
subroutine analyze_signal(order, omega, search_interval, final_time, nresonances, nfrequencies, damping, namespace)
subroutine modify_ot(time_steps, dt, order, ot, omega, power)
subroutine print_omega_file(namespace, omega, search_interval, final_time, nfrequencies)
subroutine find_resonance(omega, leftbound, rightbound, nfrequencies)
subroutine read_resonances_file(order, ffile, namespace, search_interval, final_time, nfrequencies)
subroutine write_polarizability(namespace, nfrequencies, nresonances, dw, w, c0I2, gamma)
Implements the SOS formula of the polarizability, and writes down to the "polarizability" file the re...
subroutine, public spectrum_mult_info(namespace, iunit, nspin, kick, time_steps, dt, file_units, lmax)
Definition: spectrum.F90:2342
character(len=80) function, public str_center(s_in, l_in)
puts space around string, so that it is centered
Definition: string.F90:197
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
subroutine, public unit_system_from_file(uu, fname, namespace, ierr)
This is a very primitive procedure that attempts to find out which units were used to write an octopu...
program oscillator_strength
int true(void)