! Generated by tools/generate_int2_pure_kernels.py; do not edit by hand.
module int2_pure_generated
  use precision, only: dp
  use constants, only: BAS_MXCART, BAS_MXANG, NUM_CART_BF, NUM_SPH_BF
  implicit none
  private
  integer, parameter, public :: INT2_PURE_MAX_TERMS = 4

  type, public :: int2_shell_projection_t
    integer :: ncart = 0
    integer :: nout = 0
    integer :: nterm(BAS_MXCART) = 0
    integer :: out_idx(INT2_PURE_MAX_TERMS, BAS_MXCART) = 0
    real(dp) :: coeff(INT2_PURE_MAX_TERMS, BAS_MXCART) = 0.0_dp
  end type int2_shell_projection_t

  public :: int2_init_shell_projection
  public :: int2_project_pure_block

contains

  subroutine int2_init_shell_projection(l, pure, proj)
    integer, intent(in) :: l, pure
    type(int2_shell_projection_t), intent(out) :: proj
    integer :: c

    if (l < 0 .or. l > BAS_MXANG) error stop 'int2_pure_generated: angular momentum out of range'
    proj = int2_shell_projection_t()
    proj%ncart = NUM_CART_BF(l)
    proj%nout = proj%ncart

    if (pure == 1 .and. l >= 2) then
      proj%nout = NUM_SPH_BF(l)
      select case (l)
      case (2)
        call load_l2(proj)
      case (3)
        call load_l3(proj)
      case (4)
        call load_l4(proj)
      case (5)
        call load_l5(proj)
      case (6)
        call load_l6(proj)
      case default
        error stop 'int2_pure_generated: unsupported pure angular momentum'
      end select
    else
      do c = 1, proj%ncart
        call add_term(proj, c, c, 1.0_dp)
      end do
    end if
  end subroutine int2_init_shell_projection

  subroutine int2_project_pure_block(ints, am, pure, nbf, nbf_out)
    real(dp), intent(inout), target :: ints(:)
    integer, intent(in) :: am(4), pure(4), nbf(4)
    integer, intent(out) :: nbf_out(4)
    type(int2_shell_projection_t) :: proj(4)
    real(dp), allocatable, target :: cart(:)
    real(dp), pointer :: src(:,:,:,:), dst(:,:,:,:)
    integer :: c1, c2, c3, c4, t1, t2, t3, t4
    integer :: o1, o2, o3, o4, s
    real(dp) :: val, v1, v2, v3

    do s = 1, 4
      call int2_init_shell_projection(am(s), pure(s), proj(s))
      nbf_out(s) = proj(s)%nout
    end do
    if (all(nbf_out == nbf)) return

    allocate(cart(product(nbf)))
    cart = ints(1:product(nbf))
    ints(1:product(nbf_out)) = 0.0_dp
    src(1:nbf(1), 1:nbf(2), 1:nbf(3), 1:nbf(4)) => cart
    dst(1:nbf_out(1), 1:nbf_out(2), 1:nbf_out(3), 1:nbf_out(4)) => ints

    do c4 = 1, proj(4)%ncart
      do c3 = 1, proj(3)%ncart
        do c2 = 1, proj(2)%ncart
          do c1 = 1, proj(1)%ncart
            val = src(c1,c2,c3,c4)
            if (val == 0.0_dp) cycle
            do t4 = 1, proj(4)%nterm(c4)
              o4 = proj(4)%out_idx(t4,c4)
              v3 = val * proj(4)%coeff(t4,c4)
              do t3 = 1, proj(3)%nterm(c3)
                o3 = proj(3)%out_idx(t3,c3)
                v2 = v3 * proj(3)%coeff(t3,c3)
                do t2 = 1, proj(2)%nterm(c2)
                  o2 = proj(2)%out_idx(t2,c2)
                  v1 = v2 * proj(2)%coeff(t2,c2)
                  do t1 = 1, proj(1)%nterm(c1)
                    o1 = proj(1)%out_idx(t1,c1)
                    dst(o1,o2,o3,o4) = dst(o1,o2,o3,o4) + v1 * proj(1)%coeff(t1,c1)
                  end do
                end do
              end do
            end do
          end do
        end do
      end do
    end do
    deallocate(cart)
  end subroutine int2_project_pure_block

  subroutine add_term(proj, cart_idx, out_idx, coeff)
    type(int2_shell_projection_t), intent(inout) :: proj
    integer, intent(in) :: cart_idx, out_idx
    real(dp), intent(in) :: coeff
    integer :: slot
    slot = proj%nterm(cart_idx) + 1
    if (slot > INT2_PURE_MAX_TERMS) error stop 'int2_pure_generated: sparse row overflow'
    proj%nterm(cart_idx) = slot
    proj%out_idx(slot, cart_idx) = out_idx
    proj%coeff(slot, cart_idx) = coeff
  end subroutine add_term

  subroutine load_l2(proj)
    type(int2_shell_projection_t), intent(inout) :: proj
    call add_term(proj,  1,  3, -4.999999999999999e-01_dp)
    call add_term(proj,  1,  5, 8.660254037844386e-01_dp)
    call add_term(proj,  2,  3, -4.999999999999999e-01_dp)
    call add_term(proj,  2,  5, -8.660254037844386e-01_dp)
    call add_term(proj,  3,  3, 9.999999999999999e-01_dp)
    call add_term(proj,  4,  1, 1.000000000000000e+00_dp)
    call add_term(proj,  5,  4, 1.000000000000000e+00_dp)
    call add_term(proj,  6,  2, 1.000000000000000e+00_dp)
  end subroutine load_l2

  subroutine load_l3(proj)
    type(int2_shell_projection_t), intent(inout) :: proj
    call add_term(proj,  1,  5, -6.123724356957946e-01_dp)
    call add_term(proj,  1,  7, 7.905694150420950e-01_dp)
    call add_term(proj,  2,  1, -7.905694150420950e-01_dp)
    call add_term(proj,  2,  3, -6.123724356957946e-01_dp)
    call add_term(proj,  3,  4, 1.000000000000000e+00_dp)
    call add_term(proj,  4,  1, 1.060660171779821e+00_dp)
    call add_term(proj,  4,  3, -2.738612787525830e-01_dp)
    call add_term(proj,  5,  4, -6.708203932499368e-01_dp)
    call add_term(proj,  5,  6, 8.660254037844386e-01_dp)
    call add_term(proj,  6,  5, -2.738612787525830e-01_dp)
    call add_term(proj,  6,  7, -1.060660171779821e+00_dp)
    call add_term(proj,  7,  4, -6.708203932499368e-01_dp)
    call add_term(proj,  7,  6, -8.660254037844386e-01_dp)
    call add_term(proj,  8,  5, 1.095445115010332e+00_dp)
    call add_term(proj,  9,  3, 1.095445115010332e+00_dp)
    call add_term(proj, 10,  2, 1.000000000000000e+00_dp)
  end subroutine load_l3

  subroutine load_l4(proj)
    type(int2_shell_projection_t), intent(inout) :: proj
    call add_term(proj,  1,  5, 3.750000000000000e-01_dp)
    call add_term(proj,  1,  7, -5.590169943749475e-01_dp)
    call add_term(proj,  1,  9, 7.395099728874520e-01_dp)
    call add_term(proj,  2,  5, 3.750000000000000e-01_dp)
    call add_term(proj,  2,  7, 5.590169943749475e-01_dp)
    call add_term(proj,  2,  9, 7.395099728874520e-01_dp)
    call add_term(proj,  3,  5, 1.000000000000000e+00_dp)
    call add_term(proj,  4,  1, 1.118033988749895e+00_dp)
    call add_term(proj,  4,  3, -4.225771273642583e-01_dp)
    call add_term(proj,  5,  6, -8.964214570007953e-01_dp)
    call add_term(proj,  5,  8, 7.905694150420950e-01_dp)
    call add_term(proj,  6,  1, -1.118033988749895e+00_dp)
    call add_term(proj,  6,  3, -4.225771273642583e-01_dp)
    call add_term(proj,  7,  2, -7.905694150420950e-01_dp)
    call add_term(proj,  7,  4, -8.964214570007953e-01_dp)
    call add_term(proj,  8,  6, 1.195228609334394e+00_dp)
    call add_term(proj,  9,  4, 1.195228609334394e+00_dp)
    call add_term(proj, 10,  5, 2.195775164134200e-01_dp)
    call add_term(proj, 10,  9, -1.299038105676658e+00_dp)
    call add_term(proj, 11,  5, -8.783100656536799e-01_dp)
    call add_term(proj, 11,  7, 9.819805060619657e-01_dp)
    call add_term(proj, 12,  5, -8.783100656536799e-01_dp)
    call add_term(proj, 12,  7, -9.819805060619657e-01_dp)
    call add_term(proj, 13,  2, 1.060660171779821e+00_dp)
    call add_term(proj, 13,  4, -4.008918628686365e-01_dp)
    call add_term(proj, 14,  6, -4.008918628686365e-01_dp)
    call add_term(proj, 14,  8, -1.060660171779821e+00_dp)
    call add_term(proj, 15,  3, 1.133893419027681e+00_dp)
  end subroutine load_l4

  subroutine load_l5(proj)
    type(int2_shell_projection_t), intent(inout) :: proj
    call add_term(proj,  1,  7, 4.841229182759271e-01_dp)
    call add_term(proj,  1,  9, -5.229125165837973e-01_dp)
    call add_term(proj,  1, 11, 7.015607600201139e-01_dp)
    call add_term(proj,  2,  1, 7.015607600201139e-01_dp)
    call add_term(proj,  2,  3, 5.229125165837973e-01_dp)
    call add_term(proj,  2,  5, 4.841229182759271e-01_dp)
    call add_term(proj,  3,  6, 1.000000000000000e+00_dp)
    call add_term(proj,  4,  1, 1.169267933366856e+00_dp)
    call add_term(proj,  4,  3, -5.229125165837972e-01_dp)
    call add_term(proj,  4,  5, 1.613743060919757e-01_dp)
    call add_term(proj,  5,  6, 6.250000000000001e-01_dp)
    call add_term(proj,  5,  8, -8.539125638299664e-01_dp)
    call add_term(proj,  5, 10, 7.395099728874519e-01_dp)
    call add_term(proj,  6,  7, 1.613743060919757e-01_dp)
    call add_term(proj,  6,  9, 5.229125165837972e-01_dp)
    call add_term(proj,  6, 11, 1.169267933366856e+00_dp)
    call add_term(proj,  7,  6, 6.250000000000001e-01_dp)
    call add_term(proj,  7,  8, 8.539125638299664e-01_dp)
    call add_term(proj,  7, 10, 7.395099728874519e-01_dp)
    call add_term(proj,  8,  7, 1.290994448735805e+00_dp)
    call add_term(proj,  9,  5, 1.290994448735805e+00_dp)
    call add_term(proj, 10,  7, 2.112885636821291e-01_dp)
    call add_term(proj, 10,  9, 2.282177322938192e-01_dp)
    call add_term(proj, 10, 11, -1.530931089239486e+00_dp)
    call add_term(proj, 11,  7, -1.267731382092775e+00_dp)
    call add_term(proj, 11,  9, 9.128709291752769e-01_dp)
    call add_term(proj, 12,  1, -1.530931089239486e+00_dp)
    call add_term(proj, 12,  3, -2.282177322938192e-01_dp)
    call add_term(proj, 12,  5, 2.112885636821291e-01_dp)
    call add_term(proj, 13,  3, -9.128709291752769e-01_dp)
    call add_term(proj, 13,  5, -1.267731382092775e+00_dp)
    call add_term(proj, 14,  6, -1.091089451179962e+00_dp)
    call add_term(proj, 14,  8, 1.118033988749895e+00_dp)
    call add_term(proj, 15,  6, -1.091089451179962e+00_dp)
    call add_term(proj, 15,  8, -1.118033988749895e+00_dp)
    call add_term(proj, 16,  2, 1.118033988749895e+00_dp)
    call add_term(proj, 16,  4, -6.454972243679028e-01_dp)
    call add_term(proj, 17,  2, -1.118033988749895e+00_dp)
    call add_term(proj, 17,  4, -6.454972243679028e-01_dp)
    call add_term(proj, 18,  4, 1.290994448735806e+00_dp)
    call add_term(proj, 19,  6, 3.659625273557000e-01_dp)
    call add_term(proj, 19, 10, -1.299038105676658e+00_dp)
    call add_term(proj, 20,  3, 1.224744871391589e+00_dp)
    call add_term(proj, 20,  5, -5.669467095138407e-01_dp)
    call add_term(proj, 21,  7, -5.669467095138407e-01_dp)
    call add_term(proj, 21,  9, -1.224744871391589e+00_dp)
  end subroutine load_l5

  subroutine load_l6(proj)
    type(int2_shell_projection_t), intent(inout) :: proj
    call add_term(proj,  1,  7, -3.125000000000001e-01_dp)
    call add_term(proj,  1,  9, 4.528555233184201e-01_dp)
    call add_term(proj,  1, 11, -4.960783708246108e-01_dp)
    call add_term(proj,  1, 13, 6.716932893813962e-01_dp)
    call add_term(proj,  2,  7, -3.125000000000001e-01_dp)
    call add_term(proj,  2,  9, -4.528555233184201e-01_dp)
    call add_term(proj,  2, 11, -4.960783708246108e-01_dp)
    call add_term(proj,  2, 13, -6.716932893813962e-01_dp)
    call add_term(proj,  3,  7, 1.000000000000000e+00_dp)
    call add_term(proj,  4,  1, 1.215138880951473e+00_dp)
    call add_term(proj,  4,  3, -5.982930264130993e-01_dp)
    call add_term(proj,  4,  5, 2.730821554704072e-01_dp)
    call add_term(proj,  5,  8, 8.635615996346967e-01_dp)
    call add_term(proj,  5, 10, -8.192464664112216e-01_dp)
    call add_term(proj,  5, 12, 7.015607600201141e-01_dp)
    call add_term(proj,  6,  1, 1.215138880951473e+00_dp)
    call add_term(proj,  6,  3, 5.982930264130993e-01_dp)
    call add_term(proj,  6,  5, 2.730821554704072e-01_dp)
    call add_term(proj,  7,  2, 7.015607600201141e-01_dp)
    call add_term(proj,  7,  4, 8.192464664112216e-01_dp)
    call add_term(proj,  7,  6, 8.635615996346967e-01_dp)
    call add_term(proj,  8,  8, 1.381698559415515e+00_dp)
    call add_term(proj,  9,  6, 1.381698559415515e+00_dp)
    call add_term(proj, 10,  7, -1.631978024584668e-01_dp)
    call add_term(proj, 10,  9, 7.883202798586143e-02_dp)
    call add_term(proj, 10, 11, 4.317807998173486e-01_dp)
    call add_term(proj, 10, 13, -1.753901900050285e+00_dp)
    call add_term(proj, 11,  7, 9.791868147508008e-01_dp)
    call add_term(proj, 11,  9, -1.261312447773783e+00_dp)
    call add_term(proj, 11, 11, 8.635615996346971e-01_dp)
    call add_term(proj, 12,  7, -1.631978024584668e-01_dp)
    call add_term(proj, 12,  9, -7.883202798586143e-02_dp)
    call add_term(proj, 12, 11, 4.317807998173486e-01_dp)
    call add_term(proj, 12, 13, 1.753901900050285e+00_dp)
    call add_term(proj, 13,  7, 9.791868147508008e-01_dp)
    call add_term(proj, 13,  9, 1.261312447773783e+00_dp)
    call add_term(proj, 13, 11, 8.635615996346971e-01_dp)
    call add_term(proj, 14,  7, -1.305582419667734e+00_dp)
    call add_term(proj, 14,  9, 1.261312447773783e+00_dp)
    call add_term(proj, 15,  7, -1.305582419667734e+00_dp)
    call add_term(proj, 15,  9, -1.261312447773783e+00_dp)
    call add_term(proj, 16,  2, 1.169267933366857e+00_dp)
    call add_term(proj, 16,  4, -8.192464664112215e-01_dp)
    call add_term(proj, 16,  6, 2.878538665448989e-01_dp)
    call add_term(proj, 17,  8, 2.878538665448989e-01_dp)
    call add_term(proj, 17, 10, 8.192464664112215e-01_dp)
    call add_term(proj, 17, 12, 1.169267933366857e+00_dp)
    call add_term(proj, 18,  5, 1.456438162508838e+00_dp)
    call add_term(proj, 19,  1, -1.976423537605236e+00_dp)
    call add_term(proj, 19,  5, 2.665008954445131e-01_dp)
    call add_term(proj, 20,  8, -1.685499656158105e+00_dp)
    call add_term(proj, 20, 10, 1.066003581778052e+00_dp)
    call add_term(proj, 21,  4, -1.066003581778052e+00_dp)
    call add_term(proj, 21,  6, -1.685499656158105e+00_dp)
    call add_term(proj, 22,  8, 3.768891807222045e-01_dp)
    call add_term(proj, 22, 10, 3.575484709670971e-01_dp)
    call add_term(proj, 22, 12, -1.530931089239487e+00_dp)
    call add_term(proj, 23,  3, 1.305582419667734e+00_dp)
    call add_term(proj, 23,  5, -9.534625892455924e-01_dp)
    call add_term(proj, 24,  2, -1.530931089239487e+00_dp)
    call add_term(proj, 24,  4, -3.575484709670971e-01_dp)
    call add_term(proj, 24,  6, 3.768891807222045e-01_dp)
    call add_term(proj, 25,  3, -1.305582419667734e+00_dp)
    call add_term(proj, 25,  5, -9.534625892455924e-01_dp)
    call add_term(proj, 26,  4, 1.430193883868389e+00_dp)
    call add_term(proj, 26,  6, -7.537783614444090e-01_dp)
    call add_term(proj, 27,  8, -7.537783614444090e-01_dp)
    call add_term(proj, 27, 10, -1.430193883868389e+00_dp)
    call add_term(proj, 28,  7, 5.733530903673290e-01_dp)
    call add_term(proj, 28, 11, -1.516949690542295e+00_dp)
  end subroutine load_l6

end module int2_pure_generated
