1 // GetDP - Copyright (C) 1997-2021 P. Dular and C. Geuzaine, University of Liege
2 //
3 // See the LICENSE.txt file for license information. Please report all
4 // issues on https://gitlab.onelab.info/getdp/getdp/issues.
5 
6 #include "GetDPConfig.h"
7 #include "Message.h"
8 #include "Bessel.h"
9 
10 #if defined(HAVE_NO_FORTRAN)
11 
zbesj_(double *,double *,double *,int *,int *,double *,double *,int *,int *)12 static void zbesj_(double*, double*, double*, int*, int*, double*,
13                    double*, int*, int*)
14 {
15   Message::Fatal("Bessel functions require Fortran compiler");
16 }
17 
zbesk_(double *,double *,double *,int *,int *,double *,double *,int *,int *)18 static void zbesk_(double*, double*, double*, int*, int*, double*,
19                    double*, int*, int*)
20 {
21   Message::Fatal("Bessel functions require Fortran compiler");
22 }
23 
zbesy_(double *,double *,double *,int *,int *,double *,double *,int *,double *,double *,int *)24 static void zbesy_(double*, double*, double*, int*, int*, double*,
25                    double*, int*, double*, double*, int*)
26 {
27   Message::Fatal("Bessel functions require Fortran compiler");
28 }
29 
zbesh_(double *,double *,double *,int *,int *,int *,double *,double *,int *,int *)30 static void zbesh_(double*, double*, double*, int*, int*, int*,
31                    double*, double*, int*, int*)
32 {
33   Message::Fatal("Bessel functions require Fortran compiler");
34 }
35 
36 #else
37 
38 #if defined(HAVE_UNDERSCORE)
39 #define zbesj_ zbesj
40 define zbesk_ zbesk
41 #define zbesy_ zbesy
42 #define zbesh_ zbesh
43 #endif
44 
45 extern "C" {
46   void zbesj_(double*, double*, double*, int*, int*, double*,
47               double*, int*, int*);
48   void zbesk_(double*, double*, double*, int*, int*, double*,
49               double*, int*, int*);
50 
51   void zbesy_(double*, double*, double*, int*, int*, double*,
52               double*, int*, double*,
53               double*, int*);
54   void zbesh_(double*, double*, double*, int*, int*, int*, double*,
55               double*, int*, int*);
56 }
57 
58 #endif
59 
60 static int BesselError(int ierr, const char *str)
61 {
62   static int warn=0;
63 
64   switch(ierr){
65   case 0 :
66     return 0;
67   case 1 :
68     Message::Error("Input error in %s", str);
69     return BESSEL_ERROR_INPUT;
70   case 2 :
71     return BESSEL_OVERFLOW;
72   case 3 :
73     if(!warn){
74       Message::Info("Half machine accuracy lost in %s (large argument or order)", str);
75       warn = 1;
76     }
77     return BESSEL_HALF_ACCURACY;
78   case 4 :
79     Message::Error("Complete loss of significance in %s (argument or order too large)", str);
80     return BESSEL_NO_ACCURACY;
81   case 5 :
82     Message::Error("Failed to converge in %s", str);
83     return BESSEL_NO_CONVERGENCE;
84   default:
85     Message::Info("Unknown Bessel status in %s (%d)", str, ierr);
86     return ierr;
87   }
88 }
89 
90 // First kind Bessel functions
91 
BesselJn(double n,int num,double x,double * val)92 int BesselJn(double n, int num, double x, double *val)
93 {
94   int nz = 0, ierr = 0, kode = 1;
95   double xi = 0.0;
96   double* ji = new double[num];
97 
98   zbesj_(&x, &xi, &n, &kode, &num, val, ji, &nz, &ierr) ;
99 
100   delete[] ji;
101 
102   return BesselError(ierr, "BesselJn");
103 }
104 
BesselJnComplex(double n,int num,double xr,double xi,double * valr,double * vali)105 int BesselJnComplex(double n, int num, double xr, double xi, double *valr, double *vali)
106 {
107   int nz = 0, ierr = 0, kode = 1;
108 
109   zbesj_(&xr, &xi, &n, &kode, &num, valr, vali, &nz, &ierr) ;
110 
111   return BesselError(ierr, "BesselJnComplex");
112 }
113 
BesselKnComplex(double n,int num,double xr,double xi,double * valr,double * vali)114 int BesselKnComplex(double n, int num, double xr, double xi, double *valr, double *vali)
115 {
116   int nz = 0, ierr = 0, kode = 1;
117 
118   zbesk_(&xr, &xi, &n, &kode, &num, valr, vali, &nz, &ierr) ;
119 
120   return BesselError(ierr, "BesselKnComplex");
121 }
122 
BesselSphericalJn(double n,int num,double x,double * val)123 int BesselSphericalJn(double n, int num, double x, double *val)
124 {
125   int ierr = BesselJn(n+0.5, num, x, val);
126   double coef = sqrt(0.5*M_PI/x);
127   for(int i = 0; i < num; i++){
128     val[i] *= coef;
129   }
130   return BesselError(ierr, "BesselSphericalJn");
131 }
132 
BesselAltSphericalJn(double n,int num,double x,double * val)133 int BesselAltSphericalJn(double n, int num, double x, double *val)
134 {
135   int ierr = BesselJn(n+0.5, num, x, val);
136   double coef = sqrt(0.5*M_PI*x);
137   for(int i = 0; i < num; i++){
138     val[i] *= coef;
139   }
140   return BesselError(ierr, "BesselAltSphericalJn");
141 }
142 
143 // Second kind Bessel functions
144 
BesselYn(double n,int num,double x,double * val)145 int BesselYn(double n, int num, double x, double *val)
146 {
147   int nz = 0, ierr = 0, kode = 1;
148   double xi = 0.0;
149   double* yi = new double[num];
150   double* auxyr = new double[num];
151   double* auxyi = new double[num];
152 
153   zbesy_(&x, &xi, &n, &kode, &num, val, yi, &nz, auxyr, auxyi, &ierr);
154 
155   delete[] yi;
156   delete[] auxyr;
157   delete[] auxyi;
158 
159   return BesselError(ierr, "BesselYn");
160 }
161 
BesselSphericalYn(double n,int num,double x,double * val)162 int BesselSphericalYn(double n, int num, double x, double *val)
163 {
164   int ierr = BesselYn(n+0.5, num, x, val);
165   double coef = sqrt(0.5*M_PI/x);
166   for(int i = 0; i < num; i++){
167     val[i] *= coef;
168   }
169   return BesselError(ierr, "BesselSphericalYn");
170 }
171 
BesselAltSphericalYn(double n,int num,double x,double * val)172 int BesselAltSphericalYn(double n, int num, double x, double *val)
173 {
174   int ierr = BesselYn(n+0.5, num, x, val);
175   double coef = sqrt(0.5*M_PI*x);
176   for(int i = 0; i < num; i++){
177     val[i] *= coef;
178   }
179   return BesselError(ierr, "BesselAltSphericalYn");
180 }
181 
182 // Hankel functions (type = 1 or 2)
183 
BesselHn(int type,double n,int num,double x,std::complex<double> * val)184 int BesselHn(int type, double n, int num, double x, std::complex<double> *val)
185 {
186   int nz = 0, ierr = 0, kode = 1;
187   double* hr = new double[num];
188   double* hi = new double[num];
189   double xi = 0.0;
190 
191   zbesh_(&x, &xi, &n, &kode, &type, &num, hr, hi, &nz, &ierr);
192 
193   for(int i=0; i < num; i++){
194     val[i] = std::complex<double>(hr[i], hi[i]);
195   }
196 
197   delete[] hr;
198   delete[] hi;
199 
200   return BesselError(ierr, "BesselHn");
201 }
202 
BesselSphericalHn(int type,double n,int num,double x,std::complex<double> * val)203 int BesselSphericalHn(int type, double n, int num, double x, std::complex<double> *val)
204 {
205   int ierr = BesselHn(type, n+0.5, num, x, val);
206   double coef = sqrt(0.5*M_PI/x);
207   for(int i = 0; i < num; i++){
208     val[i] *= coef;
209   }
210   return BesselError(ierr, "BesselSphericalHn");
211 }
212 
BesselAltSphericalHn(int type,double n,int num,double x,std::complex<double> * val)213 int BesselAltSphericalHn(int type, double n, int num, double x, std::complex<double> *val)
214 {
215   int ierr = BesselHn(type, n+0.5, num, x, val);
216   double coef = sqrt(0.5*M_PI*x);
217   for(int i = 0; i < num; i++){
218     val[i] *= coef;
219   }
220   return BesselError(ierr, "BesselAltSphericalHn");
221 }
222 
223 // Utilities for backward compatibility
224 
Spherical_j_n(int n,double x)225 double Spherical_j_n(int n, double x)
226 {
227   double res;
228   BesselSphericalJn(n, 1, x, &res);
229   return res;
230 }
231 
AltSpherical_j_n(int n,double x)232 double AltSpherical_j_n(int n, double x)
233 {
234   double res;
235   BesselAltSphericalJn(n, 1, x, &res);
236   return res;
237 }
238 
Spherical_y_n(int n,double x)239 double Spherical_y_n(int n, double x)
240 {
241   double res;
242   BesselSphericalYn(n, 1, x, &res);
243   return res;
244 }
245 
AltSpherical_y_n(int n,double x)246 double AltSpherical_y_n(int n, double x)
247 {
248   double res;
249   BesselAltSphericalYn(n, 1, x, &res);
250   return res;
251 }
252