Octopus
casida_spectrum.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2012-2013 D. Strubbe
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22program casida_spectrum
24 use debug_oct_m
25 use global_oct_m
26 use io_oct_m
27 use ions_oct_m
28 use, intrinsic :: iso_fortran_env
31 use parser_oct_m
33 use space_oct_m
34 use unit_oct_m
36 use utils_oct_m
38
39 implicit none
40
42 real(real64) :: br, energy_step, min_energy, max_energy
43 type(space_t) :: space
44 integer :: ispin
45 end type casida_spectrum_t
46
47 integer :: ierr, idir, jdir, iatom
48 type(space_t) :: space
49 type(casida_spectrum_t) :: cs
50 real(real64), allocatable :: rotation(:,:), rot2(:,:), identity(:,:), coord(:)
51 type(block_t) :: blk
52 type(ions_t), pointer :: ions
53
54 ! Initialize stuff
56
57 call getopt_init(ierr)
58 if (ierr == 0) call getopt_casida_spectrum()
59 call getopt_end()
60
61 call parser_init()
62 call messages_init()
63 call io_init()
67
68 allocate(rotation(space%dim, space%dim))
69 allocate(rot2(space%dim, space%dim))
70 allocate(identity(space%dim, space%dim))
71 allocate(coord(space%dim))
72
73 ! Reads the spin components. This is read here, as well as in states_init.
74 call parse_variable(global_namespace, 'SpinComponents', 1, cs%ispin)
75 if (.not. varinfo_valid_option('SpinComponents', cs%ispin)) call messages_input_error(global_namespace, 'SpinComponents')
76 cs%ispin = min(2, cs%ispin)
77
78 !%Variable CasidaSpectrumBroadening
79 !%Type float
80 !%Default 0.005 Ha
81 !%Section Utilities::oct-casida_spectrum
82 !%Description
83 !% Width of the Lorentzian used to broaden the excitations.
84 !%End
85 call parse_variable(global_namespace, 'CasidaSpectrumBroadening', 0.005_real64, cs%br, units_inp%energy)
86
87 call messages_print_var_value('CasidaSpectrumBroadening', cs%br, unit = units_out%energy)
88
89 !%Variable CasidaSpectrumEnergyStep
90 !%Type float
91 !%Default 0.001 Ha
92 !%Section Utilities::oct-casida_spectrum
93 !%Description
94 !% Sampling rate for the spectrum.
95 !%End
96 call parse_variable(global_namespace, 'CasidaSpectrumEnergyStep', 0.001_real64, cs%energy_step, units_inp%energy)
97
98 call messages_print_var_value('CasidaSpectrumEnergyStep', cs%energy_step, unit = units_out%energy)
99
100 !%Variable CasidaSpectrumMinEnergy
101 !%Type float
102 !%Default 0.0
103 !%Section Utilities::oct-casida_spectrum
104 !%Description
105 !% The broadening is done for energies greater than <tt>CasidaSpectrumMinEnergy</tt>.
106 !%End
107 call parse_variable(global_namespace, 'CasidaSpectrumMinEnergy', m_zero, cs%min_energy, units_inp%energy)
108
109 call messages_print_var_value('CasidaSpectrumMinEnergy', cs%min_energy, unit = units_out%energy)
110
111 !%Variable CasidaSpectrumMaxEnergy
112 !%Type float
113 !%Default 1.0 Ha
114 !%Section Utilities::oct-casida_spectrum
115 !%Description
116 !% The broadening is done for energies smaller than <tt>CasidaSpectrumMaxEnergy</tt>.
117 !%End
118 call parse_variable(global_namespace, 'CasidaSpectrumMaxEnergy', m_one, cs%max_energy, units_inp%energy)
119
120 call messages_print_var_value('CasidaSpectrumMaxEnergy', cs%max_energy, unit = units_out%energy)
121
122 identity = m_zero
123 do idir = 1, space%dim
124 identity(idir, idir) = m_one
125 end do
126
127 !%Variable CasidaSpectrumRotationMatrix
128 !%Type block
129 !%Default identity
130 !%Section Utilities::oct-casida_spectrum
131 !%Description
132 !% Supply a rotation matrix to apply to the transition dipoles in generating the spectrum. The rotated atomic structure
133 !% will also be output. Size of matrix must be <tt>Dimensions</tt>.
134 !%End
136 if (parse_block(global_namespace, 'CasidaSpectrumRotationMatrix', blk) == 0) then
137 do idir = 1, space%dim
138 do jdir = 1, space%dim
139 call parse_block_float(blk, idir - 1, jdir - 1, rotation(idir, jdir))
140 end do
141 end do
142 call parse_block_end(blk)
143
144 message(1) = "Info: Applying rotation matrix"
145 call messages_info(1)
146 call output_tensor(rotation, cs%space%dim, unit_one, write_average = .false., namespace=global_namespace)
147
148 ! allowing inversions is fine
149 rot2(:,:) = abs(matmul(transpose(rotation), rotation))
150 if (any(abs(rot2(:,:) - identity(:,:)) > 1e-6_real64)) then
151 write(message(1),'(a,es13.6)') "Rotation matrix is not orthogonal. max discrepancy in product = ", &
152 maxval(abs(rot2(:,:) - identity(:,:)))
153 call messages_warning(1)
154 end if
155
156 ! apply rotation to geometry
157 ions => ions_t(global_namespace)
158 do iatom = 1, ions%natoms
159 coord = ions%pos(:, iatom)
160 ions%pos(:, iatom) = matmul(rotation, coord)
161 end do
162 call ions%write_xyz(trim(casida_dir)//'rotated')
163 safe_deallocate_p(ions)
164 else
165 rotation(:,:) = identity(:,:)
166 end if
167
168 call calc_broad(cs, casida_dir, 'eps_diff', .true.)
169 call calc_broad(cs, casida_dir, 'petersilka', .false.)
170 call calc_broad(cs, casida_dir, 'tamm_dancoff', .false.)
171 call calc_broad(cs, casida_dir, 'variational', .false.)
172 call calc_broad(cs, casida_dir, 'casida', .false.)
173
174 deallocate(rotation)
175 deallocate(rot2)
176 deallocate(identity)
177 deallocate(coord)
178
180 call io_end()
181 call messages_end()
182
183 call parser_end()
184 call global_end()
185
186contains
187
188 ! ---------------------------------------------------------
189 subroutine calc_broad(cs, dir, fname, extracols)
190 type(casida_spectrum_t), intent(in) :: cs
191 character(len=*), intent(in) :: dir
192 character(len=*), intent(in) :: fname
193 logical, intent(in) :: extracols
194
195 real(real64), allocatable :: spectrum(:,:)
196 real(real64) :: omega, energy, re_tm(space%dim), im_tm(space%dim), ff(space%dim+1), tm_sq(space%dim)
197 integer :: istep, nsteps, iunit, trash(3), idir, ncols, ios
198 character(len=256) :: string
199 logical :: is_complex
200
201 push_sub(calc_broad)
202
203 nsteps = int((cs%max_energy - cs%min_energy) / cs%energy_step)
204 safe_allocate(spectrum(1:space%dim+1, 1:nsteps))
205 spectrum = m_zero
206
207 iunit = io_open(trim(dir)// fname, global_namespace, action='read', status='old', die = .false.)
208
209 if (iunit < 0) then
210 message(1) = 'Cannot open file "'//trim(dir)//trim(fname)//'".'
211 message(2) = 'The '//trim(fname)//' spectrum was not generated.'
212 call messages_warning(2)
213 return
214 end if
215
216 ! For Casida, CV(2), Tamm-Dancoff, Petersilka: first column is the index of the excitation
217 ! For eps_diff: first two columns are occ and unocc states, then spin if spin-polarized
218 ncols = 1
219 if (extracols) then
220 ncols = ncols + cs%ispin
221 end if
222
223 read(iunit, *) ! skip header
224
225 read(iunit, '(a)') string
226 ! complex has this many columns; real lacks the imaginary columns (im_tm)
227 read(string, *, iostat = ios) trash(1:ncols), energy, (re_tm(idir), im_tm(idir), idir = 1, space%dim), ff(space%dim+1)
228 is_complex = (ios == 0)
229 ! put it back to read the data in the loop
230 backspace(iunit)
231
232 do
233 if (is_complex) then
234 read(iunit, *, iostat = ios) trash(1:ncols), energy, (re_tm(idir), im_tm(idir), idir = 1, space%dim), ff(space%dim+1)
235 im_tm = units_to_atomic(units_out%length, im_tm)
236 else
237 read(iunit, *, iostat = ios) trash(1:ncols), energy, (re_tm(idir), idir = 1, space%dim), ff(space%dim+1)
238 end if
239 re_tm = units_to_atomic(units_out%length, re_tm)
240 ! ff, the last column, is a dimensionless number
241
242 if (ios < 0) then
243 exit ! end of file
244 else if (ios > 0) then
245 message(1) = "Error parsing file " // trim(fname)
246 call messages_fatal(1)
247 end if
248
249 energy = units_to_atomic(units_out%energy, energy)
250 ! transition matrix elements by themselves are dependent on gauge in degenerate subspaces
251 ! make into oscillator strengths, as in casida_inc.F90 X(oscillator_strengths), and like the last column
252 tm_sq = (matmul(rotation, re_tm))**2
253 if (is_complex) then
254 tm_sq = tm_sq + (matmul(rotation, im_tm))**2
255 end if
256 ff(1:space%dim) = m_two * energy * tm_sq
257
258 do istep = 1, nsteps
259 omega = cs%min_energy + real(istep-1, real64) *cs%energy_step
260 spectrum(:, istep) = spectrum(:, istep) + ff*cs%br/((omega-energy)**2 + cs%br**2)/m_pi ! Lorentzian
261 end do
262 end do
263 call io_close(iunit)
264
265 ! print spectra
266 iunit = io_open(trim(dir)//"/spectrum."//fname, global_namespace, action='write')
267
268 write(iunit, '(a2,a12)', advance = 'no') '# ', 'E [' // trim(units_abbrev(units_out%energy)) // ']'
269 do idir = 1, space%dim
270 write(iunit, '(a14)', advance = 'no') '<' // index2axis(idir) // index2axis(idir) // '>'
271 end do
272 write(iunit, '(a14)') '<f>'
273
274 do istep = 1, nsteps
275 write(iunit, '(99es14.6)') units_from_atomic(units_out%energy, cs%min_energy + real(istep - 1, real64) &
276 *cs%energy_step), (units_from_atomic(unit_one/units_out%energy, spectrum(idir, istep)), idir = 1, space%dim+1)
277 end do
278
279 call io_close(iunit)
280
281 safe_deallocate_a(spectrum)
282 pop_sub(calc_broad)
283 end subroutine calc_broad
284
285end program casida_spectrum
286
287!! Local Variables:
288!! mode: f90
289!! coding: utf-8
290!! End:
subroutine calc_broad(cs, dir, fname, extracols)
program casida_spectrum
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
Definition: messages.F90:180
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
character(len= *), parameter, public casida_dir
Definition: global.F90:257
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
real(real64), parameter, public m_one
Definition: global.F90:188
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_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 messages_end()
Definition: messages.F90:277
subroutine, public messages_init(output_dir)
Definition: messages.F90:224
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, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
type(namespace_t), public global_namespace
Definition: namespace.F90:132
subroutine, public parser_init()
Initialise the Octopus parser.
Definition: parser.F90:450
subroutine, public parser_end()
End the Octopus parser.
Definition: parser.F90:481
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public profiling_end(namespace)
Definition: profiling.F90:413
subroutine, public profiling_init(namespace)
Create profiling subdirectory.
Definition: profiling.F90:255
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_init(namespace)
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
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:118
subroutine, public output_tensor(tensor, ndim, unit, write_average, iunit, namespace)
Definition: utils.F90:242
character pure function, public index2axis(idir)
Definition: utils.F90:202
int true(void)