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