package gdsc.smlm.function;
import org.apache.commons.math3.util.FastMath;
/**
* Class for computing various Bessel functions
* <p>
* The implementation is based upon that presented in: Numerical Recipes in C++, The Art of Scientific Computing, Second
* Edition, W.H. Press, S.A. Teukolsky, W.T. Vetterling, B.P. Flannery (Cambridge University Press, Cambridge, 2002).
*/
public class Bessel
{
/**
* Compute the zero th order Bessel function of the first kind.
*
* @param x
*
* @return the Bessel function J0
*/
public static double J0(final double x)
{
double ax;
if ((ax = Math.abs(x)) < 8.0)
{
final double y = x * x;
final double ans1 = 57568490574.0 + y *
(-13362590354.0 + y * (651619640.7 + y * (-11214424.18 + y * (77392.33017 + y * (-184.9052456)))));
final double ans2 = 57568490411.0 + y *
(1029532985.0 + y * (9494680.718 + y * (59272.64853 + y * (267.8532712 + y * 1.0))));
return ans1 / ans2;
}
final double z = 8.0 / ax;
final double y = z * z;
final double xx = ax - 0.785398164;
final double ans1 = 1.0 + y *
(-0.1098628627e-2 + y * (0.2734510407e-4 + y * (-0.2073370639e-5 + y * 0.2093887211e-6)));
final double ans2 = -0.1562499995e-1 + y *
(0.1430488765e-3 + y * (-0.6911147651e-5 + y * (0.7621095161e-6 - y * 0.934935152e-7)));
return Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2);
}
/**
* Compute the first order Bessel function of the first kind.
*
* @param x
*
* @return the Bessel function J1
*/
public static double J1(final double x)
{
double ax;
if ((ax = Math.abs(x)) < 8.0)
{
final double y = x * x;
final double ans1 = x *
(72362614232.0 + y *
(-7895059235.0 + y *
(242396853.1 + y * (-2972611.439 + y * (15704.48260 + y * (-30.16036606))))));
final double ans2 = 144725228442.0 + y *
(2300535178.0 + y * (18583304.74 + y * (99447.43394 + y * (376.9991397 + y * 1.0))));
return ans1 / ans2;
}
final double z = 8.0 / ax;
final double xx = ax - 2.356194491;
final double y = z * z;
final double ans1 = 1.0 + y *
(0.183105e-2 + y * (-0.3516396496e-4 + y * (0.2457520174e-5 + y * (-0.240337019e-6))));
final double ans2 = 0.04687499995 + y *
(-0.2002690873e-3 + y * (0.8449199096e-5 + y * (-0.88228987e-6 + y * 0.105787412e-6)));
final double ans = Math.sqrt(0.636619772 / ax) * (Math.cos(xx) * ans1 - z * Math.sin(xx) * ans2);
return (x < 0.0) ? -ans : ans;
}
/**
* Compute the second order Bessel function of the first kind.
*
* @param x
*
* @return the Bessel function J2
*/
public static double J2(double x)
{
if (x == 0.0)
{
return 0.0;
}
double value0 = J0(x);
double value1 = J1(x);
return 2.0 * value1 / x + value0;
}
/**
* Compute the modified Bessel function of the first kind.
*
* @param x
*
* @return the modified Bessel function I1
*/
public static double I1(final double x)
{
double ax, ans, y;
if ((ax = Math.abs(x)) < 3.75)
{
y = x / 3.75;
y *= y;
ans = ax *
(0.5 + y *
(0.87890594 + y *
(0.51498869 + y *
(0.15084934 + y * (0.2658733e-1 + y * (0.301532e-2 + y * 0.32411e-3))))));
}
else
{
y = 3.75 / ax;
ans = 0.2282967e-1 + y * (-0.2895312e-1 + y * (0.1787654e-1 - y * 0.420059e-2));
ans = 0.39894228 + y *
(-0.3988024e-1 + y * (-0.362018e-2 + y * (0.163801e-2 + y * (-0.1031555e-1 + y * ans))));
ans *= (FastMath.exp(ax) / Math.sqrt(ax));
}
return x < 0.0 ? -ans : ans;
}
}