LCOV - code coverage report
Current view: top level - src - negf_integr_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 88.1 % 59 52
Test Date: 2026-07-25 06:35:44 Functions: 70.0 % 10 7

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Helper functions for integration routines.
      10              : !> \par History
      11              : !>   * 06.2017 created [Sergey Chulkov]
      12              : ! **************************************************************************************************
      13              : MODULE negf_integr_utils
      14              :    USE kinds, ONLY: dp
      15              :    USE mathconstants, ONLY: pi
      16              : #include "./base/base_uses.f90"
      17              :    #:include 'negf_integr_utils.fypp'
      18              :    IMPLICIT NONE
      19              :    PRIVATE
      20              : 
      21              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_integr_utils'
      22              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .TRUE.
      23              : 
      24              :    PUBLIC :: equidistant_nodes_a_b, rescale_normalised_nodes
      25              :    PUBLIC :: get_arc_radius, get_arc_smallest_angle
      26              :    PUBLIC :: rescale_nodes_arc, rescale_nodes_cos, rescale_nodes_linear, rescale_nodes_pi_phi
      27              : 
      28              :    INTEGER, PARAMETER, PUBLIC :: contour_shape_linear = 0, &
      29              :                                  contour_shape_arc = 1
      30              : 
      31              :    INTERFACE equidistant_nodes_a_b
      32              :       #:for nametype1, type1 in inst_params
      33              :          MODULE PROCEDURE equidistant_${nametype1}$nodes_a_b
      34              :       #:endfor
      35              :    END INTERFACE
      36              : 
      37              : CONTAINS
      38              : 
      39              :    #:for nametype1, type1 in inst_params
      40              : ! **************************************************************************************************
      41              : !> \brief Compute equidistant nodes on an interval [a, b], where a and b are complex numbers.
      42              : !> \param a       lower bound
      43              : !> \param b       upper bound
      44              : !> \param nnodes  number of nodes
      45              : !> \param xnodes  array to store the nodes
      46              : !> \par History
      47              : !>    * 05.2017 created [Sergey Chulkov]
      48              : ! **************************************************************************************************
      49           60 :       SUBROUTINE equidistant_${nametype1}$nodes_a_b(a, b, nnodes, xnodes)
      50              :          ${type1}$, INTENT(in)                              :: a, b
      51              :          INTEGER, INTENT(in)                                :: nnodes
      52              :          ${type1}$, DIMENSION(nnodes), INTENT(out)          :: xnodes
      53              : 
      54              :          INTEGER                                            :: i
      55              :          ${type1}$                                          :: rscale
      56              : 
      57           60 :          CPASSERT(nnodes >= 1)
      58              : 
      59           60 :          rscale = (b - a)/REAL(nnodes - 1, kind=dp)
      60          840 :          DO i = 1, nnodes
      61          840 :             xnodes(i) = a + rscale*REAL(i - 1, kind=dp)
      62              :          END DO
      63           60 :       END SUBROUTINE equidistant_${nametype1}$nodes_a_b
      64              :    #:endfor
      65              : 
      66          960 :    SUBROUTINE rescale_normalised_nodes(nnodes, tnodes, a, b, shape_id, xnodes, weights)
      67              :       INTEGER, INTENT(in)                                :: nnodes
      68              :       REAL(kind=dp), DIMENSION(nnodes), INTENT(in)       :: tnodes
      69              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
      70              :       INTEGER, INTENT(in)                                :: shape_id
      71              :       COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out), &
      72              :          OPTIONAL                                        :: xnodes, weights
      73              : 
      74              :       CHARACTER(len=*), PARAMETER :: routineN = 'rescale_normalised_nodes'
      75              : 
      76              :       INTEGER :: handle, i
      77              :       REAL(kind=dp)                                      :: rscale
      78          960 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: tnodes_angle
      79              : 
      80          960 :       CALL timeset(routineN, handle)
      81              : 
      82         1284 :       SELECT CASE (shape_id)
      83              :       CASE (contour_shape_linear)
      84          324 :          IF (PRESENT(xnodes)) CALL rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
      85              : 
      86         3220 :          IF (PRESENT(weights)) weights(:) = b - a
      87              : 
      88              :       CASE (contour_shape_arc)
      89         1908 :          ALLOCATE (tnodes_angle(nnodes))
      90              : 
      91        25388 :          tnodes_angle(:) = tnodes(:)
      92          636 :          CALL rescale_nodes_pi_phi(a, b, nnodes, tnodes_angle)
      93              : 
      94          636 :          IF (PRESENT(xnodes)) CALL rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
      95              : 
      96          636 :          IF (PRESENT(weights)) THEN
      97          318 :             rscale = (pi - get_arc_smallest_angle(a, b))*get_arc_radius(a, b)
      98              : 
      99        12694 :             DO i = 1, nnodes
     100        12694 :                weights(i) = rscale*CMPLX(SIN(tnodes_angle(i)), -COS(tnodes_angle(i)), kind=dp)
     101              :             END DO
     102              :          END IF
     103              : 
     104          636 :          DEALLOCATE (tnodes_angle)
     105              :       CASE DEFAULT
     106          960 :          CPABORT("Unimplemented integration shape")
     107              :       END SELECT
     108              : 
     109          960 :       CALL timestop(handle)
     110         2400 :    END SUBROUTINE rescale_normalised_nodes
     111              : 
     112              : ! **************************************************************************************************
     113              : !> \brief Compute arc radius.
     114              : !> \param a       lower bound
     115              : !> \param b       upper bound
     116              : !> \return radius
     117              : !> \par History
     118              : !>    * 05.2017 created [Sergey Chulkov]
     119              : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     120              : !             c    *
     121              : !          r   *       B-------+------
     122              : !        a  *         /   .    |
     123              : !         *        r /      .  | delta
     124              : !        *          /  phi   . |
     125              : !        A---------*-----------+------
     126              : !        <--- r --><-l->
     127              : !                  <--- r --->
     128              : ! **************************************************************************************************
     129          636 :    PURE FUNCTION get_arc_radius(a, b) RESULT(radius)
     130              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     131              :       REAL(kind=dp)                                      :: radius
     132              : 
     133              :       COMPLEX(kind=dp) :: b_minus_a
     134              : 
     135          636 :       b_minus_a = b - a
     136              : 
     137              :       ! l = REAL(B - A); delta = AIMAG(B - A)
     138              :       ! radius = (l^2 + delta^2) / (2 * l)
     139          636 :       radius = 0.5_dp*REAL(b_minus_a*CONJG(b_minus_a), kind=dp)/REAL(b_minus_a, kind=dp)
     140          636 :    END FUNCTION get_arc_radius
     141              : 
     142              : ! **************************************************************************************************
     143              : !> \brief Compute the angle phi.
     144              : !> \param a       lower bound
     145              : !> \param b       upper bound
     146              : !> \return angle
     147              : !> \par History
     148              : !>    * 05.2017 created [Sergey Chulkov]
     149              : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     150              : !             c    *
     151              : !          r   *       B-------+------
     152              : !        a  *         /   .    |
     153              : !         *        r /      .  | delta
     154              : !        *          /  phi   . |
     155              : !        A---------*-----------+------
     156              : !        <--- r --><-l->
     157              : !                  <--- r --->
     158              : ! **************************************************************************************************
     159          954 :    PURE FUNCTION get_arc_smallest_angle(a, b) RESULT(phi)
     160              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     161              :       REAL(kind=dp)                                      :: phi
     162              : 
     163              :       COMPLEX(kind=dp) :: b_minus_a
     164              :       REAL(kind=dp)    :: delta2, l2
     165              : 
     166          954 :       b_minus_a = b - a
     167              : 
     168              :       ! l = REAL(B - A); delta = AIMAG(B - A)
     169              :       ! phi = arccos((l - radius)/radius) = arccos((l^2 - delta^2) / (l^2 + delta^2))
     170          954 :       l2 = REAL(b_minus_a, dp)
     171          954 :       l2 = l2*l2
     172          954 :       delta2 = AIMAG(b_minus_a)
     173          954 :       delta2 = delta2*delta2
     174              : 
     175          954 :       phi = ACOS((l2 - delta2)/(l2 + delta2))
     176          954 :    END FUNCTION get_arc_smallest_angle
     177              : 
     178            0 :    PURE FUNCTION get_axis_rotation_angle(a, b) RESULT(phi)
     179              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     180              :       REAL(kind=dp)                                      :: phi
     181              : 
     182              :       COMPLEX(kind=dp) :: b_minus_a
     183              : 
     184            0 :       b_minus_a = b - a
     185            0 :       phi = ACOS(REAL(b_minus_a, dp)/ABS(b_minus_a))
     186            0 :    END FUNCTION get_axis_rotation_angle
     187              : 
     188              : ! **************************************************************************************************
     189              : !> \brief Rescale nodes [pi, phi] -> arc[a, b] .
     190              : !> \param nnodes        number of nodes
     191              : !> \param tnodes_angle  parametrically-defined nodes to rescale
     192              : !> \param a             lower bound
     193              : !> \param b             upper bound
     194              : !> \param xnodes        rescaled nodes (initialised on exit)
     195              : !> \par History
     196              : !>    * 05.2017 created [Sergey Chulkov]
     197              : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     198              : ! **************************************************************************************************
     199          318 :    SUBROUTINE rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
     200              :       INTEGER, INTENT(in)                                :: nnodes
     201              :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: tnodes_angle
     202              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     203              :       COMPLEX(kind=dp), DIMENSION(:), INTENT(out)        :: xnodes
     204              : 
     205              :       COMPLEX(kind=dp)                                   :: origin
     206              :       INTEGER                                            :: i
     207              :       REAL(kind=dp)                                      :: radius
     208              : 
     209          318 :       radius = get_arc_radius(a, b)
     210          318 :       origin = a + CMPLX(radius, 0.0_dp, kind=dp)
     211              : 
     212        12694 :       DO i = 1, nnodes
     213        12694 :          xnodes(i) = origin + radius*CMPLX(COS(tnodes_angle(i)), SIN(tnodes_angle(i)), kind=dp)
     214              :       END DO
     215          318 :    END SUBROUTINE rescale_nodes_arc
     216              : 
     217              : ! **************************************************************************************************
     218              : !> \brief Rescale nodes tnodes(i) = cos(pi/2 * (1-tnodes(i))); tnodes \in [-1 .. 1] .
     219              : !> \param tnodes parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
     220              : !> \par History
     221              : !>    * 05.2017 created [Sergey Chulkov]
     222              : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     223              : ! **************************************************************************************************
     224            0 :    SUBROUTINE rescale_nodes_cos(nnodes, tnodes)
     225              :       INTEGER, INTENT(in)                                :: nnodes
     226              :       REAL(kind=dp), DIMENSION(nnodes), INTENT(inout)    :: tnodes
     227              : 
     228            0 :       tnodes(:) = COS(0.5_dp*pi*(1.0_dp - tnodes(:)))
     229            0 :    END SUBROUTINE rescale_nodes_cos
     230              : 
     231              : ! **************************************************************************************************
     232              : !> \brief Rescale nodes [-1, 1] -> [a, b] .
     233              : !> \param nnodes        number of nodes
     234              : !> \param tnodes        parametrically-defined nodes to rescale
     235              : !> \param a             lower bound
     236              : !> \param b             upper bound
     237              : !> \param xnodes        rescaled nodes (initialised on exit)
     238              : !> \par History
     239              : !>    * 05.2017 created [Sergey Chulkov]
     240              : ! **************************************************************************************************
     241          162 :    SUBROUTINE rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
     242              :       INTEGER, INTENT(in)                                :: nnodes
     243              :       REAL(kind=dp), DIMENSION(nnodes), INTENT(in)       :: tnodes
     244              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     245              :       COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out)   :: xnodes
     246              : 
     247              :       COMPLEX(kind=dp)                                   :: half_len, median
     248              : 
     249          162 :       median = 0.5_dp*(b + a)
     250          162 :       half_len = 0.5_dp*(b - a)
     251              : 
     252         3058 :       xnodes(:) = median + half_len*tnodes(:)
     253          162 :    END SUBROUTINE rescale_nodes_linear
     254              : 
     255              : ! **************************************************************************************************
     256              : !> \brief Rescale nodes [-1, 1] -> [pi, phi] .
     257              : !> \param nnodes        number of nodes
     258              : !> \param a             lower bound
     259              : !> \param b             upper bound
     260              : !> \param tnodes        parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
     261              : !> \par History
     262              : !>    * 05.2017 created [Sergey Chulkov]
     263              : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     264              : ! **************************************************************************************************
     265          636 :    SUBROUTINE rescale_nodes_pi_phi(a, b, nnodes, tnodes)
     266              :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     267              :       INTEGER, INTENT(in)                                :: nnodes
     268              :       REAL(kind=dp), DIMENSION(nnodes), INTENT(inout)    :: tnodes
     269              : 
     270              :       REAL(kind=dp)                                      :: half_pi_minus_phi, phi
     271              : 
     272          636 :       phi = get_arc_smallest_angle(a, b)
     273          636 :       half_pi_minus_phi = 0.5_dp*(pi - phi)
     274              : 
     275        25388 :       tnodes(:) = phi + half_pi_minus_phi*(1.0_dp - tnodes(:))
     276          636 :    END SUBROUTINE rescale_nodes_pi_phi
     277              : END MODULE negf_integr_utils
        

Generated by: LCOV version 2.0-1