ARTEMIS
BesselRoots.H
Go to the documentation of this file.
1 /* Copyright 2019 David Grote
2  *
3  * This file is part of WarpX.
4  *
5  * License: BSD-3-Clause-LBNL
6  */
7 /* -------------------------------------------------------------------------
8 ! program to calculate the first zeroes (root abscissas) of the first
9 ! kind bessel function of integer order n using the subroutine rootj.
10 ! --------------------------------------------------------------------------
11 ! sample run:
12 !
13 ! (calculate the first 10 zeroes of 1st kind bessel function of order 2).
14 !
15 ! zeroes of bessel function of order: 2
16 !
17 ! number of calculated zeroes: 10
18 !
19 ! table of root abcissas (5 items per line)
20 ! 5.135622 8.417244 11.619841 14.795952 17.959819
21  21.116997 24.270112 27.420574 30.569204 33.716520
22 !
23 ! table of error codes (5 items per line)
24 ! 0 0 0 0 0
25 ! 0 0 0 0 0
26 !
27 ! --------------------------------------------------------------------------
28 ! reference: from numath library by tuan dang trong in fortran 77
29 ! [bibli 18].
30 !
31 ! c++ release 1.0 by j-p moreau, paris
32 ! (www.jpmoreau.fr)
33 ! ------------------------------------------------------------------------ */
34 
35 #include "Utils/WarpXConst.H"
36 
37 #include <AMReX_REAL.H>
38 
39 #include <cmath>
40 
41 
42 void SecantRootFinder(int n, int nitmx, amrex::Real tol, amrex::Real *zeroj, int *ier);
43 
44 /*----------------------------------------------------------------------
45  * calculate the first nk zeroes of bessel function j(n, x)
46  * including the trivial root (when n > 0)
47  *
48  * inputs:
49  * n order of function j (integer >= 0) i*4
50  * nk number of first zeroes (integer > 0) i*4
51  * outputs:
52  * roots(nk) table of first zeroes (abcissas) r*8
53  * ier(nk) table of error codes (must be zeroes) i*4
54  *
55  * reference :
56  * abramowitz m. & stegun irene a.
57  * handbook of mathematical functions
58  */
60  using namespace amrex::literals;
61 
62  amrex::Real zeroj;
63  int ierror, ik, k;
64 
65  const amrex::Real tol = 1e-14_rt;
66  const amrex::Real nitmx = 10;
67 
68  const amrex::Real c1 = 1.8557571_rt;
69  const amrex::Real c2 = 1.033150_rt;
70  const amrex::Real c3 = 0.00397_rt;
71  const amrex::Real c4 = 0.0908_rt;
72  const amrex::Real c5 = 0.043_rt;
73 
74  const amrex::Real t0 = 4.0_rt*n*n;
75  const amrex::Real t1 = t0 - 1.0_rt;
76  const amrex::Real t3 = 4.0_rt*t1*(7.0_rt*t0 - 31.0_rt);
77  const amrex::Real t5 = 32.0_rt*t1*((83.0_rt*t0 - 982.0_rt)*t0 + 3779.0_rt);
78  const amrex::Real t7 = 64.0_rt*t1*(((6949.0_rt*t0 - 153855.0_rt)*t0 + 1585743.0_rt)*t0 - 6277237.0_rt);
79 
80  roots.resize(nk);
81  ier.resize(nk);
82 
83  // first zero
84  if (n == 0) {
85  zeroj = c1 + c2 - c3 - c4 + c5;
86  SecantRootFinder(n, nitmx, tol, &zeroj, &ierror);
87  ier[0] = ierror;
88  roots[0] = zeroj;
89  ik = 1;
90  }
91  else {
92  // Include the trivial root
93  ier[0] = 0;
94  roots[0] = 0.;
95  const amrex::Real f1 = std::pow(n, (1.0_rt/3.0_rt));
96  const amrex::Real f2 = f1*f1*n;
97  const amrex::Real f3 = f1*n*n;
98  zeroj = n + c1*f1 + (c2/f1) - (c3/n) - (c4/f2) + (c5/f3);
99  SecantRootFinder(n, nitmx, tol, &zeroj, &ierror);
100  ier[1] = ierror;
101  roots[1] = zeroj;
102  ik = 2;
103  }
104 
105  // other zeroes
106  // k counts the nontrivial roots
107  // ik counts all roots
108  k = 2;
109  while (ik < nk) {
110 
111  // mac mahon's series for k >> n
112  const amrex::Real b0 = (k + 0.5_rt*n - 0.25_rt)*MathConst::pi;
113  const amrex::Real b1 = 8.0_rt*b0;
114  const amrex::Real b2 = b1*b1;
115  const amrex::Real b3 = 3.0_rt*b1*b2;
116  const amrex::Real b5 = 5.0_rt*b3*b2;
117  const amrex::Real b7 = 7.0_rt*b5*b2;
118 
119  zeroj = b0 - (t1/b1) - (t3/b3) - (t5/b5) - (t7/b7);
120 
121  const amrex::Real errj = std::abs(jn(n, zeroj));
122 
123  // improve solution using procedure SecantRootFinder
124  if (errj > tol) SecantRootFinder(n, nitmx, tol, &zeroj, &ierror);
125 
126  roots[ik] = zeroj;
127  ier[ik] = ierror;
128 
129  k++;
130  ik++;
131  }
132 }
133 
134 void SecantRootFinder(int n, int nitmx, amrex::Real tol, amrex::Real *zeroj, int *ier) {
135  using namespace amrex::literals;
136 
137  amrex::Real p0, p1, q0, q1, dp, p;
138  amrex::Real c[2];
139 
140  c[0] = 0.95_rt;
141  c[1] = 0.999_rt;
142  *ier = 0;
143 
144  p = *zeroj;
145  for (int ntry=0 ; ntry <= 1 ; ntry++) {
146  p0 = c[ntry]*(*zeroj);
147 
148  p1 = *zeroj;
149  q0 = jn(n, p0);
150  q1 = jn(n, p1);
151  for (int it=1; it <= nitmx; it++) {
152  if (q1 == q0) break;
153  p = p1 - q1*(p1 - p0)/(q1 - q0);
154  dp = p - p1;
155  if (it > 1 && std::abs(dp) < tol) {
156  *zeroj = p;
157  return;
158  }
159  p0 = p1;
160  q0 = q1;
161  p1 = p;
162  q1 = jn(n, p1);
163  }
164  }
165  *ier = 3;
166  *zeroj = p;
167 }
void SecantRootFinder(int n, int nitmx, amrex::Real tol, amrex::Real *zeroj, int *ier)
Definition: BesselRoots.H:134
void GetBesselRoots(int n, int nk, amrex::Vector< amrex::Real > &roots, amrex::Vector< int > &ier)
Definition: BesselRoots.H:59
static constexpr auto c
vacuum speed of light [m/s]
Definition: constant.H:44
static constexpr amrex::Real pi
ratio of a circle's circumference to its diameter
Definition: constant.H:23
int n
Definition: run_libensemble_on_warpx.py:67
dp
Definition: stencil.py:23