Octopus
vdw.F90
Go to the documentation of this file.
1!! Copyright (C) 2006 Hyllios
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 vdw_oct_m
22 use debug_oct_m
25 use global_oct_m
26 use grid_oct_m
28 use io_oct_m
29 use, intrinsic :: iso_fortran_env
31 use mesh_oct_m
33 use mpi_oct_m
35 use parser_oct_m
39 use space_oct_m
44 use unit_oct_m
46 use utils_oct_m
47 use v_ks_oct_m
48
49 implicit none
50
51 private
52 public :: &
54
55contains
56
57 ! ---------------------------------------------------------
58 subroutine vdw_run(system, from_scratch)
59 class(*), intent(inout) :: system
60 logical, intent(in) :: from_scratch
61
62 push_sub(vdw_run)
63
64 select type (system)
65 class is (multisystem_basic_t)
66 message(1) = "CalculationMode = vdw not implemented for multi-system calculations"
67 call messages_fatal(1, namespace=system%namespace)
68 type is (electrons_t)
69 call vdw_run_legacy(system, from_scratch)
70 end select
71
72 pop_sub(vdw_run)
73 end subroutine vdw_run
74
75 ! ---------------------------------------------------------
76 subroutine vdw_run_legacy(sys, fromScratch)
77 type(electrons_t), intent(inout) :: sys
78 logical, intent(in) :: fromScratch
79
80 type(lr_t) :: lr(sys%space%dim, 1)
81 type(sternheimer_t) :: sh
82
83 integer :: dir, i, iunit, gauss_start, ndir
84 complex(real64) :: omega
85 real(real64) :: domega, pol, c3, c6, cat
86
87 integer :: gaus_leg_n
88 real(real64), allocatable :: gaus_leg_points(:), gaus_leg_weights(:)
89 real(real64), parameter :: omega0 = 0.3_real64
90
91 type(restart_t) :: restart_dump
92
93 push_sub(vdw_run_legacy)
94
95 if (sys%hm%pcm%run_pcm) then
96 call messages_not_implemented("PCM for CalculationMode /= gs or td", namespace=sys%namespace)
97 end if
98
99 if (sys%space%is_periodic()) then
100 call messages_not_implemented('Van der Waals calculation for periodic system', namespace=sys%namespace)
101 end if
102
103 if (sys%kpoints%use_symmetries) call messages_experimental("KPoints symmetries with CalculationMode = vdw", &
104 namespace=sys%namespace)
105
106 call input()
107 call init_()
108 call sternheimer_init(sh, sys%namespace, sys%space, sys%gr, sys%st, sys%hm, sys%ks%xc, sys%mc, wfs_are_cplx = .true.)
109
110 if (gauss_start == 1 .and. mpi_grp_is_root(mpi_world)) then
111 iunit = io_open(vdw_dir//'vdw_c6', sys%namespace, action='write')
112 write(iunit, '(a,i3)') '# npoints = ', gaus_leg_n
113 write(iunit, '(a1,a12,2a20)') '#', 'omega', 'domega', 'pol'
114 call io_close(iunit)
115 end if
116
117 do i = gauss_start, gaus_leg_n
118 omega = m_zi*omega0*(m_one - gaus_leg_points(i))/(m_one + gaus_leg_points(i))
119 domega = gaus_leg_weights(i) * omega0 * (m_two)/(m_one + gaus_leg_points(i))**2
120
121 pol = get_pol(omega)
122 if (mpi_grp_is_root(mpi_world)) then
123 iunit = io_open(vdw_dir//'vdw_c6', sys%namespace, action='write', position='append')
124 write(iunit, '(3es20.12)') aimag(omega), domega, pol
125 call io_close(iunit)
126 end if
127
128 c3 = c3 + m_three/m_pi * domega * pol
129 c6 = c6 + m_three/m_pi * domega * pol**2
130 cat = cat + m_three/m_pi * domega * pol**3
131 end do
132
133 if ((gauss_start <= gaus_leg_n).and.mpi_grp_is_root(mpi_world)) then
134 iunit = io_open(vdw_dir//'vdw_c6', sys%namespace, action='write', position='append')
135 write(iunit, '(1x)')
136 write(iunit, '(a,es20.12)') "C_3 [a.u. ] = ", c3
137 write(iunit, '(a,es20.12)') "C_6 [a.u. ] = ", c6
138 write(iunit, '(a,es20.12)') "C_AT [a.u. ] = ", cat
139 write(iunit, '(1x)')
140
141 write(iunit, '(3a,es20.12)') "C_3 [", &
142 trim(units_abbrev(units_out%energy * units_out%length**sys%space%dim)), "] = ", &
143 units_from_atomic(units_out%energy * units_out%length**sys%space%dim, c3)
144 write(iunit, '(3a,es20.12)') "C_6 [", &
145 trim(units_abbrev(units_out%energy * units_out%length**(2*sys%space%dim))), "] = ", &
146 units_from_atomic(units_out%energy * units_out%length**(2*sys%space%dim), c6)
147 write(iunit, '(3a,es20.12)') "C_AT [", &
148 trim(units_abbrev(units_out%energy * units_out%length**(3*sys%space%dim))), "] = ", &
149 units_from_atomic(units_out%energy * units_out%length**(3*sys%space%dim), cat)
150
151 call io_close(iunit)
152 end if
153
154 call sternheimer_end(sh)
155 call end_()
156
157 pop_sub(vdw_run_legacy)
158 contains
159
160 ! --------------------------------------------------------------------
161 subroutine input()
162 integer :: equiv_axes
163
164 push_sub(vdw_run_legacy.input)
165
166 !%Variable vdWNPoints
167 !%Type integer
168 !%Default 6
169 !%Section Linear Response::Polarizabilities
170 !%Description
171 !% How many points to use in the Gauss-Legendre integration to obtain the
172 !% van der Waals coefficients.
173 !%End
174 call messages_obsolete_variable(sys%namespace, 'vdW_npoints', 'vdWNPoints')
175 call parse_variable(sys%namespace, 'vdWNPoints', 6, gaus_leg_n)
176
177 ! \todo symmetry stuff should be general
178 call parse_variable(sys%namespace, 'TDPolarizationEquivAxes', 0, equiv_axes)
179
180 select case (equiv_axes)
181 case (3)
182 ndir = 1
183 case (2)
184 ndir = min(2, sys%space%dim)
185 case default
186 ndir = min(3, sys%space%dim)
187 end select
188
189 pop_sub(vdw_run_legacy.input)
190 end subroutine input
191
192
193 ! --------------------------------------------------------------------
194 subroutine init_()
195 integer :: ierr, iunit, ii
196 logical :: file_exists
197 character(len=80) :: dirname
198 real(real64) :: iomega, domega, pol
199
200 type(restart_t) :: restart_load, gs_restart
201
202 push_sub(vdw_run_legacy.init_)
203
204 ! make some space for static polarizability
205 gaus_leg_n = gaus_leg_n + 1
206
207 ! get Gauss-Legendre points
208 safe_allocate(gaus_leg_points(1:gaus_leg_n))
209 safe_allocate(gaus_leg_weights(1:gaus_leg_n))
210
211 call gauss_legendre_points(gaus_leg_n-1, gaus_leg_points, gaus_leg_weights)
212 c3 = m_zero
213 c6 = m_zero
214 cat = m_zero
215 gauss_start = 1
216 gaus_leg_points(gaus_leg_n) = 0.99999_real64
217 gaus_leg_weights(gaus_leg_n) = m_zero
218
219 ! FIXME: this should be part of the restart framework
220 ! check if we can restart
221 inquire(file=vdw_dir//'vdw_c6', exist=file_exists)
222 if (.not. fromscratch .and. file_exists) then
223 iunit = io_open(vdw_dir//'vdw_c6', sys%namespace, action='read')
224 read(iunit, '(a12,i3)', iostat=ierr) dirname, ii
225 if (ii /= gaus_leg_n) then
226 message(1) = "Invalid restart of van der Waals calculation."
227 message(2) = "The number of points in the Gauss-Legendre integration changed."
228 write(message(3), '(i3,a,i3,a)') gaus_leg_n, " (input) != ", ii, "(restart)"
229 call messages_fatal(3, namespace=sys%namespace)
230 end if
231 read(iunit,*) ! skip comment line
232 do
233 read(iunit, *, iostat=ierr) iomega, domega, pol
234 if (ierr /= 0) exit
235 gauss_start = gauss_start + 1
236 c3 = c3 + m_three/m_pi * domega * pol
237 c6 = c6 + m_three/m_pi * domega * pol**2
238 cat = cat + m_three/m_pi * domega * pol**3
239 end do
240 call io_close(iunit)
241 end if
242
243 ! we always need complex response
244 call restart_init(gs_restart, sys%namespace, restart_gs, restart_type_load, sys%mc, ierr, mesh=sys%gr, exact=.true.)
245 if (ierr == 0) then
246 call states_elec_look_and_load(gs_restart, sys%namespace, sys%space, sys%st, sys%gr, sys%kpoints, &
247 is_complex = .true.)
248 call restart_end(gs_restart)
249 else
250 message(1) = "Previous gs calculation required."
251 call messages_fatal(1, namespace=sys%namespace)
252 end if
253
254 ! setup Hamiltonian
255 message(1) = 'Info: Setting up Hamiltonian for linear response.'
256 call messages_info(1, namespace=sys%namespace)
257 call v_ks_h_setup(sys%namespace, sys%space, sys%gr, sys%ions, sys%ext_partners, sys%st, sys%ks, sys%hm)
258
259 do dir = 1, ndir
260 call lr_init(lr(dir,1))
261 call lr_allocate(lr(dir,1), sys%st, sys%gr)
262 end do
263
264 ! load wavefunctions
265 if (.not. fromscratch) then
266 call restart_init(restart_load, sys%namespace, restart_vdw, restart_type_load, sys%mc, ierr, mesh=sys%gr)
267
268 do dir = 1, ndir
269 write(dirname,'(a,i1,a)') "wfs_", dir, "_1_1"
270 call restart_open_dir(restart_load, dirname, ierr)
271 if (ierr == 0) then
272 call states_elec_load(restart_load, sys%namespace, sys%space, sys%st, sys%gr, sys%kpoints, ierr, lr=lr(dir,1))
273 end if
274 if (ierr /= 0) then
275 message(1) = "Unable to read response wavefunctions from '"//trim(dirname)//"'."
276 call messages_warning(1, namespace=sys%namespace)
277 end if
278 call restart_close_dir(restart_load)
279 end do
280
281 call restart_end(restart_load)
282 end if
283
284 if (mpi_grp_is_root(mpi_world)) then
285 call io_mkdir(vdw_dir, sys%namespace) ! output data
286 end if
288 call restart_init(restart_dump, sys%namespace, restart_vdw, restart_type_dump, sys%mc, ierr, mesh=sys%gr)
289
290 pop_sub(vdw_run_legacy.init_)
291 end subroutine init_
292
293 ! --------------------------------------------------------------------
294 subroutine end_()
295 integer :: dir
296
297 push_sub(vdw_run_legacy.end_)
298
299 safe_deallocate_a(gaus_leg_points)
300 safe_deallocate_a(gaus_leg_weights)
301
302 do dir = 1, ndir
303 call lr_dealloc(lr(dir, 1))
304 end do
305
306 call restart_end(restart_dump)
307
308 pop_sub(vdw_run_legacy.end_)
309 end subroutine end_
310
311
312 ! --------------------------------------------------------------------
313 real(real64) function get_pol(omega)
314 complex(real64), intent(in) :: omega
315
316 complex(real64) :: alpha(1:sys%space%dim, 1:sys%space%dim)
317 type(perturbation_electric_t), pointer :: pert
318
319 push_sub(vdw_run_legacy.get_pol)
320
321 pert => perturbation_electric_t(sys%namespace)
322 do dir = 1, ndir
323 write(message(1), '(3a,f7.3)') 'Info: Calculating response for the ', index2axis(dir), &
324 '-direction and imaginary frequency ', units_from_atomic(units_out%energy, aimag(omega))
325 call messages_info(1, namespace=sys%namespace)
326
327 call pert%setup_dir(dir)
328 call zsternheimer_solve(sh, sys%namespace, sys%space, sys%gr, sys%kpoints, sys%st, sys%hm, sys%mc, &
329 lr(dir, :), 1, omega, pert, restart_dump, em_rho_tag(real(omega, real64) ,dir), em_wfs_tag(dir,1))
330 end do
331
332 call zcalc_polarizability_finite(sys%namespace, sys%space, sys%gr, sys%st, sys%hm, lr(:,:), 1, pert, &
333 alpha(:,:), ndir = ndir)
334
335 get_pol = m_zero
336 do dir = 1, ndir
337 get_pol = get_pol + real(alpha(dir, dir), real64)
338 end do
339 do dir = ndir+1, sys%space%dim
340 get_pol = get_pol + real(alpha(ndir, ndir), real64)
341 end do
342
343 get_pol = get_pol / real(sys%space%dim, real64)
344
345 safe_deallocate_p(pert)
346 pop_sub(vdw_run_legacy.get_pol)
347 end function get_pol
348
349 end subroutine vdw_run_legacy
350
351end module vdw_oct_m
352
353!! Local Variables:
354!! mode: f90
355!! coding: utf-8
356!! End:
subroutine init_(fromscratch)
Definition: geom_opt.F90:354
subroutine end_()
Definition: geom_opt.F90:804
character(len=100) function, public em_wfs_tag(idir, ifactor, idir2, ipert)
character(len=100) function, public em_rho_tag(freq, dir, dir2, ipert)
subroutine, public zcalc_polarizability_finite(namespace, space, gr, st, hm, lr, nsigma, pert, zpol, doalldirs, ndir)
alpha_ij(w) = - sum(m occ) [<psi_m(0)|r_i|psi_mj(1)(w)> + <psi_mj(1)(-w)|r_i|psi_m(0)>] minus sign is...
subroutine, public gauss_legendre_points(n, points, weights)
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public m_one
Definition: global.F90:188
real(real64), parameter, public m_three
Definition: global.F90:190
character(len= *), parameter, public vdw_dir
Definition: global.F90:256
This module implements the underlying real-space grid.
Definition: grid.F90:117
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:354
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
subroutine, public lr_allocate(lr, st, mesh, allocate_rho)
subroutine, public lr_init(lr)
subroutine, public lr_dealloc(lr)
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
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_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1057
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_experimental(name, namespace)
Definition: messages.F90:1097
logical function mpi_grp_is_root(grp)
Is the current MPI process of grpcomm, root.
Definition: mpi.F90:430
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:266
This module implements the basic mulsisystem class, a container system for other systems.
integer, parameter, public restart_gs
Definition: restart.F90:229
subroutine, public restart_init(restart, namespace, data_type, type, mc, ierr, mesh, dir, exact)
Initializes a restart object.
Definition: restart.F90:514
integer, parameter, public restart_type_dump
Definition: restart.F90:225
subroutine, public restart_open_dir(restart, dirname, ierr)
Change the restart directory to dirname, where "dirname" is a subdirectory of the base restart direct...
Definition: restart.F90:770
integer, parameter, public restart_type_load
Definition: restart.F90:225
integer, parameter, public restart_vdw
Definition: restart.F90:229
subroutine, public restart_end(restart)
Definition: restart.F90:720
subroutine, public restart_close_dir(restart)
Change back to the base directory. To be called after restart_open_dir.
Definition: restart.F90:804
This module handles reading and writing restart information for the states_elec_t.
subroutine, public states_elec_look_and_load(restart, namespace, space, st, mesh, kpoints, is_complex, packed)
subroutine, public states_elec_load(restart, namespace, space, st, mesh, kpoints, ierr, iter, lr, lowest_missing, label, verbose, skip)
returns in ierr: <0 => Fatal error, or nothing read =0 => read all wavefunctions >0 => could only rea...
subroutine, public sternheimer_init(this, namespace, space, gr, st, hm, xc, mc, wfs_are_cplx, set_ham_var, set_occ_response, set_last_occ_response, occ_response_by_sternheimer)
subroutine, public zsternheimer_solve(this, namespace, space, gr, kpoints, st, hm, mc, lr, nsigma, omega, perturbation, restart, rho_tag, wfs_tag, idir, have_restart_rho, have_exact_freq)
This routine calculates the first-order variations of the wavefunctions for an applied perturbation.
subroutine, public sternheimer_end(this)
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
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:118
character pure function, public index2axis(idir)
Definition: utils.F90:202
subroutine, public v_ks_h_setup(namespace, space, gr, ions, ext_partners, st, ks, hm, calc_eigenval, calc_current)
Definition: v_ks.F90:679
subroutine vdw_run_legacy(sys, fromScratch)
Definition: vdw.F90:170
subroutine, public vdw_run(system, from_scratch)
Definition: vdw.F90:152
Class describing the electron system.
Definition: electrons.F90:214
Container class for lists of system_oct_m::system_t.
int true(void)
real(real64) function get_pol(omega)
Definition: vdw.F90:407
subroutine input()
Definition: vdw.F90:255