Octopus
simplex.F90
Go to the documentation of this file.
1!! Copyright (C) 2025 Octopus Developers
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21module simplex_oct_m
22 use, intrinsic :: iso_fortran_env, only: real64
23 use debug_oct_m, only: debug
24#ifndef NDEBUG
26#endif
27 use global_oct_m, only: &
31 implicit none
32
33 private
34
35 public :: &
36 simplex_t, &
41
42 type simplex_t
43 integer :: rdim
44 integer :: sdim
45 integer :: n_simplices
46 integer :: n_points
47 integer, allocatable :: simplices(:,:)
48 contains
49 final :: simplex_end
50 end type simplex_t
51
52 interface simplex_t
53 module procedure simplex_init
54 end interface simplex_t
55
56 interface simplex_weights
58 end interface simplex_weights
59
60 interface simplex_dos
62 end interface simplex_dos
63
64contains
65
74 pure subroutine simplex_sort_2(values, idx)
75 real(real64), intent(inout) :: values(2)
76 integer, intent(inout) :: idx(2)
77
78 call simplex_compare_swap(values(1), values(2), idx(1), idx(2))
79 end subroutine simplex_sort_2
80
89 pure subroutine simplex_sort_3(values, idx)
90 real(real64), intent(inout) :: values(3)
91 integer, intent(inout) :: idx(3)
92
93 call simplex_compare_swap(values(1), values(2), idx(1), idx(2))
94 call simplex_compare_swap(values(2), values(3), idx(2), idx(3))
95 call simplex_compare_swap(values(1), values(2), idx(1), idx(2))
96 end subroutine simplex_sort_3
97
106 pure subroutine simplex_sort_4(values, idx)
107 real(real64), intent(inout) :: values(4)
108 integer, intent(inout) :: idx(4)
109
110 call simplex_compare_swap(values(1), values(2), idx(1), idx(2))
111 call simplex_compare_swap(values(3), values(4), idx(3), idx(4))
112 call simplex_compare_swap(values(1), values(3), idx(1), idx(3))
113 call simplex_compare_swap(values(2), values(4), idx(2), idx(4))
114 call simplex_compare_swap(values(2), values(3), idx(2), idx(3))
115 end subroutine simplex_sort_4
123 pure subroutine simplex_compare_swap(a, b, ia, ib)
124 real(real64), intent(inout) :: a, b
125 integer, intent(inout) :: ia, ib
126
127 real(real64) :: tmp_a
128 integer :: tmp_i
129
130 if (a > b) then
131 tmp_a = a
132 a = b
133 b = tmp_a
134
135 tmp_i = ia
136 ia = ib
137 ib = tmp_i
138 end if
139 end subroutine simplex_compare_swap
156 function simplex_init(dim, naxis, nshifts, shift, kpoints, equiv, opt) result(this)
157 integer, intent(in) :: dim
158 integer, intent(in) :: naxis(1:dim)
159 integer, intent(in) :: nshifts
160 real(real64), intent(in) :: shift(:,:)
161 real(real64), intent(in) :: kpoints(:,:)
162 integer, intent(in), optional :: equiv(:)
163 logical, intent(in) :: opt
164 type(simplex_t), pointer :: this
165
166 real(real64) :: kmin(dim)
167 integer :: ik, npoints
168
169 integer :: ix(dim)
170 integer, allocatable :: kl123(:,:,:)
171
172 integer :: rdim, raxis(3)
173
174 push_sub(simplex_init)
175
176 if (nshifts /= 1) then
177 message(1) = "The linear tetrahedron method only works for automatic k-point grids with a single shift"
178 call messages_fatal(1)
179 end if
180
181 safe_allocate(this)
182 safe_allocate_source(kl123(1:naxis(1), 1:naxis(2), 1:naxis(3)), -1)
183
184 npoints = product(naxis)
185 kmin = minval(kpoints, 2)
186
187 do ik = 1, npoints
188 ix(:) = nint((kpoints(:,ik) - kmin) * naxis + 1)
189 assert(kl123(ix(1), ix(2), ix(3)) == -1)
190 if (present(equiv)) then
191 kl123(ix(1), ix(2), ix(3)) = equiv(ik)
192 else
193 kl123(ix(1), ix(2), ix(3)) = ik
194 end if
195 end do
196
197 rdim = sum(merge(1, 0, naxis > 1))
198 raxis(1:rdim) = pack(naxis, naxis > 1)
199
200 if (any(raxis(1:rdim) /= naxis(1:rdim))) then
201 message(1) = "The periodic dimensions must be consecutive"
202 call messages_fatal(1)
203 end if
204
205 select case (rdim)
206 case default
207 assert(.false.)
208 case (1)
209 block
210 integer, parameter :: submesh_segments(1,2) = reshape([ &
211 1, 2 ], shape(submesh_segments), order=[2, 1])
212 ! coordinates of corners and neighbors in barycentric coordinates
213 integer, parameter :: b(4,2) = reshape([ &
214 1 , 0 , & ! k1
215 0 , 1 , & ! k2
216 2 , -1, & ! 2 * k1 - k2
217 -1, 2 & ! 2 * k2 - k1
218 ], shape(b), order=[2, 1])
219
220 integer :: i, ip1, it, n
221 integer :: corners(2,1), v(2,1), c(1)
222 integer :: this_segment(2), this_corner
223
224 this%n_points = npoints
225 this%n_simplices = npoints
226 this%rdim = rdim
227 this%sdim = merge(4, 2, opt)
228 safe_allocate(this%simplices(this%n_simplices, this%sdim))
229
230 do i = 1, raxis(1)
231 ip1 = modulo(i, raxis(1)) + 1
232 corners(:,:) = reshape([ i , ip1 ], shape(corners), order=[2, 1])
233
234 do it = 1, size(submesh_segments, 1)
235 n = (it - 1) + 1 * (i - 1) + 1
236 this_segment(:) = submesh_segments(it, :)
237 v(1,:) = corners(this_segment(1), :)
238 v(2,:) = corners(this_segment(2), :)
239 do ik = 1, this%sdim
240 c(:) = b(ik,1) * v(1,:) + b(ik,2) * v(2,:)
241 c(:) = modulo(c(:) - 1, raxis(1:rdim)) + 1
242 this_corner = kl123(c(1), 1, 1)
243 this%simplices(n,ik) = this_corner
244 end do
245 end do
246 end do
247 end block
248 case (2)
249 block
250 integer, parameter :: submesh_triangles(2,3) = reshape([ &
251 1, 2, 3, &
252 1, 4, 3], shape(submesh_triangles), order=[2, 1])
253 ! coordinates of corners and neighbors in barycentric coordinates
254 integer, parameter :: b(10,3) = reshape([ &
255 1 , 0 , 0 , & ! k1
256 0 , 1 , 0 , & ! k2
257 0 , 0 , 1 , & ! k3
258 2 , -1, 0 , & ! 2 * k1 - k2
259 0 , 2 , -1, & ! 2 * k2 - k3
260 2 , 0 , -1, & ! 2 * k1 - k3
261 -1, 0 , 2 , & ! 2 * k3 - k1
262 -1, 2 , 0 , & ! 2 * k2 - k1
263 0 , -1, 2 , & ! 2 * k3 - k2
264 1 , -1, 1 & ! k1 - k2 + k3
265 ], shape(b), order=[2, 1])
266
267 integer :: i, j, ip1, jp1, it, n
268 integer :: corners(4,2), v(3,2), c(2)
269 integer :: this_triangle(3), this_corner
270
271 this%n_points = npoints
272 this%n_simplices = 2 * npoints
273 this%rdim = rdim
274 this%sdim = merge(10, 3, opt)
275 safe_allocate(this%simplices(this%n_simplices, this%sdim))
276
277 do i = 1, raxis(1)
278 do j = 1, raxis(2)
279 ip1 = modulo(i, raxis(1)) + 1
280 jp1 = modulo(j, raxis(2)) + 1
281 corners(:,:) = reshape([ &
282 i , j , &
283 ip1 , j , &
284 ip1 , jp1 , &
285 i , jp1 ], shape(corners), order=[2, 1])
286
287 do it = 1, size(submesh_triangles, 1)
288 n = (it - 1) + 2 * ((j - 1) + raxis(2) * (i - 1)) + 1
289 this_triangle(:) = submesh_triangles(it, :)
290 v(1,:) = corners(this_triangle(1), :)
291 v(2,:) = corners(this_triangle(2), :)
292 v(3,:) = corners(this_triangle(3), :)
293 do ik = 1, this%sdim
294 c(:) = b(ik,1) * v(1,:) + b(ik,2) * v(2,:) + b(ik,3) * v(3,:)
295 c(:) = modulo(c(:) - 1, raxis(1:rdim)) + 1
296 this_corner = kl123(c(1), c(2), 1)
297 this%simplices(n,ik) = this_corner
298 end do
299 end do
300 end do
301 end do
302 end block
303 case(3)
304 block
305 integer, parameter :: submesh_tetras(6,4) = reshape([ &
306 1, 2, 3, 6, &
307 1, 3, 5, 6, &
308 3, 5, 6, 7, &
309 3, 6, 7, 8, &
310 3, 4, 6, 8, &
311 2, 3, 4, 6], shape(submesh_tetras), order=[2, 1])
312 ! coordinates of corners and neighbors in barycentric coordinates
313 integer, parameter :: b(20,4) = reshape([ &
314 1 , 0 , 0 , 0 , & ! k1
315 0 , 1 , 0 , 0 , & ! k2
316 0 , 0 , 1 , 0 , & ! k3
317 0 , 0 , 0 , 1 , & ! k4
318 2 , -1, 0 , 0 , & ! 2 * k1 - k2
319 0 , 2 , -1, 0 , & ! 2 * k2 - k3
320 0 , 0 , 2 , -1, & ! 2 * k3 - k4
321 -1, 0 , 0 , 2 , & ! 2 * k4 - k1
322 2 , 0 , -1, 0 , & ! 2 * k1 - k3
323 0 , 2 , 0 , -1, & ! 2 * k2 - k4
324 -1, 0 , 2 , 0 , & ! 2 * k3 - k1
325 0 , -1, 0 , 2 , & ! 2 * k4 - k2
326 2 , 0 , 0 , -1, & ! 2 * k1 - k4
327 -1, 2 , 0 , 0 , & ! 2 * k2 - k1
328 0 , -1, 2 , 0 , & ! 2 * k3 - k2
329 0 , 0 , -1, 2 , & ! 2 * k4 - k3
330 -1, 1 , 0 , 1 , & ! k4 - k1 + k2
331 1 , -1, 1 , 0 , & ! k1 - k2 + k3
332 0 , 1 , -1, 1 , & ! k2 - k3 + k4
333 1 , 0 , 1 , -1 & ! k3 - k4 + k1
334 ], shape(b), order=[2, 1])
335
336 integer :: i, j, k, ip1, jp1, kp1, it, n
337 integer :: corners(8,3), v(4,3), c(3)
338 integer :: this_tetra(4), this_corner
339
340 this%n_points = npoints
341 this%n_simplices = 6 * npoints
342 this%rdim = rdim
343 this%sdim = merge(20, 4, opt)
344 safe_allocate(this%simplices(this%n_simplices, this%sdim))
345
346 do i = 1, raxis(1)
347 do j = 1, raxis(2)
348 do k = 1, raxis(3)
349 ip1 = modulo(i, raxis(1)) + 1
350 jp1 = modulo(j, raxis(2)) + 1
351 kp1 = modulo(k, raxis(3)) + 1
352 corners(:,:) = reshape([ &
353 i , j , k , &
354 ip1 , j , k , &
355 i , jp1 , k , &
356 ip1 , jp1 , k , &
357 i , j , kp1 , &
358 ip1 , j , kp1 , &
359 i , jp1 , kp1 , &
360 ip1 , jp1 , kp1 ], shape(corners), order=[2, 1])
361
362 do it = 1, size(submesh_tetras, 1)
363 n = (it - 1) + 6 * ((k - 1) + raxis(3) * ((j - 1) + raxis(2) * (i - 1))) + 1
364 this_tetra(:) = submesh_tetras(it, :)
365 v(1,:) = corners(this_tetra(1), :)
366 v(2,:) = corners(this_tetra(2), :)
367 v(3,:) = corners(this_tetra(3), :)
368 v(4,:) = corners(this_tetra(4), :)
369 do ik = 1, this%sdim
370 c(:) = b(ik,1) * v(1,:) + b(ik,2) * v(2,:) + b(ik,3) * v(3,:) + b(ik,4) * v(4,:)
371 c(:) = modulo(c(:) - 1, raxis(1:rdim)) + 1
372 this_corner = kl123(c(1), c(2), c(3))
373 this%simplices(n,ik) = this_corner
374 end do
375 end do
376 end do
377 end do
378 end do
379 end block
380 end select
381
382 safe_deallocate_a(kl123)
383
384 pop_sub(simplex_init)
385 end function simplex_init
386
390 subroutine simplex_end(this)
391 type(simplex_t), intent(inout) :: this
392 push_sub(simplex_end)
393 safe_deallocate_a(this%simplices)
394 pop_sub(simplex_end)
395 end subroutine simplex_end
396
404 subroutine simplex_weights_single(rdim, esimplex, eF, weights, dos)
405 integer, intent(in) :: rdim
406 real(real64), intent(in) :: esimplex(:)
407 real(real64), intent(in) :: ef
408 real(real64), intent(out) :: weights(:)
409 real(real64), intent(out) :: dos(:)
410
411 real(real64) :: weights_array(size(weights), 1), dos_array(size(dos), 1)
412
413 ! no PUSH_SUB, called too often
414
415 call simplex_weights_array(rdim, esimplex, [ef], weights_array, dos_array)
416 weights(:) = weights_array(:, 1)
417 dos(:) = dos_array(:, 1)
418 end subroutine simplex_weights_single
419
427 subroutine simplex_weights_array(rdim, esimplex, eFs, weights, dos)
428 integer, intent(in) :: rdim
429 real(real64), intent(in) :: esimplex(:)
430 real(real64), intent(in) :: efs(:)
431 real(real64), intent(out) :: weights(:,:)
432 real(real64), intent(out) :: dos(:,:)
433
434 ! no PUSH_SUB, called too often
435
436 assert(size(weights, 1) == rdim + 1)
437 assert(size(dos, 1) == rdim + 1)
438 assert(size(weights, 2) == size(efs))
439 assert(size(dos, 2) == size(efs))
440
441 select case (rdim)
442 case (1)
443 call simplex_weights_1d(esimplex, efs, weights, dos)
444 case (2)
445 call simplex_weights_2d(esimplex, efs, weights, dos)
446 case (3)
447 call simplex_weights_3d(esimplex, efs, weights, dos)
448 case default
449 assert(.false.)
450 end select
451 end subroutine simplex_weights_array
452
459 subroutine simplex_dos_single(rdim, esimplex, eF, dos)
460 integer, intent(in) :: rdim
461 real(real64), intent(in) :: esimplex(:)
462 real(real64), intent(in) :: ef
463 real(real64), intent(out) :: dos(:)
464
465 real(real64) :: dos_array(size(dos), 1)
466
467 ! no PUSH_SUB, called too often
468
469 call simplex_dos_array(rdim, esimplex, [ef], dos_array)
470 dos(:) = dos_array(:, 1)
471 end subroutine simplex_dos_single
472
479 subroutine simplex_dos_array(rdim, esimplex, eFs, dos)
480 integer, intent(in) :: rdim
481 real(real64), intent(in) :: esimplex(:)
482 real(real64), intent(in) :: efs(:)
483 real(real64), intent(out) :: dos(:,:)
484
485 ! no PUSH_SUB, called too often
486
487 assert(size(dos, 1) == rdim + 1)
488 assert(size(dos, 2) == size(efs))
489
490 select case (rdim)
491 case (1)
492 call simplex_dos_1d(esimplex, efs, dos)
493 case (2)
494 call simplex_dos_2d(esimplex, efs, dos)
495 case (3)
496 call simplex_dos_3d(esimplex, efs, dos)
497 case default
498 assert(.false.)
499 end select
500 end subroutine simplex_dos_array
501
508 subroutine simplex_weights_1d(esegment, eFs, weights, dos)
509 real(real64), intent(in) :: esegment(:)
510 real(real64), intent(in) :: eFs(:)
511 real(real64), intent(out) :: weights(:,:)
512 real(real64), intent(out) :: dos(:,:)
513
514 real(real64) :: E(2), E1, E2, eF
515 real(real64) :: w(2), d(2), sumE, bloechl_corr(2)
516 integer :: idx(2), ie, ne
517 logical :: apply_bloechl
518
519 real(real64), parameter :: vT_vG = 1.0_real64
520 real(real64), parameter :: vT_2vG = vt_vg / 2.0_real64
521
522 real(real64), parameter :: P(2,4) = 1.0_real64 / 60.0_real64 * reshape([ &
523 64 , 1 , -3 , -2 , &
524 1 , 64 , -2 , -3 ], shape(p), order=[2, 1])
525
526 ! no PUSH_SUB, called too often
527
528 select case (size(esegment))
529 case (2)
530 e(:) = esegment(:)
531 case (4)
532 e(:) = m_zero
533 block
534 integer :: i
535 do i = 1, size(esegment)
536 e(:) = e(:) + p(:,i) * esegment(i)
537 end do
538 end block
539 case default
540 assert(.false.)
541 end select
542
543 idx = [1,2]
544 call simplex_sort_2(e, idx)
545 e1 = e(1)
546 e2 = e(2)
547 ne = size(efs)
548 apply_bloechl = (size(esegment) == 2)
549 if (apply_bloechl) then
550 sume = sum(e)
551 bloechl_corr(:) = (sume - 2.0_real64 * e) / 12.0_real64
552 end if
553
554 do ie = 1, ne
555 ef = efs(ie)
556
557 if (ef <= e1) then
558 w(:) = m_zero
559 d(:) = m_zero
560 elseif (e2 < ef) then
561 w(:) = vt_2vg
562 d(:) = m_zero
563 elseif (e1 < ef .and. ef <= e2) then
564 block
565 real(real64) :: E21, C
566 e21 = e2 - e1
567 c = vt_2vg * (ef - e1) / e21
568
569 w(:) = c * [ &
570 2.0_real64 - (ef - e1) / e21, &
571 (ef - e1) / e21]
572
573 d(:) = vt_vg / e21 * [ &
574 m_one - (ef - e1) / e21, &
575 (ef - e1) / e21]
576 end block
577 else
578 assert(.false.)
579 end if
580
581 dos(idx, ie) = d
582 weights(idx, ie) = w
583 if (apply_bloechl) weights(idx, ie) = weights(idx, ie) + sum(d) * bloechl_corr
584 end do
585 end subroutine simplex_weights_1d
586
592 subroutine simplex_dos_1d(esegment, eFs, dos)
593 real(real64), intent(in) :: esegment(:)
594 real(real64), intent(in) :: eFs(:)
595 real(real64), intent(out) :: dos(:,:)
596
597 real(real64) :: E(2), E1, E2, eF
598 real(real64) :: d(2)
599 integer :: idx(2), ie, ne
600
601 real(real64), parameter :: vT_vG = 1.0_real64
602
603 real(real64), parameter :: P(2,4) = 1.0_real64 / 60.0_real64 * reshape([ &
604 64 , 1 , -3 , -2 , &
605 1 , 64 , -2 , -3 ], shape(p), order=[2, 1])
606
607 ! no PUSH_SUB, called too often
608
609 select case (size(esegment))
610 case (2)
611 e(:) = esegment(:)
612 case (4)
613 e(:) = m_zero
614 block
615 integer :: i
616 do i = 1, size(esegment)
617 e(:) = e(:) + p(:,i) * esegment(i)
618 end do
619 end block
620 case default
621 assert(.false.)
622 end select
623
624 idx = [1, 2]
625 call simplex_sort_2(e, idx)
626 e1 = e(1)
627 e2 = e(2)
628 ne = size(efs)
629
630 do ie = 1, ne
631 ef = efs(ie)
632
633 if (ef <= e1 .or. e2 < ef) then
634 d(:) = m_zero
635 elseif (e1 < ef .and. ef <= e2) then
636 block
637 real(real64) :: E21
638 e21 = e2 - e1
639
640 d(:) = vt_vg / e21 * [ &
641 m_one - (ef - e1) / e21, &
642 (ef - e1) / e21]
643 end block
644 else
645 assert(.false.)
646 end if
647
648 dos(idx, ie) = d
649 end do
650 end subroutine simplex_dos_1d
651
664 subroutine simplex_weights_2d(etriangle, eFs, weights, dos)
665 real(real64), intent(in) :: etriangle(:)
666 real(real64), intent(in) :: eFs(:)
667 real(real64), intent(out) :: weights(:,:)
668 real(real64), intent(out) :: dos(:,:)
669
670 real(real64) :: E(3), E1, E2, E3, eF
671 real(real64) :: w(3), d(3), sumE, bloechl_corr(3)
672 integer :: idx(3), ie, ne
673 logical :: apply_bloechl
674
675 real(real64), parameter :: vT_vG = 1.0_real64 / 2.0_real64
676 real(real64), parameter :: vT_3vG = vt_vg / 3.0_real64
677
678 real(real64), parameter :: P(3,10) = 1.0_real64 / 360.0_real64 * reshape([ &
679 402 , 0 , 6 , -13 , 5 , -17 , -13 , -11 , 7 , -6 , &
680 6 , 396 , 6 , -9 , -15 , 3 , 3 , -15 , -9 , -6 , &
681 6 , 0 , 402 , 7 , -11 , -13 , -17 , 5 , -13 , -6 &
682 ], shape(p), order=[2, 1])
683
684 ! no PUSH_SUB, called too often
685
686 select case (size(etriangle))
687 case (3)
688 e(:) = etriangle(:)
689 case (10)
690 e(:) = m_zero
691 block
692 integer :: i
693 do i = 1, size(etriangle)
694 e(:) = e(:) + p(:,i) * etriangle(i)
695 end do
696 end block
697 case default
698 assert(.false.)
699 end select
700
701 idx = [1,2,3]
702 call simplex_sort_3(e, idx)
703 e1 = e(1)
704 e2 = e(2)
705 e3 = e(3)
706 ne = size(efs)
707 apply_bloechl = (size(etriangle) == 3)
708 if (apply_bloechl) then
709 sume = sum(e)
710 bloechl_corr(:) = (sume - 3.0_real64 * e) / 24.0_real64
711 end if
712
713 do ie = 1, ne
714 ef = efs(ie)
715
716 if (ef <= e1) then
717 w(:) = m_zero
718 d(:) = m_zero
719 elseif (e3 < ef) then
720 w(:) = vt_3vg
721 d(:) = m_zero
722 elseif (e1 < ef .and. ef <= e2) then
723 block
724 real(real64) :: E21, E31, C
725 e21 = e2 - e1
726 e31 = e3 - e1
727 c = vt_3vg * (ef - e1) ** 2 / (e21 * e31)
728
729 w(:) = c * [ &
730 3.0_real64 - (ef - e1) * (m_one / e21 + m_one / e31), &
731 (ef - e1) / e21, &
732 (ef - e1) / e31]
733
734 d(:) = vt_vg * (ef - e1) / (e21 * e31) * [&
735 2.0_real64 - (ef - e1) * (m_one / e31 + m_one / e21), &
736 (ef - e1) / e21, &
737 (ef - e1) / e31]
738 end block
739 elseif (e2 < ef .and. ef <= e3) then
740 block
741 real(real64) :: E23, E31, C1, C2
742 e23 = e2 - e3
743 e31 = e3 - e1
744 c1 = vt_3vg
745 c2 = vt_3vg * (ef - e3) ** 2 / (e23 * e31)
746
747 w(:) = [ &
748 c1 - c2 * (ef - e3) / e31, &
749 c1 + c2 * (ef - e3) / e23, &
750 c1 + c2 * (3.0_real64 - (ef - e3) * (m_one / e23 - m_one / e31))]
751
752 d(:) = vt_vg * (ef - e3) / (e23 * e31) * [ &
753 - (ef - e3) / e31, &
754 (ef - e3) / e23, &
755 2.0_real64 - (ef - e3) * (m_one / e23 - m_one / e31)]
756 end block
757 else
758 assert(.false.)
759 end if
760
761 dos(idx, ie) = d
762 weights(idx, ie) = w
763 if (apply_bloechl) weights(idx, ie) = weights(idx, ie) + sum(d) * bloechl_corr
764 end do
765 end subroutine simplex_weights_2d
766
775 subroutine simplex_dos_2d(etriangle, eFs, dos)
776 real(real64), intent(in) :: etriangle(:)
777 real(real64), intent(in) :: eFs(:)
778 real(real64), intent(out) :: dos(:,:)
779
780 real(real64) :: E(3), E1, E2, E3, eF
781 real(real64) :: d(3)
782 integer :: idx(3), ie, ne
783
784 real(real64), parameter :: vT_vG = 1.0_real64 / 2.0_real64
785
786 real(real64), parameter :: P(3,10) = 1.0_real64 / 360.0_real64 * reshape([ &
787 402 , 0 , 6 , -13 , 5 , -17 , -13 , -11 , 7 , -6 , &
788 6 , 396 , 6 , -9 , -15 , 3 , 3 , -15 , -9 , -6 , &
789 6 , 0 , 402 , 7 , -11 , -13 , -17 , 5 , -13 , -6 &
790 ], shape(p), order=[2, 1])
791
792 ! no PUSH_SUB, called too often
793
794 select case (size(etriangle))
795 case (3)
796 e(:) = etriangle(:)
797 case (10)
798 e(:) = m_zero
799 block
800 integer :: i
801 do i = 1, size(etriangle)
802 e(:) = e(:) + p(:,i) * etriangle(i)
803 end do
804 end block
805 case default
806 assert(.false.)
807 end select
808
809 idx = [1, 2, 3]
810 call simplex_sort_3(e, idx)
811 e1 = e(1)
812 e2 = e(2)
813 e3 = e(3)
814 ne = size(efs)
815
816 do ie = 1, ne
817 ef = efs(ie)
818
819 if (ef <= e1 .or. e3 < ef) then
820 d(:) = m_zero
821 elseif (e1 < ef .and. ef <= e2) then
822 block
823 real(real64) :: E21, E31
824 e21 = e2 - e1
825 e31 = e3 - e1
826
827 d(:) = vt_vg * (ef - e1) / (e21 * e31) * [&
828 (2.0_real64 - (ef - e1) * (m_one / e31 + m_one / e21)), &
829 (ef - e1) / e21, &
830 (ef - e1) / e31]
831 end block
832 elseif (e2 < ef .and. ef <= e3) then
833 block
834 real(real64) :: E23, E31
835 e23 = e2 - e3
836 e31 = e3 - e1
837
838 d(:) = vt_vg * (ef - e3) / (e23 * e31) * [ &
839 - (ef - e3) / e31, &
840 (ef - e3) / e23, &
841 2.0_real64 - (ef - e3) * (m_one / e23 - m_one / e31)]
842 end block
843 else
844 assert(.false.)
845 end if
846
847 dos(idx, ie) = d
848 end do
849 end subroutine simplex_dos_2d
850
866 subroutine simplex_weights_3d(etetra, eFs, weights, dos)
867 real(real64), intent(in) :: etetra(:)
868 real(real64), intent(in) :: eFs(:)
869 real(real64), intent(out) :: weights(:,:)
870 real(real64), intent(out) :: dos(:,:)
871
872 real(real64) :: E(4), E1, E2, E3, E4, eF
873 real(real64) :: w(4), d(4), sumE, bloechl_corr(4)
874 integer :: idx(4), ie, ne
875 logical :: apply_bloechl
876
877 real(real64), parameter :: vT_vG = 1.0_real64 / 6.0_real64
878 real(real64), parameter :: vT_4vG = vt_vg / 4.0_real64
879
880 real(real64), parameter :: P(4,20) = 1.0_real64 / 1260.0_real64 * reshape([ &
881 1440, 0 , 30 , 0 , -38 , 7 , 17 , -28 , -56 , 9 , -46 , 9 , -38 , -28 , 17 , 7 , -18 , -18 , 12 , -18 , &
882 0 , 1440, 0 , 30 , -28 , -38 , 7 , 17 , 9 , -56 , 9 , -46 , 7 , -38 , -28 , 17 , -18 , -18 , -18 , 12 , &
883 30 , 0 , 1440, 0 , 17 , -28 , -38 , 7 , -46 , 9 , -56 , 9 , 17 , 7 , -38 , -28 , 12 , -18 , -18 , -18 , &
884 0 , 30 , 0 , 1440, 7 , 17 , -28 , -38 , 9 , -46 , 9 , -56 , -28 , 17 , 7 , -38 , -18 , 12 , -18 , -18 &
885 ], shape(p), order=[2, 1])
886
887 ! no PUSH_SUB, called too often
888
889 select case (size(etetra))
890 case (4)
891 e(:) = etetra(:)
892 case (20)
893 e(:) = m_zero
894 block
895 integer :: i
896 do i = 1, size(etetra)
897 e(:) = e(:) + p(:,i) * etetra(i)
898 end do
899 end block
900 case default
901 assert(.false.)
902 end select
903
904 idx = [1,2,3,4]
905 call simplex_sort_4(e, idx)
906 e1 = e(1)
907 e2 = e(2)
908 e3 = e(3)
909 e4 = e(4)
910 ne = size(efs)
911 apply_bloechl = (size(etetra) == 4)
912 if (apply_bloechl) then
913 sume = sum(e)
914 bloechl_corr(:) = (sume - 4.0_real64 * e) / 40.0_real64
915 end if
916
917 do ie = 1, ne
918 ef = efs(ie)
919
920 if (e1 >= ef) then
921 w(:) = m_zero
922 d(:) = m_zero
923 elseif (e4 < ef) then
924 w(:) = vt_4vg
925 d(:) = m_zero
926 elseif (e1 < ef .and. ef <= e2) then
927 block
928 real(real64) :: E21, E31, E41, C
929 e21 = e2 - e1
930 e31 = e3 - e1
931 e41 = e4 - e1
932 c = vt_4vg * (ef - e1) ** 3 / (e21 * e31 * e41)
933
934 w(:) = c * [ &
935 4.0_real64 - (ef - e1) * (m_one / e21 + m_one / e31 + m_one / e41), &
936 (ef - e1) / e21, &
937 (ef - e1) / e31, &
938 (ef - e1) / e41]
939 end block
940 block
941 real(real64) :: f12, f13, f14, f21, f31, f41, g
942 f21 = (ef - e1) / (e2 - e1)
943 f31 = (ef - e1) / (e3 - e1)
944 f41 = (ef - e1) / (e4 - e1)
945 f12 = m_one - f21
946 f13 = m_one - f31
947 f14 = m_one - f41
948 g = f31 * f41 / (e2 - e1)
949 d(:) = vt_vg * g * [&
950 f12 + f13 + f14, &
951 f21, &
952 f31, &
953 f41]
954 end block
955 elseif (e2 < ef .and. ef <= e3) then
956 block
957 real(real64) :: E21, E31, E32, E41, E42, C1, C2, C3
958 e21 = e2 - e1
959 e31 = e3 - e1
960 e32 = e3 - e2
961 e41 = e4 - e1
962 e42 = e4 - e2
963 c1 = vt_4vg * (ef - e1) ** 2 / (e41 * e31)
964 c2 = vt_4vg * (ef - e1) * (ef - e2) * (e3 - ef) / (e41 * e32 * e31)
965 c3 = vt_4vg * (ef - e2) ** 2 * (e4 - ef) / (e42 * e32 * e41)
966
967 w(:) = [ &
968 c1 + (c1 + c2) * (e3 - ef) / e31 + (c1 + c2 + c3) * (e4 - ef) / e41, &
969 c1 + c2 + c3 + (c2 + c3) * (e3 - ef) / e32 + c3 * (e4 - ef) / e42, &
970 (c1 + c2) * (ef - e1) / e31 + (c2 + c3) * (ef - e2) / e32, &
971 (c1 + c2 + c3) * (ef - e1) / e41 + c3 * (ef - e2) / e42]
972 end block
973 block
974 real(real64) :: f13, f14, f23, f24, f31, f32, f41, f42, g, delta
975 delta = e4 - e1
976 f31 = (ef - e1) / (e3 - e1)
977 f41 = (ef - e1) / (e4 - e1)
978 f32 = (ef - e2) / (e3 - e2)
979 f42 = (ef - e2) / (e4 - e2)
980 f13 = m_one - f31
981 f14 = m_one - f41
982 f23 = m_one - f32
983 f24 = m_one - f42
984 g = 3.0_real64 / delta * (f23 * f31 + f32 * f24)
985 d(:) = vt_vg * [&
986 g * f14 / 3.0_real64 + f13 * f31 * f23 / delta, &
987 g * f23 / 3.0_real64 + f24 * f24 * f32 / delta, &
988 g * f32 / 3.0_real64 + f31 * f31 * f23 / delta, &
989 g * f41 / 3.0_real64 + f42 * f24 * f32 / delta]
990 end block
991 elseif (e3 < ef .and. ef <= e4) then
992 block
993 real(real64) :: E41, E42, E43, C
994 e41 = e4 - e1
995 e42 = e4 - e2
996 e43 = e4 - e3
997 c = vt_4vg * (e4 - ef) ** 3 / (e41 * e42 * e43)
998
999 w(:) = vt_4vg - c * [ &
1000 (e4 - ef) / e41, &
1001 (e4 - ef) / e42, &
1002 (e4 - ef) / e43, &
1003 4.0_real64 - (e4 - ef) * (m_one / e41 + m_one / e42 + m_one / e43)]
1004 end block
1005 block
1006 real(real64) :: f14, f24, f34, f41, f42, f43, g
1007 f14 = (ef - e4) / (e1 - e4)
1008 f24 = (ef - e4) / (e2 - e4)
1009 f34 = (ef - e4) / (e3 - e4)
1010 f41 = m_one - f14
1011 f42 = m_one - f24
1012 f43 = m_one - f34
1013 g = f14 * f24 / (e4 - e3)
1014 d(:) = vt_vg * g *[ &
1015 f14, &
1016 f24, &
1017 f34, &
1018 f41 + f42 + f43]
1019 end block
1020 else
1021 assert(.false.)
1022 end if
1023
1024 dos(idx, ie) = d
1025 weights(idx, ie) = w
1026 if (apply_bloechl) weights(idx, ie) = weights(idx, ie) + sum(d) * bloechl_corr
1027 end do
1028 end subroutine simplex_weights_3d
1029
1041 subroutine simplex_dos_3d(etetra, eFs, dos)
1042 real(real64), intent(in) :: etetra(:)
1043 real(real64), intent(in) :: eFs(:)
1044 real(real64), intent(out) :: dos(:,:)
1045
1046 real(real64) :: E(4), E1, E2, E3, E4, eF
1047 real(real64) :: d(4)
1048 integer :: idx(4), ie, ne
1049
1050 real(real64), parameter :: vT_vG = 1.0_real64 / 6.0_real64
1051
1052 real(real64), parameter :: P(4,20) = 1.0_real64 / 1260.0_real64 * reshape([ &
1053 1440, 0 , 30 , 0 , -38 , 7 , 17 , -28 , -56 , 9 , -46 , 9 , -38 , -28 , 17 , 7 , -18 , -18 , 12 , -18 , &
1054 0 , 1440, 0 , 30 , -28 , -38 , 7 , 17 , 9 , -56 , 9 , -46 , 7 , -38 , -28 , 17 , -18 , -18 , -18 , 12 , &
1055 30 , 0 , 1440, 0 , 17 , -28 , -38 , 7 , -46 , 9 , -56 , 9 , 17 , 7 , -38 , -28 , 12 , -18 , -18 , -18 , &
1056 0 , 30 , 0 , 1440, 7 , 17 , -28 , -38 , 9 , -46 , 9 , -56 , -28 , 17 , 7 , -38 , -18 , 12 , -18 , -18 &
1057 ], shape(p), order=[2, 1])
1058
1059 ! no PUSH_SUB, called too often
1060
1061 select case (size(etetra))
1062 case (4)
1063 e(:) = etetra(:)
1064 case (20)
1065 e(:) = m_zero
1066 block
1067 integer :: i
1068 do i = 1, size(etetra)
1069 e(:) = e(:) + p(:,i) * etetra(i)
1070 end do
1071 end block
1072 case default
1073 assert(.false.)
1074 end select
1075
1076 idx = [1, 2, 3, 4]
1077 call simplex_sort_4(e, idx)
1078 e1 = e(1)
1079 e2 = e(2)
1080 e3 = e(3)
1081 e4 = e(4)
1082 ne = size(efs)
1083
1084 do ie = 1, ne
1085 ef = efs(ie)
1086
1087 if (e1 >= ef .or. e4 < ef) then
1088 d(:) = m_zero
1089 elseif (e1 < ef .and. ef <= e2) then
1090 block
1091 real(real64) :: f12, f13, f14, f21, f31, f41, g
1092 f21 = (ef - e1) / (e2 - e1)
1093 f31 = (ef - e1) / (e3 - e1)
1094 f41 = (ef - e1) / (e4 - e1)
1095 f12 = m_one - f21
1096 f13 = m_one - f31
1097 f14 = m_one - f41
1098 g = f31 * f41 / (e2 - e1)
1099 d(:) = vt_vg * g * [&
1100 f12 + f13 + f14, &
1101 f21, &
1102 f31, &
1103 f41]
1104 end block
1105 elseif (e2 < ef .and. ef <= e3) then
1106 block
1107 real(real64) :: f13, f14, f23, f24, f31, f32, f41, f42, g, delta
1108 delta = e4 - e1
1109 f31 = (ef - e1) / (e3 - e1)
1110 f41 = (ef - e1) / (e4 - e1)
1111 f32 = (ef - e2) / (e3 - e2)
1112 f42 = (ef - e2) / (e4 - e2)
1113 f13 = m_one - f31
1114 f14 = m_one - f41
1115 f23 = m_one - f32
1116 f24 = m_one - f42
1117 g = 3.0_real64 / delta * (f23 * f31 + f32 * f24)
1118 d(:) = vt_vg * [&
1119 g * f14 / 3.0_real64 + f13 * f31 * f23 / delta, &
1120 g * f23 / 3.0_real64 + f24 * f24 * f32 / delta, &
1121 g * f32 / 3.0_real64 + f31 * f31 * f23 / delta, &
1122 g * f41 / 3.0_real64 + f42 * f24 * f32 / delta]
1123 end block
1124 elseif (e3 < ef .and. ef <= e4) then
1125 block
1126 real(real64) :: f14, f24, f34, f41, f42, f43, g
1127 f14 = (ef - e4) / (e1 - e4)
1128 f24 = (ef - e4) / (e2 - e4)
1129 f34 = (ef - e4) / (e3 - e4)
1130 f41 = m_one - f14
1131 f42 = m_one - f24
1132 f43 = m_one - f34
1133 g = f14 * f24 / (e4 - e3)
1134 d(:) = vt_vg * g *[ &
1135 f14, &
1136 f24, &
1137 f34, &
1138 f41 + f42 + f43]
1139 end block
1140 else
1141 assert(.false.)
1142 end if
1143
1144 dos(idx, ie) = d
1145 end do
1146 end subroutine simplex_dos_3d
1147
1148end module simplex_oct_m
type(debug_t), save, public debug
Definition: debug.F90:158
subroutine, public debug_pop_sub(sub_name)
Pop a routine from the debug trace.
Definition: debug.F90:521
subroutine, public debug_push_sub(sub_name)
Push a routine to the debug trace.
Definition: debug.F90:448
real(real64), parameter, public m_zero
Definition: global.F90:200
integer(int64), public global_sizeof
Definition: global.F90:273
logical pure function, public not_in_openmp()
Definition: global.F90:566
character(len=100), public global_alloc_errmsg
Definition: global.F90:274
integer, public global_alloc_err
Definition: global.F90:272
real(real64), parameter, public m_one
Definition: global.F90:201
subroutine, public alloc_error(size, file, line)
Definition: messages.F90:669
subroutine, public dealloc_error(size, file, line)
Definition: messages.F90:680
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
type(profile_vars_t), target, save, public prof_vars
Definition: profiling.F90:248
integer, parameter, public profiling_memory
Definition: profiling.F90:208
subroutine, public profiling_memory_deallocate(var, file, line, size)
Definition: profiling.F90:1404
subroutine, public profiling_memory_allocate(var, file, line, size_)
Definition: profiling.F90:1333
subroutine simplex_dos_2d(etriangle, eFs, dos)
Get only the DOS contribution of a single triangle.
Definition: simplex.F90:871
pure subroutine simplex_compare_swap(a, b, ia, ib)
Swap two value-index pairs if they are out of ascending order.
Definition: simplex.F90:219
subroutine simplex_weights_3d(etetra, eFs, weights, dos)
Get the weights and DOS contribution of a single tetrahedron.
Definition: simplex.F90:962
pure subroutine simplex_sort_3(values, idx)
Sort three real values in ascending order while permuting indices.
Definition: simplex.F90:185
subroutine simplex_dos_single(rdim, esimplex, eF, dos)
Get only the DOS contribution of a single simplex.
Definition: simplex.F90:555
subroutine simplex_weights_1d(esegment, eFs, weights, dos)
Get the weights and DOS contribution of a single segment.
Definition: simplex.F90:604
subroutine simplex_weights_2d(etriangle, eFs, weights, dos)
Get the weights and DOS contribution of a single tetrahedron.
Definition: simplex.F90:760
type(simplex_t) function, pointer, public simplex_init(dim, naxis, nshifts, shift, kpoints, equiv, opt)
Constructor for linear simplex methods.
Definition: simplex.F90:252
subroutine, public simplex_end(this)
Destructor for linear simplex methods.
Definition: simplex.F90:486
subroutine simplex_weights_array(rdim, esimplex, eFs, weights, dos)
Get the weights and DOS contribution of a single simplex for multiple reference energies.
Definition: simplex.F90:523
subroutine simplex_dos_3d(etetra, eFs, dos)
Get only the DOS contribution of a single tetrahedron.
Definition: simplex.F90:1137
pure subroutine simplex_sort_4(values, idx)
Sort four real values in ascending order while permuting indices.
Definition: simplex.F90:202
pure subroutine simplex_sort_2(values, idx)
Sort two real values in ascending order while permuting indices.
Definition: simplex.F90:170
subroutine simplex_dos_array(rdim, esimplex, eFs, dos)
Get only the DOS contribution of a single simplex for multiple reference energies.
Definition: simplex.F90:575
subroutine simplex_dos_1d(esegment, eFs, dos)
Get only the DOS contribution of a single segment.
Definition: simplex.F90:688
subroutine simplex_weights_single(rdim, esimplex, eF, weights, dos)
Get the weights and DOS contribution of a single simplex.
Definition: simplex.F90:500