module sparse

! <itype=4,4,4,8,8,8>
! <mtype=4,4,8,4,4,8>
! <vtype=4,8,8,4,8,8>

    type PointingElement_i4_m4
        integer*4 :: index
        real*4 :: value
    end type

    type PointingElement_i8_m4
        integer*8 :: index
        real*4 :: value
    end type

    type PointingElement_i4_m8
        integer*4 :: index
        real*8 :: value
    end type

    type PointingElement_i8_m8
        integer*8 :: index
        real*8 :: value
    end type

    type PointingElementRot3d_i4_m4
        integer*4 :: index
        real*4 :: r11, r22, r32
    end type

    type PointingElementRot3d_i8_m4
        integer*8 :: index
        real*4 :: r11, r22, r32
    end type

    type PointingElementRot3d_i4_m8
        integer*4 :: index
        real*8 :: r11, r22, r32
    end type

    type PointingElementRot3d_i8_m8
        integer*8 :: index
        real*8 :: r11, r22, r32
    end type


contains


    subroutine fsc_matvec_i4_m4_v4(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i4_m4), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*4, intent(in)    :: input(ninput)
        real*4, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_matvec_i4_m4_v8(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i4_m4), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(ninput)
        real*8, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_matvec_i4_m8_v8(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 8
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i4_m8), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(ninput)
        real*8, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_matvec_i8_m4_v4(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i8_m4), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*4, intent(in)    :: input(ninput)
        real*4, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_matvec_i8_m4_v8(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i8_m4), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(ninput)
        real*8, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_matvec_i8_m8_v8(matrix, input, output,    &
                                   nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 8
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElement_i8_m8), intent(in) ::                 &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(ninput)
        real*8, intent(inout) :: output(0:noutput-1)

        integer*8 :: i, j

        if (nrowmax == 1) then
            !$omp parallel do
            do i = 1, ninput
                if (matrix(1,i)%index < 0) continue
                !$omp atomic
                output(matrix(1,i)%index) = output(matrix(1,i)%index) +    &
                                            matrix(1,i)%value * input(i)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                !$omp atomic
                output(matrix(j,i)%index) = output(matrix(j,i)%index) +        &
                                            matrix(j,i)%value * input(i)
            end do
        end do
        !$omp end parallel do

    end subroutine




    subroutine fsr_matvec_i4_m4_v4(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i4_m4), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*4, intent(in)    :: input(0:ninput-1)
        real*4, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_matvec_i4_m4_v8(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i4_m4), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(0:ninput-1)
        real*8, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_matvec_i4_m8_v8(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 8
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i4_m8), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(0:ninput-1)
        real*8, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_matvec_i8_m4_v4(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i8_m4), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*4, intent(in)    :: input(0:ninput-1)
        real*4, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_matvec_i8_m4_v8(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i8_m4), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(0:ninput-1)
        real*8, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_matvec_i8_m8_v8(matrix, input, output,    &
                                   ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 8
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElement_i8_m8), intent(in) ::                 &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(0:ninput-1)
        real*8, intent(inout) :: output(noutput)

        integer*8 :: i, j

        if (ncolmax == 1) then
            !$omp parallel do
            do i = 1, noutput
                if (matrix(1,i)%index < 0) continue
                output(i) = output(i) +                                        &
                            matrix(1,i)%value * input(matrix(1,i)%index)
            end do
            !$omp end parallel do
            return
        end if

        !$omp parallel do
        do i = 1, noutput
!!$            output(i) = sum(input(matrix(:,i)%index) * matrix(:,i)%value)
            do j = 1, ncolmax
                if (matrix(j,i)%index < 0) exit
                output(i) = output(i) +                                        &
                            matrix(j,i)%value * input(matrix(j,i)%index)
            end do
        end do
        !$omp end parallel do

    end subroutine




    subroutine fsc_rot3d_matvec_i4_m4_v4(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i4_m4), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*4, intent(in)    :: input(3,ninput)
        real*4, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_rot3d_matvec_i4_m4_v8(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i4_m4), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(3,ninput)
        real*8, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_rot3d_matvec_i4_m8_v8(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 8
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i4_m8), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(3,ninput)
        real*8, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_rot3d_matvec_i8_m4_v4(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i8_m4), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*4, intent(in)    :: input(3,ninput)
        real*4, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_rot3d_matvec_i8_m4_v8(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 4
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i8_m4), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(3,ninput)
        real*8, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsc_rot3d_matvec_i8_m8_v8(matrix, input,      &
                                         output, nrowmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 8
        integer*8, intent(in)       :: nrowmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(nrowmax*ninput*s)
        type(PointingElementRot3d_i8_m8), intent(in) ::            &
            matrix(nrowmax, ninput)
        real*8, intent(in)    :: input(3,ninput)
        real*8, intent(inout) :: output(3,0:noutput-1)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, ninput
            do j = 1, nrowmax
                if (matrix(j,i)%index < 0) exit
                col = matrix(j,i)%index
                !$omp atomic
                output(1,col) = output(1,col) + matrix(j,i)%r11 * input(1,i)
                !$omp atomic
                output(2,col) = output(2,col) + (matrix(j,i)%r22 * input(2,i) +&
                                                 matrix(j,i)%r32 * input(3,i))
                !$omp atomic
                output(3,col) = output(3,col) + (-matrix(j,i)%r32 * input(2,i)+&
                                                  matrix(j,i)%r22 * input(3,i))
            end do
        end do
        !$omp end parallel do

    end subroutine




    subroutine fsr_rot3d_matvec_i4_m4_v4(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i4_m4), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*4, intent(in)    :: input(3,0:ninput-1)
        real*4, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_rot3d_matvec_i4_m4_v8(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i4_m4), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(3,0:ninput-1)
        real*8, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_rot3d_matvec_i4_m8_v8(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 4 + 3 * 8
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i4_m8), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(3,0:ninput-1)
        real*8, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*4 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_rot3d_matvec_i8_m4_v4(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i8_m4), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*4, intent(in)    :: input(3,0:ninput-1)
        real*4, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_rot3d_matvec_i8_m4_v8(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 4
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i8_m4), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(3,0:ninput-1)
        real*8, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine



    subroutine fsr_rot3d_matvec_i8_m8_v8(matrix, input,      &
                                         output, ncolmax, ninput, noutput)
        integer, parameter          :: s = 8 + 3 * 8
        integer*8, intent(in)       :: ncolmax
        integer*8, intent(in)       :: ninput
        integer*8, intent(in)       :: noutput
        !f2py integer*1, intent(in) :: matrix(ncolmax*noutput*s)
        type(PointingElementRot3d_i8_m8), intent(in) ::            &
            matrix(ncolmax, noutput)
        real*8, intent(in)    :: input(3,0:ninput-1)
        real*8, intent(inout) :: output(3,noutput)

        integer*8 :: i, j
        integer*8 :: col

        !$omp parallel do private(col)
        do i = 1, noutput
            do j = 1, ncolmax
                col = matrix(j,i)%index
                if (col < 0) exit
                output(1,i) = output(1,i) + matrix(j,i)%r11 * input(1,col)
                output(2,i) = output(2,i) + matrix(j,i)%r22 * input(2,col) -   &
                                            matrix(j,i)%r32 * input(3,col)
                output(3,i) = output(3,i) + matrix(j,i)%r32 * input(2,col) +   &
                                            matrix(j,i)%r22 * input(3,col)
            end do
        end do
        !$omp end parallel do

    end subroutine




end module sparse
