| 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., 59 Temple Place - Suite 330, Boston, MA |
|---|
| 16 | !! 02111-1307, USA. |
|---|
| 17 | !! |
|---|
| 18 | !! $Id: kpoints.F90 5635 2009-06-25 14:55:35Z nitsche $ |
|---|
| 19 | |
|---|
| 20 | #include "global.h" |
|---|
| 21 | |
|---|
| 22 | module kpoints_m |
|---|
| 23 | use datasets_m |
|---|
| 24 | use geometry_m |
|---|
| 25 | use global_m |
|---|
| 26 | use loct_m |
|---|
| 27 | use parser_m |
|---|
| 28 | use messages_m |
|---|
| 29 | use profiling_m |
|---|
| 30 | use unit_m |
|---|
| 31 | use unit_system_m |
|---|
| 32 | |
|---|
| 33 | implicit none |
|---|
| 34 | |
|---|
| 35 | private |
|---|
| 36 | public :: & |
|---|
| 37 | kpoints_t, & |
|---|
| 38 | kpoints_init, & |
|---|
| 39 | kpoints_end, & |
|---|
| 40 | kpoints_copy |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | type kpoints_t |
|---|
| 44 | integer :: method |
|---|
| 45 | |
|---|
| 46 | integer :: nik_full ! number of k-points in full Brillouin zone |
|---|
| 47 | FLOAT, pointer :: points_full(:,:) ! k-points in absolute coordinates |
|---|
| 48 | FLOAT, pointer :: points_full_red(:,:) ! k-points in reduced coordinates |
|---|
| 49 | FLOAT, pointer :: weights_full(:) ! weights for the k-point integrations |
|---|
| 50 | |
|---|
| 51 | integer :: nik ! number of k-points in the irreducible zone |
|---|
| 52 | logical :: use_symmetries |
|---|
| 53 | logical :: use_inversion |
|---|
| 54 | |
|---|
| 55 | ! For the modified Monkhorst-Pack scheme |
|---|
| 56 | integer :: nik_axis(MAX_DIM) ! number of MP divisions |
|---|
| 57 | FLOAT :: shifts(MAX_DIM) ! |
|---|
| 58 | |
|---|
| 59 | end type kpoints_t |
|---|
| 60 | |
|---|
| 61 | integer, parameter :: & |
|---|
| 62 | KPOINTS_GAMMA = 1, & |
|---|
| 63 | KPOINTS_MONKH_PACK = 2, & |
|---|
| 64 | KPOINTS_USER = 3 |
|---|
| 65 | |
|---|
| 66 | contains |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | ! --------------------------------------------------------- |
|---|
| 70 | subroutine kpoints_init(this, dim, periodic_dim, rlattice, klattice, geo) |
|---|
| 71 | type(kpoints_t), intent(out) :: this |
|---|
| 72 | integer, intent(in) :: dim, periodic_dim |
|---|
| 73 | FLOAT, intent(in) :: rlattice(:,:), klattice(:,:) |
|---|
| 74 | type(geometry_t), intent(in) :: geo |
|---|
| 75 | |
|---|
| 76 | call push_sub('kpoints.kpoints_init') |
|---|
| 77 | |
|---|
| 78 | if(periodic_dim==0) then |
|---|
| 79 | this%method = KPOINTS_GAMMA |
|---|
| 80 | call read_MP(.true.) |
|---|
| 81 | call generate_MP() |
|---|
| 82 | else |
|---|
| 83 | if(read_user_kpoints()) then |
|---|
| 84 | this%method = KPOINTS_USER |
|---|
| 85 | else |
|---|
| 86 | this%method = KPOINTS_MONKH_PACK |
|---|
| 87 | call read_MP(.false.) |
|---|
| 88 | call generate_MP() |
|---|
| 89 | end if |
|---|
| 90 | end if |
|---|
| 91 | |
|---|
| 92 | call pop_sub() |
|---|
| 93 | |
|---|
| 94 | contains |
|---|
| 95 | ! --------------------------------------------------------- |
|---|
| 96 | subroutine read_MP(gamma_only) |
|---|
| 97 | logical, intent(in) :: gamma_only |
|---|
| 98 | |
|---|
| 99 | logical :: gamma_only_ |
|---|
| 100 | integer :: ii |
|---|
| 101 | type(block_t) :: blk |
|---|
| 102 | |
|---|
| 103 | call push_sub('kpoints.kpoints_init.read_MP') |
|---|
| 104 | |
|---|
| 105 | call messages_obsolete_variable('KPointsMonkhorstPack', 'KPointsGrid') |
|---|
| 106 | |
|---|
| 107 | !%Variable KPointsGrid |
|---|
| 108 | !%Type block |
|---|
| 109 | !%Default Gamma-point only |
|---|
| 110 | !%Section Mesh::KPoints |
|---|
| 111 | !%Description |
|---|
| 112 | !% When this block is given (and the <tt>KPoints</tt> block is not present), |
|---|
| 113 | !% <i>k</i>-points are distributed in a uniform grid. |
|---|
| 114 | !% |
|---|
| 115 | !% The first row of the block is a triplet of integers defining |
|---|
| 116 | !% the number of <i>k</i>-points to be used along each direction |
|---|
| 117 | !% in reciprocal space. The numbers refer to the whole Brillouin |
|---|
| 118 | !% zone, and the actual number of <i>k</i>-points is usually |
|---|
| 119 | !% reduced exploiting the symmetries of the system. By default |
|---|
| 120 | !% the grid will always include the Gamma point. An optional |
|---|
| 121 | !% second row can specify a shift in the <i>k</i>-points. |
|---|
| 122 | !% |
|---|
| 123 | !% For example, the following input samples the BZ with 100 points in the |
|---|
| 124 | !% <i>xy</i>-plane of reciprocal space: |
|---|
| 125 | !% |
|---|
| 126 | !% <tt>%KPointsGrid |
|---|
| 127 | !% <br> 10 | 10 | 1 |
|---|
| 128 | !% <br>%</tt> |
|---|
| 129 | !% |
|---|
| 130 | !%End |
|---|
| 131 | |
|---|
| 132 | gamma_only_ = gamma_only |
|---|
| 133 | if(.not.gamma_only_) gamma_only_ = (parse_block(datasets_check('KPointsGrid'), blk) .ne. 0) |
|---|
| 134 | |
|---|
| 135 | this%nik_axis(:) = 1 |
|---|
| 136 | this%shifts(:) = M_ZERO |
|---|
| 137 | |
|---|
| 138 | if(.not.gamma_only_) then |
|---|
| 139 | do ii = 1, periodic_dim |
|---|
| 140 | call parse_block_integer(blk, 0, ii-1, this%nik_axis(ii)) |
|---|
| 141 | end do |
|---|
| 142 | |
|---|
| 143 | if (any(this%nik_axis < 1)) then |
|---|
| 144 | message(1) = 'Input: KPointsGrid is not valid' |
|---|
| 145 | call write_fatal(1) |
|---|
| 146 | end if |
|---|
| 147 | |
|---|
| 148 | if(parse_block_n(blk) > 1) then ! we have a shift |
|---|
| 149 | do ii = 1, periodic_dim |
|---|
| 150 | call parse_block_float(blk, 1, ii-1, this%shifts(ii)) |
|---|
| 151 | end do |
|---|
| 152 | end if |
|---|
| 153 | |
|---|
| 154 | call parse_block_end(blk) |
|---|
| 155 | end if |
|---|
| 156 | |
|---|
| 157 | this%nik_full = product(this%nik_axis(:)) |
|---|
| 158 | |
|---|
| 159 | SAFE_ALLOCATE(this%points_full (1:MAX_DIM, 1:this%nik_full)) |
|---|
| 160 | SAFE_ALLOCATE(this%points_full_red(1:MAX_DIM, 1:this%nik_full)) |
|---|
| 161 | SAFE_ALLOCATE(this%weights_full(1:this%nik_full)) |
|---|
| 162 | |
|---|
| 163 | this%points_full(:,:) = M_ZERO |
|---|
| 164 | this%points_full_red(:,:) = M_ZERO |
|---|
| 165 | this%weights_full(:) = M_ONE / TOFLOAT(this%nik_full) |
|---|
| 166 | |
|---|
| 167 | call pop_sub() |
|---|
| 168 | end subroutine read_MP |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | ! --------------------------------------------------------- |
|---|
| 172 | subroutine generate_MP() |
|---|
| 173 | !generate k-points using the MP scheme |
|---|
| 174 | FLOAT :: dx(1:MAX_DIM) |
|---|
| 175 | integer :: ii, jj, kk, ix(1:MAX_DIM), idir, ikp, odd_shifts(1:MAX_DIM) |
|---|
| 176 | |
|---|
| 177 | call push_sub('kpoints.kpoints_init.generate_MP') |
|---|
| 178 | |
|---|
| 179 | dx(:) = M_ONE/TOFLOAT(2*this%nik_axis(:)) |
|---|
| 180 | odd_shifts(:) = M_ZERO |
|---|
| 181 | do idir = 1, periodic_dim |
|---|
| 182 | if(mod(this%nik_axis(idir), 2) == 1) odd_shifts(idir) = 1 |
|---|
| 183 | end do |
|---|
| 184 | |
|---|
| 185 | ikp = 0 |
|---|
| 186 | ix(:) = M_ZERO |
|---|
| 187 | do ii = 1, this%nik_axis(1) |
|---|
| 188 | do jj = 1, this%nik_axis(2) |
|---|
| 189 | do kk = 1, this%nik_axis(3) |
|---|
| 190 | ikp = ikp + 1 |
|---|
| 191 | ix(1:3) = (/ii, jj, kk/) |
|---|
| 192 | |
|---|
| 193 | do idir = 1, periodic_dim |
|---|
| 194 | this%points_full_red(idir, ikp) = TOFLOAT(2*ix(idir) - this%nik_axis(idir) - odd_shifts(idir)) |
|---|
| 195 | this%points_full_red(idir, ikp) = (this%points_full_red(idir, ikp) + M_TWO*this%shifts(idir))*dx(idir) |
|---|
| 196 | this%points_full_red(idir, ikp) = mod(this%points_full_red(idir, ikp) + M_HALF, M_ONE) - M_HALF |
|---|
| 197 | |
|---|
| 198 | end do |
|---|
| 199 | print *,this%points_full_red(: ,ikp) |
|---|
| 200 | end do |
|---|
| 201 | end do |
|---|
| 202 | end do |
|---|
| 203 | |
|---|
| 204 | call pop_sub() |
|---|
| 205 | |
|---|
| 206 | end subroutine generate_MP |
|---|
| 207 | |
|---|
| 208 | |
|---|
| 209 | ! --------------------------------------------------------- |
|---|
| 210 | logical function read_user_kpoints() |
|---|
| 211 | type(block_t) :: blk |
|---|
| 212 | logical :: reduced |
|---|
| 213 | integer :: ik, idim |
|---|
| 214 | |
|---|
| 215 | call push_sub('kpoints.kpoints_init.read_user_kpoints') |
|---|
| 216 | |
|---|
| 217 | !%Variable KPoints |
|---|
| 218 | !%Type block |
|---|
| 219 | !%Section Mesh::KPoints |
|---|
| 220 | !%Description |
|---|
| 221 | !% This block defines an explicit set of <i>k</i>-points and their weights for |
|---|
| 222 | !% a periodic-system calculation. The first column is the weight |
|---|
| 223 | !% of each <i>k</i>-point and the following are the components of the <i>k</i>-point |
|---|
| 224 | !% vector. You only need to specify the components for the |
|---|
| 225 | !% periodic directions. Note that the <i>k</i>-points should be given in |
|---|
| 226 | !% Cartesian coordinates (not in reduced coordinates), <i>i.e.</i> |
|---|
| 227 | !% what Octopus writes in a line in the ground-state standard output as |
|---|
| 228 | !% <tt>#k = 1, k = ( 0.154000, 0.154000, 0.154000)</tt>. |
|---|
| 229 | !% |
|---|
| 230 | !% For example, if you want to include only the Gamma point, you can |
|---|
| 231 | !% use: |
|---|
| 232 | !% |
|---|
| 233 | !% <tt>%KPoints |
|---|
| 234 | !% <br> 1.0 | 0 | 0 | 0 |
|---|
| 235 | !% <br>%</tt> |
|---|
| 236 | !% |
|---|
| 237 | !%End |
|---|
| 238 | |
|---|
| 239 | !%Variable KPointsReduced |
|---|
| 240 | !%Type block |
|---|
| 241 | !%Section Mesh::KPoints |
|---|
| 242 | !%Description |
|---|
| 243 | !% Same as the block <tt>KPoints</tt> but this time the input is given in reduced |
|---|
| 244 | !% coordinates. |
|---|
| 245 | !%End |
|---|
| 246 | |
|---|
| 247 | this%nik_full = 0 |
|---|
| 248 | reduced = .false. |
|---|
| 249 | if(parse_block(datasets_check('KPoints'), blk).ne.0) then |
|---|
| 250 | if(parse_block(datasets_check('KPointsReduced'), blk) == 0) then |
|---|
| 251 | reduced = .true. |
|---|
| 252 | else |
|---|
| 253 | read_user_kpoints = .false. |
|---|
| 254 | call pop_sub(); return |
|---|
| 255 | end if |
|---|
| 256 | end if |
|---|
| 257 | read_user_kpoints = .true. |
|---|
| 258 | |
|---|
| 259 | this%nik_full = parse_block_n(blk) |
|---|
| 260 | |
|---|
| 261 | SAFE_ALLOCATE(this%points_full(1:MAX_DIM, 1:this%nik_full)) |
|---|
| 262 | SAFE_ALLOCATE(this%points_full_red(1:MAX_DIM, 1:this%nik_full)) |
|---|
| 263 | SAFE_ALLOCATE(this%weights_full(1:this%nik_full)) |
|---|
| 264 | |
|---|
| 265 | this%points_full = M_ZERO |
|---|
| 266 | this%weights_full = M_ZERO |
|---|
| 267 | |
|---|
| 268 | if(reduced) then |
|---|
| 269 | do ik = 1, this%nik_full |
|---|
| 270 | call parse_block_float(blk, ik - 1, 0, this%weights_full(ik)) |
|---|
| 271 | do idim = 1, periodic_dim |
|---|
| 272 | call parse_block_float(blk, ik - 1, idim, this%points_full_red(idim, ik)) |
|---|
| 273 | end do |
|---|
| 274 | end do |
|---|
| 275 | |
|---|
| 276 | ! generate also the absolute coordinates |
|---|
| 277 | do ik = 1, this%nik_full |
|---|
| 278 | call kpoints_to_absolute(klattice, this%points_full_red(:,ik), this%points_full(:,ik)) |
|---|
| 279 | end do |
|---|
| 280 | else |
|---|
| 281 | do ik = 1, this%nik_full |
|---|
| 282 | call parse_block_float(blk, ik - 1, 0, this%weights_full(ik)) |
|---|
| 283 | do idim = 1, periodic_dim |
|---|
| 284 | call parse_block_float(blk, ik - 1, idim, this%points_full(idim, ik)) |
|---|
| 285 | end do |
|---|
| 286 | end do |
|---|
| 287 | |
|---|
| 288 | do ik = 1, this%nik_full |
|---|
| 289 | ! k-points have 1/length units |
|---|
| 290 | this%points_full(:, ik) = units_to_atomic(unit_one/units_inp%length, this%points_full(:, ik)) |
|---|
| 291 | |
|---|
| 292 | ! generate also the reduced coordinates |
|---|
| 293 | call kpoints_to_reduced(rlattice, this%points_full(:,ik), this%points_full_red(:,ik)) |
|---|
| 294 | end do |
|---|
| 295 | end if |
|---|
| 296 | call parse_block_end(blk) |
|---|
| 297 | |
|---|
| 298 | write(message(1), '(a,i4,a)') 'Input: ', this%nik_full, ' k-points were read from the input file' |
|---|
| 299 | call write_info(1) |
|---|
| 300 | |
|---|
| 301 | call pop_sub() |
|---|
| 302 | end function read_user_kpoints |
|---|
| 303 | |
|---|
| 304 | end subroutine kpoints_init |
|---|
| 305 | |
|---|
| 306 | |
|---|
| 307 | ! --------------------------------------------------------- |
|---|
| 308 | subroutine kpoints_end(this) |
|---|
| 309 | type(kpoints_t), intent(inout) :: this |
|---|
| 310 | |
|---|
| 311 | SAFE_DEALLOCATE_P(this%points_full) |
|---|
| 312 | SAFE_DEALLOCATE_P(this%points_full_red) |
|---|
| 313 | SAFE_DEALLOCATE_P(this%weights_full) |
|---|
| 314 | |
|---|
| 315 | end subroutine kpoints_end |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | ! --------------------------------------------------------- |
|---|
| 319 | subroutine kpoints_to_absolute(klattice, kin, kout) |
|---|
| 320 | FLOAT, intent(in) :: klattice(:,:), kin(:) |
|---|
| 321 | FLOAT, intent(out) :: kout(:) |
|---|
| 322 | |
|---|
| 323 | integer :: ii |
|---|
| 324 | |
|---|
| 325 | call push_sub('kpoints.kpoints_to_absolute') |
|---|
| 326 | |
|---|
| 327 | kout(:) = M_ZERO |
|---|
| 328 | do ii = 1, MAX_DIM |
|---|
| 329 | kout(:) = kout(:) + kin(ii)*klattice(:, ii) |
|---|
| 330 | end do |
|---|
| 331 | |
|---|
| 332 | call pop_sub() |
|---|
| 333 | |
|---|
| 334 | end subroutine kpoints_to_absolute |
|---|
| 335 | |
|---|
| 336 | |
|---|
| 337 | ! --------------------------------------------------------- |
|---|
| 338 | subroutine kpoints_to_reduced(rlattice, kin, kout) |
|---|
| 339 | FLOAT, intent(in) :: rlattice(:,:) |
|---|
| 340 | FLOAT, intent(in) :: kin(:) |
|---|
| 341 | FLOAT, intent(out) :: kout(:) |
|---|
| 342 | |
|---|
| 343 | integer :: ii |
|---|
| 344 | |
|---|
| 345 | call push_sub('kpoints.kpoints_to_reduced') |
|---|
| 346 | |
|---|
| 347 | kout(:) = M_ZERO |
|---|
| 348 | do ii = 1, MAX_DIM |
|---|
| 349 | kout(:) = kout(:) + kin(ii)*rlattice(ii, :) |
|---|
| 350 | end do |
|---|
| 351 | kout(:) = kout(:) / (M_TWO*M_PI) |
|---|
| 352 | |
|---|
| 353 | call pop_sub() |
|---|
| 354 | end subroutine kpoints_to_reduced |
|---|
| 355 | |
|---|
| 356 | |
|---|
| 357 | ! --------------------------------------------------------- |
|---|
| 358 | subroutine kpoints_copy(kout, kin) |
|---|
| 359 | type(kpoints_t), intent(out) :: kout |
|---|
| 360 | type(kpoints_t), intent(in) :: kin |
|---|
| 361 | |
|---|
| 362 | call push_sub('kpoints.kpoints_copy') |
|---|
| 363 | |
|---|
| 364 | kout%method = kin%method |
|---|
| 365 | kout%nik_full = kin%nik_full |
|---|
| 366 | call loct_pointer_copy(kout%points_full, kin%points_full) |
|---|
| 367 | call loct_pointer_copy(kout%points_full_red, kin%points_full_red) |
|---|
| 368 | call loct_pointer_copy(kout%weights_full, kin%weights_full) |
|---|
| 369 | |
|---|
| 370 | kout%nik = kin%nik |
|---|
| 371 | kout%use_symmetries = kin%use_symmetries |
|---|
| 372 | kout%use_inversion = kin%use_inversion |
|---|
| 373 | |
|---|
| 374 | kout%nik_axis = kin%nik_axis |
|---|
| 375 | kout%shifts = kin%shifts |
|---|
| 376 | |
|---|
| 377 | call pop_sub() |
|---|
| 378 | end subroutine kpoints_copy |
|---|
| 379 | |
|---|
| 380 | end module kpoints_m |
|---|
| 381 | |
|---|
| 382 | !! Local Variables: |
|---|
| 383 | !! mode: f90 |
|---|
| 384 | !! coding: utf-8 |
|---|
| 385 | !! End: |
|---|