Line data Source code
1 : !!****m* ABINIT/m_tetrahedron
2 : !! NAME
3 : !! m_tetrahedron
4 : !!
5 : !! FUNCTION
6 : !! module for tetrahedron interpolation of DOS and similar quantities
7 : !! depends on sort_tetra and on m_kpt_rank
8 : !!
9 : !! COPYRIGHT
10 : !! Copyright (C) 2010-2026 ABINIT group (MJV)
11 : !! This file is distributed under the terms of the
12 : !! GNU General Public License, see ~abinit/COPYING
13 : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : !!
15 : !! TODO
16 : !! 1) Test carefully the case of degenerate tetrahedron
17 : !! 2) Change API so that we can pass the energy mesh instead of omega_min and omega_max
18 : !! 3) Add table ik_ibz --> tetra_list to avoid cycling inside big loop over ntetra
19 : !! 4) Add options to get only delta and/or theta ?
20 : !!
21 : !! SOURCE
22 :
23 : #if defined HAVE_CONFIG_H
24 : #include "config.h"
25 : #endif
26 :
27 : #include "libtetra.h"
28 :
29 : module m_tetrahedron
30 :
31 : ! make sure stdout is defined, as libtetra.h needs it
32 : use, intrinsic :: iso_fortran_env, only : stdin=>input_unit, &
33 : stdout=>output_unit, &
34 : stderr=>error_unit
35 : USE_MEMORY_PROFILING
36 : USE_MSG_HANDLING
37 : use m_krank
38 : USE_MPI
39 : #ifdef HAVE_LIBTETRA_ABINIT
40 : use m_io_tools, only : open_file
41 : use m_xmpi
42 : use defs_basis, only : dp, zero, one, tol14, pi
43 : #elif
44 : integer, parameter :: dp = kind(1.0d0)
45 : real(dp), parameter :: tol14 = 1.d-14, zero = 0.d0, one = 1.d0
46 : real(dp), parameter :: pi=3.141592653589793238462643383279502884197_dp
47 : #endif
48 :
49 : implicit none
50 :
51 : #if defined HAVE_MPI1
52 : include 'mpif.h'
53 : #endif
54 :
55 : private
56 : !!***
57 :
58 : !!****t* m_tetrahedron/t_tetrahedron
59 : !! NAME
60 : !! t_tetrahedron
61 : !!
62 : !! FUNCTION
63 : !! tetrahedron geometry object
64 : !!
65 : !! SOURCE
66 :
67 : type, public :: t_tetrahedron
68 :
69 : integer :: ntetra = 0
70 : ! Number of tetrahedra
71 :
72 : real(dp) :: vv
73 : ! volume of the tetrahedra
74 :
75 : real(dp) :: klatt(3, 3)
76 : ! reciprocal of lattice vectors for full kpoint grid
77 :
78 : integer,allocatable :: tetra_full(:,:,:)
79 : !(4,2,ntetra)
80 : ! For each tetra
81 : ! (:,1,itetra) indices of the vertex in IBZ (symmetrical image)
82 : ! (:,2,itetra) indices of the vertexes in the BZ
83 :
84 : integer,allocatable :: tetra_mult(:)
85 : !(ntetra)
86 : ! multiplicity of each irred tetrahedron
87 :
88 : integer,allocatable :: tetra_wrap(:,:,:)
89 : !(3,4,ntetra)
90 : ! flag to wrap tetrahedron summit into IBZ
91 :
92 : integer,allocatable :: ibz_tetra_count(:)
93 : ! ibz_tetra_mapping(nkpt_ibz)
94 : ! Number of tetrahedra associated to a point in the IBZ.
95 :
96 : integer,allocatable :: ibz_tetra_mapping(:,:)
97 : ! ibz_tetra_mapping(nkpt_ibz, maxval(tetra%ibz_tetra_count)))
98 : ! map ikbz to tetra index.
99 :
100 : end type t_tetrahedron
101 :
102 : public :: init_tetra ! Initialize the object
103 : ! See also the high-level interface tetra_from_kptrlatt provided by m_kpts.
104 : public :: get_tetra_weight ! Calculate integration weights and their derivatives. shape (nkpt, nene).
105 : public :: tetra_blochl_weights ! Same as in get_tetra_weight but weights have shape (nene, nkpt).
106 : public :: get_dbl_tetra_weight ! Calculate integration weights for double tetrahedron integration of delta functions.
107 : ! (NB these correspond to the derivative terms in normal tetrahedron).
108 : public :: destroy_tetra ! Free memory.
109 : public :: tetra_write ! Write text file (XML format) with tetra info.
110 : public :: tetralib_has_mpi ! Return True if the library has been compiled with MPI support.
111 : public :: tetra_get_onewk ! Calculate integration weights and their derivatives for a single k-point in the IBZ.
112 : public :: tetra_get_onewk_wvals ! Similar to tetra_get_onewk_wvalsa but receives arbitrary list of frequency points.
113 : public :: tetra_get_onetetra_wvals ! Get weights for one tetrahedra with arbitrary list of frequency points
114 : !!***
115 :
116 : contains
117 : !!***
118 :
119 : !----------------------------------------------------------------------
120 :
121 : !!****f* m_tetrahedron/destroy_tetra
122 : !! NAME
123 : !! destroy_tetra
124 : !!
125 : !! FUNCTION
126 : !! deallocate tetrahedra pointers if needed
127 : !!
128 : !! SOURCE
129 :
130 11 : subroutine destroy_tetra (tetra)
131 :
132 : type(t_tetrahedron), intent(inout) :: tetra
133 :
134 11 : if (allocated(tetra%tetra_full)) then
135 4 : TETRA_DEALLOCATE(tetra%tetra_full)
136 : end if
137 11 : if (allocated(tetra%tetra_mult)) then
138 4 : TETRA_DEALLOCATE(tetra%tetra_mult)
139 : end if
140 11 : if (allocated(tetra%tetra_wrap)) then
141 4 : TETRA_DEALLOCATE(tetra%tetra_wrap)
142 : end if
143 11 : if (allocated(tetra%ibz_tetra_count)) then
144 4 : TETRA_DEALLOCATE(tetra%ibz_tetra_count)
145 : end if
146 11 : if (allocated(tetra%ibz_tetra_mapping)) then
147 4 : TETRA_DEALLOCATE(tetra%ibz_tetra_mapping)
148 : end if
149 :
150 11 : end subroutine destroy_tetra
151 : !!***
152 :
153 : !----------------------------------------------------------------------
154 :
155 : !!****f* m_tetrahedron/init_tetra
156 : !! NAME
157 : !! init_tetra
158 : !!
159 : !! FUNCTION
160 : !! get tetrahedra characterized by apexes
161 : !!
162 : !! INPUTS
163 : !! indkpt(nkpt_fullbz)=indexes of irred kpoints equivalent to kpt_fullbz
164 : !! gprimd(3,3) = reciprocal space vectors
165 : !! klatt(3,3)=reciprocal of lattice vectors for full kpoint grid
166 : !! kpt_fullbz(3,nkpt_fullbz)=kpoints in full brillouin zone
167 : !! nkpt_fullbz=number of kpoints in full brillouin zone
168 : !! comm= MPI communicator
169 : !!
170 : !! OUTPUT
171 : !! tetra%tetra_full(4,2,ntetra)=for each tetrahedron,
172 : !! the different instances of the tetrahedron (fullbz kpoints)
173 : !! tetra%tetra_mult(ntetra) = store multiplicity of each irred tetrahedron
174 : !! tetra%tetra_wrap(3,4,ntetra) = store flag to wrap tetrahedron summit into IBZ
175 : !! tetra%ntetra = final number of irred tetra (dimensions of tetra_* remain larger)
176 : !! tetra%vv = tetrahedron volume divided by full BZ volume
177 : !!
178 : !! SOURCE
179 :
180 4 : subroutine init_tetra(indkpt, gprimd, klatt, kpt_fullbz, nkpt_fullbz, tetra, ierr, errorstring, comm)
181 :
182 : !Arguments ------------------------------------
183 : !scalars
184 : integer,intent(in) :: nkpt_fullbz, comm
185 : integer, intent(out) :: ierr
186 : character(len=80), intent(out) :: errorstring
187 : type(t_tetrahedron),intent(out) :: tetra
188 : !arrays
189 : integer,intent(in) :: indkpt(nkpt_fullbz)
190 : real(dp) ,intent(in) :: gprimd(3,3),klatt(3,3),kpt_fullbz(3,nkpt_fullbz)
191 :
192 : !Local variables-------------------------------
193 : !scalars
194 : integer :: ialltetra,ikpt2,ikpt_full,isummit,itetra,jalltetra,jsummit
195 : integer :: ii,jj,ikibz,nkpt_ibz, my_rank, nprocs
196 : integer :: symrankkpt,mtetra,itmp,ntetra_irred
197 : real(dp) :: shift1,shift2,shift3, rcvol,hashfactor
198 : !real :: cpu_start, cpu_stop
199 4 : type(krank_t) :: krank
200 : !arrays
201 : integer :: ind_ibz(4), tetra_shifts(3,4,6) ! 3 dimensions, 4 summits, and 6 tetrahedra / kpoint box
202 : real(dp) :: k1(3),k2(3),k3(3)
203 4 : integer,allocatable :: tetra_full_(:,:,:)
204 4 : integer,allocatable :: tetra_mult_(:)
205 4 : integer,allocatable :: tetra_wrap_(:,:,:)
206 4 : integer, allocatable :: reforder(:)
207 4 : integer, allocatable :: irred_itetra(:)
208 4 : real(dp), allocatable :: tetra_hash(:)
209 :
210 : ! *********************************************************************
211 :
212 : !call cpu_time(cpu_start)
213 :
214 4 : my_rank = 0; nprocs = 1
215 : #ifdef HAVE_LIBTETRA_ABINIT
216 4 : my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
217 : #endif
218 :
219 4 : ierr = 0
220 4 : errorstring = ""
221 : !jmb
222 4 : shift1 = zero
223 4 : shift2 = zero
224 4 : shift3 = zero
225 :
226 52 : tetra%klatt = klatt
227 :
228 4 : mtetra = 6 * nkpt_fullbz
229 12 : TETRA_ALLOCATE(tetra_full_, (4,2,mtetra))
230 12 : TETRA_ALLOCATE(tetra_mult_, (mtetra))
231 12 : TETRA_ALLOCATE(tetra_wrap_, (3,4,mtetra))
232 :
233 5188 : tetra_mult_ = 1
234 57028 : tetra_full_ = 0
235 88132 : tetra_wrap_ = 0
236 :
237 : ! tetra_shifts(:,1,1) = (/0,0,0/)
238 : ! tetra_shifts(:,2,1) = (/0,1,0/)
239 : ! tetra_shifts(:,3,1) = (/0,1,1/)
240 : ! tetra_shifts(:,4,1) = (/1,1,0/)
241 : ! tetra_shifts(:,1,2) = (/0,0,0/)
242 : ! tetra_shifts(:,2,2) = (/0,1,1/)
243 : ! tetra_shifts(:,3,2) = (/1,1,0/)
244 : ! tetra_shifts(:,4,2) = (/1,1,1/)
245 : ! tetra_shifts(:,1,3) = (/0,0,0/)
246 : ! tetra_shifts(:,2,3) = (/1,0,0/)
247 : ! tetra_shifts(:,3,3) = (/1,1,0/)
248 : ! tetra_shifts(:,4,3) = (/1,1,1/)
249 : ! tetra_shifts(:,1,4) = (/0,0,0/)
250 : ! tetra_shifts(:,2,4) = (/0,0,1/)
251 : ! tetra_shifts(:,3,4) = (/1,0,0/)
252 : ! tetra_shifts(:,4,4) = (/1,1,1/)
253 : ! tetra_shifts(:,1,5) = (/0,0,1/)
254 : ! tetra_shifts(:,2,5) = (/1,0,0/)
255 : ! tetra_shifts(:,3,5) = (/1,0,1/)
256 : ! tetra_shifts(:,4,5) = (/1,1,1/)
257 : ! tetra_shifts(:,1,6) = (/0,0,0/)
258 : ! tetra_shifts(:,2,6) = (/0,0,1/)
259 : ! tetra_shifts(:,3,6) = (/0,1,1/)
260 : ! tetra_shifts(:,4,6) = (/1,1,1/)
261 :
262 : ! bxu, the following division scheme is according to Bloechl's paper
263 16 : tetra_shifts(:,1,1) = (/0,0,0/)
264 16 : tetra_shifts(:,2,1) = (/1,0,0/)
265 16 : tetra_shifts(:,3,1) = (/0,1,0/)
266 16 : tetra_shifts(:,4,1) = (/1,0,1/)
267 16 : tetra_shifts(:,1,2) = (/1,0,0/)
268 16 : tetra_shifts(:,2,2) = (/1,1,0/)
269 16 : tetra_shifts(:,3,2) = (/0,1,0/)
270 16 : tetra_shifts(:,4,2) = (/1,0,1/)
271 16 : tetra_shifts(:,1,3) = (/0,1,0/)
272 16 : tetra_shifts(:,2,3) = (/1,1,0/)
273 16 : tetra_shifts(:,3,3) = (/1,0,1/)
274 16 : tetra_shifts(:,4,3) = (/1,1,1/)
275 16 : tetra_shifts(:,1,4) = (/0,0,0/)
276 16 : tetra_shifts(:,2,4) = (/0,1,0/)
277 16 : tetra_shifts(:,3,4) = (/0,0,1/)
278 16 : tetra_shifts(:,4,4) = (/1,0,1/)
279 16 : tetra_shifts(:,1,5) = (/0,0,1/)
280 16 : tetra_shifts(:,2,5) = (/1,0,1/)
281 16 : tetra_shifts(:,3,5) = (/0,1,0/)
282 16 : tetra_shifts(:,4,5) = (/0,1,1/)
283 16 : tetra_shifts(:,1,6) = (/0,1,0/)
284 16 : tetra_shifts(:,2,6) = (/1,0,1/)
285 16 : tetra_shifts(:,3,6) = (/0,1,1/)
286 16 : tetra_shifts(:,4,6) = (/1,1,1/)
287 :
288 : ! Make full k-point rank arrays
289 : ! TODO: Lot of memory allocated here if dense mesh e.g ~ 300 ** 3
290 4 : call krank%init(nkpt_fullbz, kpt_fullbz)
291 :
292 4 : ialltetra = 1
293 868 : do ikpt_full=1,nkpt_fullbz
294 6052 : do itetra=1,6
295 : !ialltetra = itetra + (ikpt_full -1) * 6
296 : !if (mod(ialltetra, nprocs) /= my_rank) cycle ! MPI parallelism.
297 25920 : do isummit=1,4
298 : k1(:) = kpt_fullbz(:,ikpt_full) &
299 : + tetra_shifts(1,isummit,itetra)*klatt(:,1) &
300 : + tetra_shifts(2,isummit,itetra)*klatt(:,2) &
301 82944 : + tetra_shifts(3,isummit,itetra)*klatt(:,3)
302 :
303 : ! Find full kpoint which is summit isummit of tetrahedron itetra around full kpt ikpt_full !
304 20736 : symrankkpt = krank%get_rank(k1)
305 20736 : ikpt2 = krank%invrank(symrankkpt)
306 20736 : if (ikpt2 < 1) then
307 0 : errorstring = 'Error in ranking k-points - exiting with un-initialized tetrahedra.'
308 0 : ierr = 2
309 0 : call krank%free()
310 0 : TETRA_ALLOCATE(tetra%tetra_full, (4,2,1))
311 0 : TETRA_ALLOCATE(tetra%tetra_mult, (1))
312 0 : TETRA_ALLOCATE(tetra%tetra_wrap, (3,4,1))
313 0 : TETRA_DEALLOCATE(tetra_full_)
314 0 : TETRA_DEALLOCATE(tetra_mult_)
315 0 : TETRA_DEALLOCATE(tetra_wrap_)
316 0 : return
317 : end if
318 :
319 : ! Store irreducible kpoint equivalent to kpt_fullbz(:,ikpt2)
320 20736 : tetra_full_(isummit,1,ialltetra) = indkpt(ikpt2)
321 20736 : tetra_full_(isummit,2,ialltetra) = ikpt2
322 20736 : shift1 = k1(1)-kpt_fullbz(1,ikpt2)
323 20736 : shift2 = k1(2)-kpt_fullbz(2,ikpt2)
324 20736 : shift3 = k1(3)-kpt_fullbz(3,ikpt2)
325 20736 : if (shift1>0.5d0) then
326 1728 : tetra_wrap_(1,isummit,ialltetra) = 1
327 19008 : else if (shift1<-0.5d0) then
328 0 : tetra_wrap_(1,isummit,ialltetra) = -1
329 : end if
330 20736 : if (shift2>0.5d0) then
331 1728 : tetra_wrap_(2,isummit,ialltetra) = 1
332 19008 : else if (shift2<-0.5d0) then
333 0 : tetra_wrap_(2,isummit,ialltetra) = -1
334 : end if
335 20736 : if (shift3>0.5d0) then
336 1728 : tetra_wrap_(3,isummit,ialltetra) = 1
337 19008 : else if (shift3<-0.5d0) then
338 0 : tetra_wrap_(3,isummit,ialltetra) = -1
339 : end if
340 :
341 : ! sort itetra summits
342 : ! TODO: replace with sort_int
343 57024 : do jsummit=isummit,2,-1
344 51840 : if ( tetra_full_(jsummit,1,ialltetra) < tetra_full_(jsummit-1,1,ialltetra) ) then
345 6912 : itmp = tetra_full_(jsummit,1,ialltetra)
346 6912 : tetra_full_(jsummit,1,ialltetra) = tetra_full_(jsummit-1,1,ialltetra)
347 6912 : tetra_full_(jsummit-1,1,ialltetra) = itmp
348 6912 : itmp = tetra_full_(jsummit,2,ialltetra)
349 6912 : tetra_full_(jsummit,2,ialltetra) = tetra_full_(jsummit-1,2,ialltetra)
350 6912 : tetra_full_(jsummit-1,2,ialltetra) = itmp
351 : ! keep fullbz_kpt tetrahedra points in same order
352 6912 : itmp = tetra_wrap_(1,jsummit,ialltetra)
353 6912 : tetra_wrap_(1,jsummit,ialltetra) = tetra_wrap_(1,jsummit-1,ialltetra)
354 6912 : tetra_wrap_(1,jsummit-1,ialltetra) = itmp
355 6912 : itmp = tetra_wrap_(2,jsummit,ialltetra)
356 6912 : tetra_wrap_(2,jsummit,ialltetra) = tetra_wrap_(2,jsummit-1,ialltetra)
357 6912 : tetra_wrap_(2,jsummit-1,ialltetra) = itmp
358 6912 : itmp = tetra_wrap_(1,jsummit,ialltetra)
359 6912 : tetra_wrap_(3,jsummit,ialltetra) = tetra_wrap_(3,jsummit-1,ialltetra)
360 6912 : tetra_wrap_(3,jsummit-1,ialltetra) = itmp
361 : end if
362 : end do ! jsummit
363 :
364 : end do ! isummit
365 :
366 5184 : if (ialltetra > mtetra) then
367 : write (errorstring, '(3a,i0,a,i0)' ) &
368 0 : 'init_tetra: BUG - ',&
369 0 : ' ialltetra > mtetra ',&
370 0 : ' ialltetra= ',ialltetra,', mtetra= ',mtetra
371 0 : ierr = 1
372 0 : return
373 : end if
374 6048 : ialltetra = ialltetra+1
375 : end do ! itetra
376 : end do ! ikpt_full
377 :
378 : !call cpu_time(cpu_stop)
379 : !write(*,*)"tetra_init ikpt_loop:", cpu_stop - cpu_start
380 : !cpu_start = cpu_stop
381 :
382 4 : call krank%free()
383 :
384 : rcvol = abs (gprimd(1,1)*(gprimd(2,2)*gprimd(3,3)-gprimd(3,2)*gprimd(2,3)) &
385 : & -gprimd(2,1)*(gprimd(1,2)*gprimd(3,3)-gprimd(3,2)*gprimd(1,3)) &
386 4 : & +gprimd(3,1)*(gprimd(1,2)*gprimd(2,3)-gprimd(2,2)*gprimd(1,3)))
387 :
388 : ! Volume of all tetrahedra should be the same as that of tetra 1
389 : ! this is the volume of 1 tetrahedron, should be coherent with notation in Lehmann & Taut
390 16 : k1(:) = gprimd(:,1)*klatt(1,1) + gprimd(:,2)*klatt(2,1) + gprimd(:,3)*klatt(3,1)
391 16 : k2(:) = gprimd(:,1)*klatt(1,2) + gprimd(:,2)*klatt(2,2) + gprimd(:,3)*klatt(3,2)
392 16 : k3(:) = gprimd(:,1)*klatt(1,3) + gprimd(:,2)*klatt(2,3) + gprimd(:,3)*klatt(3,3)
393 : tetra%vv = abs (k1(1)*(k2(2)*k3(3)-k2(3)*k3(2)) &
394 : & -k1(2)*(k2(1)*k3(3)-k2(3)*k3(1)) &
395 4 : & +k1(3)*(k2(1)*k3(2)-k2(2)*k3(1))) / 6.d0 / rcvol
396 :
397 : ! eliminate equivalent tetrahedra by symmetry and account for them in multiplicity tetra_mult
398 4 : tetra%ntetra = mtetra
399 :
400 : ! FIXME: could we replace this with a ranking algorithm to avoid the O(tetra%ntetra^2) step? For example:
401 : ! get tetrahedron rank - problem too many combinations in principle = nkpt_irred^4 - only a few used in practice
402 : ! sort ranks and keep indices
403 :
404 : ! make hash table = tetra_full_(1)*nkptirred**3+tetra_full_(2)*nkptirred**2+tetra_full_(3)*nkptirred**1+tetra_full_(4)
405 :
406 4 : hashfactor = 100.d0 ! *acos(-1.d0) ! 100 pi should be far from an integer...
407 12 : TETRA_ALLOCATE(tetra_hash, (tetra%ntetra))
408 12 : TETRA_ALLOCATE(reforder, (tetra%ntetra))
409 :
410 : !MG: In principle the order of the indices should not matter.
411 5188 : do ialltetra=1, tetra%ntetra
412 : tetra_hash(ialltetra) = tetra_full_(1,1,ialltetra)*hashfactor**3+&
413 : & tetra_full_(2,1,ialltetra)*hashfactor**2+&
414 : & tetra_full_(3,1,ialltetra)*hashfactor**1+&
415 5184 : & tetra_full_(4,1,ialltetra)
416 5188 : reforder(ialltetra) = ialltetra
417 : end do
418 :
419 4 : call sort_tetra(tetra%ntetra, tetra_hash, reforder, tol14)
420 : ! Most of the wall-time is spent in the preamble of this routine (up to this point).
421 : ! sort_tetra is not easy to parallelize...
422 :
423 : ! determine number of tetra after reduction
424 12 : TETRA_ALLOCATE(irred_itetra, (tetra%ntetra))
425 4 : jalltetra = 1
426 4 : irred_itetra(1) = 1
427 5184 : do ialltetra=2, tetra%ntetra
428 5180 : if (abs(tetra_hash(ialltetra)-tetra_hash(ialltetra-1)) > tol14) then
429 : ! found a new series
430 5180 : jalltetra = jalltetra + 1
431 : end if
432 5184 : irred_itetra(ialltetra) = jalltetra
433 : end do
434 :
435 : ! reset number of tetra
436 4 : ntetra_irred = jalltetra
437 :
438 : ! allocate definitive tetra arrays and transfer to new arrays
439 12 : TETRA_ALLOCATE(tetra%tetra_full, (4,2,ntetra_irred))
440 12 : TETRA_ALLOCATE(tetra%tetra_mult, (ntetra_irred))
441 12 : TETRA_ALLOCATE(tetra%tetra_wrap, (3,4,ntetra_irred))
442 :
443 : ! eliminate equal rank tetrahedra and accumulate multiplicity into first one
444 57028 : tetra%tetra_full = 0
445 5188 : tetra%tetra_mult = 0
446 88132 : tetra%tetra_wrap = 0
447 4 : jalltetra = 1
448 44 : tetra%tetra_full(:,:,1) = tetra_full_(:,:,reforder(1))
449 4 : tetra%tetra_mult(1) = 1
450 68 : tetra%tetra_wrap(:,:,1) = tetra_wrap_(:,:,reforder(1))
451 5184 : do ialltetra=2, tetra%ntetra
452 : ! TODO: check if tolerance is adapted
453 5184 : if (abs(tetra_hash(ialltetra)-tetra_hash(ialltetra-1)) > tol14) then
454 : ! found a new series
455 5180 : jalltetra = jalltetra + 1
456 56980 : tetra%tetra_full(:,:,jalltetra) = tetra_full_(:,:,reforder(ialltetra))
457 88060 : tetra%tetra_wrap(:,:,jalltetra) = tetra_wrap_(:,:,reforder(ialltetra))
458 5180 : tetra%tetra_mult(jalltetra) = 1
459 : else
460 : ! TODO: add real check that the tetra are equivalent...
461 : ! otherwise increment jalltetra here as well, generate new series?
462 0 : tetra%tetra_mult(jalltetra) = tetra%tetra_mult(jalltetra) + tetra_mult_(reforder(ialltetra))
463 : !tetra_mult_(reforder(ialltetra)) = 0
464 : end if
465 : end do
466 :
467 : ! reset of ntetra for final version after checks and debu
468 4 : tetra%ntetra = ntetra_irred
469 :
470 4 : TETRA_DEALLOCATE(tetra_hash)
471 4 : TETRA_DEALLOCATE(reforder)
472 4 : TETRA_DEALLOCATE(irred_itetra)
473 4 : TETRA_DEALLOCATE(tetra_full_)
474 4 : TETRA_DEALLOCATE(tetra_mult_)
475 4 : TETRA_DEALLOCATE(tetra_wrap_)
476 :
477 : ! Create mapping between the irreducible k-points
478 : ! and all the tetrahedron contributing with some weight
479 868 : nkpt_ibz = maxval(indkpt)
480 :
481 : ! 1. First we count what is the maximum number of distinct tetrahedra that each k-point contains
482 12 : TETRA_ALLOCATE(tetra%ibz_tetra_count,(nkpt_ibz))
483 868 : tetra%ibz_tetra_count(:) = 0
484 :
485 : ! Count max tetra contributing
486 5188 : do ii=1,tetra%ntetra
487 : ! Here we need the original ordering to reference the correct irred kpoints
488 25920 : ind_ibz(:) = tetra%tetra_full(:,1,ii)
489 : ! count max tetra contributing
490 25924 : do jj=1,4
491 20736 : ikibz = ind_ibz(jj)
492 20736 : if (ikibz > nkpt_ibz) cycle
493 25920 : tetra%ibz_tetra_count(ikibz) = tetra%ibz_tetra_count(ikibz) + 1
494 : end do
495 : end do
496 :
497 : ! 2. Then we build mapping of ikbz to tetra
498 880 : TETRA_ALLOCATE(tetra%ibz_tetra_mapping,(nkpt_ibz,maxval(tetra%ibz_tetra_count)))
499 868 : tetra%ibz_tetra_count(:) = 0
500 5188 : do ii=1,tetra%ntetra
501 : ! Here we need the original ordering to reference the correct irred kpoints
502 25920 : ind_ibz(:) = tetra%tetra_full(:,1,ii)
503 : ! Use the counter to move pointer and then fill index
504 25924 : do jj=1,4
505 20736 : ikibz = ind_ibz(jj)
506 20736 : if (ikibz > nkpt_ibz) cycle
507 : ! avoid putting the same index twice
508 20736 : if (tetra%ibz_tetra_count(ikibz) > 0) then
509 19872 : if (tetra%ibz_tetra_mapping(ikibz,tetra%ibz_tetra_count(ikibz)) == ii) cycle
510 : end if
511 20736 : tetra%ibz_tetra_count(ikibz) = tetra%ibz_tetra_count(ikibz) + 1
512 25920 : tetra%ibz_tetra_mapping(ikibz,tetra%ibz_tetra_count(ikibz)) = ii
513 : end do
514 : end do
515 :
516 : !call cpu_time(cpu_stop)
517 : !write(*,*)"tetra_init 2nd part:", cpu_stop - cpu_start
518 : !cpu_start = cpu_stop
519 :
520 4 : end subroutine init_tetra
521 : !!***
522 :
523 : !----------------------------------------------------------------------
524 :
525 : !!****f* m_tetrahedron/tetra_write
526 : !! NAME
527 : !! tetra_write
528 : !!
529 : !! FUNCTION
530 : !! Write text file with tetra info.
531 : !!
532 : !! INPUTS
533 : !! tetra<t_tetrahedron>=tetrahedron geometry object
534 : !! nkibz=Number of k-points in the IBZ used to generate tetra
535 : !! kibz(3,nkibz)=Reduced coordinates of the IBZ
536 : !! path=Name of output file
537 : !!
538 : !! OUTPUT
539 : !! Output is written to file.
540 : !!
541 : !! SOURCE
542 :
543 0 : subroutine tetra_write(tetra, nkibz, kibz, path)
544 :
545 : !Arguments ------------------------------------
546 : !scalars
547 : integer,intent(in) :: nkibz
548 : character(len=*),intent(in) :: path
549 : type(t_tetrahedron),intent(in) :: tetra
550 : !arrays
551 : real(dp),intent(in) :: kibz(3,nkibz)
552 :
553 : !Local variables-------------------------------
554 : integer,parameter :: version=1
555 : integer :: ik,it,unt
556 : #ifdef HAVE_LIBTETRA_ABINIT
557 : character(len=500) :: msg
558 : #endif
559 :
560 : ! *********************************************************************
561 :
562 : #ifdef HAVE_LIBTETRA_ABINIT
563 0 : if (open_file(file=trim(path),iomsg=msg,newunit=unt,form="formatted",status="unknown",action="write")/=0) then
564 0 : TETRA_ERROR(msg)
565 : end if
566 : #else
567 : open(file=trim(path),newunit=unt,form="formatted",status="unknown",action="write")
568 : #endif
569 :
570 0 : write(unt,*)version, " # version number"
571 :
572 : ! Write IBZ
573 0 : write(unt,*)nkibz, " # number of k-points in the IBZ"
574 0 : write(unt,"(a)")"<irreducible_zone>"
575 0 : do ik=1,nkibz
576 0 : write(unt,"(3es22.12)") kibz(:,ik)
577 : end do
578 0 : write(unt,"(a)")"</irreducible_zone>"
579 :
580 : ! Write tetra info
581 0 : write(unt,"(i0,a)")tetra%ntetra, " # number of tetrahedra"
582 0 : write(unt,"(es22.12,a)")tetra%vv, " # tetrahedron volume"
583 :
584 0 : write(unt,"(a)")"<tetra_full>"
585 0 : do it=1,tetra%ntetra
586 0 : write(unt,"(8(i0,1x))")tetra%tetra_full(:,:,it)
587 : end do
588 0 : write(unt,"(a)")"</tetra_full>"
589 :
590 0 : write(unt,"(a)")"<tetra_mult>"
591 0 : do it=1,tetra%ntetra
592 0 : write(unt,"(i0)")tetra%tetra_mult(it)
593 : end do
594 0 : write(unt,"(a)")"</tetra_mult>"
595 :
596 0 : write(unt,"(a)")"<tetra_wrap>"
597 0 : do it=1,tetra%ntetra
598 0 : write(unt,"(12(i0,1x))")tetra%tetra_wrap(:,:,it)
599 : end do
600 0 : write(unt,"(a)")"</tetra_wrap>"
601 :
602 0 : close(unt)
603 :
604 0 : end subroutine tetra_write
605 : !!***
606 :
607 : !----------------------------------------------------------------------
608 :
609 : !!****f* m_tetrahedron/get_tetra_weight
610 : !! NAME
611 : !! get_tetra_weight
612 : !!
613 : !! FUNCTION
614 : !! calculate integration weights and their derivatives from Blochl et al PRB 49 16223 [[cite:Bloechl1994a]]
615 : !!
616 : !! INPUTS
617 : !! eigen_in(nkpt)=eigenenergies for each k point
618 : !! enemin=minimal energy for DOS
619 : !! enemax=maximal energy for DOS
620 : !! max_occ=maximal occupation number (2 for nsppol=1, 1 for nsppol=2)
621 : !! nene=number of energies for DOS
622 : !! nkpt=number of irreducible kpoints
623 : !! tetra<t_tetrahedron>
624 : !! %ntetra=number of tetrahedra
625 : !! %tetra_full(4,2,ntetra)=for each irred tetrahedron, the list of k point vertices
626 : !! 1 -> irred kpoint 2 -> fullkpt
627 : !! %tetra_mult(ntetra)=for each irred tetrahedron, its multiplicity
628 : !! %vv = ratio of volume of one tetrahedron in reciprocal space to full BZ volume
629 : !! bcorr=1 to include Blochl correction else 0.
630 : !! comm=MPI communicator
631 : !!
632 : !! OUTPUT
633 : !! tweight(nkpt,nene) = integration weights for each irred kpoint from all adjacent tetrahedra
634 : !! dtweightde(nkpt,nene) = derivative of tweight wrt energy
635 : !!
636 : !! SOURCE
637 :
638 : ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 : ! THIS FUNCTION IS DEPRECATED, USE tetra_blochl_weights
640 : ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 18 : subroutine get_tetra_weight(eigen_in,enemin,enemax,max_occ,nene,nkpt,tetra,&
642 18 : bcorr,tweight,dtweightde,comm)
643 :
644 : !Arguments ------------------------------------
645 : !scalars
646 : integer,intent(in) :: nene,nkpt,bcorr,comm
647 : type(t_tetrahedron), intent(in) :: tetra
648 : real(dp) ,intent(in) :: enemax,enemin,max_occ
649 : !arrays
650 : real(dp) ,intent(in) :: eigen_in(nkpt)
651 : real(dp) ,intent(out) :: dtweightde(nkpt,nene),tweight(nkpt,nene)
652 :
653 : !Local variables-------------------------------
654 18 : real(dp), allocatable :: dtweightde_ek(:, :), tweight_ek(:, :)
655 :
656 : ! *********************************************************************
657 :
658 72 : TETRA_ALLOCATE(dtweightde_ek, (nene, nkpt))
659 54 : TETRA_ALLOCATE(tweight_ek, (nene, nkpt))
660 :
661 18 : call tetra_blochl_weights(tetra,eigen_in,enemin,enemax,max_occ,nene,nkpt,bcorr,tweight_ek,dtweightde_ek,comm)
662 :
663 : ! transpose: otherwise the data access is crap and the code slows by an order of magnitude
664 782520 : tweight = transpose(tweight_ek)
665 782520 : dtweightde = transpose(dtweightde_ek)
666 :
667 18 : TETRA_DEALLOCATE(dtweightde_ek)
668 18 : TETRA_DEALLOCATE(tweight_ek)
669 :
670 18 : end subroutine get_tetra_weight
671 : !!***
672 :
673 : !----------------------------------------------------------------------
674 :
675 : !!****f* m_tetrahedron/tetra_blochl_weights
676 : !! NAME
677 : !! tetra_blochl_weights
678 : !!
679 : !! FUNCTION
680 : !! calculate integration weights and their derivatives from Blochl et al PRB 49 16223 [[cite:Bloechl1994a]]
681 : !! Same API as get_tetra_weight but output weights here have shape (nene, nkpt)
682 : !!
683 : !! SOURCE
684 :
685 18 : subroutine tetra_blochl_weights(tetra,eigen_in,enemin,enemax,max_occ,nene,nkpt,&
686 18 : bcorr,tweight_t,dtweightde_t,comm)
687 :
688 : !Arguments ------------------------------------
689 : !scalars
690 : integer,intent(in) :: nene,nkpt,bcorr,comm
691 : type(t_tetrahedron), intent(in) :: tetra
692 : real(dp) ,intent(in) :: enemax,enemin,max_occ
693 : !arrays
694 : real(dp) ,intent(in) :: eigen_in(nkpt)
695 : real(dp) ,intent(out) :: dtweightde_t(nene,nkpt),tweight_t(nene,nkpt)
696 :
697 : !Local variables-------------------------------
698 : !scalars
699 : integer :: itetra,nprocs,my_start,my_stop,ierr,ii
700 : !arrays
701 : integer :: ind_ibz(4)
702 : real(dp) :: eigen_1tetra(4)
703 18 : real(dp), allocatable :: tweight_tmp(:,:),dtweightde_tmp(:,:),buffer(:,:)
704 :
705 : ! *********************************************************************
706 :
707 54 : TETRA_ALLOCATE(tweight_tmp, (nene, 4))
708 36 : TETRA_ALLOCATE(dtweightde_tmp, (nene, 4))
709 1565604 : tweight_t = zero; dtweightde_t = zero
710 :
711 18 : call split_work(tetra%ntetra, comm, nprocs, my_start, my_stop, ierr)
712 18 : if (ierr /= 0) TETRA_ERROR("Error in MPI layer")
713 :
714 : ! for each tetrahedron
715 23346 : do itetra=my_start,my_stop
716 18810144 : tweight_tmp = zero
717 18810144 : dtweightde_tmp = zero
718 :
719 : ! Here we need the original ordering to reference the correct irred kpoints
720 116640 : ind_ibz(:) = tetra%tetra_full(:,1,itetra)
721 :
722 : ! Sort energies before calling get_onetetra_
723 116640 : eigen_1tetra(:) = eigen_in(ind_ibz(:))
724 23328 : call sort_tetra(4, eigen_1tetra, ind_ibz, tol14)
725 :
726 23328 : call get_onetetra_(tetra,itetra,eigen_1tetra,enemin,enemax,max_occ,nene,bcorr,tweight_tmp,dtweightde_tmp)
727 :
728 : ! NOTE: the following blas calls are not working systematically, or do not give speed ups, strange...
729 : !if (nene > 100) then
730 : ! do ii=1,4
731 : ! call daxpy (nene, 1.d0, tweight_tmp(:,ii), 1, tweight_t(:,ind_ibz(ii)), 1)
732 : ! end do
733 : ! do ii=1,4
734 : ! call daxpy (nene, 1.d0, dtweightde_tmp(:,ii), 1, dtweightde_t(:,ind_ibz(ii)), 1)
735 : ! end do
736 : !else
737 116640 : do ii=1,4
738 18810144 : tweight_t(:,ind_ibz(ii)) = tweight_t(:,ind_ibz(ii)) + tweight_tmp(:,ii)
739 : end do
740 116658 : do ii=1,4
741 18810144 : dtweightde_t(:,ind_ibz(ii)) = dtweightde_t(:,ind_ibz(ii)) + dtweightde_tmp(:,ii)
742 : end do
743 : !end if
744 : end do ! itetra
745 :
746 18 : TETRA_DEALLOCATE(tweight_tmp)
747 18 : TETRA_DEALLOCATE(dtweightde_tmp)
748 :
749 18 : if (nprocs > 1) then
750 : #ifdef HAVE_MPI
751 0 : TETRA_ALLOCATE(buffer, (nene, nkpt))
752 0 : call MPI_ALLREDUCE(tweight_t,buffer,nene*nkpt,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ierr)
753 0 : tweight_t = buffer
754 :
755 0 : call MPI_ALLREDUCE(dtweightde_t,buffer,nene*nkpt,MPI_DOUBLE_PRECISION,MPI_SUM,comm,ierr)
756 0 : dtweightde_t = buffer
757 0 : TETRA_DEALLOCATE(buffer)
758 : #endif
759 : end if
760 :
761 18 : end subroutine tetra_blochl_weights
762 : !!***
763 :
764 : !----------------------------------------------------------------------
765 :
766 : !!****f* m_tetrahedron/get_dbl_tetra_weight
767 : !! NAME
768 : !! get_dbl_tetra_weight
769 : !!
770 : !! FUNCTION
771 : !! calculate integration weights and their derivatives
772 : !! for double tetrahedron method from Allen Phys Stat Sol B 120 529 (1983) [[cite:Allen1983b]]
773 : !! the k-points and tetrahedra must be the same for both grids, of course,
774 : !! but the range of energies is arbitrary
775 : !!
776 : !! Omega is called eigen1 here
777 : !! E is called eigen2 here
778 : !! indexing goes from 1 to 4 for the tetrahedron corners, in order of increasing eigen1
779 : !! in Allen, from 0 to 3...
780 : !!
781 : !! INPUTS
782 : !! eigen1_in(nkpt)=eigenenergies for each k point
783 : !! eigen2_in(nkpt)=eigenenergies for each k point
784 : !! enemin1=minimal energy for DOS in energy 1
785 : !! enemax1=maximal energy for DOS
786 : !! enemin2=minimal energy for DOS in energy 2
787 : !! enemax2=maximal energy for DOS
788 : !! max_occ=maximal occupation number (2 for nsppol=1, 1 for nsppol=2)
789 : !! nene1=number of energies for DOS in energy 1
790 : !! nene2=number of energies for DOS in energy 2
791 : !! nkpt=number of irreducible kpoints
792 : !! tetra%ntetra=number of tetra
793 : !! tetra%tetra_full(4,2,ntetra)=for each irred tetrahedron, the list of k point vertices
794 : !! 1 -> irred kpoint 2 -> fullkpt
795 : !! tetra%tetra_mult(ntetra)=for each irred tetrahedron, its multiplicity
796 : !! tetra%vv = ratio of volume of one tetrahedron in reciprocal space to full BZ volume
797 : !! ierr = error code on exit
798 : !!
799 : !! OUTPUT
800 : !! tweight(nkpt,nene1,nene2) = integration weights for each irred kpoint from all adjacent tetrahedra
801 : !! dtweightde(nkpt,nene1,nene2) = derivative of tweight wrt energy
802 : !!
803 : !! SOURCE
804 :
805 0 : subroutine get_dbl_tetra_weight(eigen1_in,eigen2_in,enemin1,enemax1,enemin2,enemax2,&
806 0 : & max_occ,nene1,nene2,nkpt,tetra,tweight,dtweightde, ierr)
807 :
808 : !Arguments ------------------------------------
809 : !scalars
810 : integer,intent(in) :: nene1,nene2,nkpt
811 : integer,intent(out) :: ierr
812 : type(t_tetrahedron), intent(in) :: tetra
813 : real(dp),intent(in) :: enemax1,enemin1
814 : real(dp),intent(in) :: enemax2,enemin2
815 : real(dp),intent(in) :: max_occ
816 : !arrays
817 : real(dp),intent(in) :: eigen1_in(nkpt)
818 : real(dp),intent(in) :: eigen2_in(nkpt)
819 : real(dp),intent(out) :: dtweightde(nkpt,nene1,nene2),tweight(nkpt,nene1,nene2)
820 :
821 : !Local variables-------------------------------
822 : ! needed for gaussian replacement of Dirac functions
823 : ! the three coefficients of the DOS as quadratic form,
824 : ! in the interval [eig(ikpt-1), eig(ikpt)]
825 : ! for ikpt = 1 we add a point below eigen(1) which doesnt
826 : ! contribute to the DOS in any tetrahedron
827 : !scalars
828 : integer :: ieps1,ieps2,itetra
829 : integer :: nn1_1,nn1_2,nn1_3,nn1_4
830 : integer :: nn2_1,nn2_2,nn2_3
831 : integer :: ind_a(3), ind_b(3), ind_c(3)
832 : real(dp) :: deltaene1,eps1
833 : real(dp) :: deltaene2,eps2
834 : ! real(dp) :: gau_prefactor,gau_width,gau_width2
835 : real(dp) :: epsilon1(4,4)
836 : real(dp) :: epsilon2(4,4)
837 : real(dp) :: inv_epsilon1(4,4)
838 : real(dp) :: aa(3),bb(3),cc(3)
839 : real(dp) :: delaa(3),delbb(3),delcc(3)
840 : real(dp) :: delaa0,delbb0,delcc0
841 : real(dp) :: inv_delaa(3),inv_delbb(3),inv_delcc(3)
842 : real(dp) :: deleps1, deleps2
843 : real(dp) :: inv_deleps1
844 : real(dp) :: dccde1, dccde1_pre
845 : real(dp) :: volconst,volconst_mult
846 : real(dp) :: ii0, ii1, ii3
847 : !arrays
848 : integer :: ind_k(4)
849 0 : real(dp), allocatable :: tweight_tmp(:,:,:)
850 0 : real(dp), allocatable :: dtweightde_tmp(:,:,:)
851 : real(dp) :: eigen1_1tetra(4)
852 : real(dp) :: eigen2_1tetra(4)
853 :
854 : ! *********************************************************************
855 :
856 0 : ierr = 0
857 0 : if (nene1 <= 1 .or. nene2 <= 1) then
858 : !'get_dbl_tetra_weight: nene must be at least 2'
859 0 : ierr = 1
860 : return
861 : else
862 0 : deltaene1 = (enemax1-enemin1) / (nene1-1)
863 0 : deltaene2 = (enemax2-enemin2) / (nene2-1)
864 : end if
865 :
866 0 : TETRA_ALLOCATE(tweight_tmp, (4, nene2, nene1))
867 0 : TETRA_ALLOCATE(dtweightde_tmp, (4, nene2, nene1))
868 :
869 : !print *, "warning: for the moment, heaviside weights are 0. The delta function / DOS weights are the only ones calculated "
870 :
871 0 : volconst = tetra%vv/4.d0
872 :
873 : ! for each tetrahedron
874 0 : do itetra=1,tetra%ntetra
875 : ! these are for 1 tetrahedron only.
876 0 : tweight_tmp = zero
877 0 : dtweightde_tmp = zero
878 :
879 0 : volconst_mult = max_occ*volconst*dble(tetra%tetra_mult(itetra))
880 :
881 : ! Here we need the original ordering to reference the correct irred kpoints
882 : ! ind_k refers to the index in the full k list of the summits of the present tetrahedra
883 : ! we can forget the order of the summits within the tetrahedron, because eigen1 fixes that
884 : ! order with its increasing value
885 0 : ind_k(1) = tetra%tetra_full(1,1,itetra)
886 0 : ind_k(2) = tetra%tetra_full(2,1,itetra)
887 0 : ind_k(3) = tetra%tetra_full(3,1,itetra)
888 0 : ind_k(4) = tetra%tetra_full(4,1,itetra)
889 0 : eigen1_1tetra(1) = eigen1_in(ind_k(1))
890 0 : eigen1_1tetra(2) = eigen1_in(ind_k(2))
891 0 : eigen1_1tetra(3) = eigen1_in(ind_k(3))
892 0 : eigen1_1tetra(4) = eigen1_in(ind_k(4))
893 0 : call sort_tetra(4,eigen1_1tetra,ind_k,tol14)
894 :
895 : ! re-sort eigen2 values according to order chosen for eigen1. Eigen2 are _not_ in increasing order!
896 0 : eigen2_1tetra(1) = eigen2_in(ind_k(1))
897 0 : eigen2_1tetra(2) = eigen2_in(ind_k(2))
898 0 : eigen2_1tetra(3) = eigen2_in(ind_k(3))
899 0 : eigen2_1tetra(4) = eigen2_in(ind_k(4))
900 :
901 : ! the epsilons are energy differences for the two eigenvalue sets
902 0 : epsilon1 = zero
903 0 : epsilon2 = zero
904 0 : do ieps1 = 1, 4
905 0 : do ieps2 = ieps1+1, 4
906 0 : epsilon1(ieps1,ieps2) = eigen1_1tetra(ieps1)-eigen1_1tetra(ieps2)
907 0 : epsilon1(ieps2,ieps1) = -epsilon1(ieps1,ieps2)
908 0 : epsilon2(ieps1,ieps2) = eigen2_1tetra(ieps1)-eigen2_1tetra(ieps2)
909 0 : epsilon2(ieps2,ieps1) = -epsilon2(ieps1,ieps2)
910 : end do
911 : end do
912 :
913 : ! we precalculate the inverses to avoid doing tons of divisions in the energy loops below
914 : ! Allen formulae only require the inverses of the differences of eigen1 + the a b c below
915 0 : inv_epsilon1 = zero
916 0 : do ieps1 = 1, 4
917 0 : do ieps2 = ieps1+1, 4
918 0 : if (abs(epsilon1(ieps1,ieps2)) > tol14) then
919 0 : inv_epsilon1(ieps1,ieps2) = 1.d0 / epsilon1(ieps1,ieps2)
920 0 : inv_epsilon1(ieps2,ieps1) = -inv_epsilon1(ieps1,ieps2)
921 : end if
922 : end do
923 : end do
924 :
925 : ! these bounds determine the intervals for Omega in Allen paper, and cases A, B, C
926 0 : nn1_1 = int((eigen1_1tetra(1)-enemin1)/deltaene1)+1
927 0 : nn1_2 = int((eigen1_1tetra(2)-enemin1)/deltaene1)+1
928 0 : nn1_3 = int((eigen1_1tetra(3)-enemin1)/deltaene1)+1
929 0 : nn1_4 = int((eigen1_1tetra(4)-enemin1)/deltaene1)+1
930 :
931 0 : nn1_1 = max(1,nn1_1)
932 0 : nn1_1 = min(nn1_1,nene1)
933 0 : nn1_2 = max(1,nn1_2)
934 0 : nn1_2 = min(nn1_2,nene1)
935 0 : nn1_3 = max(1,nn1_3)
936 0 : nn1_3 = min(nn1_3,nene1)
937 0 : nn1_4 = max(1,nn1_4)
938 0 : nn1_4 = min(nn1_4,nene1)
939 :
940 : ! calculate Allen a_i b_i and c_i parameters
941 : ! sort the a_i b_i c_i
942 : !
943 : ! NOTE: indices here go from 1 to 4 instead of 0 to 3 as in Allen...
944 0 : aa(1) = epsilon2(2,1) * inv_epsilon1(2,1)
945 0 : aa(2) = epsilon2(3,1) * inv_epsilon1(3,1)
946 0 : aa(3) = epsilon2(4,1) * inv_epsilon1(4,1)
947 0 : ind_a = (/2,3,4/)
948 0 : call sort_tetra(3,aa,ind_a,tol14)
949 : ! aa are now in order a_s a_m a_l !!! Preserve the hash function ind_a to order the positions of k below
950 0 : delaa(1) = aa(2)-aa(1)
951 0 : delaa(2) = aa(3)-aa(1)
952 0 : delaa(3) = aa(3)-aa(2)
953 0 : inv_delaa = zero
954 0 : if(delaa(1)> tol14) inv_delaa(1)= 1.0d0 / delaa(1)
955 0 : if(delaa(2)> tol14) inv_delaa(2)= 1.0d0 / delaa(2)
956 0 : if(delaa(3)> tol14) inv_delaa(3)= 1.0d0 / delaa(3)
957 :
958 0 : bb(1) = epsilon2(1,2) * inv_epsilon1(1,2)
959 0 : bb(2) = epsilon2(3,2) * inv_epsilon1(3,2)
960 0 : bb(3) = epsilon2(4,2) * inv_epsilon1(4,2)
961 0 : ind_b = (/1,3,4/)
962 0 : call sort_tetra(3,bb,ind_b,tol14)
963 0 : delbb(1) = bb(2)-bb(1)
964 0 : delbb(2) = bb(3)-bb(1)
965 0 : delbb(3) = bb(3)-bb(2)
966 0 : inv_delbb = zero
967 0 : if(delbb(1)> tol14) inv_delbb(1)= 1.0d0 / delbb(1)
968 0 : if(delbb(2)> tol14) inv_delbb(2)= 1.0d0 / delbb(2)
969 0 : if(delbb(3)> tol14) inv_delbb(3)= 1.0d0 / delbb(3)
970 :
971 0 : cc(1) = epsilon2(1,4) * inv_epsilon1(1,4)
972 0 : cc(2) = epsilon2(2,4) * inv_epsilon1(2,4)
973 0 : cc(3) = epsilon2(3,4) * inv_epsilon1(3,4)
974 0 : ind_c = (/1,2,3/)
975 0 : call sort_tetra(3,cc,ind_c,tol14)
976 0 : delcc(1) = cc(2)-cc(1)
977 0 : delcc(2) = cc(3)-cc(1)
978 0 : delcc(3) = cc(3)-cc(2)
979 0 : inv_delcc = zero
980 0 : if(delcc(1)> tol14) inv_delcc(1)= 1.0d0 / delcc(1)
981 0 : if(delcc(2)> tol14) inv_delcc(2)= 1.0d0 / delcc(2)
982 0 : if(delcc(3)> tol14) inv_delcc(3)= 1.0d0 / delcc(3)
983 :
984 : !----------------------------------------------------------------------
985 : ! start main loop A B C over eps1
986 : !----------------------------------------------------------------------
987 :
988 : !
989 : ! interval enemin1 < eps1 < e1 nothing to do
990 : !
991 : !
992 : ! interval e1 < eps1 < e3 CASE A in Allen + first term in B
993 : !
994 : ! NB: eps1 is not updated inside the loop, only between the loops
995 0 : eps1 = enemin1+nn1_1*deltaene1
996 0 : deleps1 = eps1-eigen1_1tetra(1) ! this is Omega - omega_0
997 0 : dccde1_pre = 6.d0*volconst_mult*inv_epsilon1(2,1)*inv_epsilon1(3,1)*inv_epsilon1(4,1)
998 :
999 : ! note we go to nn1_3
1000 0 : do ieps1=nn1_1+1,nn1_3
1001 :
1002 0 : dccde1 = dccde1_pre * deleps1 ! this is f_0(Omega)*6*v
1003 :
1004 : ! at fixed ieps1 we can find the pivot indices for the ieps2 loop
1005 0 : nn2_1 = int((eigen2_1tetra(1)+deleps1*aa(1) -enemin2)/deltaene2)+1
1006 0 : nn2_2 = int((eigen2_1tetra(1)+deleps1*aa(2) -enemin2)/deltaene2)+1
1007 0 : nn2_3 = int((eigen2_1tetra(1)+deleps1*aa(3) -enemin2)/deltaene2)+1
1008 :
1009 0 : nn2_1 = max(1,nn2_1)
1010 0 : nn2_1 = min(nn2_1,nene2)
1011 0 : nn2_2 = max(1,nn2_2)
1012 0 : nn2_2 = min(nn2_2,nene2)
1013 0 : nn2_3 = max(1,nn2_3)
1014 0 : nn2_3 = min(nn2_3,nene2)
1015 :
1016 0 : inv_deleps1 = 1.0d0 / deleps1
1017 :
1018 0 : eps2 = enemin2+nn2_1*deltaene2 ! this is E
1019 0 : deleps2 = eps2 - eigen2_1tetra(1) ! this is E-epsilon_0
1020 :
1021 : !-----------------------------------------------------------------------
1022 : ! This is case AI
1023 : !-----------------------------------------------------------------------
1024 0 : do ieps2 = nn2_1+1, nn2_2
1025 : ! calculate running value of del "a" = a-a_s: first term should really mix eps1 and eps2
1026 0 : delaa0 = deleps2*inv_deleps1 - aa(1) ! a - a_s
1027 :
1028 0 : ii0 = dccde1*delaa0*inv_delaa(1)*inv_delaa(2) ! this is I_0(Omega E)
1029 :
1030 : dtweightde_tmp(1,ieps2,ieps1) = dtweightde_tmp(1,ieps2,ieps1) + &
1031 : & ii0*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_a(1),1)* &
1032 : & (-2.0d0 + delaa0*inv_delaa(1)*epsilon1(ind_a(2),ind_a(1))*inv_epsilon1(ind_a(2),1) &
1033 0 : & + delaa0*inv_delaa(2)*epsilon1(ind_a(3),ind_a(1))*inv_epsilon1(ind_a(3),1)))
1034 : dtweightde_tmp(ind_a(1),ieps2,ieps1) = dtweightde_tmp(ind_a(1),ieps2,ieps1) + &
1035 0 : & ii0*0.5d0*deleps1*inv_epsilon1(ind_a(1),1)*(2.0d0 - delaa0*inv_delaa(1) - delaa0*inv_delaa(2))
1036 : dtweightde_tmp(ind_a(2),ieps2,ieps1) = dtweightde_tmp(ind_a(2),ieps2,ieps1) + &
1037 0 : & ii0*0.5d0*delaa0*inv_delaa(1)*deleps1*inv_epsilon1(ind_a(2),1)
1038 : dtweightde_tmp(ind_a(3),ieps2,ieps1) = dtweightde_tmp(ind_a(3),ieps2,ieps1) + &
1039 0 : & ii0*0.5d0*delaa0*inv_delaa(2)*deleps1*inv_epsilon1(ind_a(3),1)
1040 0 : deleps2 = deleps2 + deltaene2
1041 : end do
1042 :
1043 :
1044 0 : eps2 = enemin2+nn2_2*deltaene2 ! this is E
1045 0 : deleps2 = eps2 - eigen2_1tetra(1) ! E-E_0
1046 :
1047 : !-----------------------------------------------------------------------
1048 : ! This is case AII
1049 : !-----------------------------------------------------------------------
1050 0 : do ieps2 = nn2_2+1, nn2_3
1051 : ! calculate running value of del "a" = a_l-a: first term should really mix eps1 and eps2
1052 0 : delaa0 = aa(3) - deleps2*inv_deleps1 ! a_l - a
1053 :
1054 0 : ii0 = dccde1*delaa0*inv_delaa(3)*inv_delaa(2) ! this is I_0(Omega E)
1055 :
1056 : dtweightde_tmp(1,ieps2,ieps1) = dtweightde_tmp(1,ieps2,ieps1) + &
1057 : & ii0*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_a(3),1)* &
1058 : & (-2.0d0 + delaa0*inv_delaa(3)*epsilon1(ind_a(2),ind_a(3))*inv_epsilon1(ind_a(2),1) &
1059 0 : & + delaa0*inv_delaa(2)*epsilon1(ind_a(1),ind_a(3))*inv_epsilon1(ind_a(1),1)))
1060 : dtweightde_tmp(ind_a(3),ieps2,ieps1) = dtweightde_tmp(ind_a(3),ieps2,ieps1) + &
1061 0 : & ii0*0.5d0*deleps1*inv_epsilon1(ind_a(3),1)*(2.0d0 - delaa0*inv_delaa(3) - delaa0*inv_delaa(2))
1062 : dtweightde_tmp(ind_a(2),ieps2,ieps1) = dtweightde_tmp(ind_a(2),ieps2,ieps1) + &
1063 0 : & ii0*0.5d0*delaa0*inv_delaa(3)*deleps1*inv_epsilon1(ind_a(2),1)
1064 : dtweightde_tmp(ind_a(1),ieps2,ieps1) = dtweightde_tmp(ind_a(1),ieps2,ieps1) + &
1065 0 : & ii0*0.5d0*delaa0*inv_delaa(2)*deleps1*inv_epsilon1(ind_a(1),1)
1066 :
1067 0 : deleps2 = deleps2 + deltaene2
1068 : end do
1069 0 : deleps1 = deleps1 + deltaene1
1070 : end do
1071 : !
1072 : ! interval e2 < eps < e3
1073 : !
1074 0 : eps1 = eps1 + (nn1_2-nn1_1)*deltaene1
1075 :
1076 0 : deleps1 = eps1-eigen1_1tetra(2) ! Omega - omega_1
1077 :
1078 0 : dccde1_pre = 6.d0*volconst_mult*inv_epsilon1(2,1)*inv_epsilon1(3,2)*inv_epsilon1(4,2) ! f1 function
1079 0 : do ieps1=nn1_2+1,nn1_3
1080 :
1081 0 : dccde1 = dccde1_pre * deleps1 ! f2(Omega) * 6 * v
1082 :
1083 : ! at fixed ieps1 we can find the pivot indices for the ieps2 loop
1084 0 : nn2_1 = int((eigen2_1tetra(2)+deleps1*bb(1) -enemin2)/deltaene2)+1
1085 0 : nn2_2 = int((eigen2_1tetra(2)+deleps1*bb(2) -enemin2)/deltaene2)+1
1086 0 : nn2_3 = int((eigen2_1tetra(2)+deleps1*bb(3) -enemin2)/deltaene2)+1
1087 :
1088 0 : nn2_1 = max(1,nn2_1)
1089 0 : nn2_1 = min(nn2_1,nene2)
1090 0 : nn2_2 = max(1,nn2_2)
1091 0 : nn2_2 = min(nn2_2,nene2)
1092 0 : nn2_3 = max(1,nn2_3)
1093 0 : nn2_3 = min(nn2_3,nene2)
1094 :
1095 0 : inv_deleps1 = 1.0d0 / deleps1
1096 :
1097 0 : eps2 = enemin2+nn2_1*deltaene2 ! starting value for E
1098 0 : deleps2 = eps2 - eigen2_1tetra(2) ! E - epsilon_1
1099 :
1100 : !-----------------------------------------------------------------------
1101 : ! This is case BI
1102 : !-----------------------------------------------------------------------
1103 0 : do ieps2 = nn2_1+1, nn2_2
1104 : ! calculate running value of del "b" = b-b_s: first term should really mix eps1 and eps2
1105 0 : delbb0 = deleps2*inv_deleps1 - bb(1)
1106 :
1107 0 : ii1 = dccde1*delbb0*inv_delbb(1)*inv_delbb(2) ! this is I_1(Omega E)
1108 :
1109 : ! note negative sign here - we are correcting the I0 a0 term already calculated above
1110 : dtweightde_tmp(2,ieps2,ieps1) = dtweightde_tmp(2,ieps2,ieps1) - &
1111 : & ii1*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_b(1),2)* &
1112 : & (-2.0d0 + delbb0*inv_delbb(1)*epsilon1(ind_b(2),ind_b(1))*inv_epsilon1(ind_b(2),2) &
1113 0 : & + delbb0*inv_delbb(2)*epsilon1(ind_b(3),ind_b(1))*inv_epsilon1(ind_b(3),2)))
1114 : dtweightde_tmp(ind_b(1),ieps2,ieps1) = dtweightde_tmp(ind_b(1),ieps2,ieps1) - &
1115 0 : & ii1*0.5d0*deleps1*inv_epsilon1(ind_b(1),2)*(2.0d0 - delbb0*inv_delbb(1) - delbb0*inv_delbb(2))
1116 : dtweightde_tmp(ind_b(2),ieps2,ieps1) = dtweightde_tmp(ind_b(2),ieps2,ieps1) - &
1117 0 : & ii1*0.5d0*delbb0*inv_delbb(1)*deleps1*inv_epsilon1(ind_b(2),2)
1118 : dtweightde_tmp(ind_b(3),ieps2,ieps1) = dtweightde_tmp(ind_b(3),ieps2,ieps1) - &
1119 0 : & ii1*0.5d0*delbb0*inv_delbb(2)*deleps1*inv_epsilon1(ind_b(3),2)
1120 0 : deleps2 = deleps2 + deltaene2
1121 : end do
1122 :
1123 0 : eps2 = enemin2+nn2_2*deltaene2
1124 0 : deleps2 = eps2 - eigen2_1tetra(2)
1125 :
1126 : !-----------------------------------------------------------------------
1127 : ! This is case BII
1128 : !-----------------------------------------------------------------------
1129 0 : do ieps2 = nn2_2+1, nn2_3
1130 : ! calculate running value of del "b" = b_l-b: first term should really mix eps1 and eps2
1131 0 : delbb0 = bb(3) - deleps2*inv_deleps1
1132 :
1133 0 : ii1 = dccde1*delbb0*inv_delbb(3)*inv_delbb(2) ! this is I_1(Omega E)
1134 :
1135 : ! note negative sign here - we are correcting the I0 a0 term already calculated above
1136 : dtweightde_tmp(2,ieps2,ieps1) = dtweightde_tmp(2,ieps2,ieps1) - &
1137 : & ii1*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_b(3),2)* &
1138 : & (-2.0d0 + delbb0*inv_delbb(3)*epsilon1(ind_b(2),ind_b(3))*inv_epsilon1(ind_b(2),2) &
1139 0 : & + delbb0*inv_delbb(2)*epsilon1(ind_b(1),ind_b(3))*inv_epsilon1(ind_b(1),2)))
1140 : dtweightde_tmp(ind_b(3),ieps2,ieps1) = dtweightde_tmp(ind_b(3),ieps2,ieps1) - &
1141 0 : & ii1*0.5d0*deleps1*inv_epsilon1(ind_b(3),2)*(2.0d0 - delbb0*inv_delbb(3) - delbb0*inv_delbb(2))
1142 : dtweightde_tmp(ind_b(2),ieps2,ieps1) = dtweightde_tmp(ind_b(2),ieps2,ieps1) - &
1143 0 : & ii1*0.5d0*delbb0*inv_delbb(3)*deleps1*inv_epsilon1(ind_b(2),2)
1144 : dtweightde_tmp(ind_b(1),ieps2,ieps1) = dtweightde_tmp(ind_b(1),ieps2,ieps1) - &
1145 0 : & ii1*0.5d0*delbb0*inv_delbb(2)*deleps1*inv_epsilon1(ind_b(1),2)
1146 :
1147 0 : deleps2 = deleps2 + deltaene2
1148 : end do
1149 :
1150 0 : deleps1 = deleps1 + deltaene1
1151 : end do
1152 :
1153 : !
1154 : ! interval e3 < eps < e4
1155 : !
1156 0 : eps1 = eps1 + (nn1_3-nn1_2)*deltaene1
1157 0 : deleps1 = eps1-eigen1_1tetra(4)
1158 0 : dccde1_pre = 6.d0*volconst_mult*inv_epsilon1(4,1)*inv_epsilon1(4,2)*inv_epsilon1(4,3)
1159 0 : do ieps1=nn1_3+1,nn1_4
1160 : ! note - sign from definition of f3
1161 0 : dccde1 = -dccde1_pre * deleps1 ! f3(Omega) * 6 * v
1162 :
1163 : ! at fixed ieps1 we can find the pivot indices for the ieps2 loop
1164 : ! NB: order is inverted for cc because deleps1 is defined negative (Omega is always less than omega_3)
1165 0 : nn2_1 = int((eigen2_1tetra(4)+deleps1*cc(3) -enemin2)/deltaene2)+1
1166 0 : nn2_2 = int((eigen2_1tetra(4)+deleps1*cc(2) -enemin2)/deltaene2)+1
1167 0 : nn2_3 = int((eigen2_1tetra(4)+deleps1*cc(1) -enemin2)/deltaene2)+1
1168 :
1169 0 : nn2_1 = max(1,nn2_1)
1170 0 : nn2_1 = min(nn2_1,nene2)
1171 0 : nn2_2 = max(1,nn2_2)
1172 0 : nn2_2 = min(nn2_2,nene2)
1173 0 : nn2_3 = max(1,nn2_3)
1174 0 : nn2_3 = min(nn2_3,nene2)
1175 0 : inv_deleps1 = 1.0d0 / deleps1
1176 :
1177 0 : eps2 = enemin2+nn2_1*deltaene2 ! starting value for E
1178 0 : deleps2 = eps2 - eigen2_1tetra(4) ! E - epsilon_3
1179 :
1180 : !-----------------------------------------------------------------------
1181 : ! This is case CII
1182 : !-----------------------------------------------------------------------
1183 0 : do ieps2 = nn2_1+1, nn2_2
1184 : ! calculate running value of del "c" = c_l-c: first term should really mix eps1 and eps2
1185 0 : delcc0 = cc(3) - deleps2*inv_deleps1
1186 :
1187 0 : ii3 = dccde1*delcc0*inv_delcc(3)*inv_delcc(2) ! this is I_3(Omega E)
1188 :
1189 : dtweightde_tmp(4,ieps2,ieps1) = dtweightde_tmp(4,ieps2,ieps1) + &
1190 : & ii3*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_c(3),4)* &
1191 : & (-2.0d0 + delcc0*inv_delcc(3)*epsilon1(ind_c(2),ind_c(3))*inv_epsilon1(ind_c(2),4) &
1192 0 : & + delcc0*inv_delcc(2)*epsilon1(ind_c(1),ind_c(3))*inv_epsilon1(ind_c(1),4)))
1193 : dtweightde_tmp(ind_c(3),ieps2,ieps1) = dtweightde_tmp(ind_c(3),ieps2,ieps1) + &
1194 0 : & ii3*0.5d0*deleps1*inv_epsilon1(ind_c(3),4)*(2.0d0 - delcc0*inv_delcc(3) - delcc0*inv_delcc(2))
1195 : dtweightde_tmp(ind_c(2),ieps2,ieps1) = dtweightde_tmp(ind_c(2),ieps2,ieps1) + &
1196 0 : & ii3*0.5d0*delcc0*inv_delcc(3)*deleps1*inv_epsilon1(ind_c(2),4)
1197 : dtweightde_tmp(ind_c(1),ieps2,ieps1) = dtweightde_tmp(ind_c(1),ieps2,ieps1) + &
1198 0 : & ii3*0.5d0*delcc0*inv_delcc(2)*deleps1*inv_epsilon1(ind_c(1),4)
1199 :
1200 0 : deleps2 = deleps2 + deltaene2
1201 : end do
1202 :
1203 :
1204 0 : eps2 = enemin2+nn2_2*deltaene2
1205 0 : deleps2 = eps2 - eigen2_1tetra(4)
1206 :
1207 : !-----------------------------------------------------------------------
1208 : ! This is case CI
1209 : !-----------------------------------------------------------------------
1210 0 : do ieps2 = nn2_2+1, nn2_3
1211 : ! calculate running value of del "c" = c-c_s: first term should really mix eps1 and eps2
1212 0 : delcc0 = deleps2*inv_deleps1 - cc(1) ! c - c_s
1213 :
1214 0 : ii3 = dccde1*delcc0*inv_delcc(1)*inv_delcc(2) ! this is I_3(Omega E)
1215 :
1216 : dtweightde_tmp(4,ieps2,ieps1) = dtweightde_tmp(4,ieps2,ieps1) + &
1217 : & ii3*(1.d0 + 0.5d0*deleps1*inv_epsilon1(ind_c(1),4)* &
1218 : & (-2.0d0 + delcc0*inv_delcc(1)*epsilon1(ind_c(2),ind_c(1))*inv_epsilon1(ind_c(2),4) &
1219 0 : & + delcc0*inv_delcc(2)*epsilon1(ind_c(3),ind_c(1))*inv_epsilon1(ind_c(3),4)))
1220 : dtweightde_tmp(ind_c(1),ieps2,ieps1) = dtweightde_tmp(ind_c(1),ieps2,ieps1) + &
1221 0 : & ii3*0.5d0*deleps1*inv_epsilon1(ind_c(1),4)*(2.0d0 - delcc0*inv_delcc(1) - delcc0*inv_delcc(2))
1222 : dtweightde_tmp(ind_c(2),ieps2,ieps1) = dtweightde_tmp(ind_c(2),ieps2,ieps1) + &
1223 0 : & ii3*0.5d0*delcc0*inv_delcc(1)*deleps1*inv_epsilon1(ind_c(2),4)
1224 : dtweightde_tmp(ind_c(3),ieps2,ieps1) = dtweightde_tmp(ind_c(3),ieps2,ieps1) + &
1225 0 : & ii3*0.5d0*delcc0*inv_delcc(2)*deleps1*inv_epsilon1(ind_c(3),4)
1226 0 : deleps2 = deleps2 + deltaene2
1227 : end do
1228 :
1229 0 : deleps1 = deleps1 + deltaene1
1230 : end do
1231 :
1232 0 : eps1 = eps1 + (nn1_4-nn1_3)*deltaene1
1233 : !
1234 : !
1235 : ! interval e4 < eps < enemax
1236 : !
1237 0 : do ieps1=nn1_4+1,nene1
1238 : ! dtweightde unchanged by this tetrahedron
1239 : end do
1240 :
1241 : ! if we have a fully degenerate tetrahedron,
1242 : ! 1) the tweight is a Heaviside (step) function, which is correct above, but
1243 : ! 2) the dtweightde should contain a Dirac function: add a Gaussian here
1244 :
1245 : ! TODO: add treatment in double tetra case
1246 : ! end degenerate tetrahedron if
1247 :
1248 : ! the following blas calls are not working systematically, or do not give speed ups, strange...
1249 : !call daxpy (nene, 1.d0, dtweightde_tmp(:,1), 1, dtweightde_t(:,ind_ibz(1)), 1)
1250 : !call daxpy (nene, 1.d0, dtweightde_tmp(:,2), 1, dtweightde_t(:,ind_ibz(2)), 1)
1251 : !call daxpy (nene, 1.d0, dtweightde_tmp(:,3), 1, dtweightde_t(:,ind_ibz(3)), 1)
1252 : !call daxpy (nene, 1.d0, dtweightde_tmp(:,4), 1, dtweightde_t(:,ind_ibz(4)), 1)
1253 :
1254 0 : do ieps2 = 1, nene2
1255 0 : dtweightde(ind_k(1),:,ieps2) = dtweightde(ind_k(1),:,ieps2) + dtweightde_tmp(1,ieps2,:)
1256 0 : dtweightde(ind_k(2),:,ieps2) = dtweightde(ind_k(2),:,ieps2) + dtweightde_tmp(2,ieps2,:)
1257 0 : dtweightde(ind_k(3),:,ieps2) = dtweightde(ind_k(3),:,ieps2) + dtweightde_tmp(3,ieps2,:)
1258 0 : dtweightde(ind_k(4),:,ieps2) = dtweightde(ind_k(4),:,ieps2) + dtweightde_tmp(4,ieps2,:)
1259 : !tweight(nkpt,nene1,nene2)
1260 : end do
1261 :
1262 : end do ! itetra
1263 :
1264 : ! transpose: otherwise the data access is crap and the code slows by an order of magnitude
1265 0 : TETRA_DEALLOCATE(tweight_tmp)
1266 0 : TETRA_DEALLOCATE(dtweightde_tmp)
1267 :
1268 : end subroutine get_dbl_tetra_weight
1269 : !!***
1270 :
1271 : !!****f* m_tetrahedron/sort_tetra
1272 : !! NAME
1273 : !! sort_tetra
1274 : !!
1275 : !! FUNCTION
1276 : !! Sort double precision array list(n) into ascending numerical order using Heapsort
1277 : !! algorithm, while making corresponding rearrangement of the integer
1278 : !! array iperm. Consider that two double precision numbers
1279 : !! within tolerance tol are equal.
1280 : !!
1281 : !! INPUTS
1282 : !! n intent(in) dimension of the list
1283 : !! tol intent(in) numbers within tolerance are equal
1284 : !! list(n) intent(inout) list of double precision numbers to be sorted
1285 : !! iperm(n) intent(inout) iperm(i)=i (very important)
1286 : !!
1287 : !! OUTPUT
1288 : !! list(n) sorted list
1289 : !! iperm(n) index of permutation given the right ascending order
1290 : !!
1291 : !! SOURCE
1292 :
1293 :
1294 23332 : subroutine sort_tetra(n,list,iperm,tol)
1295 :
1296 : integer, intent(in) :: n
1297 : integer, intent(inout) :: iperm(n)
1298 : real(dp), intent(inout) :: list(n)
1299 : real(dp), intent(in) :: tol
1300 :
1301 : integer :: l,ir,iap,i,j
1302 : real(dp) :: ap
1303 : character(len=500) :: msg
1304 :
1305 23332 : if (n==1) then
1306 : ! Accomodate case of array of length 1: already sorted!
1307 0 : return
1308 23332 : else if (n<1) then
1309 : ! Should not call with n<1
1310 0 : write(msg,1000) n
1311 : 1000 format(/,' sort_tetra has been called with array length n=',i12,/, &
1312 : & ' having a value less than 1. This is not allowed.')
1313 0 : TETRA_ERROR(msg)
1314 :
1315 : else ! n>1
1316 :
1317 : ! Conduct the usual sort
1318 23332 : l=n/2+1
1319 23332 : ir=n
1320 :
1321 101080 : do ! Infinite do-loop
1322 124412 : if (l>1) then
1323 49248 : l=l-1
1324 49248 : ap=list(l)
1325 49248 : iap=iperm(l)
1326 :
1327 : else ! l<=1
1328 75164 : ap=list(ir)
1329 75164 : iap=iperm(ir)
1330 75164 : list(ir)=list(1)
1331 75164 : iperm(ir)=iperm(1)
1332 75164 : ir=ir-1
1333 :
1334 75164 : if (ir==1) then
1335 23332 : list(1)=ap
1336 23332 : iperm(1)=iap
1337 23332 : exit ! This is the end of this algorithm
1338 : end if
1339 : end if ! l>1
1340 :
1341 101080 : i=l
1342 101080 : j=l+l
1343 :
1344 252290 : do while (j<=ir)
1345 151210 : if (j<ir) then
1346 92732 : if ( list(j)<list(j+1)-tol .or. &
1347 151210 : & (list(j)<list(j+1)+tol.and.iperm(j)<iperm(j+1))) j=j+1
1348 : endif
1349 252290 : if (ap<list(j)-tol .or. (ap<list(j)+tol.and.iap<iperm(j))) then
1350 119156 : list(i)=list(j)
1351 119156 : iperm(i)=iperm(j)
1352 119156 : i=j
1353 119156 : j=j+j
1354 : else
1355 32054 : j=ir+1
1356 : end if
1357 : enddo
1358 :
1359 101080 : list(i)=ap
1360 101080 : iperm(i)=iap
1361 :
1362 : enddo ! End infinite do-loop
1363 :
1364 : end if ! n>1
1365 :
1366 : end subroutine sort_tetra
1367 : !!***
1368 :
1369 : !----------------------------------------------------------------------
1370 :
1371 : !!****f* m_tetrahedron/tetralib_has_mpi
1372 : !! NAME
1373 : !! tetralib_has_mpi
1374 : !!
1375 : !! FUNCTION
1376 : !! Return True if library has been compiled with MPI support
1377 : !!
1378 : !! SOURCE
1379 :
1380 0 : logical function tetralib_has_mpi() result(ans)
1381 :
1382 : ans = .False.
1383 : #ifdef HAVE_MPI
1384 0 : ans = .True.
1385 : #endif
1386 :
1387 0 : end function tetralib_has_mpi
1388 : !!***
1389 :
1390 : !----------------------------------------------------------------------
1391 :
1392 : !!****f* m_tetrahedron/split_work
1393 : !! NAME
1394 : !! split_work
1395 : !!
1396 : !! FUNCTION
1397 : !! Splits the number of tasks, ntasks, among nprocs processors. Used for the MPI parallelization of simple loops.
1398 : !!
1399 : !! INPUTS
1400 : !! ntasks=number of tasks
1401 : !! comm=MPI communicator.
1402 : !!
1403 : !! OUTPUT
1404 : !! nprocs=Number of MPI processes in the communicator.
1405 : !! my_start,my_stop= indices defining the initial and final task for this processor
1406 : !! ierr=Exit status.
1407 : !!
1408 : !! NOTES
1409 : !! If nprocs>ntasks then :
1410 : !! my_start=ntasks+1
1411 : !! my_stop=ntask
1412 : !!
1413 : !! In this particular case, loops of the form
1414 : !!
1415 : !! do ii=my_start,my_stop
1416 : !! ...
1417 : !! end do
1418 : !!
1419 : !! are not executed. Moreover allocation such as foo(my_start:my_stop) will generate a zero-sized array.
1420 : !!
1421 : !! SOURCE
1422 :
1423 18 : subroutine split_work(ntasks,comm,nprocs,my_start,my_stop,ierr)
1424 :
1425 : !Arguments ------------------------------------
1426 : integer,intent(in) :: ntasks,comm
1427 : integer,intent(out) :: nprocs,my_start,my_stop,ierr
1428 :
1429 : !Local variables-------------------------------
1430 : integer :: res,my_rank,block_p1,block,mpierr
1431 :
1432 : ! *************************************************************************
1433 :
1434 18 : nprocs = 1; my_start = 1; my_stop = ntasks; ierr = 1
1435 : #ifdef HAVE_MPI
1436 18 : call MPI_COMM_SIZE(comm,nprocs,mpierr); if (mpierr /= MPI_SUCCESS) return
1437 18 : call MPI_COMM_RANK(comm,my_rank,mpierr); if (mpierr /= MPI_SUCCESS) return
1438 :
1439 18 : block = ntasks/nprocs
1440 18 : res = MOD(ntasks,nprocs)
1441 18 : block_p1= block+1
1442 :
1443 18 : if (my_rank<res) then
1444 0 : my_start = my_rank *block_p1+1
1445 0 : my_stop = (my_rank+1)*block_p1
1446 : else
1447 18 : my_start = res*block_p1 + (my_rank-res )*block + 1
1448 18 : my_stop = res*block_p1 + (my_rank-res+1)*block
1449 : end if
1450 : #endif
1451 18 : ierr = 0
1452 :
1453 : end subroutine split_work
1454 : !!***
1455 :
1456 : !----------------------------------------------------------------------
1457 :
1458 : !!****f* m_tetrahedron/get_onetetra_
1459 : !! NAME
1460 : !! get_onetetra_
1461 : !!
1462 : !! FUNCTION
1463 : !! Private function to calculate the contributions to the weights due to a single tetrahedron.
1464 : !! Extracted from get_tetra_weight
1465 : !!
1466 : !! SOURCE
1467 :
1468 23328 : pure subroutine get_onetetra_(tetra,itetra,eigen_1tetra,enemin,enemax,max_occ,nene,bcorr, &
1469 23328 : & tweight_tmp,dtweightde_tmp)
1470 :
1471 : !Arguments ------------------------------------
1472 : !scalars
1473 : integer,intent(in) :: nene,bcorr,itetra
1474 : type(t_tetrahedron), intent(in) :: tetra
1475 : real(dp) ,intent(in) :: enemax,enemin,max_occ
1476 : !arrays
1477 : ! MGTODO: This layout is not optimal (lots of cache thrashing, I will optimize it later on)
1478 : real(dp), intent(out) :: tweight_tmp(nene, 4)
1479 : real(dp), intent(out) :: dtweightde_tmp(nene, 4)
1480 : real(dp),intent(in) :: eigen_1tetra(4)
1481 :
1482 : !Local variables-------------------------------
1483 : ! needed for gaussian replacement of Dirac functions
1484 : ! the three coefficients of the DOS as quadratic form,
1485 : ! in the interval [eig(ikpt-1), eig(ikpt)]
1486 : ! for ikpt = 1 we add a point below eigen(1) which doesnt
1487 : ! contribute to the DOS in any tetrahedron
1488 : !scalars
1489 : integer :: ieps,nn1,nn2,nn3,nn4
1490 : real(dp) :: cc,cc1,cc2,cc3,dcc1de,dcc2de,dcc3de,dccde,deltaene,eps
1491 : real(dp) :: epsilon21,epsilon31,epsilon32,epsilon41,epsilon42,epsilon43
1492 : real(dp) :: gau_prefactor,gau_width,gau_width2,inv_epsilon21,inv_epsilon31,gval
1493 : real(dp) :: inv_epsilon32,inv_epsilon41,inv_epsilon42,inv_epsilon43
1494 : real(dp) :: deleps1, deleps2, deleps3, deleps4
1495 : real(dp) :: invepsum, cc_pre, dccde_pre
1496 : real(dp) :: cc1_pre, cc2_pre, cc3_pre
1497 : real(dp) :: cc_tmp, dccde_tmp
1498 : real(dp) :: dcc1de_pre, dcc2de_pre, dcc3de_pre
1499 : real(dp) :: tmp,volconst,volconst_mult
1500 :
1501 : ! *********************************************************************
1502 :
1503 23328 : volconst = tetra%vv/4.d0
1504 :
1505 23328 : deltaene = (enemax-enemin) / (nene-1)
1506 :
1507 : ! This is output
1508 37596960 : tweight_tmp = zero; dtweightde_tmp = zero
1509 :
1510 23328 : volconst_mult = max_occ*volconst*dble(tetra%tetra_mult(itetra))
1511 :
1512 : ! all notations are from Blochl PRB 49 16223 [[cite:Bloechl1994a]] Appendix B
1513 23328 : epsilon21 = eigen_1tetra(2)-eigen_1tetra(1)
1514 23328 : epsilon31 = eigen_1tetra(3)-eigen_1tetra(1)
1515 23328 : epsilon41 = eigen_1tetra(4)-eigen_1tetra(1)
1516 23328 : epsilon32 = eigen_1tetra(3)-eigen_1tetra(2)
1517 23328 : epsilon42 = eigen_1tetra(4)-eigen_1tetra(2)
1518 23328 : epsilon43 = eigen_1tetra(4)-eigen_1tetra(3)
1519 23328 : inv_epsilon21 = zero; if (epsilon21 > tol14) inv_epsilon21 = 1.d0 / epsilon21
1520 23328 : inv_epsilon31 = zero; if (epsilon31 > tol14) inv_epsilon31 = 1.d0 / epsilon31
1521 23328 : inv_epsilon41 = zero; if (epsilon41 > tol14) inv_epsilon41 = 1.d0 / epsilon41
1522 23328 : inv_epsilon32 = zero; if (epsilon32 > tol14) inv_epsilon32 = 1.d0 / epsilon32
1523 23328 : inv_epsilon42 = zero; if (epsilon42 > tol14) inv_epsilon42 = 1.d0 / epsilon42
1524 23328 : inv_epsilon43 = zero; if (epsilon43 > tol14) inv_epsilon43 = 1.d0 / epsilon43
1525 :
1526 23328 : nn1 = int((eigen_1tetra(1)-enemin)/deltaene)+1
1527 23328 : nn2 = int((eigen_1tetra(2)-enemin)/deltaene)+1
1528 23328 : nn3 = int((eigen_1tetra(3)-enemin)/deltaene)+1
1529 23328 : nn4 = int((eigen_1tetra(4)-enemin)/deltaene)+1
1530 :
1531 23328 : nn1 = max(1,nn1)
1532 23328 : nn1 = min(nn1,nene)
1533 23328 : nn2 = max(1,nn2)
1534 23328 : nn2 = min(nn2,nene)
1535 23328 : nn3 = max(1,nn3)
1536 23328 : nn3 = min(nn3,nene)
1537 23328 : nn4 = max(1,nn4)
1538 23328 : nn4 = min(nn4,nene)
1539 :
1540 23328 : eps = enemin+nn1*deltaene
1541 : !
1542 : !interval enemin < eps < e1 nothing to do
1543 : !
1544 : !
1545 : !interval e1 < eps < e2
1546 : !
1547 23328 : deleps1 = eps-eigen_1tetra(1)
1548 23328 : cc_pre = volconst_mult*inv_epsilon21*inv_epsilon31*inv_epsilon41
1549 23328 : invepsum = inv_epsilon21+inv_epsilon31+inv_epsilon41
1550 23328 : dccde_pre = 3.d0*volconst_mult*inv_epsilon21*inv_epsilon31*inv_epsilon41
1551 302416 : do ieps=nn1+1,nn2
1552 279088 : cc = cc_pre * deleps1*deleps1*deleps1
1553 279088 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + cc*(4.d0-deleps1*invepsum)
1554 279088 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + cc*deleps1*inv_epsilon21
1555 279088 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + cc*deleps1*inv_epsilon31
1556 279088 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + cc*deleps1*inv_epsilon41
1557 :
1558 279088 : dccde = dccde_pre * deleps1*deleps1
1559 279088 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) + dccde*(4.d0 - deleps1*invepsum) -cc*invepsum
1560 279088 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) + (dccde*deleps1 + cc) * inv_epsilon21
1561 279088 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) + (dccde*deleps1 + cc) * inv_epsilon31
1562 279088 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) + (dccde*deleps1 + cc) * inv_epsilon41
1563 :
1564 279088 : if (bcorr == 1) then
1565 : ! bxu, correction terms based on Bloechl's paper
1566 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + &
1567 0 : & 4.d0*dccde_pre*deleps1*deleps1*(epsilon21+epsilon31+epsilon41)/40.d0
1568 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + &
1569 0 : & 4.d0*dccde_pre*deleps1*deleps1*(-epsilon21+epsilon32+epsilon42)/40.d0
1570 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + &
1571 0 : & 4.d0*dccde_pre*deleps1*deleps1*(-epsilon31-epsilon32+epsilon43)/40.d0
1572 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + &
1573 0 : & 4.d0*dccde_pre*deleps1*deleps1*(-epsilon41-epsilon42-epsilon43)/40.d0
1574 :
1575 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) + &
1576 0 : & 8.d0*dccde_pre*deleps1*(epsilon21+epsilon31+epsilon41)/40.d0
1577 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) + &
1578 0 : & 8.d0*dccde_pre*deleps1*(-epsilon21+epsilon32+epsilon42)/40.d0
1579 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) + &
1580 0 : & 8.d0*dccde_pre*deleps1*(-epsilon31-epsilon32+epsilon43)/40.d0
1581 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) + &
1582 0 : & 8.d0*dccde_pre*deleps1*(-epsilon41-epsilon42-epsilon43)/40.d0
1583 : end if
1584 :
1585 302416 : deleps1 = deleps1 + deltaene
1586 : end do
1587 :
1588 23328 : eps = eps + (nn2-nn1)*deltaene
1589 : !
1590 : ! interval e2 < eps < e3
1591 : !
1592 23328 : deleps1 = eps-eigen_1tetra(1)
1593 23328 : deleps2 = eps-eigen_1tetra(2)
1594 23328 : deleps3 = eigen_1tetra(3)-eps
1595 23328 : deleps4 = eigen_1tetra(4)-eps
1596 :
1597 23328 : cc1_pre = volconst_mult*inv_epsilon31*inv_epsilon41
1598 23328 : cc2_pre = volconst_mult*inv_epsilon41*inv_epsilon32*inv_epsilon31
1599 23328 : cc3_pre = volconst_mult*inv_epsilon42*inv_epsilon32*inv_epsilon41
1600 :
1601 23328 : dcc1de_pre = 2.d0*cc1_pre
1602 23328 : dcc2de_pre = cc2_pre
1603 23328 : dcc3de_pre = cc3_pre
1604 228264 : do ieps=nn2+1,nn3
1605 204936 : cc1 = cc1_pre * deleps1*deleps1
1606 204936 : cc2 = cc2_pre * deleps1*deleps2*deleps3
1607 204936 : cc3 = cc3_pre * deleps2*deleps2*deleps4
1608 :
1609 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + &
1610 204936 : & cc1 + (cc1+cc2)*deleps3*inv_epsilon31 + (cc1+cc2+cc3)*deleps4*inv_epsilon41
1611 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + &
1612 204936 : & cc1+cc2+cc3+(cc2+cc3)*deleps3*inv_epsilon32 + cc3*deleps4*inv_epsilon42
1613 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + &
1614 204936 : & (cc1+cc2)*deleps1*inv_epsilon31 + (cc2+cc3)*deleps2*inv_epsilon32
1615 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + &
1616 204936 : & (cc1+cc2+cc3)*deleps1*inv_epsilon41 + cc3*deleps2*inv_epsilon42
1617 :
1618 :
1619 204936 : dcc1de = dcc1de_pre * deleps1
1620 204936 : dcc2de = dcc2de_pre * (-deleps1*deleps2 +deleps1*deleps3 +deleps2*deleps3)
1621 204936 : dcc3de = dcc3de_pre * (2.d0*deleps2*deleps4 -deleps2*deleps2)
1622 :
1623 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) &
1624 : & + dcc1de &
1625 : & + ((dcc1de+dcc2de)*deleps3 -(cc1+cc2)) * inv_epsilon31 &
1626 204936 : & + ((dcc1de+dcc2de+dcc3de)*deleps4 -(cc1+cc2+cc3)) * inv_epsilon41
1627 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) &
1628 : & + dcc1de+dcc2de+dcc3de &
1629 : & + ((dcc2de+dcc3de)*deleps3 -(cc2+cc3) ) * inv_epsilon32 &
1630 204936 : & + (dcc3de*deleps4 -cc3 ) * inv_epsilon42
1631 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) &
1632 : & + ((dcc1de+dcc2de)*deleps1 + (cc1+cc2) ) * inv_epsilon31 &
1633 204936 : & + ((dcc2de+dcc3de)*deleps2 + (cc2+cc3) ) * inv_epsilon32
1634 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) &
1635 : & + ((dcc1de+dcc2de+dcc3de)*deleps1 + (cc1+cc2+cc3) ) * inv_epsilon41 &
1636 204936 : & + (dcc3de*deleps2 + cc3) * inv_epsilon42
1637 :
1638 204936 : if (bcorr == 1) then
1639 : ! bxu, correction terms based on Bloechl's paper
1640 : ! The correction terms may cause the dtweightde become negative
1641 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + &
1642 : & 4.d0*cc1_pre* &
1643 : & (3.d0*epsilon21+6.d0*deleps2-3.d0*(epsilon31+epsilon42)*deleps2**2.d0*inv_epsilon32*inv_epsilon42)* &
1644 0 : & (epsilon21+epsilon31+epsilon41)/40.d0
1645 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + &
1646 : & 4.d0*cc1_pre* &
1647 : & (3.d0*epsilon21+6.d0*deleps2-3.d0*(epsilon31+epsilon42)*deleps2**2.d0*inv_epsilon32*inv_epsilon42)* &
1648 0 : & (-epsilon21+epsilon32+epsilon42)/40.d0
1649 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + &
1650 : & 4.d0*cc1_pre* &
1651 : & (3.d0*epsilon21+6.d0*deleps2-3.d0*(epsilon31+epsilon42)*deleps2**2.d0*inv_epsilon32*inv_epsilon42)* &
1652 0 : & (-epsilon31-epsilon32+epsilon43)/40.d0
1653 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + &
1654 : & 4.d0*cc1_pre* &
1655 : & (3.d0*epsilon21+6.d0*deleps2-3.d0*(epsilon31+epsilon42)*deleps2**2.d0*inv_epsilon32*inv_epsilon42)* &
1656 0 : & (-epsilon41-epsilon42-epsilon43)/40.d0
1657 :
1658 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) + &
1659 : & 4.d0*cc1_pre* &
1660 : & (6.d0-6.d0*(epsilon31+epsilon42)*deleps2*inv_epsilon32*inv_epsilon42)* &
1661 0 : & (epsilon21+epsilon31+epsilon41)/40.d0
1662 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) + &
1663 : & 4.d0*cc1_pre* &
1664 : & (6.d0-6.d0*(epsilon31+epsilon42)*deleps2*inv_epsilon32*inv_epsilon42)* &
1665 0 : & (-epsilon21+epsilon32+epsilon42)/40.d0
1666 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) + &
1667 : & 4.d0*cc1_pre* &
1668 : & (6.d0-6.d0*(epsilon31+epsilon42)*deleps2*inv_epsilon32*inv_epsilon42)* &
1669 0 : & (-epsilon31-epsilon32+epsilon43)/40.d0
1670 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) + &
1671 : & 4.d0*cc1_pre* &
1672 : & (6.d0-6.d0*(epsilon31+epsilon42)*deleps2*inv_epsilon32*inv_epsilon42)* &
1673 0 : & (-epsilon41-epsilon42-epsilon43)/40.d0
1674 : end if
1675 :
1676 204936 : deleps1 = deleps1 + deltaene
1677 204936 : deleps2 = deleps2 + deltaene
1678 204936 : deleps3 = deleps3 - deltaene
1679 228264 : deleps4 = deleps4 - deltaene
1680 : end do
1681 :
1682 23328 : eps = eps + (nn3-nn2)*deltaene
1683 : !
1684 : ! interval e3 < eps < e4
1685 : !
1686 23328 : deleps4 = eigen_1tetra(4)-eps
1687 23328 : cc_pre = volconst_mult*inv_epsilon41*inv_epsilon42*inv_epsilon43
1688 23328 : invepsum = inv_epsilon41+inv_epsilon42+inv_epsilon43
1689 23328 : dccde_pre = -3.d0*cc_pre
1690 244400 : do ieps=nn3+1,nn4
1691 221072 : cc = cc_pre * deleps4*deleps4*deleps4
1692 221072 : cc_tmp = cc * deleps4
1693 221072 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + volconst_mult - cc_tmp*inv_epsilon41
1694 221072 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + volconst_mult - cc_tmp*inv_epsilon42
1695 221072 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + volconst_mult - cc_tmp*inv_epsilon43
1696 221072 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + volconst_mult - cc*4.d0 + cc_tmp*invepsum
1697 :
1698 221072 : dccde = dccde_pre * deleps4*deleps4
1699 221072 : dccde_tmp = -dccde*deleps4 + cc
1700 221072 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) + dccde_tmp * inv_epsilon41
1701 221072 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) + dccde_tmp * inv_epsilon42
1702 221072 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) + dccde_tmp * inv_epsilon43
1703 221072 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) - dccde*4.d0 - dccde_tmp*invepsum
1704 :
1705 221072 : if (bcorr == 1) then
1706 : ! bxu, correction terms based on Bloechl's paper
1707 : ! The correction terms may cause the dtweightde become negative
1708 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + &
1709 0 : & 12.d0*cc_pre*deleps4*deleps4*(epsilon21+epsilon31+epsilon41)/40.d0
1710 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + &
1711 0 : & 12.d0*cc_pre*deleps4*deleps4*(-epsilon21+epsilon32+epsilon42)/40.d0
1712 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + &
1713 0 : & 12.d0*cc_pre*deleps4*deleps4*(-epsilon31-epsilon32+epsilon43)/40.d0
1714 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + &
1715 0 : & 12.d0*cc_pre*deleps4*deleps4*(-epsilon41-epsilon42-epsilon43)/40.d0
1716 :
1717 : dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) - &
1718 0 : & 24.d0*cc_pre*deleps4*(epsilon21+epsilon31+epsilon41)/40.d0
1719 : dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) - &
1720 0 : & 24.d0*cc_pre*deleps4*(-epsilon21+epsilon32+epsilon42)/40.d0
1721 : dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) - &
1722 0 : & 24.d0*cc_pre*deleps4*(-epsilon31-epsilon32+epsilon43)/40.d0
1723 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) - &
1724 0 : & 24.d0*cc_pre*deleps4*(-epsilon41-epsilon42-epsilon43)/40.d0
1725 : end if
1726 :
1727 244400 : deleps4 = deleps4 - deltaene
1728 : end do
1729 23328 : eps = eps + (nn4-nn3)*deltaene
1730 : !
1731 : !
1732 : ! interval e4 < eps < enemax
1733 : !
1734 1429904 : do ieps=nn4+1,nene
1735 1406576 : tweight_tmp(ieps,1) = tweight_tmp(ieps,1) + volconst_mult
1736 1406576 : tweight_tmp(ieps,2) = tweight_tmp(ieps,2) + volconst_mult
1737 1406576 : tweight_tmp(ieps,3) = tweight_tmp(ieps,3) + volconst_mult
1738 1429904 : tweight_tmp(ieps,4) = tweight_tmp(ieps,4) + volconst_mult
1739 : ! dtweightde unchanged by this tetrahedron
1740 : end do
1741 :
1742 : !
1743 : ! if we have a fully degenerate tetrahedron,
1744 : ! 1) the tweight is a Heaviside (step) function, which is correct above, but
1745 : ! 2) the dtweightde should contain a Dirac function: add a Gaussian here
1746 : !
1747 23328 : if (epsilon41 < tol14) then
1748 :
1749 : ! to ensure the gaussian will integrate properly:
1750 : ! WARNING: this smearing could be problematic if too large
1751 : ! and doesnt integrate well if its too small
1752 0 : gau_width = 10.0d0*deltaene
1753 0 : gau_width2 = 1.0 / gau_width / gau_width
1754 0 : gau_prefactor = volconst_mult / gau_width / sqrt(pi)
1755 : !
1756 : ! average position since bracket for epsilon41 is relatively large
1757 0 : cc = (eigen_1tetra(1)+eigen_1tetra(2)+eigen_1tetra(3)+eigen_1tetra(4))/4.d0
1758 0 : eps = enemin
1759 0 : do ieps=1,nene
1760 0 : tmp = eps - cc
1761 0 : gval = gau_prefactor*exp(-tmp*tmp*gau_width2)
1762 : ! MG TODO: I think this is not correct, because we have divided by 4 so
1763 : ! the other points should be accumulated as well.
1764 : ! There are however changes in the unit tests if I activate these lines...
1765 : !dtweightde_tmp(ieps,1) = dtweightde_tmp(ieps,1) + gval
1766 : !dtweightde_tmp(ieps,2) = dtweightde_tmp(ieps,2) + gval
1767 : !dtweightde_tmp(ieps,3) = dtweightde_tmp(ieps,3) + gval
1768 0 : dtweightde_tmp(ieps,4) = dtweightde_tmp(ieps,4) + gval
1769 0 : eps = eps + deltaene
1770 : end do
1771 : end if ! end degenerate tetrahedron if
1772 :
1773 23328 : end subroutine get_onetetra_
1774 : !!***
1775 :
1776 : !----------------------------------------------------------------------
1777 :
1778 : !!****f* m_tetrahedron/tetra_get_onewk
1779 : !! NAME
1780 : !! tetra_get_onewk
1781 : !!
1782 : !! FUNCTION
1783 : !! Calculate integration weights and their derivatives for a single k-point in the IBZ.
1784 : !!
1785 : !! INPUTS
1786 : !! tetra<t_tetrahedron>=Object with tables for tetrahedron method.
1787 : !! ik_ibz=Index of the k-point in the IBZ array
1788 : !! bcorr=1 to include Blochl correction else 0.
1789 : !! nene=number of energies for DOS
1790 : !! nibz=number of irreducible kpoints
1791 : !! eigen_ibz(nkibz)=eigenenergies for each k point
1792 : !! enemin=minimal energy for DOS
1793 : !! enemax=maximal energy for DOS
1794 : !! max_occ=maximal occupation number (2 for nsppol=1, 1 for nsppol=2)
1795 : !!
1796 : !! OUTPUT
1797 : !! weights(nene,2) = integration weights for
1798 : !! Dirac delta (derivative of theta wrt energy) and Theta (Heaviside function)
1799 : !! for a given (band, k-point, spin).
1800 : !!
1801 : !! SOURCE
1802 :
1803 0 : subroutine tetra_get_onewk(tetra,ik_ibz,bcorr,nene,nkibz,eig_ibz,enemin,enemax,max_occ,weights)
1804 :
1805 : !Arguments ------------------------------------
1806 : !scalars
1807 : integer,intent(in) :: ik_ibz,nene,nkibz,bcorr
1808 : type(t_tetrahedron), intent(in) :: tetra
1809 : real(dp) ,intent(in) :: enemin,enemax,max_occ
1810 : !arrays
1811 : real(dp),intent(in) :: eig_ibz(nkibz)
1812 : real(dp),intent(out) :: weights(nene,2)
1813 :
1814 : !Local variables-------------------------------
1815 : !scalars
1816 : integer :: itetra,ii
1817 : !arrays
1818 : integer :: ind_ibz(4)
1819 0 : real(dp) :: tweight_tmp(nene,4),dtweightde_tmp(nene,4),eigen_1tetra(4)
1820 :
1821 : ! *********************************************************************
1822 :
1823 0 : weights = zero
1824 :
1825 : ! For each tetrahedron
1826 0 : do itetra=1,tetra%ntetra
1827 :
1828 : ! Here we need the original ordering to reference the correct irred kpoints
1829 0 : ind_ibz(:) = tetra%tetra_full(:,1,itetra)
1830 : ! Cycle if this tetra does not contribute to this k-point.
1831 0 : if (all(ind_ibz /= ik_ibz)) cycle
1832 :
1833 : ! Sort energies before calling get_onetetra_
1834 0 : eigen_1tetra(:) = eig_ibz(ind_ibz(:))
1835 0 : call sort_tetra(4, eigen_1tetra, ind_ibz, tol14)
1836 :
1837 : call get_onetetra_(tetra, itetra, eigen_1tetra, enemin, enemax, max_occ, nene, bcorr, &
1838 0 : tweight_tmp, dtweightde_tmp)
1839 :
1840 : ! Accumulate contributions to ik_ibz (there might be multiple vertexes that map onto ik_ibz)
1841 0 : do ii=1,4
1842 0 : if (ind_ibz(ii) == ik_ibz) then
1843 0 : weights(:,1) = weights(:,1) + dtweightde_tmp(:,ii)
1844 0 : weights(:,2) = weights(:,2) + tweight_tmp(:,ii)
1845 : end if
1846 : end do
1847 : end do ! itetra
1848 :
1849 0 : end subroutine tetra_get_onewk
1850 : !!***
1851 :
1852 : !----------------------------------------------------------------------
1853 :
1854 : !!****f* m_tetrahedron/tetra_get_onewk_wvals
1855 : !! NAME
1856 : !! tetra_get_onewk_wvals
1857 : !!
1858 : !! FUNCTION
1859 : !! Calculate integration weights and their derivatives for a single k-point in the IBZ.
1860 : !!
1861 : !! INPUTS
1862 : !! tetra<t_tetrahedron>=Object with tables for tetrahedron method.
1863 : !! ik_ibz=Index of the k-point in the IBZ array
1864 : !! bcorr=1 to include Blochl correction else 0.
1865 : !! nw=number of energies in wvals
1866 : !! nibz=number of irreducible kpoints
1867 : !! wvals(nw)=Frequency points.
1868 : !! eigen_ibz(nkibz)=eigenenergies for each k point
1869 : !! [wtol]: If present, frequency points that differ by less that wtol are treated as equivalent.
1870 : !! and the tetrahedron integration is performed only once per frequency point.
1871 : !!
1872 : !! OUTPUT
1873 : !! weights(nw,2) = integration weights for
1874 : !! Dirac delta (derivative of theta wrt energy) and Theta (Heaviside function)
1875 : !! for a given (band, k-point, spin).
1876 : !!
1877 : !! SOURCE
1878 :
1879 0 : subroutine tetra_get_onewk_wvals(tetra, ik_ibz, bcorr, nw, wvals, nkibz, eig_ibz, weights, wtol)
1880 :
1881 : !Arguments ------------------------------------
1882 : !scalars
1883 : integer,intent(in) :: ik_ibz,nw,nkibz,bcorr
1884 : real(dp), optional, intent(in) :: wtol
1885 : type(t_tetrahedron), intent(in) :: tetra
1886 : !arrays
1887 : real(dp),intent(in) :: wvals(nw)
1888 : real(dp),intent(in) :: eig_ibz(nkibz)
1889 : real(dp),intent(out) :: weights(nw, 2)
1890 :
1891 : !Local variables-------------------------------
1892 : !scalars
1893 : !integer,save :: done = 0
1894 : integer,parameter :: nene=3
1895 : integer :: itetra,ii,jj,iw,ie
1896 : logical :: samew
1897 : real(dp),parameter :: max_occ1 = one
1898 : real(dp) :: enemin, enemax
1899 : !arrays
1900 : integer :: ind_ibz(4)
1901 : real(dp) :: theta_tmp(nene,4), delta_tmp(nene,4), eigen_1tetra(4)
1902 :
1903 : ! *********************************************************************
1904 :
1905 0 : weights = zero
1906 :
1907 : ! For each tetrahedron
1908 0 : do jj=1,tetra%ibz_tetra_count(ik_ibz)
1909 0 : itetra = tetra%ibz_tetra_mapping(ik_ibz,jj)
1910 :
1911 : ! Here we need the original ordering to reference the correct irred kpoints
1912 0 : ind_ibz(:) = tetra%tetra_full(:,1,itetra)
1913 :
1914 : ! Sort energies before calling get_onetetra_
1915 0 : eigen_1tetra(:) = eig_ibz(ind_ibz(:))
1916 0 : call sort_tetra(4, eigen_1tetra, ind_ibz, tol14)
1917 :
1918 0 : do iw=1,nw
1919 0 : samew = .False.
1920 0 : if (present(wtol)) then
1921 0 : if (iw > 1) samew = abs(wvals(iw) - wvals(iw - 1)) < wtol
1922 : end if
1923 0 : if (.not. samew) then
1924 0 : enemin = wvals(iw) - 0.01; enemax = wvals(iw) + 0.01
1925 0 : ie = nene / 2 + 1
1926 : call get_onetetra_(tetra, itetra, eigen_1tetra, enemin, enemax, max_occ1, nene, bcorr, &
1927 0 : theta_tmp, delta_tmp)
1928 : end if
1929 :
1930 : ! Accumulate contributions to ik_ibz (there might be multiple vertexes that map onto ik_ibz)
1931 0 : do ii=1,4
1932 0 : if (ind_ibz(ii) == ik_ibz) then
1933 0 : weights(iw, 1) = weights(iw, 1) + delta_tmp(ie, ii)
1934 0 : weights(iw, 2) = weights(iw, 2) + theta_tmp(ie, ii)
1935 : end if
1936 : end do
1937 : end do ! iw
1938 : end do ! itetra
1939 :
1940 0 : end subroutine tetra_get_onewk_wvals
1941 : !!***
1942 :
1943 : !----------------------------------------------------------------------
1944 :
1945 : !!****f* m_tetrahedron/tetra_get_onetetra_wvals
1946 : !! NAME
1947 : !! tetra_get_onetetra_wvals
1948 : !!
1949 : !! FUNCTION
1950 : !! Calculate integration weights and their derivatives for a single k-point in the IBZ.
1951 : !!
1952 : !! INPUTS
1953 : !! tetra<t_tetrahedron>=Object with tables for tetrahedron method.
1954 : !! ik_ibz=Index of the k-point in the IBZ array
1955 : !! bcorr=1 to include Blochl correction else 0.
1956 : !! nw=number of energies in wvals
1957 : !! nibz=number of irreducible kpoints
1958 : !! wvals(nw)=Frequency points.
1959 : !! eigen_ibz(nkibz)=eigenenergies for each k point
1960 : !! [wtol]: If present, frequency points that differ by less that wtol are treated as equivalent.
1961 : !! and the tetrahedron integration is performed only once per frequency point.
1962 : !!
1963 : !! OUTPUT
1964 : !! weights(nw,2) = integration weights for
1965 : !! Dirac delta (derivative of theta wrt energy) and Theta (Heaviside function)
1966 : !! for a given (band, k-point, spin).
1967 : !!
1968 : !! SOURCE
1969 :
1970 0 : subroutine tetra_get_onetetra_wvals(tetra, itetra, eigen_1tetra, bcorr, nw, wvals, weights, wtol)
1971 :
1972 : !Arguments ------------------------------------
1973 : !scalars
1974 : integer,intent(in) :: nw,bcorr
1975 : real(dp), optional, intent(in) :: wtol
1976 : type(t_tetrahedron), intent(in) :: tetra
1977 : !arrays
1978 : real(dp),intent(in) :: wvals(nw)
1979 : real(dp),intent(out) :: weights(nw, 2, 4)
1980 :
1981 : !Local variables-------------------------------
1982 : !scalars
1983 : !integer,save :: done = 0
1984 : integer,parameter :: nene3=3
1985 : integer :: itetra,ii,idx,iw,ie
1986 : integer :: ind(4)
1987 : logical :: samew
1988 : real(dp),parameter :: max_occ1 = one
1989 : real(dp) :: enemin, enemax
1990 : !arrays
1991 : real(dp) :: theta_tmp(nene3,4), delta_tmp(nene3,4), eigen_1tetra(4)
1992 :
1993 : ! *********************************************************************
1994 :
1995 0 : ind = [1,2,3,4]
1996 0 : call sort_tetra(4, eigen_1tetra, ind, tol14)
1997 0 : weights = 0
1998 :
1999 : !for all the frequencies
2000 0 : do iw=1,nw
2001 0 : samew = .False.
2002 0 : if (present(wtol)) then
2003 0 : if (iw > 1) samew = abs(wvals(iw) - wvals(iw - 1)) < wtol
2004 : end if
2005 0 : if (.not. samew) then
2006 0 : enemin = wvals(iw) - 0.01
2007 0 : enemax = wvals(iw) + 0.01
2008 0 : ie = nene3 / 2 + 1
2009 : call get_onetetra_(tetra, itetra, eigen_1tetra, enemin, enemax, max_occ1, nene3, bcorr, &
2010 0 : theta_tmp, delta_tmp)
2011 : end if
2012 :
2013 : ! Accumulate contributions to ik_ibz (there might be multiple vertexes that map onto ik_ibz)
2014 0 : do ii=1,4
2015 0 : idx = ind(ii)
2016 0 : weights(iw, 1, idx) = weights(iw, 1, idx) + delta_tmp(ie, ii)
2017 0 : weights(iw, 2, idx) = weights(iw, 2, idx) + theta_tmp(ie, ii)
2018 : end do
2019 : end do !iw
2020 :
2021 0 : end subroutine tetra_get_onetetra_wvals
2022 : !!***
2023 :
2024 0 : end module m_tetrahedron
2025 : !!***
|