1 // This code has been mechanically translated from the original FORTRAN
2 // code at http://netlib.org/quadpack.
3 
4 /** Authors:    Lars Tandle Kyllingstad
5     Copyright:  Copyright (c) 2009, Lars T. Kyllingstad. All rights reserved.
6     License:    Boost License 1.0
7 */
8 module scid.ports.quadpack.qk15w;
9 
10 
11 import std.algorithm: min, max;
12 import std.math;
13 
14 import scid.core.fortran;
15 
16 
17 
18 
19 ///
20 void qk15w(Real, Func)(Func f, Real function(Real,Real,Real,Real,Real,int) w,
21     Real p1, Real p2, Real p3, Real p4, int kp, Real a, Real b,
22     out Real result, out Real abserr, out Real resabs, out Real resasc)
23 {
24 //***begin prologue  dqk15w
25 //***date written   810101   (yymmdd)
26 //***revision date  830518   (mmddyy)
27 //***category no.  h2a2a2
28 //***keywords  15-point gauss-kronrod rules
29 //***author  piessens,robert,appl. math. & progr. div. - k.u.leuven
30 //           de doncker,elise,appl. math. & progr. div. - k.u.leuven
31 //***purpose  to compute i = integral of f*w over (a,b), with error
32 //                           estimate
33 //                       j = integral of abs(f*w) over (a,b)
34 //***description
35 //
36 //           integration rules
37 //           standard fortran subroutine
38 //           double precision version
39 //
40 //           parameters
41 //             on entry
42 //              f      - double precision
43 //                       function subprogram defining the integrand
44 //                       function f(x). the actual name for f needs to be
45 //                       declared e x t e r n a l in the driver program.
46 //
47 //              w      - double precision
48 //                       function subprogram defining the integrand
49 //                       weight function w(x). the actual name for w
50 //                       needs to be declared e x t e r n a l in the
51 //                       calling program.
52 //
53 //              p1, p2, p3, p4 - double precision
54 //                       parameters in the weight function
55 //
56 //              kp     - integer
57 //                       key for indicating the type of weight function
58 //
59 //              a      - double precision
60 //                       lower limit of integration
61 //
62 //              b      - double precision
63 //                       upper limit of integration
64 //
65 //            on return
66 //              result - double precision
67 //                       approximation to the integral i
68 //                       result is computed by applying the 15-point
69 //                       kronrod rule (resk) obtained by optimal addition
70 //                       of abscissae to the 7-point gauss rule (resg).
71 //
72 //              abserr - double precision
73 //                       estimate of the modulus of the absolute error,
74 //                       which should equal or exceed abs(i-result)
75 //
76 //              resabs - double precision
77 //                       approximation to the integral of abs(f)
78 //
79 //              resasc - double precision
80 //                       approximation to the integral of abs(f-i/(b-a))
81 //
82 //
83 //***references  (none)
84 //***routines called  d1mach
85 //***end prologue  dqk15w
86 //
87       Real absc,absc1,absc2,centr,dhlgth,
88         epmach,fc,fsum,fval1,fval2,hlgth,
89         resg,resk,reskh,uflow;
90       Real[7] fv1_, fv2_;
91       int j=1,jtw=1,jtwm1=1;
92 //
93 //           the abscissae and weights are given for the interval (-1,1).
94 //           because of symmetry only the positive abscissae and their
95 //           corresponding weights are given.
96 //
97 //           xgk    - abscissae of the 15-point gauss-kronrod rule
98 //                    xgk(2), xgk(4), ... abscissae of the 7-point
99 //                    gauss rule
100 //                    xgk(1), xgk(3), ... abscissae which are optimally
101 //                    added to the 7-point gauss rule
102 //
103 //           wgk    - weights of the 15-point gauss-kronrod rule
104 //
105 //           wg     - weights of the 7-point gauss rule
106 //
107       static immutable Real[8] xgk_ = [
108            0.9914553711208126,
109            0.9491079123427585,
110            0.8648644233597691,
111            0.7415311855993944,
112            0.5860872354676911,
113            0.4058451513773972,
114            0.2077849550078985,
115            0.0000000000000000
116         ];
117 //
118      static immutable Real[8] wgk_ = [
119            0.2293532201052922e-1,
120            0.6309209262997855e-1,
121            0.1047900103222502,
122            0.1406532597155259,
123            0.1690047266392679,
124            0.1903505780647854,
125            0.2044329400752989,
126            0.2094821410847278
127         ];
128 //
129       static immutable Real[4] wg_ = [
130            0.1294849661688697,
131            0.2797053914892767,
132            0.3818300505051889,
133            0.4179591836734694
134         ];
135 //
136       auto fv1 = dimension(fv1_.ptr, 7);
137       auto fv2 = dimension(fv2_.ptr, 7);
138       auto xgk = dimension(xgk_.ptr, 8);
139       auto wgk = dimension(wgk_.ptr, 8);
140       auto wg = dimension(wg_.ptr, 4);
141 //
142 //
143 //           list of major variables
144 //           -----------------------
145 //
146 //           centr  - mid point of the interval
147 //           hlgth  - half-length of the interval
148 //           absc*  - abscissa
149 //           fval*  - function value
150 //           resg   - result of the 7-point gauss formula
151 //           resk   - result of the 15-point kronrod formula
152 //           reskh  - approximation to the mean value of f*w over (a,b),
153 //                    i.e. to i/(b-a)
154 //
155 //           machine dependent constants
156 //           ---------------------------
157 //
158 //           epmach is the largest relative spacing.
159 //           uflow is the smallest positive magnitude.
160 //
161 //***first executable statement  dqk15w
162       epmach = Real.epsilon;
163       uflow = Real.min_normal;
164 //
165       centr = 0.5*(a+b);
166       hlgth = 0.5*(b-a);
167       dhlgth = fabs(hlgth);
168 //
169 //           compute the 15-point kronrod approximation to the
170 //           integral, and estimate the error.
171 //
172       fc = f(centr)*w(centr,p1,p2,p3,p4,kp);
173       resg = wg[4]*fc;
174       resk = wgk[8]*fc;
175       resabs = fabs(resk);
176       for (j=1; j<=3; j++) { // end: 10
177         jtw = j*2;
178         absc = hlgth*xgk[jtw];
179         absc1 = centr-absc;
180         absc2 = centr+absc;
181         fval1 = f(absc1)*w(absc1,p1,p2,p3,p4,kp);
182         fval2 = f(absc2)*w(absc2,p1,p2,p3,p4,kp);
183         fv1[jtw] = fval1;
184         fv2[jtw] = fval2;
185         fsum = fval1+fval2;
186         resg = resg+wg[j]*fsum;
187         resk = resk+wgk[jtw]*fsum;
188         resabs = resabs+wgk[jtw]*(fabs(fval1)+fabs(fval2));
189  l10:;}
190       for(j=1; j<=4; j++) { // end: 15
191         jtwm1 = j*2-1;
192         absc = hlgth*xgk[jtwm1];
193         absc1 = centr-absc;
194         absc2 = centr+absc;
195         fval1 = f(absc1)*w(absc1,p1,p2,p3,p4,kp);
196         fval2 = f(absc2)*w(absc2,p1,p2,p3,p4,kp);
197         fv1[jtwm1] = fval1;
198         fv2[jtwm1] = fval2;
199         fsum = fval1+fval2;
200         resk = resk+wgk[jtwm1]*fsum;
201         resabs = resabs+wgk[jtwm1]*(fabs(fval1)+fabs(fval2));
202  l15:;}
203       reskh = resk*0.5;
204       resasc = wgk[8]*fabs(fc-reskh);
205       for (j=1; j<=7; j++) { // end: 20
206         resasc = resasc+wgk[j]*(fabs(fv1[j]-reskh)+fabs(fv2[j]-reskh));
207  l20:;}
208       result = resk*hlgth;
209       resabs = resabs*dhlgth;
210       resasc = resasc*dhlgth;
211       abserr = fabs((resk-resg)*hlgth);
212       if(resasc != 0.0 && abserr != 0.0)
213         abserr = resasc*min(0.1e1, ((cast(Real)0.2e3)*abserr/resasc)^^(cast(Real)1.5));
214       if(resabs > uflow/(0.5e2*epmach)) abserr = max((epmach*
215         0.5e2)*resabs,abserr);
216       return;
217 }
218 
219 
220 unittest
221 {
222     alias qk15w!(float, float delegate(float)) fqk15w;
223     alias qk15w!(double, double delegate(double)) dqk15w;
224     alias qk15w!(double, double function(double)) dfqk15w;
225     alias qk15w!(real, real delegate(real)) rqk15w;
226 }