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