ecp.F90 Source File


This file depends on

sourcefile~~ecp.f90~~EfferentGraph sourcefile~ecp.f90 ecp.F90 sourcefile~basis_tools.f90 basis_tools.F90 sourcefile~ecp.f90->sourcefile~basis_tools.f90 sourcefile~constants.f90 constants.F90 sourcefile~ecp.f90->sourcefile~constants.f90 sourcefile~ecpint.f90 ecpint.F90 sourcefile~ecp.f90->sourcefile~ecpint.f90 sourcefile~precision.f90 precision.F90 sourcefile~ecp.f90->sourcefile~precision.f90 sourcefile~basis_tools.f90->sourcefile~constants.f90 sourcefile~basis_tools.f90->sourcefile~precision.f90 sourcefile~atomic_structure.f90 atomic_structure.F90 sourcefile~basis_tools.f90->sourcefile~atomic_structure.f90 sourcefile~basis_library.f90 basis_library.F90 sourcefile~basis_tools.f90->sourcefile~basis_library.f90 sourcefile~constants_io.f90 constants_io.F90 sourcefile~basis_tools.f90->sourcefile~constants_io.f90 sourcefile~elements.f90 elements.F90 sourcefile~basis_tools.f90->sourcefile~elements.f90 sourcefile~messages.f90 messages.F90 sourcefile~basis_tools.f90->sourcefile~messages.f90 sourcefile~parallel.f90 parallel.F90 sourcefile~basis_tools.f90->sourcefile~parallel.f90 sourcefile~constants.f90->sourcefile~precision.f90 sourcefile~strings.f90 strings.F90 sourcefile~atomic_structure.f90->sourcefile~strings.f90 sourcefile~basis_library.f90->sourcefile~constants.f90 sourcefile~basis_library.f90->sourcefile~constants_io.f90 sourcefile~basis_library.f90->sourcefile~elements.f90 sourcefile~basis_library.f90->sourcefile~strings.f90 sourcefile~physical_constants.f90 physical_constants.F90 sourcefile~elements.f90->sourcefile~physical_constants.f90 sourcefile~elements.f90->sourcefile~strings.f90 sourcefile~messages.f90->sourcefile~precision.f90 sourcefile~messages.f90->sourcefile~constants_io.f90 sourcefile~parallel.f90->sourcefile~precision.f90

Files dependent on this one

sourcefile~~ecp.f90~~AfferentGraph sourcefile~ecp.f90 ecp.F90 sourcefile~grd1.f90 grd1.F90 sourcefile~grd1.f90->sourcefile~ecp.f90 sourcefile~int1.f90 int1.F90 sourcefile~int1.f90->sourcefile~ecp.f90 sourcefile~electric_moments.f90 electric_moments.F90 sourcefile~electric_moments.f90->sourcefile~int1.f90 sourcefile~get_basis_overlap.f90 get_basis_overlap.F90 sourcefile~get_basis_overlap.f90->sourcefile~int1.f90 sourcefile~hf_gradient.f90 hf_gradient.F90 sourcefile~hf_gradient.f90->sourcefile~grd1.f90 sourcefile~huckel.f90 huckel.F90 sourcefile~huckel.f90->sourcefile~int1.f90 sourcefile~int1e.f90 int1e.F90 sourcefile~int1e.f90->sourcefile~int1.f90 sourcefile~resp.f90 resp.F90 sourcefile~resp.f90->sourcefile~int1.f90 sourcefile~tdhf_energy.f90 tdhf_energy.F90 sourcefile~tdhf_energy.f90->sourcefile~int1.f90 sourcefile~tdhf_gradient.f90 tdhf_gradient.F90 sourcefile~tdhf_gradient.f90->sourcefile~grd1.f90 sourcefile~tdhf_sf_lib.f90 tdhf_sf_lib.F90 sourcefile~tdhf_sf_lib.f90->sourcefile~int1.f90 sourcefile~guess_huckel.f90 guess_huckel.F90 sourcefile~guess_huckel.f90->sourcefile~huckel.f90 sourcefile~tdhf_mrsf_energy.f90 tdhf_mrsf_energy.F90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~tdhf_sf_lib.f90 sourcefile~tdhf_sf_energy.f90 tdhf_sf_energy.F90 sourcefile~tdhf_sf_energy.f90->sourcefile~tdhf_sf_lib.f90 sourcefile~tdhf_z_vector.f90 tdhf_z_vector.F90 sourcefile~tdhf_z_vector.f90->sourcefile~tdhf_sf_lib.f90

Source Code

module ecp_tool
    use iso_c_binding, only: c_double, c_ptr, c_int,&
            c_f_pointer, C_LOC, c_null_ptr
    use, intrinsic :: iso_fortran_env, only: real64
    use libecpint_wrapper
    use libecp_result, only : ecp_result
    use basis_tools, only: basis_set
    use precision, only: dp

    implicit none

    private
    public add_ecpint
    public add_ecpder

contains

    subroutine add_ecpint(basis, coord, hcore)
        real(real64), contiguous, intent(in) :: coord(:,:)
        type(basis_set), intent(in) :: basis
        real(real64), contiguous, intent(inout) :: hcore(:)
        type(c_ptr) :: integrator
        type(ecp_result) :: result_ptr
        real(c_double), pointer :: libecp_res(:)
        integer :: i, j, c
        integer(c_int) :: driv_order

        if (.not.(basis%ecp_params%is_ecp)) then
            return
        end if
        driv_order = 0

        call set_integrator(integrator, basis, coord, driv_order)

        result_ptr = compute_integrals(integrator)
        call c_f_pointer(result_ptr%data, libecp_res, [result_ptr%size])


        call transform_matrix(basis, libecp_res)

        c = 0
        do i = 1, basis%nbf
            do j = 1, i
                c = c + 1
                hcore(c) = libecp_res((i - 1) * basis%nbf + j) + hcore(c)
            end do
        end do

        result_ptr%data = c_null_ptr
        result_ptr%size = 0
        nullify(libecp_res)

        call free_integrator(integrator)
        call free_result(result_ptr)

    end subroutine add_ecpint

    subroutine add_ecpder(basis, coord, denab, de)

        real(real64), contiguous, intent(in) :: coord(:,:)
        type(basis_set), intent(in) :: basis
        REAL(kind=dp), INTENT(INOUT) :: denab(:)
        REAL(kind=dp), intent(INOUT) :: de(:,:)

        type(ecp_result) :: result_ptr
        type(c_ptr) :: integrator
        real(c_double), pointer :: libecp_res(:)
        real(real64), allocatable :: res_x(:), res_y(:), res_z(:)
        real(real64), allocatable :: deloc(:,:)
        integer :: i, j, c, n, natm, prim
        integer :: tri_size, full_size
        integer(c_int) :: driv_order

        if (.not.(basis%ecp_params%is_ecp)) then
            return
        end if

        driv_order = 1

        tri_size = basis%nbf * (basis%nbf + 1) / 2
        full_size = basis%nbf * basis%nbf

        allocate(res_x(full_size))
        allocate(res_y(full_size))
        allocate(res_z(full_size))

        natm = size(coord, dim=2)

        allocate(deloc(3, natm))
        deloc = 0

        call set_integrator(integrator, basis, coord, driv_order)

        result_ptr = compute_first_derivs(integrator)

        call c_f_pointer(result_ptr%data, libecp_res, [result_ptr%size])


        do n = 1, natm
            res_x = libecp_res(full_size * (3 * n - 3)+1:full_size * (3 * n - 2))
            res_y = libecp_res(full_size * (3 * n - 2)+1:full_size * (3 * n - 1))
            res_z = libecp_res(full_size * (3 * n - 1)+1:full_size * (3 * n))
            call transform_matrix(basis, res_x)
            call transform_matrix(basis, res_y)
            call transform_matrix(basis, res_z)

            do j = 1, basis%nbf
                do i = 1, j
                    c = j * (j - 1) / 2 + i

                    if (i == j) then
                        prim = 1
                    else
                        prim = 2
                    end if

                    deloc(1, n) = deloc(1, n) + prim * res_x((i - 1) * basis%nbf + j) * denab(c)
                    deloc(2, n) = deloc(2, n) + prim * res_y((i - 1) * basis%nbf + j) * denab(c)
                    deloc(3, n) = deloc(3, n) + prim * res_z((i - 1) * basis%nbf + j) * denab(c)
                end do
            end do

        end do

        de(:, 1:natm) = de(:, 1:natm) + deloc(:, 1:natm)

        result_ptr%data = c_null_ptr
        result_ptr%size = 0
        nullify(libecp_res)

        call free_integrator(integrator)
        call free_result(result_ptr)

    end subroutine add_ecpder

    subroutine set_integrator(integrator, basis, coord, deriv_order)

        real(c_double), intent(in), contiguous :: coord(:,:)
        type(basis_set), intent(in) :: basis
        integer(c_int), intent(in) :: deriv_order

        type(c_ptr) :: integrator
        real(c_double), allocatable :: g_coords(:), g_exps(:), g_coefs(:)
        integer(c_int), allocatable :: g_ams(:), g_lengths(:)
        real(c_double), allocatable :: u_coords(:), u_exps(:), u_coefs(:)
        integer(c_int), allocatable :: u_ams(:), u_ns(:), u_lengths(:)
        integer(c_int) :: num_ecps, num_gaussians, n_coord, f_expo_len
        integer :: tri_size, full_size, natm


        tri_size = basis%nbf * (basis%nbf + 1) / 2
        full_size = basis%nbf * basis%nbf

        f_expo_len = sum(basis%ecp_params%n_expo)
        natm = size(coord, dim=2)

        num_gaussians = basis%nshell
        n_coord = num_gaussians * 3

        allocate(g_coords(n_coord), g_exps(basis%nprim), g_coefs(basis%nprim))
        allocate(g_ams(basis%nshell), g_lengths(basis%nshell))

        allocate(u_coords(size(basis%ecp_params%ecp_coord)), u_exps(f_expo_len))
        allocate(u_coefs(f_expo_len), u_ams(f_expo_len))
        allocate(u_ns(f_expo_len), u_lengths(size(basis%ecp_params%n_expo)))

        call libecp_g_coords(basis, coord, g_coords)
        g_exps = real(basis%ex, kind=c_double)
        g_coefs = real(basis%cc, kind=c_double)
        g_ams = int(basis%am, kind=c_int)
        g_lengths = int(basis%ncontr, kind=c_int)

        num_ecps = int(size(basis%ecp_params%n_expo), kind=c_int)
        u_coords = real(basis%ecp_params%ecp_coord, kind=c_double)
        u_exps = real(basis%ecp_params%ecp_ex, kind=c_double)
        u_coefs = real(basis%ecp_params%ecp_cc, kind=c_double)
        u_ams = int(basis%ecp_params%ecp_am, kind=c_int)
        u_ns = int(basis%ecp_params%ecp_r_ex, kind=c_int)
        u_lengths = int(basis%ecp_params%n_expo, kind=c_int)


        integrator = init_integrator(num_gaussians, g_coords, g_exps, g_coefs, &
                                     g_ams, g_lengths)

        call set_ecp_basis(integrator, num_ecps, u_coords, u_exps, u_coefs, &
                           u_ams, u_ns, u_lengths)

        call init_integrator_instance(integrator, deriv_order)

    end subroutine set_integrator

  subroutine libecpint_map(basis, label_map)

    use basis_tools, only: basis_set
    use constants, only: map_canonical

    type(basis_set), intent(in) :: basis
    integer, dimension(:), intent(inout):: label_map
    integer :: i,j

    do i = 1, basis%nbf
      j = basis%bf_to_shell(i)
      label_map(i + map_canonical(i-basis%ao_offset(j)+1, basis%am(j))) = i
    end do

  end  subroutine libecpint_map

  subroutine libecp_g_coords(basis, coord, g_coords)

      type(basis_set), intent(in) :: basis
      real(real64), intent(in) :: coord(:,:)
      real(c_double), intent(out) :: g_coords(:)

      integer :: shell

      do shell = 1, basis%nshell
          g_coords(3*shell-2:3*shell) = real(coord(1:3, basis%origin(shell)),c_double)
      end do
  end subroutine libecp_g_coords

  subroutine transform_matrix(basis, matrix)

    use basis_tools, only: basis_set
    type(basis_set), intent(in) :: basis
    real(c_double), dimension(:), intent(inout) :: matrix
    real(c_double), dimension(:), allocatable :: tmp_matrix
    integer, dimension(:), allocatable :: label_map
    integer :: i, j, row, col, n

    n = basis%nbf
    allocate(label_map(n))

    if (size(matrix) /= n * n) then
      print *, "Error: original_matrix size does not match labels."
      stop
    end if

    call libecpint_map(basis, label_map)
    allocate(tmp_matrix(n * n))

    tmp_matrix = matrix

    do i = 1, n
      do j = 1, n
        row = label_map(i)
        col = label_map(j)
        matrix((row - 1) * n + col) = tmp_matrix((i - 1) * n + j)
      end do
    end do
  end subroutine transform_matrix


end module ecp_tool