packages feed

BesselJ-0.2.0.0: src/Math/AngerJ.hs

module Math.AngerJ
  ( AngerResult(..), angerJ )
  where
import Data.Complex          ( imagPart, realPart, Complex(..) )
import Numerical.Integration ( integration, IntegralResult(..) )
import Foreign.C             ( CDouble )


-- | Data type to store the result of a computation of the Anger J-function.
-- The fields are @_result@ for the value, @_errors@ for the error estimates 
-- of the integrals used for the computation, and @_codes@ for the convergence 
-- codes of these integrals (0 for success).
data AngerResult = AngerResult {
    _result :: Complex Double
  , _errors :: (Double, Double)
  , _codes  :: (Int, Int)
} deriving Show


cpxdbl2cpxcdbl :: Complex Double -> Complex CDouble
cpxdbl2cpxcdbl z = realToFrac (realPart z) :+ realToFrac (imagPart z)


-- | Anger-J function. It is computed with two integrals. The field @_errors@ 
-- in the result provides the error estimates of the integrals. The field 
-- @_codes@ provides the codes indicating success (0) or failure of each integral.
angerJ :: Complex Double  -- ^ order, complex number 
       -> Complex Double  -- ^ the variable, a complex number
       -> Double          -- ^ target relative accuracy for the integrals, e.g. 1e-5
       -> Int             -- ^ number of subdivisions for the integrals, e.g. 5000
       -> IO AngerResult  -- ^ result
angerJ nu z err subdiv = do
  let z' = cpxdbl2cpxcdbl z
      x' = realPart z'
      y' = imagPart z'
      nu' = cpxdbl2cpxcdbl nu
      a' = realPart nu'
      b' = imagPart nu'
      reintegrand t = cosh(b' * t - y' * sin t) * cos(a' * t - x' * sin t)
      imintegrand t = -sinh(b' * t - y' * sin t) * sin(a' * t - x' * sin t)
  re <- integration reintegrand 0 pi 0.0 err subdiv
  im <- integration imintegrand 0 pi 0.0 err subdiv
  return AngerResult {
      _result = (_value re :+ _value im) / pi
    , _errors = (_error re, _error im)
    , _codes  = (_code re, _code im)
  }