LCOV - code coverage report
Current view: top level - src - negf_integr_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 58 62 93.5 %
Date: 2024-12-21 06:28:57 Functions: 8 10 80.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 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         170 :       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         170 :          CPASSERT(nnodes >= 1)
      58             : 
      59         170 :          rscale = (b - a)/REAL(nnodes - 1, kind=dp)
      60        2156 :          DO i = 1, nnodes
      61        2156 :             xnodes(i) = a + rscale*REAL(i - 1, kind=dp)
      62             :          END DO
      63         170 :       END SUBROUTINE equidistant_${nametype1}$nodes_a_b
      64             :    #:endfor
      65             : 
      66         612 :    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         612 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: tnodes_angle
      79             : 
      80         612 :       CALL timeset(routineN, handle)
      81             : 
      82         852 :       SELECT CASE (shape_id)
      83             :       CASE (contour_shape_linear)
      84         240 :          IF (PRESENT(xnodes)) &
      85         120 :             CALL rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
      86             : 
      87         240 :          IF (PRESENT(weights)) &
      88        2736 :             weights(:) = b - a
      89             : 
      90             :       CASE (contour_shape_arc)
      91        1116 :          ALLOCATE (tnodes_angle(nnodes))
      92             : 
      93       12832 :          tnodes_angle(:) = tnodes(:)
      94         372 :          CALL rescale_nodes_pi_phi(a, b, nnodes, tnodes_angle)
      95             : 
      96         372 :          IF (PRESENT(xnodes)) &
      97         186 :             CALL rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
      98             : 
      99         372 :          IF (PRESENT(weights)) THEN
     100         186 :             rscale = (pi - get_arc_smallest_angle(a, b))*get_arc_radius(a, b)
     101             : 
     102        6416 :             DO i = 1, nnodes
     103        6416 :                weights(i) = rscale*CMPLX(SIN(tnodes_angle(i)), -COS(tnodes_angle(i)), kind=dp)
     104             :             END DO
     105             :          END IF
     106             : 
     107         372 :          DEALLOCATE (tnodes_angle)
     108             :       CASE DEFAULT
     109         612 :          CPABORT("Unimplemented integration shape")
     110             :       END SELECT
     111             : 
     112         612 :       CALL timestop(handle)
     113        1530 :    END SUBROUTINE rescale_normalised_nodes
     114             : 
     115             : ! **************************************************************************************************
     116             : !> \brief Compute arc radius.
     117             : !> \param a       lower bound
     118             : !> \param b       upper bound
     119             : !> \return radius
     120             : !> \par History
     121             : !>    * 05.2017 created [Sergey Chulkov]
     122             : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     123             : !             c    *
     124             : !          r   *       B-------+------
     125             : !        a  *         /   .    |
     126             : !         *        r /      .  | delta
     127             : !        *          /  phi   . |
     128             : !        A---------*-----------+------
     129             : !        <--- r --><-l->
     130             : !                  <--- r --->
     131             : ! **************************************************************************************************
     132         372 :    PURE FUNCTION get_arc_radius(a, b) RESULT(radius)
     133             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     134             :       REAL(kind=dp)                                      :: radius
     135             : 
     136             :       COMPLEX(kind=dp) :: b_minus_a
     137             : 
     138         372 :       b_minus_a = b - a
     139             : 
     140             :       ! l = REAL(B - A); delta = AIMAG(B - A)
     141             :       ! radius = (l^2 + delta^2) / (2 * l)
     142         372 :       radius = 0.5_dp*REAL(b_minus_a*CONJG(b_minus_a), kind=dp)/REAL(b_minus_a, kind=dp)
     143         372 :    END FUNCTION get_arc_radius
     144             : 
     145             : ! **************************************************************************************************
     146             : !> \brief Compute the angle phi.
     147             : !> \param a       lower bound
     148             : !> \param b       upper bound
     149             : !> \return angle
     150             : !> \par History
     151             : !>    * 05.2017 created [Sergey Chulkov]
     152             : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     153             : !             c    *
     154             : !          r   *       B-------+------
     155             : !        a  *         /   .    |
     156             : !         *        r /      .  | delta
     157             : !        *          /  phi   . |
     158             : !        A---------*-----------+------
     159             : !        <--- r --><-l->
     160             : !                  <--- r --->
     161             : ! **************************************************************************************************
     162         558 :    PURE FUNCTION get_arc_smallest_angle(a, b) RESULT(phi)
     163             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     164             :       REAL(kind=dp)                                      :: phi
     165             : 
     166             :       COMPLEX(kind=dp) :: b_minus_a
     167             :       REAL(kind=dp)    :: delta2, l2
     168             : 
     169         558 :       b_minus_a = b - a
     170             : 
     171             :       ! l = REAL(B - A); delta = AIMAG(B - A)
     172             :       ! phi = arccos((l - radius)/radius) = arccos((l^2 - delta^2) / (l^2 + delta^2))
     173         558 :       l2 = REAL(b_minus_a, dp)
     174         558 :       l2 = l2*l2
     175         558 :       delta2 = AIMAG(b_minus_a)
     176         558 :       delta2 = delta2*delta2
     177             : 
     178         558 :       phi = ACOS((l2 - delta2)/(l2 + delta2))
     179         558 :    END FUNCTION get_arc_smallest_angle
     180             : 
     181           0 :    PURE FUNCTION get_axis_rotation_angle(a, b) RESULT(phi)
     182             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     183             :       REAL(kind=dp)                                      :: phi
     184             : 
     185             :       COMPLEX(kind=dp) :: b_minus_a
     186             : 
     187           0 :       b_minus_a = b - a
     188           0 :       phi = ACOS(REAL(b_minus_a, dp)/ABS(b_minus_a))
     189           0 :    END FUNCTION get_axis_rotation_angle
     190             : 
     191             : ! **************************************************************************************************
     192             : !> \brief Rescale nodes [pi, phi] -> arc[a, b] .
     193             : !> \param nnodes        number of nodes
     194             : !> \param tnodes_angle  parametrically-defined nodes to rescale
     195             : !> \param a             lower bound
     196             : !> \param b             upper bound
     197             : !> \param xnodes        rescaled nodes (initialised on exit)
     198             : !> \par History
     199             : !>    * 05.2017 created [Sergey Chulkov]
     200             : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     201             : ! **************************************************************************************************
     202         186 :    SUBROUTINE rescale_nodes_arc(nnodes, tnodes_angle, a, b, xnodes)
     203             :       INTEGER, INTENT(in)                                :: nnodes
     204             :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: tnodes_angle
     205             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     206             :       COMPLEX(kind=dp), DIMENSION(:), INTENT(out)        :: xnodes
     207             : 
     208             :       COMPLEX(kind=dp)                                   :: origin
     209             :       INTEGER                                            :: i
     210             :       REAL(kind=dp)                                      :: radius
     211             : 
     212         186 :       radius = get_arc_radius(a, b)
     213         186 :       origin = a + CMPLX(radius, 0.0_dp, kind=dp)
     214             : 
     215        6416 :       DO i = 1, nnodes
     216        6416 :          xnodes(i) = origin + radius*CMPLX(COS(tnodes_angle(i)), SIN(tnodes_angle(i)), kind=dp)
     217             :       END DO
     218         186 :    END SUBROUTINE rescale_nodes_arc
     219             : 
     220             : ! **************************************************************************************************
     221             : !> \brief Rescale nodes tnodes(i) = cos(pi/2 * (1-tnodes(i))); tnodes \in [-1 .. 1] .
     222             : !> \param tnodes parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
     223             : !> \par History
     224             : !>    * 05.2017 created [Sergey Chulkov]
     225             : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     226             : ! **************************************************************************************************
     227         160 :    SUBROUTINE rescale_nodes_cos(nnodes, tnodes)
     228             :       INTEGER, INTENT(in)                                :: nnodes
     229             :       REAL(kind=dp), DIMENSION(nnodes), INTENT(inout)    :: tnodes
     230             : 
     231        1888 :       tnodes(:) = COS(0.5_dp*pi*(1.0_dp - tnodes(:)))
     232         160 :    END SUBROUTINE rescale_nodes_cos
     233             : 
     234             : ! **************************************************************************************************
     235             : !> \brief Rescale nodes [-1, 1] -> [a, b] .
     236             : !> \param nnodes        number of nodes
     237             : !> \param tnodes        parametrically-defined nodes to rescale
     238             : !> \param a             lower bound
     239             : !> \param b             upper bound
     240             : !> \param xnodes        rescaled nodes (initialised on exit)
     241             : !> \par History
     242             : !>    * 05.2017 created [Sergey Chulkov]
     243             : ! **************************************************************************************************
     244         120 :    SUBROUTINE rescale_nodes_linear(nnodes, tnodes, a, b, xnodes)
     245             :       INTEGER, INTENT(in)                                :: nnodes
     246             :       REAL(kind=dp), DIMENSION(nnodes), INTENT(in)       :: tnodes
     247             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     248             :       COMPLEX(kind=dp), DIMENSION(nnodes), INTENT(out)   :: xnodes
     249             : 
     250             :       COMPLEX(kind=dp)                                   :: half_len, median
     251             : 
     252         120 :       median = 0.5_dp*(b + a)
     253         120 :       half_len = 0.5_dp*(b - a)
     254             : 
     255        2736 :       xnodes(:) = median + half_len*tnodes(:)
     256         120 :    END SUBROUTINE rescale_nodes_linear
     257             : 
     258             : ! **************************************************************************************************
     259             : !> \brief Rescale nodes [-1, 1] -> [pi, phi] .
     260             : !> \param nnodes        number of nodes
     261             : !> \param a             lower bound
     262             : !> \param b             upper bound
     263             : !> \param tnodes        parametrically-defined nodes to rescale / rescaled nodes (modified on exit)
     264             : !> \par History
     265             : !>    * 05.2017 created [Sergey Chulkov]
     266             : !> \note Assuming Re(a) < Re(b) and Im(a) < Im(b)
     267             : ! **************************************************************************************************
     268         372 :    SUBROUTINE rescale_nodes_pi_phi(a, b, nnodes, tnodes)
     269             :       COMPLEX(kind=dp), INTENT(in)                       :: a, b
     270             :       INTEGER, INTENT(in)                                :: nnodes
     271             :       REAL(kind=dp), DIMENSION(nnodes), INTENT(inout)    :: tnodes
     272             : 
     273             :       REAL(kind=dp)                                      :: half_pi_minus_phi, phi
     274             : 
     275         372 :       phi = get_arc_smallest_angle(a, b)
     276         372 :       half_pi_minus_phi = 0.5_dp*(pi - phi)
     277             : 
     278       12832 :       tnodes(:) = phi + half_pi_minus_phi*(1.0_dp - tnodes(:))
     279         372 :    END SUBROUTINE rescale_nodes_pi_phi
     280             : END MODULE negf_integr_utils

Generated by: LCOV version 1.15