hf_gradient.F90 Source File


This file depends on

sourcefile~~hf_gradient.f90~~EfferentGraph sourcefile~hf_gradient.f90 hf_gradient.F90 sourcefile~basis_tools.f90 basis_tools.F90 sourcefile~hf_gradient.f90->sourcefile~basis_tools.f90 sourcefile~c_interop.f90 c_interop.F90 sourcefile~hf_gradient.f90->sourcefile~c_interop.f90 sourcefile~constants.f90 constants.F90 sourcefile~hf_gradient.f90->sourcefile~constants.f90 sourcefile~constants_io.f90 constants_io.F90 sourcefile~hf_gradient.f90->sourcefile~constants_io.f90 sourcefile~dft.f90 dft.F90 sourcefile~hf_gradient.f90->sourcefile~dft.f90 sourcefile~dft_molgrid.f90 dft_molgrid.F90 sourcefile~hf_gradient.f90->sourcefile~dft_molgrid.f90 sourcefile~grd1.f90 grd1.F90 sourcefile~hf_gradient.f90->sourcefile~grd1.f90 sourcefile~grd2.f90 grd2.F90 sourcefile~hf_gradient.f90->sourcefile~grd2.f90 sourcefile~mathlib.f90 mathlib.F90 sourcefile~hf_gradient.f90->sourcefile~mathlib.f90 sourcefile~messages.f90 messages.F90 sourcefile~hf_gradient.f90->sourcefile~messages.f90 sourcefile~precision.f90 precision.F90 sourcefile~hf_gradient.f90->sourcefile~precision.f90 sourcefile~printing.f90 printing.F90 sourcefile~hf_gradient.f90->sourcefile~printing.f90 sourcefile~strings.f90 strings.F90 sourcefile~hf_gradient.f90->sourcefile~strings.f90 sourcefile~tagarray_driver.f90 tagarray_driver.F90 sourcefile~hf_gradient.f90->sourcefile~tagarray_driver.f90 sourcefile~types.f90 types.F90 sourcefile~hf_gradient.f90->sourcefile~types.f90 sourcefile~util.f90 util.F90 sourcefile~hf_gradient.f90->sourcefile~util.f90 sourcefile~basis_tools.f90->sourcefile~constants.f90 sourcefile~basis_tools.f90->sourcefile~constants_io.f90 sourcefile~basis_tools.f90->sourcefile~messages.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~elements.f90 elements.F90 sourcefile~basis_tools.f90->sourcefile~elements.f90 sourcefile~parallel.f90 parallel.F90 sourcefile~basis_tools.f90->sourcefile~parallel.f90 sourcefile~c_interop.f90->sourcefile~basis_tools.f90 sourcefile~c_interop.f90->sourcefile~messages.f90 sourcefile~c_interop.f90->sourcefile~strings.f90 sourcefile~c_interop.f90->sourcefile~tagarray_driver.f90 sourcefile~c_interop.f90->sourcefile~types.f90 sourcefile~constants.f90->sourcefile~precision.f90 sourcefile~dft.f90->sourcefile~basis_tools.f90 sourcefile~dft.f90->sourcefile~constants.f90 sourcefile~dft.f90->sourcefile~constants_io.f90 sourcefile~dft.f90->sourcefile~dft_molgrid.f90 sourcefile~dft.f90->sourcefile~mathlib.f90 sourcefile~dft.f90->sourcefile~messages.f90 sourcefile~dft.f90->sourcefile~precision.f90 sourcefile~dft.f90->sourcefile~strings.f90 sourcefile~dft.f90->sourcefile~tagarray_driver.f90 sourcefile~dft.f90->sourcefile~types.f90 sourcefile~bragg_slater.f90 bragg_slater.F90 sourcefile~dft.f90->sourcefile~bragg_slater.f90 sourcefile~dft_fuzzycell.f90 dft_fuzzycell.F90 sourcefile~dft.f90->sourcefile~dft_fuzzycell.f90 sourcefile~dft_gridint_energy.f90 dft_gridint_energy.F90 sourcefile~dft.f90->sourcefile~dft_gridint_energy.f90 sourcefile~dft_gridint_grad.f90 dft_gridint_grad.F90 sourcefile~dft.f90->sourcefile~dft_gridint_grad.f90 sourcefile~grid_storage.f90 grid_storage.F90 sourcefile~dft.f90->sourcefile~grid_storage.f90 sourcefile~libxc.f90 libxc.F90 sourcefile~dft.f90->sourcefile~libxc.f90 sourcefile~physical_constants.f90 physical_constants.F90 sourcefile~dft.f90->sourcefile~physical_constants.f90 sourcefile~radial_grid_types.f90 radial_grid_types.F90 sourcefile~dft.f90->sourcefile~radial_grid_types.f90 sourcefile~dft_molgrid.f90->sourcefile~constants.f90 sourcefile~dft_molgrid.f90->sourcefile~precision.f90 sourcefile~dft_molgrid.f90->sourcefile~bragg_slater.f90 sourcefile~dft_partfunc.f90 dft_partfunc.F90 sourcefile~dft_molgrid.f90->sourcefile~dft_partfunc.f90 sourcefile~dft_molgrid.f90->sourcefile~grid_storage.f90 sourcefile~lebedev.f90 lebedev.F90 sourcefile~dft_molgrid.f90->sourcefile~lebedev.f90 sourcefile~grd1.f90->sourcefile~basis_tools.f90 sourcefile~grd1.f90->sourcefile~constants_io.f90 sourcefile~grd1.f90->sourcefile~mathlib.f90 sourcefile~grd1.f90->sourcefile~messages.f90 sourcefile~grd1.f90->sourcefile~precision.f90 sourcefile~grd1.f90->sourcefile~tagarray_driver.f90 sourcefile~grd1.f90->sourcefile~types.f90 sourcefile~grd1.f90->sourcefile~atomic_structure.f90 sourcefile~ecp.f90 ecp.F90 sourcefile~grd1.f90->sourcefile~ecp.f90 sourcefile~mod_1e_primitives.f90 mod_1e_primitives.F90 sourcefile~grd1.f90->sourcefile~mod_1e_primitives.f90 sourcefile~mod_shell_tools.f90 mod_shell_tools.F90 sourcefile~grd1.f90->sourcefile~mod_shell_tools.f90 sourcefile~grd1.f90->sourcefile~parallel.f90 sourcefile~grd2.f90->sourcefile~basis_tools.f90 sourcefile~grd2.f90->sourcefile~constants.f90 sourcefile~grd2.f90->sourcefile~constants_io.f90 sourcefile~grd2.f90->sourcefile~dft_molgrid.f90 sourcefile~grd2.f90->sourcefile~messages.f90 sourcefile~grd2.f90->sourcefile~precision.f90 sourcefile~grd2.f90->sourcefile~tagarray_driver.f90 sourcefile~grd2.f90->sourcefile~types.f90 sourcefile~grd2.f90->sourcefile~util.f90 sourcefile~grd2_rys.f90 grd2_rys.F90 sourcefile~grd2.f90->sourcefile~grd2_rys.f90 sourcefile~int2.f90 int2.F90 sourcefile~grd2.f90->sourcefile~int2.f90 sourcefile~int2_pairs.f90 int2_pairs.F90 sourcefile~grd2.f90->sourcefile~int2_pairs.f90 sourcefile~grd2.f90->sourcefile~parallel.f90 sourcefile~mathlib.f90->sourcefile~messages.f90 sourcefile~mathlib.f90->sourcefile~precision.f90 sourcefile~eigen.f90 eigen.F90 sourcefile~mathlib.f90->sourcefile~eigen.f90 sourcefile~oqp_linalg.f90 oqp_linalg.F90 sourcefile~mathlib.f90->sourcefile~oqp_linalg.f90 sourcefile~messages.f90->sourcefile~constants_io.f90 sourcefile~messages.f90->sourcefile~precision.f90 sourcefile~printing.f90->sourcefile~basis_tools.f90 sourcefile~printing.f90->sourcefile~constants_io.f90 sourcefile~printing.f90->sourcefile~messages.f90 sourcefile~printing.f90->sourcefile~precision.f90 sourcefile~printing.f90->sourcefile~tagarray_driver.f90 sourcefile~printing.f90->sourcefile~types.f90 sourcefile~tagarray_driver.f90->sourcefile~messages.f90 sourcefile~types.f90->sourcefile~basis_tools.f90 sourcefile~types.f90->sourcefile~precision.f90 sourcefile~types.f90->sourcefile~atomic_structure.f90 sourcefile~functionals.f90 functionals.F90 sourcefile~types.f90->sourcefile~functionals.f90 sourcefile~types.f90->sourcefile~parallel.f90 sourcefile~util.f90->sourcefile~precision.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~strings.f90 sourcefile~basis_library.f90->sourcefile~elements.f90 sourcefile~bragg_slater.f90->sourcefile~precision.f90 sourcefile~dft_fuzzycell.f90->sourcefile~basis_tools.f90 sourcefile~dft_fuzzycell.f90->sourcefile~constants.f90 sourcefile~dft_fuzzycell.f90->sourcefile~dft_molgrid.f90 sourcefile~dft_fuzzycell.f90->sourcefile~precision.f90 sourcefile~dft_fuzzycell.f90->sourcefile~atomic_structure.f90 sourcefile~dft_fuzzycell.f90->sourcefile~dft_partfunc.f90 sourcefile~dft_fuzzycell.f90->sourcefile~grid_storage.f90 sourcefile~dft_gridint_energy.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_energy.f90->sourcefile~dft_molgrid.f90 sourcefile~dft_gridint_energy.f90->sourcefile~precision.f90 sourcefile~dft_gridint_energy.f90->sourcefile~types.f90 sourcefile~dft_gridint_energy.f90->sourcefile~oqp_linalg.f90 sourcefile~dft_gridint.f90 dft_gridint.F90 sourcefile~dft_gridint_energy.f90->sourcefile~dft_gridint.f90 sourcefile~dft_gridint_grad.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_grad.f90->sourcefile~dft_molgrid.f90 sourcefile~dft_gridint_grad.f90->sourcefile~precision.f90 sourcefile~dft_gridint_grad.f90->sourcefile~types.f90 sourcefile~dft_gridint_grad.f90->sourcefile~dft_gridint.f90 sourcefile~dft_partfunc.f90->sourcefile~precision.f90 sourcefile~ecp.f90->sourcefile~basis_tools.f90 sourcefile~ecp.f90->sourcefile~constants.f90 sourcefile~ecp.f90->sourcefile~precision.f90 sourcefile~ecpint.f90 ecpint.F90 sourcefile~ecp.f90->sourcefile~ecpint.f90 sourcefile~eigen.f90->sourcefile~messages.f90 sourcefile~eigen.f90->sourcefile~precision.f90 sourcefile~eigen.f90->sourcefile~oqp_linalg.f90 sourcefile~mathlib_types.f90 mathlib_types.F90 sourcefile~eigen.f90->sourcefile~mathlib_types.f90 sourcefile~elements.f90->sourcefile~strings.f90 sourcefile~elements.f90->sourcefile~physical_constants.f90 sourcefile~functionals.f90->sourcefile~messages.f90 sourcefile~functionals.f90->sourcefile~precision.f90 sourcefile~grd2_rys.f90->sourcefile~basis_tools.f90 sourcefile~grd2_rys.f90->sourcefile~constants.f90 sourcefile~grd2_rys.f90->sourcefile~precision.f90 sourcefile~grd2_rys.f90->sourcefile~int2_pairs.f90 sourcefile~rys.f90 rys.F90 sourcefile~grd2_rys.f90->sourcefile~rys.f90 sourcefile~grid_storage.f90->sourcefile~precision.f90 sourcefile~int2.f90->sourcefile~basis_tools.f90 sourcefile~int2.f90->sourcefile~constants.f90 sourcefile~int2.f90->sourcefile~constants_io.f90 sourcefile~int2.f90->sourcefile~messages.f90 sourcefile~int2.f90->sourcefile~precision.f90 sourcefile~int2.f90->sourcefile~tagarray_driver.f90 sourcefile~int2.f90->sourcefile~types.f90 sourcefile~int2.f90->sourcefile~atomic_structure.f90 sourcefile~int2.f90->sourcefile~int2_pairs.f90 sourcefile~int2.f90->sourcefile~parallel.f90 sourcefile~int_libint.f90 int_libint.F90 sourcefile~int2.f90->sourcefile~int_libint.f90 sourcefile~int_rotaxis.f90 int_rotaxis.F90 sourcefile~int2.f90->sourcefile~int_rotaxis.f90 sourcefile~int_rys.f90 int_rys.F90 sourcefile~int2.f90->sourcefile~int_rys.f90 sourcefile~int2_pairs.f90->sourcefile~basis_tools.f90 sourcefile~int2_pairs.f90->sourcefile~precision.f90 sourcefile~lebedev.f90->sourcefile~messages.f90 sourcefile~lebedev.f90->sourcefile~precision.f90 sourcefile~libxc.f90->sourcefile~messages.f90 sourcefile~libxc.f90->sourcefile~precision.f90 sourcefile~libxc.f90->sourcefile~types.f90 sourcefile~libxc.f90->sourcefile~functionals.f90 sourcefile~mod_1e_primitives.f90->sourcefile~constants.f90 sourcefile~mod_1e_primitives.f90->sourcefile~mod_shell_tools.f90 sourcefile~mod_gauss_hermite.f90 mod_gauss_hermite.F90 sourcefile~mod_1e_primitives.f90->sourcefile~mod_gauss_hermite.f90 sourcefile~mod_1e_primitives.f90->sourcefile~rys.f90 sourcefile~xyzorder.f90 xyzorder.F90 sourcefile~mod_1e_primitives.f90->sourcefile~xyzorder.f90 sourcefile~mod_shell_tools.f90->sourcefile~basis_tools.f90 sourcefile~mod_shell_tools.f90->sourcefile~precision.f90 sourcefile~blas_wrap.f90 blas_wrap.F90 sourcefile~oqp_linalg.f90->sourcefile~blas_wrap.f90 sourcefile~lapack_wrap.f90 lapack_wrap.F90 sourcefile~oqp_linalg.f90->sourcefile~lapack_wrap.f90 sourcefile~parallel.f90->sourcefile~precision.f90 sourcefile~radial_grid_types.f90->sourcefile~precision.f90 sourcefile~blas_wrap.f90->sourcefile~messages.f90 sourcefile~blas_wrap.f90->sourcefile~precision.f90 sourcefile~blas_wrap.f90->sourcefile~mathlib_types.f90 sourcefile~dft_gridint.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint.f90->sourcefile~constants_io.f90 sourcefile~dft_gridint.f90->sourcefile~dft_molgrid.f90 sourcefile~dft_gridint.f90->sourcefile~precision.f90 sourcefile~dft_gridint.f90->sourcefile~functionals.f90 sourcefile~dft_gridint.f90->sourcefile~oqp_linalg.f90 sourcefile~dft_gridint.f90->sourcefile~parallel.f90 sourcefile~dft_xc_libxc.f90 dft_xc_libxc.F90 sourcefile~dft_gridint.f90->sourcefile~dft_xc_libxc.f90 sourcefile~int_libint.f90->sourcefile~basis_tools.f90 sourcefile~int_libint.f90->sourcefile~constants.f90 sourcefile~int_libint.f90->sourcefile~precision.f90 sourcefile~int_libint.f90->sourcefile~int2_pairs.f90 sourcefile~libint_f.f90 libint_f.F90 sourcefile~int_libint.f90->sourcefile~libint_f.f90 sourcefile~int_rotaxis.f90->sourcefile~basis_tools.f90 sourcefile~int_rotaxis.f90->sourcefile~constants.f90 sourcefile~int_rotaxis.f90->sourcefile~precision.f90 sourcefile~int_rotaxis.f90->sourcefile~int2_pairs.f90 sourcefile~int_rys.f90->sourcefile~basis_tools.f90 sourcefile~int_rys.f90->sourcefile~constants.f90 sourcefile~int_rys.f90->sourcefile~precision.f90 sourcefile~int_rys.f90->sourcefile~int2_pairs.f90 sourcefile~int_rys.f90->sourcefile~rys.f90 sourcefile~lapack_wrap.f90->sourcefile~messages.f90 sourcefile~lapack_wrap.f90->sourcefile~precision.f90 sourcefile~lapack_wrap.f90->sourcefile~mathlib_types.f90 sourcefile~mod_gauss_hermite.f90->sourcefile~precision.f90 sourcefile~rys.f90->sourcefile~constants.f90 sourcefile~rys.f90->sourcefile~precision.f90 sourcefile~rys_lut.f90 rys_lut.F90 sourcefile~rys.f90->sourcefile~rys_lut.f90 sourcefile~dft_xc_libxc.f90->sourcefile~precision.f90 sourcefile~dft_xc_libxc.f90->sourcefile~functionals.f90 sourcefile~dft_xclib.f90 dft_xclib.F90 sourcefile~dft_xc_libxc.f90->sourcefile~dft_xclib.f90 sourcefile~dft_xclib.f90->sourcefile~precision.f90 sourcefile~dft_xclib.f90->sourcefile~functionals.f90

Source Code

module hf_gradient_mod

  use precision, only: dp
  use grd2, only: grd2_driver, grd2_compute_data_t
  use basis_tools, only: basis_set
  use types, only: information

  implicit none

  character(len=*), parameter :: module_name = "hf_gradient_mod"

!###############################################################################

  type, extends(grd2_compute_data_t), abstract :: grd2_hf_compute_data_t
    real(kind=dp), pointer :: da(:) => null()
    real(kind=dp), pointer :: db(:) => null()
    real(kind=dp), allocatable :: d2a(:,:), d2b(:,:)
    integer :: nbf = 0
  contains
  end type

!###############################################################################

  type, extends(grd2_hf_compute_data_t) :: grd2_rhf_compute_data_t
  contains
    procedure :: init => grd2_rhf_compute_data_t_init
    procedure :: clean => grd2_rhf_compute_data_t_clean
    procedure :: get_density => grd2_rhf_compute_data_t_get_density
  end type

!###############################################################################

  type, extends(grd2_hf_compute_data_t) :: grd2_uhf_compute_data_t
  contains
    procedure :: init => grd2_uhf_compute_data_t_init
    procedure :: clean => grd2_uhf_compute_data_t_clean
    procedure :: get_density => grd2_uhf_compute_data_t_get_density
  end type

!###############################################################################

  private

  public hf_gradient

!###############################################################################

contains

!###############################################################################

  subroutine hf_gradient_C(c_handle) bind(C, name="hf_gradient")
    use c_interop, only: oqp_handle_t, oqp_handle_get_info
    use types, only: information
    type(oqp_handle_t) :: c_handle
    type(information), pointer :: inf
    inf => oqp_handle_get_info(c_handle)
    call hf_gradient(inf)
  end subroutine hf_gradient_C

!###############################################################################

  subroutine hf_gradient(infos)
    use io_constants, only: iw
    use grd1, only: print_gradient
    use dft, only: dft_initialize, dftclean, dftder
    use strings, only: Cstring, fstring
    use mod_dft_molgrid, only: dft_grid_t
    use util, only: measure_time
    use printing, only: print_module_info

    implicit none

    type(information), target, intent(inout) :: infos

    integer :: b_size, c_size, s_size
    type(basis_Set), pointer :: basis
    logical :: urohf, dft
    type(dft_grid_t) :: molGrid

!   3. LOG: Write: Main output file
    open (unit=IW, file=infos%log_filename, position="append")
!
    call print_module_info('HF_DFT_Gradient','Computing Gradient of HF/DFT')

    urohf = infos%control%scftype == 2 .or. infos%control%scftype == 3
    dft = infos%control%hamilton == 20

!   Load basis set
    basis => infos%basis
    basis%atoms => infos%atoms

!   Allocate memory
    b_size = basis%nbf*(basis%nbf+1)/2
    c_size = basis%nbf
    s_size = (basis%nshell**2+basis%nshell)/2


!   Compute 1e gradient

    write(iw,"(/' ..... Beginning Gradient Calculation...'/)")
    call flush(iw)

    call hf_1e_grad(infos, basis)

    write(iw,"(' ..... End Of 1-Eelectron Gradient ......')")

    call measure_time(print_total=1, log_unit=iw)
    call flush(iw)

!   Calculate DFT contribution
    if (dft) then
      write(iw,"(/' ..... Gradient XC terms...'/)")
      call dft_initialize(infos, basis, molGrid, verbose=.true.)
      call dftder(basis, infos, molGrid)
      call dftclean(infos)
      write(iw,"(' ..... End of gradient XC terms......')")
      call measure_time(print_total=1, log_unit=iw)
      call flush(iw)
    end if

!   Compute 2e gradient
    call hf_2e_grad(basis, infos)

    write(iw, fmt="(' ...... End Of 2-Electron Gradient ......')")

    call measure_time(print_total=1, log_unit=iw)
    call flush(iw)


!   Print out gradient
    call print_gradient(infos)

!   Print timings
    call measure_time(print_total=1, log_unit=iw)
    close(iw)

  end subroutine hf_gradient

!-------------------------------------------------------------------------------

  subroutine hf_1e_grad(infos, basis)

    use types, only: information
    use oqp_tagarray_driver
    use basis_tools, only: basis_set
    use util, only: measure_time
    use messages, only: show_message, WITH_ABORT
    use constants, only: tol_int
    use grd1, only: eijden, grad_nn, grad_ee_overlap, &
            grad_ee_kinetic, grad_en_hellman_feynman, &
            grad_en_pulay, grad_1e_ecp

    implicit none

    character(len=*), parameter :: subroutine_name = "hf_1e_grad"

    type(information), intent(inout) :: infos
    type(basis_set), intent(inout) :: basis

    real(kind=dp), allocatable :: dens(:)
    real(kind=dp) :: tol
    integer :: nbf, nbf_tri, ok
    integer(4) :: status

    real(kind=dp), pointer :: dmat_a(:), dmat_b(:)

    nbf = basis%nbf
    nbf_tri = nbf*(nbf+1)/2

    tol = tol_int*log(10.0_dp)

!   initial memory allocation
    allocate(dens(nbf_tri), source=0.0_dp, stat=ok)
    if(ok/=0) call show_message('Cannot allocate memory', WITH_ABORT)

    call tagarray_get_data(infos%dat, OQP_DM_A, dmat_a, status)
    call check_status(status, module_name, subroutine_name, OQP_DM_A)

    if (infos%control%scftype>=2) then
      call tagarray_get_data(infos%dat, OQP_DM_B, dmat_b, status)
      call check_status(status, module_name, subroutine_name, OQP_DM_B)
    endif

    associate(grad  => infos%atoms%grad, &
              xyz   => infos%atoms%xyz, &
              zn    => infos%atoms%zn - infos%basis%ecp_zn_num)

!     Zero out gradient
      grad = 0.0d0

!     Nuclear repulsion force
      call grad_nn(infos%atoms, infos%basis%ecp_zn_num)

!     Obtain Lagrangian matrix (`dens`)
      call eijden(dens, nbf, infos)

!     Overlap gradient
      call grad_ee_overlap(basis, dens, grad, logtol=tol)


!     Compute total density matrix, discard Lagrangian
      dens = dmat_a
      if (infos%control%scftype>=2) dens = dens + dmat_b

!     Kinetic gradient
      call grad_ee_kinetic(basis, dens, grad, logtol=tol)

!     Hellmann-Feynman force
      call grad_en_hellman_feynman(basis, xyz, zn, dens, grad, logtol=tol)

!     Pulay force
      call grad_en_pulay(basis, xyz, zn, dens, grad, logtol=tol)

!     Effective core potential gradient
      call grad_1e_ecp(infos, basis, xyz, dens, grad, logtol=tol)

    end associate

   end subroutine

!###############################################################################

!> @brief The driver for the two electron gradient
  subroutine hf_2e_grad(basis, infos)

    use basis_tools, only: basis_set
    use precision, only: dp
    use oqp_tagarray_driver
    use messages, only: show_message, WITH_ABORT
    use types, only: information

    implicit none

    character(len=*), parameter :: subroutine_name = "hf_2e_grad"

    type(information), target, intent(inout) :: infos
    type(basis_set) :: basis

    logical :: urohf
    real(kind=dp) :: hfscale

    integer :: ok
    real(kind=dp), allocatable :: de(:,:)
    class(grd2_compute_data_t), allocatable :: gcomp

    ! tagarray
    real(kind=dp), contiguous, pointer :: dmat_a(:), dmat_b(:)
    integer(4) :: status

    urohf = infos%control%scftype >= 2
    hfscale = 1.0d0
    if(infos%control%hamilton.ge.20) hfscale = infos%dft%hfscale

    allocate(de(3,ubound(infos%atoms%zn,1)), &
            source=0.0d0, &
            stat=ok)

    if(ok/=0) call show_message('cannot allocate memory', WITH_ABORT)

    if (urohf) then

      call tagarray_get_data(infos%dat, OQP_DM_A, dmat_a, status)
      call check_status(status, module_name, subroutine_name, OQP_DM_A)
      call tagarray_get_data(infos%dat, OQP_DM_B, dmat_b, status)
      call check_status(status, module_name, subroutine_name, OQP_DM_B)

      gcomp = &
        grd2_uhf_compute_data_t( da = dmat_a &
                               , db = dmat_b &
                               , hfscale = hfscale &
                               , nbf = basis%nbf &
        )
    else

      call tagarray_get_data(infos%dat, OQP_DM_A, dmat_a, status)
      call check_status(status, module_name, subroutine_name, OQP_DM_A)

      gcomp = &
        grd2_rhf_compute_data_t( da = dmat_a &
                               , hfscale = hfscale &
                               , nbf = basis%nbf &
        )
    end if

    call gcomp%init()

    call grd2_driver(infos, basis, de, gcomp)
    infos%atoms%grad = infos%atoms%grad + de

    call gcomp%clean()

  end subroutine

!###############################################################################

  subroutine grd2_rhf_compute_data_t_init(this)
    use messages, only: show_message, WITH_ABORT
    use mathlib, only: unpack_matrix
    implicit none
    class(grd2_rhf_compute_data_t), target, intent(inout) :: this
    integer :: iok

    call this%clean()

    allocate(this%d2a(this%nbf,this%nbf), stat=iok, source=0.0d0)
    if (iok/=0) call show_message('cannot allocate memory', WITH_ABORT)
    call unpack_matrix(this%da, this%d2a)

  end subroutine

!###############################################################################

  subroutine grd2_uhf_compute_data_t_init(this)
    use messages, only: show_message, WITH_ABORT
    use mathlib, only: unpack_matrix
    implicit none
    class(grd2_uhf_compute_data_t), target, intent(inout) :: this
    integer :: iok

    call this%clean()

    allocate(this%d2a(this%nbf,this%nbf), this%d2b(this%nbf,this%nbf), stat=iok, source=0.0d0)
    if (iok/=0) call show_message('cannot allocate memory', WITH_ABORT)
    call unpack_matrix(this%da, this%d2a)
    call unpack_matrix(this%db, this%d2b)
    this%d2a = this%d2a + this%d2b
    this%d2b = this%d2a - 2*this%d2b

  end subroutine

!###############################################################################

  subroutine grd2_rhf_compute_data_t_clean(this)
    implicit none
    class(grd2_rhf_compute_data_t), target, intent(inout) :: this
    if (allocated(this%d2a)) deallocate(this%d2a)
  end subroutine

!###############################################################################

  subroutine grd2_uhf_compute_data_t_clean(this)
    implicit none
    class(grd2_uhf_compute_data_t), target, intent(inout) :: this
    if (allocated(this%d2a)) deallocate(this%d2a)
    if (allocated(this%d2b)) deallocate(this%d2b)
  end subroutine

!###############################################################################

!> @brief This routine forms the product of density
!>        matrices for use in forming the two electron
!>        gradient. Valid for closed and open shell SCF.
  subroutine grd2_rhf_compute_data_t_get_density(this, basis, id, dab, dabmax)

    implicit none

    class(grd2_rhf_compute_data_t), target, intent(inout) :: this
    type(basis_set), intent(in) :: basis
    integer, intent(in) :: id(4)
    real(kind=dp), target, intent(out) :: dab(*)
    real(kind=dp), intent(out) :: dabmax

    real(kind=dp) :: coulfact, xcfact, df1, dq1
    integer :: i, j, k, l
    integer :: loc(4)
    integer :: nbf(4)
    real(kind=dp), pointer :: ab(:,:,:,:)
    integer :: i1, j1, k1, l1

    coulfact = 4*this%coulscale
    xcfact = this%hfscale

    dabmax = 0
    loc = basis%ao_offset(id)-1

    nbf = basis%naos(id)

    ab(1:nbf(4),1:nbf(3),1:nbf(2),1:nbf(1)) => dab(1:product(nbf))

    do i = 1, nbf(1)
      i1 = loc(1) + i

      do j = 1, nbf(2)
        j1 = loc(2) + j

        do k = 1, nbf(3)
          k1 = loc(3) + k

          do l = 1, nbf(4)
            l1 = loc(4) + l
            df1 = coulfact*this%d2a(i1,j1)*this%d2a(k1,l1)
            if (xcfact/=0.0_dp) then
              dq1 = this%d2a(i1,k1)*this%d2a(j1,l1) &
                  + this%d2a(i1,l1)*this%d2a(j1,k1)
              df1 = df1-xcfact*dq1
            end if
            dabmax = max(dabmax, abs(df1))
            ab(l,k,j,i) = df1*product(basis%bfnrm([i1,j1,k1,l1]))
          end do
        end do
      end do
    end do
  end subroutine grd2_rhf_compute_data_t_get_density

!###############################################################################

!> @brief This routine forms the product of density
!>        matrices for use in forming the two electron
!>        gradient. Valid for closed and open shell SCF.
  subroutine grd2_uhf_compute_data_t_get_density(this, basis, id, dab, dabmax)

    implicit none

    class(grd2_uhf_compute_data_t), target, intent(inout) :: this
    type(basis_set), intent(in) :: basis
    integer, intent(in) :: id(4)
    real(kind=dp), target, intent(out) :: dab(*)
    real(kind=dp), intent(out) :: dabmax

    real(kind=dp) :: coulfact, xcfact, df1, dq1
    integer :: i, j, k, l
    integer :: loc(4)
    integer :: nbf(4)
    real(kind=dp), pointer :: ab(:,:,:,:)
    integer :: i1, j1, k1, l1

    coulfact = 4*this%coulscale
    xcfact = this%hfscale

    dabmax = 0
    loc = basis%ao_offset(id)-1

    nbf = basis%naos(id)

    ab(1:nbf(4),1:nbf(3),1:nbf(2),1:nbf(1)) => dab(1:product(nbf))

    do i = 1, nbf(1)
      i1 = loc(1) + i

      do j = 1, nbf(2)
        j1 = loc(2) + j

        do k = 1, nbf(3)
          k1 = loc(3) + k

          do l = 1, nbf(4)
            l1 = loc(4) + l
            df1 = coulfact*this%d2a(i1,j1)*this%d2a(k1,l1)
            if (xcfact/=0.0_dp) then
              dq1 = this%d2a(i1,k1)*this%d2a(j1,l1) &
                  + this%d2a(i1,l1)*this%d2a(j1,k1) &
                  + this%d2b(i1,k1)*this%d2b(j1,l1) &
                  + this%d2b(i1,l1)*this%d2b(j1,k1)
              df1 = df1-xcfact*dq1
            end if
            dabmax = max(dabmax, abs(df1))
            ab(l,k,j,i) = df1*product(basis%bfnrm([i1,j1,k1,l1]))
          end do
        end do
      end do
    end do
  end subroutine grd2_uhf_compute_data_t_get_density

end module hf_gradient_mod