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 }