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.qawoe; 9 10 11 import std.algorithm: max; 12 import std.math: fabs; 13 14 import scid.core.fortran; 15 import scid.ports.quadpack.qc25f; 16 import scid.ports.quadpack.qpsrt; 17 import scid.ports.quadpack.qelg; 18 19 20 21 22 /// 23 void qawoe(Real, Func)(Func f, Real a, Real b, Real omega, int integr, 24 Real epsabs, Real epsrel, int limit, int icall, int maxp1, 25 out Real result, out Real abserr, out int neval, out int ier, 26 out int last, Real* alist_, Real* blist_, Real* rlist_, Real* elist_, 27 int* iord_, int* nnlog_, ref int momcom, Real* chebmo_) 28 { 29 //***begin prologue dqawoe 30 //***date written 800101 (yymmdd) 31 //***revision date 830518 (yymmdd) 32 //***category no. h2a2a1 33 //***keywords automatic integrator, special-purpose, 34 // integrand with oscillatory cos or sin factor, 35 // clenshaw-curtis method, (end point) singularities, 36 // extrapolation, globally adaptive 37 //***author piessens,robert,appl. math. & progr. div. - k.u.leuven 38 // de doncker,elise,appl. math. & progr. div. - k.u.leuven 39 //***purpose the routine calculates an approximation result to a given 40 // definite integral 41 // i = integral of f(x)*w(x) over (a,b) 42 // where w(x) = cos(omega*x) or w(x)=sin(omega*x), 43 // hopefully satisfying following claim for accuracy 44 // abs(i-result).le.max(epsabs,epsrel*abs(i)). 45 //***description 46 // 47 // computation of oscillatory integrals 48 // standard fortran subroutine 49 // double precision version 50 // 51 // parameters 52 // on entry 53 // f - double precision 54 // function subprogram defining the integrand 55 // function f(x). the actual name for f needs to be 56 // declared e x t e r n a l in the driver program. 57 // 58 // a - double precision 59 // lower limit of integration 60 // 61 // b - double precision 62 // upper limit of integration 63 // 64 // omega - double precision 65 // parameter in the integrand weight function 66 // 67 // integr - integer 68 // indicates which of the weight functions is to be 69 // used 70 // integr = 1 w(x) = cos(omega*x) 71 // integr = 2 w(x) = sin(omega*x) 72 // if integr.ne.1 and integr.ne.2, the routine 73 // will end with ier = 6. 74 // 75 // epsabs - double precision 76 // absolute accuracy requested 77 // epsrel - double precision 78 // relative accuracy requested 79 // if epsabs.le.0 80 // and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), 81 // the routine will end with ier = 6. 82 // 83 // limit - integer 84 // gives an upper bound on the number of subdivisions 85 // in the partition of (a,b), limit.ge.1. 86 // 87 // icall - integer 88 // if dqawoe is to be used only once, icall must 89 // be set to 1. assume that during this call, the 90 // chebyshev moments (for clenshaw-curtis integration 91 // of degree 24) have been computed for intervals of 92 // lenghts (abs(b-a))*2**(-l), l=0,1,2,...momcom-1. 93 // if icall.gt.1 this means that dqawoe has been 94 // called twice or more on intervals of the same 95 // length abs(b-a). the chebyshev moments already 96 // computed are then re-used in subsequent calls. 97 // if icall.lt.1, the routine will end with ier = 6. 98 // 99 // maxp1 - integer 100 // gives an upper bound on the number of chebyshev 101 // moments which can be stored, i.e. for the 102 // intervals of lenghts abs(b-a)*2**(-l), 103 // l=0,1, ..., maxp1-2, maxp1.ge.1. 104 // if maxp1.lt.1, the routine will end with ier = 6. 105 // 106 // on return 107 // result - double precision 108 // approximation to the integral 109 // 110 // abserr - double precision 111 // estimate of the modulus of the absolute error, 112 // which should equal or exceed abs(i-result) 113 // 114 // neval - integer 115 // number of integrand evaluations 116 // 117 // ier - integer 118 // ier = 0 normal and reliable termination of the 119 // routine. it is assumed that the 120 // requested accuracy has been achieved. 121 // - ier.gt.0 abnormal termination of the routine. 122 // the estimates for integral and error are 123 // less reliable. it is assumed that the 124 // requested accuracy has not been achieved. 125 // error messages 126 // ier = 1 maximum number of subdivisions allowed 127 // has been achieved. one can allow more 128 // subdivisions by increasing the value of 129 // limit (and taking according dimension 130 // adjustments into account). however, if 131 // this yields no improvement it is advised 132 // to analyze the integrand, in order to 133 // determine the integration difficulties. 134 // if the position of a local difficulty can 135 // be determined (e.g. singularity, 136 // discontinuity within the interval) one 137 // will probably gain from splitting up the 138 // interval at this point and calling the 139 // integrator on the subranges. if possible, 140 // an appropriate special-purpose integrator 141 // should be used which is designed for 142 // handling the type of difficulty involved. 143 // = 2 the occurrence of roundoff error is 144 // detected, which prevents the requested 145 // tolerance from being achieved. 146 // the error may be under-estimated. 147 // = 3 extremely bad integrand behaviour occurs 148 // at some points of the integration 149 // interval. 150 // = 4 the algorithm does not converge. 151 // roundoff error is detected in the 152 // extrapolation table. 153 // it is presumed that the requested 154 // tolerance cannot be achieved due to 155 // roundoff in the extrapolation table, 156 // and that the returned result is the 157 // best which can be obtained. 158 // = 5 the integral is probably divergent, or 159 // slowly convergent. it must be noted that 160 // divergence can occur with any other value 161 // of ier.gt.0. 162 // = 6 the input is invalid, because 163 // (epsabs.le.0 and 164 // epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) 165 // or (integr.ne.1 and integr.ne.2) or 166 // icall.lt.1 or maxp1.lt.1. 167 // result, abserr, neval, last, rlist(1), 168 // elist(1), iord(1) and nnlog(1) are set 169 // to zero. alist(1) and blist(1) are set 170 // to a and b respectively. 171 // 172 // last - integer 173 // on return, last equals the number of 174 // subintervals produces in the subdivision 175 // process, which determines the number of 176 // significant elements actually in the 177 // work arrays. 178 // alist - double precision 179 // vector of dimension at least limit, the first 180 // last elements of which are the left 181 // end points of the subintervals in the partition 182 // of the given integration range (a,b) 183 // 184 // blist - double precision 185 // vector of dimension at least limit, the first 186 // last elements of which are the right 187 // end points of the subintervals in the partition 188 // of the given integration range (a,b) 189 // 190 // rlist - double precision 191 // vector of dimension at least limit, the first 192 // last elements of which are the integral 193 // approximations on the subintervals 194 // 195 // elist - double precision 196 // vector of dimension at least limit, the first 197 // last elements of which are the moduli of the 198 // absolute error estimates on the subintervals 199 // 200 // iord - integer 201 // vector of dimension at least limit, the first k 202 // elements of which are pointers to the error 203 // estimates over the subintervals, 204 // such that elist(iord(1)), ..., 205 // elist(iord(k)) form a decreasing sequence, with 206 // k = last if last.le.(limit/2+2), and 207 // k = limit+1-last otherwise. 208 // 209 // nnlog - integer 210 // vector of dimension at least limit, containing the 211 // subdivision levels of the subintervals, i.e. 212 // iwork(i) = l means that the subinterval 213 // numbered i is of length abs(b-a)*2**(1-l) 214 // 215 // on entry and return 216 // momcom - integer 217 // indicating that the chebyshev moments 218 // have been computed for intervals of lengths 219 // (abs(b-a))*2**(-l), l=0,1,2, ..., momcom-1, 220 // momcom.lt.maxp1 221 // 222 // chebmo - double precision 223 // array of dimension (maxp1,25) containing the 224 // chebyshev moments 225 // 226 //***references (none) 227 //***routines called d1mach,dqc25f,dqelg,dqpsrt 228 //***end prologue dqawoe 229 // 230 Real abseps, area, area1, area12, area2, a1, 231 a2, b1, b2, correc, defab1, defab2, defabs, 232 domega, dres, epmach, erlarg, erlast, 233 errbnd, errmax, error1, erro12, error2, errsum, ertest, oflow, 234 resabs, reseps, small, uflow, width; 235 int id=1, ierro=1, iroff1=1, iroff2=1, iroff3=1, 236 jupbnd=1, k=1, ksgn=1, ktmin=1, maxerr=1, nev=1, 237 nres=1, nrmax=1, nrmom=1, numrl2=1; 238 bool extrap, noext, extall; 239 // 240 auto alist = dimension(alist_, limit); 241 auto blist = dimension(blist_, limit); 242 auto rlist = dimension(rlist_, limit); 243 auto elist = dimension(elist_, limit); 244 auto iord = dimension(iord_, limit); 245 Real[52] rlist2_; 246 auto rlist2 = dimension(rlist2_.ptr, 52); 247 Real[3] res3la_; 248 auto res3la = dimension(res3la_.ptr, 3); 249 auto chebmo = dimension(chebmo_, maxp1, 25); 250 auto nnlog = dimension(nnlog_, limit); 251 // 252 // the dimension of rlist2 is determined by the value of 253 // limexp in subroutine dqelg (rlist2 should be of 254 // dimension (limexp+2) at least). 255 // 256 // list of major variables 257 // ----------------------- 258 // 259 // alist - list of left end points of all subintervals 260 // considered up to now 261 // blist - list of right end points of all subintervals 262 // considered up to now 263 // rlist(i) - approximation to the integral over 264 // (alist(i),blist(i)) 265 // rlist2 - array of dimension at least limexp+2 266 // containing the part of the epsilon table 267 // which is still needed for further computations 268 // elist(i) - error estimate applying to rlist(i) 269 // maxerr - pointer to the interval with largest 270 // error estimate 271 // errmax - elist(maxerr) 272 // erlast - error on the interval currently subdivided 273 // area - sum of the integrals over the subintervals 274 // errsum - sum of the errors over the subintervals 275 // errbnd - requested accuracy max(epsabs,epsrel* 276 // abs(result)) 277 // *****1 - variable for the left subinterval 278 // *****2 - variable for the right subinterval 279 // last - index for subdivision 280 // nres - number of calls to the extrapolation routine 281 // numrl2 - number of elements in rlist2. if an appropriate 282 // approximation to the compounded integral has 283 // been obtained it is put in rlist2(numrl2) after 284 // numrl2 has been increased by one 285 // small - length of the smallest interval considered 286 // up to now, multiplied by 1.5 287 // erlarg - sum of the errors over the intervals larger 288 // than the smallest interval considered up to now 289 // extrap - logical variable denoting that the routine is 290 // attempting to perform extrapolation, i.e. before 291 // subdividing the smallest interval we try to 292 // decrease the value of erlarg 293 // noext - logical variable denoting that extrapolation 294 // is no longer allowed (true value) 295 // 296 // machine dependent constants 297 // --------------------------- 298 // 299 // epmach is the largest relative spacing. 300 // uflow is the smallest positive magnitude. 301 // oflow is the largest positive magnitude. 302 // 303 //***first executable statement dqawoe 304 epmach = Real.epsilon; 305 // 306 // test on validity of parameters 307 // ------------------------------ 308 // 309 ier = 0; 310 neval = 0; 311 last = 0; 312 result = 0.0; 313 abserr = 0.0; 314 alist[1] = a; 315 blist[1] = b; 316 rlist[1] = 0.0; 317 elist[1] = 0.0; 318 iord[1] = 0; 319 nnlog[1] = 0; 320 if ((integr != 1 && integr != 2) || (epsabs <= 0.0 && 321 epsrel < 0.5e2*epmach) || icall < 1 || 322 maxp1 < 1) ier = 6; 323 if (ier == 6) goto l999; 324 // 325 // first approximation to the integral 326 // ----------------------------------- 327 // 328 domega = fabs(omega); 329 nrmom = 0; 330 if (icall > 1) goto l5; 331 momcom = 0; 332 l5: qc25f!(Real, Func)(f, a, b, domega, integr, nrmom, maxp1, 0, result, abserr, 333 neval, defabs, resabs, momcom, chebmo.ptr); 334 // 335 // test on accuracy. 336 // 337 dres = fabs(result); 338 errbnd = max(epsabs, epsrel*dres); 339 rlist[1] = result; 340 elist[1] = abserr; 341 iord[1] = 1; 342 if (abserr <= 0.1e3*epmach*defabs && abserr > errbnd) ier = 2; 343 if (limit == 1) ier = 1; 344 if (ier != 0 || abserr <= errbnd) goto l200; 345 // 346 // initializations 347 // --------------- 348 // 349 uflow = Real.min_normal; 350 oflow = Real.max; 351 errmax = abserr; 352 maxerr = 1; 353 area = result; 354 errsum = abserr; 355 abserr = oflow; 356 nrmax = 1; 357 extrap = false; 358 noext = false; 359 ierro = 0; 360 iroff1 = 0; 361 iroff2 = 0; 362 iroff3 = 0; 363 ktmin = 0; 364 small = fabs(b-a)*0.75; 365 nres = 0; 366 numrl2 = 0; 367 extall = false; 368 if (0.5*fabs(b-a)*domega > 0.2e1) goto l10; 369 numrl2 = 1; 370 extall = true; 371 rlist2[1] = result; 372 l10: if (0.25*fabs(b-a)*domega <= 0.2e1) extall = true; 373 ksgn = -1; 374 if(dres >= (0.1e1-0.5e2*epmach)*defabs) ksgn = 1; 375 // 376 // main do-loop 377 // ------------ 378 // 379 for (last = 2; last <= limit; last++) // end: l140 380 { 381 // 382 // bisect the subinterval with the nrmax-th largest 383 // error estimate. 384 // 385 nrmom = nnlog[maxerr]+1; 386 a1 = alist[maxerr]; 387 b1 = 0.5*(alist[maxerr]+blist[maxerr]); 388 a2 = b1; 389 b2 = blist[maxerr]; 390 erlast = errmax; 391 qc25f!(Real, Func)(f,a1,b1,domega,integr,nrmom,maxp1,0, 392 area1,error1,nev,resabs,defab1,momcom,chebmo.ptr); 393 neval = neval+nev; 394 qc25f!(Real, Func)(f,a2,b2,domega,integr,nrmom,maxp1,1, 395 area2,error2,nev,resabs,defab2,momcom,chebmo.ptr); 396 neval = neval+nev; 397 // 398 // improve previous approximations to integral 399 // and error and test for accuracy. 400 // 401 area12 = area1+area2; 402 erro12 = error1+error2; 403 errsum = errsum+erro12-errmax; 404 area = area+area12-rlist[maxerr]; 405 if (defab1 == error1 || defab2 == error2) goto l25; 406 if (fabs(rlist[maxerr]-area12) > 0.1e-4*fabs(area12) 407 || erro12 < 0.99*errmax) goto l20; 408 if (extrap) iroff2 = iroff2+1; 409 else iroff1 = iroff1+1; 410 l20: if (last > 10 && erro12 > errmax) iroff3 = iroff3+1; 411 l25: rlist[maxerr] = area1; 412 rlist[last] = area2; 413 nnlog[maxerr] = nrmom; 414 nnlog[last] = nrmom; 415 errbnd = max(epsabs, epsrel*fabs(area)); 416 // 417 // test for roundoff error and eventually set error flag. 418 // 419 if (iroff1+iroff2 >= 10 || iroff3 >= 20) ier = 2; 420 if (iroff2 >= 5) ierro = 3; 421 // 422 // set error flag in the case that the number of 423 // subintervals equals limit. 424 // 425 if (last == limit) ier = 1; 426 // 427 // set error flag in the case of bad integrand behaviour 428 // at a point of the integration range. 429 // 430 if (max(fabs(a1),fabs(b2)) <= (0.1e1+0.1e3*epmach) 431 * (fabs(a2)+0.1e4*uflow)) ier = 4; 432 // 433 // append the newly-created intervals to the list. 434 // 435 if(error2 > error1) goto l30; 436 alist[last] = a2; 437 blist[maxerr] = b1; 438 blist[last] = b2; 439 elist[maxerr] = error1; 440 elist[last] = error2; 441 goto l40; 442 l30: alist[maxerr] = a2; 443 alist[last] = a1; 444 blist[last] = b1; 445 rlist[maxerr] = area2; 446 rlist[last] = area1; 447 elist[maxerr] = error2; 448 elist[last] = error1; 449 // 450 // call subroutine dqpsrt to maintain the descending ordering 451 // in the list of error estimates and select the subinterval 452 // with nrmax-th largest error estimate (to bisected next). 453 // 454 l40: qpsrt!Real(limit,last,maxerr,errmax,elist.ptr,iord.ptr,nrmax); 455 // ***jump out of do-loop 456 if (errsum <= errbnd) goto l170; 457 if (ier != 0) goto l150; 458 if (last == 2 && extall) goto l120; 459 if (noext) goto l140; 460 if (!extall) goto l50; 461 erlarg = erlarg-erlast; 462 if (fabs(b1-a1) > small) erlarg = erlarg+erro12; 463 if (extrap) goto l70; 464 // 465 // test whether the interval to be bisected next is the 466 // smallest interval. 467 // 468 l50: width = fabs(blist[maxerr]-alist[maxerr]); 469 if (width > small) goto l140; 470 if (extall) goto l60; 471 // 472 // test whether we can start with the extrapolation procedure 473 // (we do this if we integrate over the next interval with 474 // use of a gauss-kronrod rule - see subroutine dqc25f). 475 // 476 small = small*0.5; 477 if (0.25*width*domega > 0.2e1) goto l140; 478 extall = true; 479 goto l130; 480 l60: extrap = true; 481 nrmax = 2; 482 l70: if (ierro == 3 || erlarg <= ertest) goto l90; 483 // 484 // the smallest interval has the largest error. 485 // before bisecting decrease the sum of the errors over 486 // the larger intervals (erlarg) and perform extrapolation. 487 // 488 jupbnd = last; 489 if (last > (limit/2+2)) jupbnd = limit+3-last; 490 id = nrmax; 491 for (k = id; k<=jupbnd; k++) // end: l80 492 { 493 maxerr = iord[nrmax]; 494 errmax = elist[maxerr]; 495 if(fabs(blist[maxerr]-alist[maxerr]) > small) goto l140; 496 nrmax = nrmax+1; 497 l80:; } 498 // 499 // perform extrapolation. 500 // 501 l90: numrl2 = numrl2+1; 502 rlist2[numrl2] = area; 503 if (numrl2 < 3) goto l110; 504 qelg!Real(numrl2,rlist2.ptr,reseps,abseps,res3la.ptr,nres); 505 ktmin = ktmin+1; 506 if (ktmin > 5 && abserr < 0.1e-2*errsum) ier = 5; 507 if (abseps >= abserr) goto l100; 508 ktmin = 0; 509 abserr = abseps; 510 result = reseps; 511 correc = erlarg; 512 ertest = max(epsabs, epsrel*fabs(reseps)); 513 // ***jump out of do-loop 514 if (abserr <= ertest) goto l150; 515 // 516 // prepare bisection of the smallest interval. 517 // 518 l100: if (numrl2 == 1) noext = true; 519 if (ier == 5) goto l150; 520 l110: maxerr = iord[1]; 521 errmax = elist[maxerr]; 522 nrmax = 1; 523 extrap = false; 524 small = small*0.5; 525 erlarg = errsum; 526 goto l140; 527 l120: small = small*0.5; 528 numrl2 = numrl2+1; 529 rlist2[numrl2] = area; 530 l130: ertest = errbnd; 531 erlarg = errsum; 532 l140:;} 533 // 534 // set the final result. 535 // --------------------- 536 // 537 l150: if (abserr == oflow || nres == 0) goto l170; 538 if (ier+ierro == 0) goto l165; 539 if (ierro == 3) abserr = abserr+correc; 540 if (ier == 0) ier = 3; 541 if (result != 0.0 && area != 0.0) goto l160; 542 if (abserr > errsum) goto l170; 543 if (area == 0.0) goto l190; 544 goto l165; 545 l160: if (abserr/fabs(result) > errsum/fabs(area)) goto l170; 546 // 547 // test on divergence. 548 // 549 l165: if (ksgn == (-1) && max(fabs(result),fabs(area)) <= 550 defabs*0.1e-1) goto l190; 551 if (0.1e-1 > (result/area) || (result/area) > 0.1e3 552 || errsum >= fabs(area)) ier = 6; 553 goto l190; 554 // 555 // compute global integral sum. 556 // 557 l170: result = 0.0; 558 for (k=1; k<=last; k++) // end: l180 559 { 560 result = result+rlist[k]; 561 l180:;} 562 abserr = errsum; 563 l190: if (ier > 2) ier=ier-1; 564 l200: if (integr == 2 && omega < 0.0) result=-result; 565 l999: return; 566 } 567 568 569 unittest 570 { 571 alias qawoe!(float, float delegate(float)) fqawoe; 572 alias qawoe!(double, double delegate(double)) dqawoe; 573 alias qawoe!(double, double function(double)) dfqawoe; 574 alias qawoe!(real, real delegate(real)) rqawoe; 575 }