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.qc25c;
9 
10 
11 import std.math: fabs, log;
12 
13 import scid.core.fortran;
14 import scid.ports.quadpack.qcheb;
15 import scid.ports.quadpack.qk15w;
16 import scid.ports.quadpack.qwgtc;
17 
18 
19 
20 
21 ///
22 void qc25c(Real, Func)(Func f, Real a, Real b, Real c, out Real result,
23     out Real abserr, ref int krul, out int neval)
24 {
25 //***begin prologue  dqc25c
26 //***date written   810101   (yymmdd)
27 //***revision date  830518   (yymmdd)
28 //***category no.  h2a2a2,j4
29 //***keywords  25-point clenshaw-curtis integration
30 //***author  piessens,robert,appl. math. & progr. div. - k.u.leuven
31 //           de doncker,elise,appl. math. & progr. div. - k.u.leuven
32 //***purpose  to compute i = integral of f*w over (a,b) with
33 //            error estimate, where w(x) = 1/(x-c)
34 //***description
35 //
36 //        integration rules for the computation of cauchy
37 //        principal value integrals
38 //        standard fortran subroutine
39 //        double precision version
40 //
41 //        parameters
42 //           f      - double precision
43 //                    function subprogram defining the integrand function
44 //                    f(x). the actual name for f needs to be declared
45 //                    e x t e r n a l  in the driver program.
46 //
47 //           a      - double precision
48 //                    left end point of the integration interval
49 //
50 //           b      - double precision
51 //                    right end point of the integration interval, b.gt.a
52 //
53 //           c      - double precision
54 //                    parameter in the weight function
55 //
56 //           result - double precision
57 //                    approximation to the integral
58 //                    result is computed by using a generalized
59 //                    clenshaw-curtis method if c lies within ten percent
60 //                    of the integration interval. in the other case the
61 //                    15-point kronrod rule obtained by optimal addition
62 //                    of abscissae to the 7-point gauss rule, is applied.
63 //
64 //           abserr - double precision
65 //                    estimate of the modulus of the absolute error,
66 //                    which should equal or exceed abs(i-result)
67 //
68 //           krul   - integer
69 //                    key which is decreased by 1 if the 15-point
70 //                    gauss-kronrod scheme has been used
71 //
72 //           neval  - integer
73 //                    number of integrand evaluations
74 //
75 //.......................................................................
76 //***references  (none)
77 //***routines called  dqcheb,dqk15w,dqwgtc
78 //***end prologue  dqc25c
79 //
80       Real ak22,amom0,amom1,amom2,cc,centr,
81         hlgth,p2,p3,p4,resabs,
82         resasc,res12,res24,u;
83       Real[13] cheb12_;
84       Real[25] fval_, cheb24_;
85       int i=1,isym=1,k=1,kp=1;
86 //
87 //           the vector x contains the values cos(k*pi/24),
88 //           k = 1, ..., 11, to be used for the chebyshev series
89 //           expansion of f
90 //
91       static immutable Real[11] x_ = [
92           0.9914448613_7381041114_4557526928_563,
93           0.9659258262_8906828674_9743199728_897,
94           0.9238795325_1128675612_8183189396_788,
95           0.8660254037_8443864676_3723170752_936,
96           0.7933533402_9123516457_9776961501_299,
97           0.7071067811_8654752440_0844362104_849,
98           0.6087614290_0872063941_6097542898_164,
99           0.5000000000_0000000000_0000000000_000,
100           0.3826834323_6508977172_8459984030_399,
101           0.2588190451_0252076234_8898837624_048,
102           0.1305261922_2005159154_8406227895_489];
103 //
104     auto x = dimension(x_.ptr, 11);
105     auto fval = dimension(fval_.ptr, 25);
106     auto cheb12 = dimension(cheb12_.ptr, 13);
107     auto cheb24 = dimension(cheb24_.ptr, 25);
108 //
109 //           list of major variables
110 //           ----------------------
111 //           fval   - value of the function f at the points
112 //                    cos(k*pi/24),  k = 0, ..., 24
113 //           cheb12 - chebyshev series expansion coefficients,
114 //                    for the function f, of degree 12
115 //           cheb24 - chebyshev series expansion coefficients,
116 //                    for the function f, of degree 24
117 //           res12  - approximation to the integral corresponding
118 //                    to the use of cheb12
119 //           res24  - approximation to the integral corresponding
120 //                    to the use of cheb24
121 //           dqwgtc - external function subprogram defining
122 //                    the weight function
123 //           hlgth  - half-length of the interval
124 //           centr  - mid point of the interval
125 //
126 //
127 //           check the position of c.
128 //
129 //***first executable statement  dqc25c
130       cc = (0.2e1*c-b-a)/(b-a);
131       if(fabs(cc) < 0.11e1) goto l10;
132 //
133 //           apply the 15-point gauss-kronrod scheme.
134 //
135       krul = krul-1;
136       qk15w!(Real,Func)(f,&qwgtc!Real,c,p2,p3,p4,kp,a,b,result,abserr,
137         resabs,resasc);
138       neval = 15;
139       if (resasc == abserr) krul = krul+1;
140       goto l50;
141 //
142 //           use the generalized clenshaw-curtis method.
143 //
144  l10: hlgth = 0.5*(b-a);
145       centr = 0.5*(b+a);
146       neval = 25;
147       fval[1] = 0.5*f(hlgth+centr);
148       fval[13] = f(centr);
149       fval[25] = 0.5*f(centr-hlgth);
150       for (i=2; i<=12; i++) { //do 20 i=2,12
151         u = hlgth*x[i-1];
152         isym = 26-i;
153         fval[i] = f(u+centr);
154         fval[isym] = f(centr-u);
155  l20: ;}
156 //
157 //           compute the chebyshev series expansion.
158 //
159       qcheb!Real(x.ptr,fval.ptr,cheb12.ptr,cheb24.ptr);
160 //
161 //           the modified chebyshev moments are computed by forward
162 //           recursion, using amom0 and amom1 as starting values.
163 //
164       amom0 = log(fabs((0.1e1-cc)/(0.1e1+cc)));
165       amom1 = 0.2e1+cc*amom0;
166       res12 = cheb12[1]*amom0+cheb12[2]*amom1;
167       res24 = cheb24[1]*amom0+cheb24[2]*amom1;
168       for (k=3; k<=13; k++) { //do 30 k=3,13
169         amom2 = 0.2e1*cc*amom1-amom0;
170         ak22 = (k-2)*(k-2);
171         if((k/2)*2 == k) amom2 = amom2-0.4e1/(ak22-0.1e1);
172         res12 = res12+cheb12[k]*amom2;
173         res24 = res24+cheb24[k]*amom2;
174         amom0 = amom1;
175         amom1 = amom2;
176  l30: ;}
177       for (k=14; k<=25; k++) { //do 40 k=14,25
178         amom2 = 0.2e1*cc*amom1-amom0;
179         ak22 = (k-2)*(k-2);
180         if((k/2)*2 == k) amom2 = amom2-0.4e1/(ak22-0.1e1);
181         res24 = res24+cheb24[k]*amom2;
182         amom0 = amom1;
183         amom1 = amom2;
184  l40: ;}
185       result = res24;
186       abserr = fabs(res24-res12);
187  l50: return;
188 }
189 
190 
191 unittest
192 {
193     alias qc25c!(float, float delegate(float)) fqc25c;
194     alias qc25c!(double, double delegate(double)) dqc25c;
195     alias qc25c!(double, double function(double)) dfqc25c;
196     alias qc25c!(real, real delegate(real)) rqc25c;
197 }