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 }