MODULE  nrm2_Other
! Module implementing the BLAS-1 nrm2 routines by using the
! new Fortran intrinsic function norm2
  USE set_precision, ONLY : dkind, skind
! CHARACTER (LEN=10), PARAMETER :: cmplxMeth = 'TRANSFER'
  CHARACTER (LEN=10), PARAMETER :: cmplxMeth = 'REAL/AIMAG'
  CHARACTER (LEN=*), PARAMETER :: descript = &
        'the norm2 intrinsic function available from '//&
        'Fortran 2008 -- using ' // cmplxMeth
CONTAINS
  FUNCTION snrm2(n, x, incx) RESULT(res)
  INTEGER, INTENT(IN) :: n, incx
  REAL(skind), INTENT(IN) :: x(1:1+(n-1)*incx)
  REAL(skind) :: res
  REAL(skind), PARAMETER :: zero = 0.0E0_skind
    IF (n<1 .OR. incx<1) THEN
      res = zero
    ELSE
      res = norm2(x(1:1+(n-1)*incx:incx))
    END IF
  END FUNCTION snrm2

  FUNCTION dnrm2(n, x, incx) RESULT(res)
  INTEGER, INTENT(IN) :: n, incx
  REAL(dkind), INTENT(IN) :: x(1:1+(n-1)*incx)
  REAL(dkind) :: res
  REAL(dkind), PARAMETER :: zero = 0.0E0_dkind
    IF (n<1 .OR. incx<1) THEN
      res = zero
    ELSE
      res = norm2(x(1:1+(n-1)*incx:incx))
    END IF
  END FUNCTION dnrm2

! The norm2 intrinsic function is only defined for real
! arguments. There are a number of ways that we may build
! a real array from a complex one.
! Assume that c is a complex vector of length n then we 
! may form a real array of length 2*n using
!
! 1.   r(1:2*n) = [REAL(c(1:n)), AIMAG(c(1:n))]
!    This forms a real vector with the first n elements
!    being the real parts of c(1)...c(n) and the elements
!    (n+1)...(2*n) being the complex parts.
!
! 2.   r(1:2*n) = TRANSFER(c(1:n), r, size=2*n)
!    This uses the Fortran intrinsic function to transfer
!    the n complex values C(1:n) into a real array of length
!    2*n. The second argument defines the type into which
!    the values in the array c are to be transferred to 
!    without any conversion.

  FUNCTION scnrm2(n, x, incx) RESULT(res)
  INTEGER, INTENT(IN) :: n, incx
  COMPLEX(skind), INTENT(IN) :: x(1:1+(n-1)*incx)
  REAL(skind) :: res
  REAL(skind), PARAMETER :: zero = 0.0E0_skind
    IF (n<1 .OR. incx<1) THEN
      res = zero
    ELSE
! If you change this method change the value assigned to
! cmplxMeth module parameter at line 5
      res = NORM2([REAL(x(1:1+(n-1)*incx:incx)), &
                   AIMAG(x(1:1+(n-1)*incx:incx))])
!     res = NORM2(TRANSFER(x(1:1+(n-1)*incx:incx),res,SIZE=2*n))
    END IF
  END FUNCTION scnrm2

  FUNCTION dznrm2(n, x, incx) RESULT(res)
  INTEGER, INTENT(IN) :: n, incx
  COMPLEX(dkind), INTENT(IN) :: x(1:1+(n-1)*incx)
  REAL(dkind) :: res
  REAL(dkind), PARAMETER :: zero = 0.0E0_dkind
    IF (n<1 .OR. incx<1) THEN
      res = zero
    ELSE
! If you change this method change the value assigned to
! cmplxMeth module parameter at line 5
      res = NORM2([REAL(x(1:1+(n-1)*incx:incx)), &
                   AIMAG(x(1:1+(n-1)*incx:incx))])
!     res = NORM2(TRANSFER(x(1:1+(n-1)*incx:incx),res,SIZE=2*n))
    END IF
  END FUNCTION dznrm2

END MODULE nrm2_Other
