SAF
Loading...
Searching...
No Matches
saf_utility_bessel.c
Go to the documentation of this file.
1/*
2 * Copyright 2020 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
28#include "saf_utilities.h"
29
30/* ========================================================================== */
31/* Internal Functions */
32/* ========================================================================== */
33
40static double ENVJ
41(
42 int N,
43 double X
44)
45{
46 return (0.5*log(6.28*N)-N*log(1.36*X/N));
47}
48
55static int MSTA1
56(
57 double X,
58 int MP
59)
60{
61 double A0,F,F0,F1;
62 int IT,NN,N0,N1;
63
64 NN = 0;
65 A0=fabs(X);
66 N0=(int)(floor(1.1*A0)+1.0);
67 F0=ENVJ(N0,A0)-MP;
68 N1=N0+5;
69 F1=ENVJ(N1,A0)-MP;
70 for (IT=1; IT<=20; IT++) {
71 //NN=N1-(N1-N0)/(1.0-F0/F1);
72 NN = N1-(int)((double)(N1-N0) / (1.0-F0/F1));
73 F=ENVJ(NN,A0)-MP;
74 if (abs(NN-N1) < 1) goto e20;
75 N0=N1;
76 F0=F1;
77 N1=NN;
78 F1=F;
79 }
80e20: return NN;
81}
82
89static int MSTA2
90(
91 double X,
92 int N,
93 int MP
94)
95{
96 double A0,EJN,F,F0,F1,HMP,OBJ;
97 int IT,N0,N1,NN;
98
99 NN = 0;
100 A0=fabs(X);
101 HMP=0.5*MP;
102 EJN=ENVJ(N,A0);
103 if (EJN <= HMP) {
104 OBJ=MP;
105 N0=(int)floor(1.1*A0);
106 }
107 else {
108 OBJ=HMP+EJN;
109 N0=N;
110 }
111 F0=ENVJ(N0,A0)-OBJ;
112 N1=N0+5;
113 F1=ENVJ(N1,A0)-OBJ;
114 for (IT=1; IT<=20; IT++) {
115 //NN=N1-(N1-N0)/(1.0-F0/F1);
116 NN = N1-(int)((double)(N1-N0)/(1.0-F0/F1));
117 F=ENVJ(NN,A0)-OBJ;
118 if (abs(NN-N1) < 1) goto e20;
119 N0=N1;
120 F0=F1;
121 N1=NN;
122 F1=F;
123 }
124e20: return NN+10;
125}
126
138static void SPHI
139(
140 int N,
141 double X,
142 int *NM,
143 double *SI,
144 double *DI
145)
146{
147 int K, M, i;
148 double CS, F, F0, F1, SI0;
149
150 *NM=N;
151 if (fabs(X) < 1e-20) {
152 for (K=0; K<=N; K++) {
153 SI[K]=0.0;
154 DI[K]=0.0;
155 }
156 SI[0]=1.0;
157 DI[1]=0.333333333333333;
158 return;
159 }
160 SI[0]=sinh(X)/X;
161 SI[1]=-(sinh(X)/X-cosh(X))/X;
162 SI0=SI[0];
163 if (N >= 2) {
164 M=MSTA1(X,200);
165 if (M < N)
166 *NM=M;
167 else
168 M=MSTA2(X,N,15);
169 /* I had to add this while loop to avoid NaNs and sacrifice some precision, but only when needed */
170 i=0;
171 while (M < 0) {
172 M=MSTA2(X,N,14-i);
173 i++;
174 if(i==14)
175 M=0;
176 }
177 F0=0.0;
178 F1=1.0-100;
179 F=1;
180 for (K=M; K>-1; K--) {
181 F=(2.0*K+3.0)*F1/X+F0;
182 if (K <= *NM) SI[K]=F;
183 F0=F1;
184 F1=F;
185 }
186 CS=SI0/F;
187 for (K=0; K<=*NM; K++) SI[K] *= CS;
188 }
189 DI[0]=SI[1];
190 for (K=1; K<=*NM; K++)
191 DI[K]=SI[K-1]-(K+1.0)/X*SI[K];
192}
193
201static void SPHK
202(
203 int N,
204 double X,
205 int *NM,
206 double *SK,
207 double *DK
208)
209{
210 int K;
211 double F, F0, F1;
212
213 *NM=N;
214 if (X < 1e-20) {
215 for (K=0; K<=N; K++) {
216 SK[K]=1.0e+300;
217 DK[K]=-1.0e+300;
218 }
219 return;
220 }
221 SK[0]=0.5*SAF_PId/X*exp(-X);
222 SK[1]=SK[0]*(1.0+1.0/X);
223 F0=SK[0];
224 F1=SK[1];
225 for (K=2; K<=N; K++) {
226 F=(2.0*K-1.0)*F1/X+F0;
227 SK[K]=F;
228 if (fabs(F) > 1.0e+300) goto e20;
229 F0=F1;
230 F1=F;
231 }
232e20: *NM=K-1;
233 DK[0]=-SK[1];
234 for (K=1; K<=*NM; K++)
235 DK[K]=-SK[K-1]-(K+1.0)/X*SK[K];
236}
237
249static void SPHJ
250(
251 int N,
252 double X,
253 int *NM,
254 double *SJ,
255 double *DJ
256)
257{
258 int K, M, i;
259 double CS, F, F0, F1, SA, SB;
260
261 *NM=N;
262 if (fabs(X) < 1e-80) {
263 for (K=0; K<=N; K++) {
264 SJ[K]=0.0;
265 DJ[K]=0.0;
266 }
267 SJ[0]=1.0;
268 DJ[1]=0.333333333333333;
269 return;
270 }
271 SJ[0]=sin(X)/X;
272 SJ[1]=(SJ[0]-cos(X))/X;
273 if (N >= 2) {
274 SA=SJ[0];
275 SB=SJ[1];
276 M=MSTA1(X,200);
277 if (M < N)
278 *NM=M;
279 else
280 M=MSTA2(X,N,15);
281 /* I had to add this while loop to avoid NaNs and sacrifice some precision, but only when needed */
282 i=0;
283 while (M < 0) {
284 M=MSTA2(X,N,14-i);
285 i++;
286 if(i==14)
287 M=0;
288 }
289 F0=0.0;
290 F1=1.0-100;
291 F=1;
292 CS=1;
293 for (K=M; K>-1; K--) {
294 F=(2.0*K+3.0)*F1/X-F0;
295 if (K <= *NM) SJ[K]=F;
296 F0=F1;
297 F1=F;
298 }
299 if (fabs(SA) > fabs(SB)) CS=SA/F;
300 if (fabs(SA) <= fabs(SB)) CS=SB/F0;
301 for (K=0; K<=*NM; K++) SJ[K] *= CS;
302 }
303 DJ[0]=(cos(X)-sin(X)/X)/X;
304 for (K=1; K<=*NM; K++)
305 DJ[K]=SJ[K-1]-(K+1.0)*SJ[K]/X;
306}
307
314static void SPHY
315(
316 int N,
317 double X,
318 int *NM,
319 double *SY,
320 double *DY
321)
322{
323 int K;
324 double F, F0, F1;
325
326 *NM=N;
327 if (X < 1e-20) {
328 for (K=0; K<=N; K++) {
329 SY[K]=-1.0e+300;
330 DY[K]=1e+300;
331 }
332 return;
333 }
334 SY[0]=-cos(X)/X;
335 SY[1]=(SY[0]-sin(X))/X;
336 F0=SY[0];
337 F1=SY[1];
338 for (K=2; K<=N; K++) {
339 F=(2.0*K-1.0)*F1/X-F0;
340 SY[K]=F;
341 if (fabs(F) >= 1e+300) goto e20;
342 F0=F1;
343 F1=F;
344 }
345e20: *NM=K-1;
346 DY[0]=(sin(X)+cos(X)/X)/X;
347 for (K=1; K<=*NM; K++)
348 DY[K]=SY[K-1]-(K+1.0)*SY[K]/X;
349}
350
354static double Jn(int n, double z)
355{
356#ifndef _MSC_VER
357 return jn(n,z);
358#else
359 return _jn(n,z); /* Why Microsoft?! Why?! */
360#endif
361}
362
366static double Yn(int n, double z)
367{
368#ifndef _MSC_VER
369 return yn(n,z);
370#else
371 return _yn(n,z); /* ... */
372#endif
373}
374
375
376/* ========================================================================== */
377/* Cylindrical Bessel Functions */
378/* ========================================================================== */
379
381(
382 int N,
383 double* z,
384 int nZ,
385 double* J_n,
386 double* dJ_n
387)
388{
389 int i;
390
391 for(i=0; i<nZ; i++){
392 if(z[i] <= 1e-15){
393 if(J_n!=NULL)
394 J_n[i] = 0.0;
395 if(dJ_n!=NULL)
396 dJ_n[i] = 0.0;
397 }
398 else{
399 if(J_n!=NULL)
400 J_n[i] = Jn(N, z[i]);
401 if(N==0 && dJ_n!=NULL)
402 dJ_n[i] = -Jn(1, z[i]);
403 else if(dJ_n!=NULL)
404 dJ_n[i] = (Jn(N-1, z[i])-Jn(N+1, z[i]))/2.0;
405 }
406 }
407}
408
410(
411 int N,
412 double* z,
413 int nZ,
414 double* J_n,
415 double* dJ_n
416)
417{
418 int n, i;
419
420 for(i=0; i<nZ; i++){
421 if(z[i] <= 1e-15){
422 for(n=0; n<N+1; n++){
423 if(J_n!=NULL)
424 J_n[i*(N+1)+n] = 0.0;
425 if(dJ_n!=NULL)
426 dJ_n[i*(N+1)+n] = 0.0;
427 }
428 }
429 else{
430 for(n=0; n<N+1; n++){
431 if(J_n!=NULL)
432 J_n[i*(N+1)+n] = Jn(n, z[i]);
433 if(n==0 && dJ_n!=NULL)
434 dJ_n[i*(N+1)+n] = -Jn(1, z[i]);
435 else if(dJ_n!=NULL)
436 dJ_n[i*(N+1)+n] = (Jn(n-1, z[i])-Jn(n+1, z[i]))/2.0;
437 }
438 }
439 }
440}
441
443(
444 int N,
445 double* z,
446 int nZ,
447 double* Y_n,
448 double* dY_n
449)
450{
451 int i;
452
453 for(i=0; i<nZ; i++){
454 if(z[i] <= 1e-15){
455 if(Y_n!=NULL)
456 Y_n[i] = 0.0;
457 if(dY_n!=NULL)
458 dY_n[i] = 0.0;
459 }
460 else{
461 if(Y_n!=NULL)
462 Y_n[i] = Yn(N, z[i]);
463 if(N==0 && dY_n!=NULL)
464 dY_n[i] = -Yn(1, z[i]);
465 else if(dY_n!=NULL)
466 dY_n[i] = (Yn(N-1, z[i])-Yn(N+1, z[i]))/2.0;
467 }
468 }
469}
470
472(
473 int N,
474 double* z,
475 int nZ,
476 double* Y_n,
477 double* dY_n
478)
479{
480 int n, i;
481
482 for(i=0; i<nZ; i++){
483 if(z[i] <= 1e-15){
484 for(n=0; n<N+1; n++){
485 if(Y_n!=NULL)
486 Y_n[i*(N+1)+n] = 0.0;
487 if(dY_n!=NULL)
488 dY_n[i*(N+1)+n] = 0.0;
489 }
490 }
491 else{
492 for(n=0; n<N+1; n++){
493 if(Y_n!=NULL)
494 Y_n[i*(N+1)+n] = Yn(n, z[i]);
495 if(n==0 && dY_n!=NULL)
496 dY_n[i*(N+1)+n] = -Yn(1, z[i]);
497 else if(dY_n!=NULL)
498 dY_n[i*(N+1)+n] = (Yn(n-1, z[i])-Yn(n+1, z[i]))/2.0;
499 }
500 }
501 }
502}
503
505(
506 int N,
507 double* z,
508 int nZ,
509 double_complex* H_n1,
510 double_complex* dH_n1
511)
512{
513 int i;
514
515 for(i=0; i<nZ; i++){
516 if(z[i] <= 1e-15){
517 if(H_n1!=NULL)
518 H_n1[i] = cmplx(0.0, 0.0);
519 if(dH_n1!=NULL)
520 dH_n1[i] = cmplx(0.0, 0.0);
521 }
522 else{
523 if(H_n1!=NULL)
524 H_n1[i] = cmplx(Jn(N, z[i]), Yn(N, z[i]));
525 if(dH_n1!=NULL)
526 dH_n1[i] = ccsub(crmul(cmplx(Jn(N, z[i]), Yn(N, z[i])), (double)N/SAF_MAX(z[i],2.23e-13f)), cmplx(Jn(N+1, z[i]), Yn(N+1, z[i])));
527 }
528 }
529}
530
532(
533 int N,
534 double* z,
535 int nZ,
536 double_complex* H_n1,
537 double_complex* dH_n1
538)
539{
540 int n, i;
541
542 for(i=0; i<nZ; i++){
543 if(z[i] <= 1e-15){
544 for(n=0; n<N+1; n++){
545 if(H_n1!=NULL)
546 H_n1[i*(N+1)+n] = cmplx(0.0, 0.0);
547 if(dH_n1!=NULL)
548 dH_n1[i*(N+1)+n] = cmplx(0.0, 0.0);
549 }
550 }
551 else{
552 for(n=0; n<N+1; n++){
553 if(H_n1!=NULL)
554 H_n1[i*(N+1)+n] = cmplx(Jn(n, z[i]), Yn(n, z[i]));
555 if(dH_n1!=NULL)
556 dH_n1[i*(N+1)+n] = ccsub(crmul(cmplx(Jn(n, z[i]), Yn(n, z[i])), (double)n/SAF_MAX(z[i],2.23e-13f)), cmplx(Jn(n+1, z[i]), Yn(n+1, z[i])));
557 }
558 }
559 }
560}
561
563(
564 int N,
565 double* z,
566 int nZ,
567 double_complex* H_n2,
568 double_complex* dH_n2
569)
570{
571 int i;
572
573 for(i=0; i<nZ; i++){
574 if(z[i] <= 1e-15){
575 if(H_n2!=NULL)
576 H_n2[i] = cmplx(0.0, 0.0);
577 if(dH_n2!=NULL)
578 dH_n2[i] = cmplx(0.0, 0.0);
579 }
580 else{
581 if(H_n2!=NULL)
582 H_n2[i] = cmplx(Jn(N, z[i]), -Yn(N, z[i]));
583 if(N==0 && dH_n2!=NULL)
584 dH_n2[i] = crmul(ccsub(ccmul(cmplx(Jn(1, z[i]), Yn(1, z[i])), cexp(cmplx(0.0, -SAF_PId))), cmplx(Jn(1, z[i]), -Yn(1, z[i]))), 0.5);
585 else if(dH_n2!=NULL)
586 dH_n2[i] = crmul(ccsub(cmplx(Jn(N-1, z[i]), -Yn(N-1, z[i])), cmplx(Jn(N+1, z[i]), -Yn(N+1, z[i]))), 0.5);
587 }
588 }
589}
590
592(
593 int N,
594 double* z,
595 int nZ,
596 double_complex* H_n2,
597 double_complex* dH_n2
598)
599{
600 int n, i;
601
602 for(i=0; i<nZ; i++){
603 if(z[i] <= 1e-15){
604 for(n=0; n<N+1; n++){
605 if(H_n2!=NULL)
606 H_n2[i*(N+1)+n] = cmplx(0.0, 0.0);
607 if(dH_n2!=NULL)
608 dH_n2[i*(N+1)+n] = cmplx(0.0, 0.0);
609 }
610 }
611 else{
612 for(n=0; n<N+1; n++){
613 if(H_n2!=NULL)
614 H_n2[i*(N+1)+n] = cmplx(Jn(n, z[i]), -Yn(n, z[i]));
615 if(n==0 && dH_n2!=NULL)
616 dH_n2[i*(N+1)+n] = crmul(ccsub(ccmul(cmplx(Jn(1, z[i]), Yn(1, z[i])), cexp(cmplx(0.0, -SAF_PId))), cmplx(Jn(1, z[i]), -Yn(1, z[i]))), 0.5);
617 else if(dH_n2!=NULL)
618 dH_n2[i*(N+1)+n] = crmul(ccsub(cmplx(Jn(n-1, z[i]), -Yn(n-1, z[i])), cmplx(Jn(n+1, z[i]), -Yn(n+1, z[i]))), 0.5);
619 }
620 }
621 }
622}
623
624
625/* ========================================================================== */
626/* Spherical Bessel Functions */
627/* ========================================================================== */
628
630(
631 int N,
632 double* z,
633 int nZ,
634 double* j_n,
635 double* dj_n
636)
637{
638 int computedN, i;
639 double* j_0N, *dj_0N;
640
641 saf_assert(j_n!=NULL || dj_n!=NULL, "Either j_n or dj_n must be not NULL!");
642
643 /* Compute the function for all orders */
644 j_0N = j_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
645 dj_0N = dj_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
646 bessel_jn_ALL(N, z, nZ, &computedN, j_0N, dj_0N);
647
648 /* Output only the function values for order 'N' */
649 if(j_n!=NULL)
650 for(i=0; i<nZ; i++)
651 j_n[i] = computedN==N ? j_0N[i*(N+1)+(N)] : 0.0;
652 if(dj_n!=NULL)
653 for(i=0; i<nZ; i++)
654 dj_n[i] = computedN==N ? dj_0N[i*(N+1)+(N)] : 0.0;
655
656 /* clean-up */
657 free(j_0N);
658 free(dj_0N);
659 return computedN==N ? 1 : 0;
660}
661
663(
664 int N,
665 double* z,
666 int nZ,
667 int* maxN,
668 double* j_n,
669 double* dj_n
670)
671{
672 int n, i, NM;
673 double* j_n_tmp, *dj_n_tmp;
674
675 j_n_tmp = malloc1d((N+1)*sizeof(double));
676 dj_n_tmp = malloc1d((N+1)*sizeof(double));
677 *maxN = 1000000000;
678 for(i=0; i<nZ; i++){
679 if(z[i] <= 1e-15){
680 if(j_n!=NULL){
681 memset(&j_n[0], 0, (N+1)*sizeof(double));
682 j_n[0] = 1.0f;
683 }
684 if(dj_n!=NULL){
685 memset(&dj_n[0], 0, (N+1)*sizeof(double));
686 if(N>0)
687 dj_n[1] = 1.0/3.0;
688 }
689 }
690 else{
691 SPHJ(N, z[i], &NM, j_n_tmp, dj_n_tmp);
692 *maxN = SAF_MIN(NM, *maxN );
693 for(n=0; n<NM+1; n++){
694 if(j_n!=NULL)
695 j_n [i*(N+1)+n] = j_n_tmp[n];
696 if(dj_n!=NULL)
697 dj_n[i*(N+1)+n] = dj_n_tmp[n];
698 }
699 for(; n<N+1; n++){
700 if(j_n!=NULL)
701 j_n [i*(N+1)+n] = 0.0;
702 if(dj_n!=NULL)
703 dj_n [i*(N+1)+n] = 0.0;
704 }
705 }
706 }
707 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
708#ifndef NDEBUG
709 if(*maxN<N){
710 /* Unable to compute the spherical Bessel (jn) function at the specified
711 * order (N) and input value(s). In this case, the Bessel functions are
712 * instead returned at the maximum order that was possible (maxN). The
713 * maximum order is made known to the caller/returned by this function,
714 * so that things can be handled accordingly. */
715 saf_print_warning("Unable to compute the spherical Bessel (jn) function at the specified order and input value(s).");
716 }
717#endif
718
719 free(j_n_tmp);
720 free(dj_n_tmp);
721}
722
724(
725 int N,
726 double* z,
727 int nZ,
728 double* i_n,
729 double* di_n
730)
731{
732 int computedN, i;
733 double* i_0N, *di_0N;
734
735 saf_assert(i_n!=NULL || di_n!=NULL, "Either i_n or di_n must be not NULL!");
736
737 /* Compute the function for all orders */
738 i_0N = i_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
739 di_0N = di_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
740 bessel_in_ALL(N, z, nZ, &computedN, i_0N, di_0N);
741
742 /* Output only the function values for order 'N' */
743 if(i_n!=NULL)
744 for(i=0; i<nZ; i++)
745 i_n[i] = computedN==N ? i_0N[i*(N+1)+(N)] : 0.0;
746 if(di_n!=NULL)
747 for(i=0; i<nZ; i++)
748 di_n[i] = computedN==N ? di_0N[i*(N+1)+(N)] : 0.0;
749
750 /* clean-up */
751 free(i_0N);
752 free(di_0N);
753 return computedN==N ? 1 : 0;
754}
755
757(
758 int N,
759 double* z,
760 int nZ,
761 int* maxN,
762 double* i_n,
763 double* di_n
764)
765{
766 int n, i, NM;
767 double* i_n_tmp, *di_n_tmp;
768
769 i_n_tmp = malloc1d((N+1)*sizeof(double));
770 di_n_tmp = malloc1d((N+1)*sizeof(double));
771 *maxN = 1000000000;
772 for(i=0; i<nZ; i++){
773 if(z[i] <= 1e-15){
774 if(i_n!=NULL){
775 memset(&i_n[0], 0, (N+1)*sizeof(double));
776 i_n[0] = 1.0f;
777 }
778 if(di_n!=NULL){
779 memset(&di_n[0], 0, (N+1)*sizeof(double));
780 if(N>0)
781 di_n[1] = 1.0/3.0;
782 }
783 }
784 else{
785 SPHI(N, z[i], &NM, i_n_tmp, di_n_tmp);
786 *maxN = SAF_MIN(NM, *maxN );
787 for(n=0; n<NM+1; n++){
788 if(i_n!=NULL)
789 i_n [i*(N+1)+n] = i_n_tmp[n];
790 if(di_n!=NULL)
791 di_n[i*(N+1)+n] = di_n_tmp[n];
792 }
793 for(; n<N+1; n++){
794 if(i_n!=NULL)
795 i_n [i*(N+1)+n] = 0.0;
796 if(di_n!=NULL)
797 di_n [i*(N+1)+n] = 0.0;
798 }
799 }
800 }
801 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
802#ifndef NDEBUG
803 if(*maxN<N){
804 /* Unable to compute the spherical Bessel (in) function at the specified
805 * order (N) and input value(s). In this case, the Bessel functions are
806 * instead returned at the maximum order that was possible (maxN). The
807 * maximum order is made known to the caller/returned by this function,
808 * so that things can be handled accordingly. */
809 saf_print_warning("Unable to compute the spherical Bessel (in) function at the specified order and input value(s).");
810 }
811#endif
812
813 free(i_n_tmp);
814 free(di_n_tmp);
815}
816
818(
819 int N,
820 double* z,
821 int nZ,
822 double* y_n,
823 double* dy_n
824)
825{
826 int computedN, i;
827 double* y_0N, *dy_0N;
828
829 saf_assert(y_n!=NULL || dy_n!=NULL, "Either y_n or dy_n must be not NULL!");
830
831 /* Compute the function for all orders */
832 y_0N = y_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
833 dy_0N = dy_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
834 bessel_yn_ALL(N, z, nZ, &computedN, y_0N, dy_0N);
835
836 /* Output only the function values for order 'N' */
837 if(y_n!=NULL)
838 for(i=0; i<nZ; i++)
839 y_n[i] = computedN==N ? y_0N[i*(N+1)+(N)] : 0.0;
840 if(dy_n!=NULL)
841 for(i=0; i<nZ; i++)
842 dy_n[i] = computedN==N ? dy_0N[i*(N+1)+(N)] : 0.0;
843
844 /* clean-up */
845 free(y_0N);
846 free(dy_0N);
847 return computedN==N ? 1 : 0;
848}
849
851(
852 int N,
853 double* z,
854 int nZ,
855 int* maxN,
856 double* y_n,
857 double* dy_n
858)
859{
860 int n, i, NM;
861 double* y_n_tmp, *dy_n_tmp;
862
863 y_n_tmp = malloc1d((N+1)*sizeof(double));
864 dy_n_tmp = malloc1d((N+1)*sizeof(double));
865 *maxN = 1000000000;
866 for(i=0; i<nZ; i++){
867 if(z[i] <= 1e-15){
868 if(y_n!=NULL)
869 memset(&y_n[0], 0, (N+1)*sizeof(double));
870 if(dy_n!=NULL)
871 memset(&dy_n[0], 0, (N+1)*sizeof(double));
872 }
873 else{
874 SPHY(N, z[i], &NM, y_n_tmp, dy_n_tmp);
875 *maxN = SAF_MIN(NM, *maxN );
876 for(n=0; n<NM+1; n++){
877 if(y_n!=NULL)
878 y_n [i*(N+1)+n] = y_n_tmp[n];
879 if(dy_n!=NULL)
880 dy_n[i*(N+1)+n] = dy_n_tmp[n];
881 }
882 for(; n<N+1; n++){
883 if(y_n!=NULL)
884 y_n [i*(N+1)+n] = 0.0;
885 if(dy_n!=NULL)
886 dy_n [i*(N+1)+n] = 0.0;
887 }
888 }
889 }
890 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
891#ifndef NDEBUG
892 if(*maxN<N){
893 /* Unable to compute the spherical Bessel (yn) function at the specified
894 * order (N) and input value(s). In this case, the Bessel functions are
895 * instead returned at the maximum order that was possible (maxN). The
896 * maximum order is made known to the caller/returned by this function,
897 * so that things can be handled accordingly. */
898 saf_print_warning("Unable to compute the spherical Bessel (yn) function at the specified order and input value(s).");
899 }
900#endif
901
902 free(y_n_tmp);
903 free(dy_n_tmp);
904}
905
907(
908 int N,
909 double* z,
910 int nZ,
911 double* k_n,
912 double* dk_n
913)
914{
915 int computedN, i;
916 double* k_0N, *dk_0N;
917
918 saf_assert(k_n!=NULL || dk_n!=NULL, "Either k_n or dk_n must be not NULL!");
919
920 /* Compute the function for all orders */
921 k_0N = k_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
922 dk_0N = dk_n==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double));
923 bessel_kn_ALL(N, z, nZ, &computedN, k_0N, dk_0N);
924
925 /* Output only the function values for order 'N' */
926 if(k_n!=NULL)
927 for(i=0; i<nZ; i++)
928 k_n[i] = computedN==N ? k_0N[i*(N+1)+(N)] : 0.0;
929 if(dk_n!=NULL)
930 for(i=0; i<nZ; i++)
931 dk_n[i] = computedN==N ? dk_0N[i*(N+1)+(N)] : 0.0;
932
933 /* clean-up */
934 free(k_0N);
935 free(dk_0N);
936 return computedN==N ? 1 : 0;
937}
938
940(
941 int N,
942 double* z,
943 int nZ,
944 int* maxN,
945 double* k_n,
946 double* dk_n
947)
948{
949 int n, i, NM;
950 double* k_n_tmp, *dk_n_tmp;
951
952 k_n_tmp = malloc1d((N+1)*sizeof(double));
953 dk_n_tmp = malloc1d((N+1)*sizeof(double));
954 *maxN = 1000000000;
955 for(i=0; i<nZ; i++){
956 if(z[i] <= 1e-15){
957 if(k_n!=NULL)
958 memset(&k_n[0], 0, (N+1)*sizeof(double));
959 if(dk_n!=NULL)
960 memset(&dk_n[0], 0, (N+1)*sizeof(double));
961 }
962 else{
963 SPHK(N, z[i], &NM, k_n_tmp, dk_n_tmp);
964 *maxN = SAF_MIN(NM, *maxN );
965 for(n=0; n<NM+1; n++){
966 if(k_n!=NULL)
967 k_n [i*(N+1)+n] = k_n_tmp[n];
968 if(dk_n!=NULL)
969 dk_n[i*(N+1)+n] = dk_n_tmp[n];
970 }
971 for(; n<N+1; n++){
972 if(k_n!=NULL)
973 k_n [i*(N+1)+n] = 0.0;
974 if(dk_n!=NULL)
975 dk_n [i*(N+1)+n] = 0.0;
976 }
977 }
978 }
979 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
980#ifndef NDEBUG
981 if(*maxN<N){
982 /* Unable to compute the spherical Bessel (kn) function at the specified
983 * order (N) and input value(s). In this case, the Bessel functions are
984 * instead returned at the maximum order that was possible (maxN). The
985 * maximum order is made known to the caller/returned by this function,
986 * so that things can be handled accordingly. */
987 saf_print_warning("Unable to compute the spherical Bessel (kn) function at the specified order and input value(s).");
988 }
989#endif
990
991 free(k_n_tmp);
992 free(dk_n_tmp);
993}
994
996(
997 int N,
998 double* z,
999 int nZ,
1000 double_complex* h_n1,
1001 double_complex* dh_n1
1002)
1003{
1004 int computedN, i;
1005 double_complex* h1_0N, *dh1_0N;
1006
1007 saf_assert(h_n1!=NULL || dh_n1!=NULL, "Either h_n1 or dh_n1 must be not NULL!");
1008
1009 /* Compute the function for all orders */
1010 h1_0N = h_n1==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double_complex));
1011 dh1_0N = dh_n1==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double_complex));
1012 hankel_hn1_ALL(N, z, nZ, &computedN, h1_0N, dh1_0N);
1013
1014 /* Output only the function values for order 'N' */
1015 if(h_n1!=NULL)
1016 for(i=0; i<nZ; i++)
1017 h_n1[i] = computedN==N ? h1_0N[i*(N+1)+(N)] : cmplx(0.0, 0.0);
1018 if(dh_n1!=NULL)
1019 for(i=0; i<nZ; i++)
1020 dh_n1[i] = computedN==N ? dh1_0N[i*(N+1)+(N)] : cmplx(0.0, 0.0);
1021
1022 /* clean-up */
1023 free(h1_0N);
1024 free(dh1_0N);
1025 return computedN==N ? 1 : 0;
1026}
1027
1029(
1030 int N,
1031 double* z,
1032 int nZ,
1033 int* maxN,
1034 double_complex* h_n1,
1035 double_complex* dh_n1
1036)
1037{
1038 int n, i, NM1, NM2;
1039 double* j_n_tmp, *dj_n_tmp, *y_n_tmp, *dy_n_tmp;
1040
1041 j_n_tmp = calloc1d((N+1),sizeof(double));
1042 dj_n_tmp = calloc1d((N+1),sizeof(double));
1043 y_n_tmp = calloc1d((N+1),sizeof(double));
1044 dy_n_tmp = calloc1d((N+1),sizeof(double));
1045 *maxN = 1000000000;
1046 for(i=0; i<nZ; i++){
1047 if(z[i] <= 1e-15){
1048 if(h_n1!=NULL){
1049 memset(&h_n1[0], 0, (N+1)*sizeof(double_complex));
1050 h_n1[0] = cmplx(1.0, 0.0);
1051 }
1052 if(dh_n1!=NULL)
1053 memset(&dh_n1[0], 0, (N+1)*sizeof(double_complex));
1054 }
1055 else{
1056 SPHJ(N, z[i], &NM1, j_n_tmp, dj_n_tmp);
1057 *maxN = SAF_MIN(NM1, *maxN );
1058 SPHY(N, z[i], &NM2, y_n_tmp, dy_n_tmp);
1059 *maxN = SAF_MIN(NM2, *maxN );
1060 for(n=0; n<SAF_MIN(NM1,NM2)+1; n++){
1061 if(h_n1!=NULL)
1062 h_n1 [i*(N+1)+n] = cmplx(j_n_tmp[n], y_n_tmp[n]);
1063 if(dh_n1!=NULL)
1064 dh_n1[i*(N+1)+n] = cmplx(dj_n_tmp[n], dy_n_tmp[n]);
1065 }
1066 for(; n<N+1; n++){
1067 if(h_n1!=NULL)
1068 h_n1 [i*(N+1)+n] = cmplx(0.0,0.0);
1069 if(dh_n1!=NULL)
1070 dh_n1 [i*(N+1)+n] = cmplx(0.0,0.0);
1071 }
1072 }
1073 }
1074 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
1075#ifndef NDEBUG
1076 if(*maxN<N){
1077 /* Unable to compute the spherical Hankel (hn1) function at the
1078 * specified order (N) and input value(s). In this case, the Hankel
1079 * functions are instead returned at the maximum order that was possible
1080 * (maxN). The maximum order is made known to the caller/returned by
1081 * this function, so that things can be handled accordingly. */
1082 saf_print_warning("Unable to compute the spherical Hankel (hn1) function at the specified order and input value(s).");
1083 }
1084#endif
1085
1086 free(j_n_tmp);
1087 free(dj_n_tmp);
1088 free(y_n_tmp);
1089 free(dy_n_tmp);
1090}
1091
1093(
1094 int N,
1095 double* z,
1096 int nZ,
1097 double_complex* h_n2,
1098 double_complex* dh_n2
1099)
1100{
1101 int computedN, i;
1102 double_complex* h2_0N, *dh2_0N;
1103
1104 saf_assert(h_n2!=NULL || dh_n2!=NULL, "Either h_n2 or dh_n2 must be not NULL!");
1105
1106 /* Compute the function for all orders */
1107 h2_0N = h_n2==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double_complex));
1108 dh2_0N = dh_n2==NULL ? NULL : malloc1d(nZ*(N+1)*sizeof(double_complex));
1109 hankel_hn2_ALL(N, z, nZ, &computedN, h2_0N, dh2_0N);
1110
1111 /* Output only the function values for order 'N' */
1112 if(h_n2!=NULL)
1113 for(i=0; i<nZ; i++)
1114 h_n2[i] = computedN==N ? h2_0N[i*(N+1)+(N)] : cmplx(0.0, 0.0);
1115 if(dh_n2!=NULL)
1116 for(i=0; i<nZ; i++)
1117 dh_n2[i] = computedN==N ? dh2_0N[i*(N+1)+(N)] : cmplx(0.0, 0.0);
1118
1119 /* clean-up */
1120 free(h2_0N);
1121 free(dh2_0N);
1122 return computedN==N ? 1 : 0;
1123}
1124
1126(
1127 int N,
1128 double* z,
1129 int nZ,
1130 int* maxN,
1131 double_complex* h_n2,
1132 double_complex* dh_n2
1133)
1134{
1135 int n, i, NM1, NM2;
1136 double* j_n_tmp, *dj_n_tmp, *y_n_tmp, *dy_n_tmp;
1137
1138 j_n_tmp = calloc1d((N+1),sizeof(double));
1139 dj_n_tmp = calloc1d((N+1),sizeof(double));
1140 y_n_tmp = calloc1d((N+1),sizeof(double));
1141 dy_n_tmp = calloc1d((N+1),sizeof(double));
1142 *maxN = 1000000000;
1143 for(i=0; i<nZ; i++){
1144 if(z[i] <= 1e-15){
1145 if(h_n2!=NULL){
1146 memset(&h_n2[0], 0, (N+1)*sizeof(double_complex));
1147 h_n2[0] = cmplx(1.0, 0.0);
1148 }
1149 if(dh_n2!=NULL)
1150 memset(&dh_n2[0], 0, (N+1)*sizeof(double_complex));
1151 }
1152 else{
1153 SPHJ(N, z[i], &NM1, j_n_tmp, dj_n_tmp);
1154 *maxN = SAF_MIN(NM1, *maxN );
1155 SPHY(N, z[i], &NM2, y_n_tmp, dy_n_tmp);
1156 *maxN = SAF_MIN(NM2, *maxN );
1157 for(n=0; n<SAF_MIN(NM1,NM2)+1; n++){
1158 if(h_n2!=NULL)
1159 h_n2 [i*(N+1)+n] = cmplx(j_n_tmp[n], -y_n_tmp[n]);
1160 if(dh_n2!=NULL)
1161 dh_n2[i*(N+1)+n] = cmplx(dj_n_tmp[n], -dy_n_tmp[n]);
1162 }
1163 for(; n<N+1; n++){
1164 if(h_n2!=NULL)
1165 h_n2 [i*(N+1)+n] = cmplx(0.0,0.0);
1166 if(dh_n2!=NULL)
1167 dh_n2 [i*(N+1)+n] = cmplx(0.0,0.0);
1168 }
1169 }
1170 }
1171 *maxN = *maxN==1e8 ? 0 : *maxN; /* maximum order that could be computed */
1172#ifndef NDEBUG
1173 if(*maxN<N){
1174 /* Unable to compute the spherical Hankel (hn2) function at the
1175 * specified order (N) and input value(s). In this case, the Hankel
1176 * functions are instead returned at the maximum order that was possible
1177 * (maxN). The maximum order is made known to the caller/returned by
1178 * this function, so that things can be handled accordingly. */
1179 saf_print_warning("Unable to compute the spherical Hankel (hn2) function at the specified order and input value(s).");
1180 }
1181#endif
1182
1183 free(j_n_tmp);
1184 free(dj_n_tmp);
1185 free(y_n_tmp);
1186 free(dy_n_tmp);
1187}
void bessel_jn_ALL(int N, double *z, int nZ, int *maxN, double *j_n, double *dj_n)
Computes the spherical Bessel function of the first kind (jn) and their derivatives (djn) for ALL ord...
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
void bessel_Yn_ALL(int N, double *z, int nZ, double *Y_n, double *dY_n)
Computes the (cylindrical) Bessel function of the second kind (Yn) and their derivatives (dYn) for AL...
int hankel_hn2(int N, double *z, int nZ, double_complex *h_n2, double_complex *dh_n2)
Computes the values of the spherical Hankel function of the second kind (hn2) and it's derivative (dh...
void hankel_hn2_ALL(int N, double *z, int nZ, int *maxN, double_complex *h_n2, double_complex *dh_n2)
Computes the spherical Hankel function of the second kind (hn2) and their derivatives (dhn2) for ALL ...
void bessel_yn_ALL(int N, double *z, int nZ, int *maxN, double *y_n, double *dy_n)
Computes the spherical Bessel function of the second kind (yn) and their derivatives (dyn) for ALL or...
void hankel_Hn1_ALL(int N, double *z, int nZ, double_complex *H_n1, double_complex *dH_n1)
Computes the (cylindrical) Hankel function of the first kind (Hn1) and their derivatives (dHn1) for A...
#define SAF_MAX(a, b)
Returns the maximum of the two values.
void bessel_Jn(int N, double *z, int nZ, double *J_n, double *dJ_n)
Computes the values of the (cylindrical) Bessel function of the first kind (Jn) and it's derivative (...
#define SAF_PId
pi constant (double precision)
int hankel_hn1(int N, double *z, int nZ, double_complex *h_n1, double_complex *dh_n1)
Computes the values of the spherical Hankel function of the first kind (hn1) and it's derivative (dhn...
void hankel_hn1_ALL(int N, double *z, int nZ, int *maxN, double_complex *h_n1, double_complex *dh_n1)
Computes the spherical Hankel function of the first kind (hn1) and their derivatives (dhn1) for ALL o...
void bessel_Jn_ALL(int N, double *z, int nZ, double *J_n, double *dJ_n)
Computes the (cylindrical) Bessel function of the first kind (Jn) and their derivatives (dJn) for ALL...
void bessel_in_ALL(int N, double *z, int nZ, int *maxN, double *i_n, double *di_n)
Computes the modified spherical Bessel function of the first kind (in) and their derivatives (din) fo...
void hankel_Hn2(int N, double *z, int nZ, double_complex *H_n2, double_complex *dH_n2)
Computes the values of the (cylindrical) Hankel function of the second kind (Hn2) and it's derivative...
#define SAF_MIN(a, b)
Returns the minimum of the two values.
#define saf_print_warning(message)
Macro to print a warning message along with the filename and line number.
void hankel_Hn2_ALL(int N, double *z, int nZ, double_complex *H_n2, double_complex *dH_n2)
Computes the (cylindrical) Hankel function of the second kind (Hn2) and their derivatives (dHn2) for ...
int bessel_yn(int N, double *z, int nZ, double *y_n, double *dy_n)
Computes the values of the spherical Bessel function of the second kind (yn) and it's derivative (dyn...
void hankel_Hn1(int N, double *z, int nZ, double_complex *H_n1, double_complex *dH_n1)
Computes the values of the (cylindrical) Hankel function of the first kind (Hn1) and it's derivative ...
int bessel_jn(int N, double *z, int nZ, double *j_n, double *dj_n)
Computes the values of the spherical Bessel function of the first kind (jn) and it's derivative (djn)
int bessel_kn(int N, double *z, int nZ, double *k_n, double *dk_n)
Computes the values of the modified spherical Bessel function of the second kind (kn) and it's deriva...
void bessel_Yn(int N, double *z, int nZ, double *Y_n, double *dY_n)
Computes the values of the (cylindrical) Bessel function of the second kind (Yn) and it's derivative ...
void bessel_kn_ALL(int N, double *z, int nZ, int *maxN, double *k_n, double *dk_n)
Computes the modified spherical Bessel function of the second kind (kn) and their derivatives (dkn) f...
int bessel_in(int N, double *z, int nZ, double *i_n, double *di_n)
Computes the values of the modified spherical Bessel function of the first kind (in) and it's derivat...
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Definition md_malloc.c:69
Main header for the utilities module (SAF_UTILITIES_MODULE)
static int MSTA2(double X, int N, int MP)
Helper function, used when computing spherical bessel function values.
static void SPHK(int N, double X, int *NM, double *SK, double *DK)
Helper function for bessel_kn.
static double Jn(int n, double z)
Wrapper for the cylindrical Bessel function of the first kind.
static void SPHJ(int N, double X, int *NM, double *SJ, double *DJ)
Helper function for bessel_in.
static void SPHY(int N, double X, int *NM, double *SY, double *DY)
Helper function for bessel_yn.
static double ENVJ(int N, double X)
Helper function, used when computing spherical bessel function values.
static int MSTA1(double X, int MP)
Helper function, used when computing spherical bessel function values.
static void SPHI(int N, double X, int *NM, double *SI, double *DI)
Helper function for bessel_in.
static double Yn(int n, double z)
Wrapper for the cylindrical Bessel function of the second kind.