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 }