1 SUBROUTINE FUNLXP (FUNC,XFCUM,X2LOW,X2HIGH)
4 C Prepares the user function FUNC for FUNLUX
5 C Inspired by and mostly copied from FUNPRE and FUNRAN
7 C 1. FUNLUX uses RANLUX underneath,
8 C 2. FUNLXP expands the first and last bins to cater for
9 C functions with long tails on left and/or right,
10 C 3. FUNLXP calls FUNPCT to do the actual finding of percentiles.
11 C 4. both FUNLXP and FUNPCT use RADAPT for Gaussian integration.
16 PARAMETER (RTEPS=0.0002)
20 C FIND RANGE WHERE FUNCTION IS NON-ZERO.
21 CALL FUNLZ(FUNC,X2LOW,X2HIGH,XLOW,XHIGH)
23 IF(XRANGE .LE. 0.) THEN
24 WRITE (6,'(A,2G15.5)') ' FUNLXP finds function range .LE.0',
28 CALL RADAPT(FUNC,XLOW,XHIGH,1,RTEPS,0.,TFTOT ,UNCERT)
29 WRITE(6,1003) IFUNC,XLOW,XHIGH,TFTOT
30 1003 FORMAT(' FUNLXP: integral of USER FUNCTION',
31 + I3,' from ',E12.5,' to ',E12.5,' is ',E14.6)
33 C WRITE (6,'(A,A)') ' FUNLXP preparing ',
34 C + 'first the whole range, then left tail, then right tail.'
35 CALL FUNPCT(FUNC,IFUNC,XLOW,XHIGH,XFCUM,1,99,TFTOT,IERR)
36 IF (IERR .GT. 0) GO TO 900
38 CALL RADAPT(FUNC,XLOW,X2,1,RTEPS,0.,TFTOT1 ,UNCERT)
39 CALL FUNPCT(FUNC,IFUNC,XLOW,X2 ,XFCUM,101,49,TFTOT1,IERR)
40 IF (IERR .GT. 0) GO TO 900
42 CALL RADAPT(FUNC,X3,XHIGH,1,RTEPS,0.,TFTOT2 ,UNCERT)
43 CALL FUNPCT(FUNC,IFUNC,X3,XHIGH,XFCUM,151,49,TFTOT2,IERR)
44 IF (IERR .GT. 0) GO TO 900
45 WRITE(6,1001) IFUNC,XLOW,XHIGH
46 1001 FORMAT(' FUNLXP has prepared USER FUNCTION',I3,
47 + ' between',G12.3,' and',G12.3,' for FUNLUX')
50 WRITE (6,'(A)') ' Fatal error in FUNLXP. FUNLUX will not work.'
53 SUBROUTINE FUNPCT(FUNC,IFUNC,XLOW,XHIGH,XFCUM,NLO,NBINS,TFTOT,
55 C Array XFCUM is filled from NLO to NLO+NBINS, which makes
56 C the number of values NBINS+1, or the number of bins NBINS
59 PARAMETER (RTEPS=0.005, NZ=10, MAXZ=20, NITMAX=6,PRECIS=1.E-6)
60 CC DOUBLE PRECISION TPCTIL, TZ, TCUM, XINCR, DTABS,
61 CC + TINCR, TZMAX, XBEST, DTBEST, DTPAR2
64 IF (TFTOT .LE. 0.) GO TO 900
69 XFCUM(NLO+NBINS) = XHIGH
72 IF (F .LT. 0.) GO TO 900
73 C Loop over percentile bins
74 DO 600 IBIN = NLO, NLO+NBINS-2
78 DXMAX = (XHIGH -X) / NZ
81 C Loop over trapezoids within a supposed percentile
83 XINCR = TZ/MAX(F1,FMIN,FMINZ)
86 IF (F .LT. 0.) GO TO 900
87 TINCR = (X-X1) * 0.5 * (F+F1)
88 IF (TINCR .LT. TZMAX) GO TO 370
93 IF (TCUM .GE. TPCTIL*0.99) GO TO 520
94 FMINZ = TZ*F/ (TPCTIL-TCUM)
98 WRITE(6,'(A)') ' FUNLUX: WARNING. FUNPCT fails trapezoid.'
99 C END OF TRAPEZOID LOOP
100 C Adjust interval using Gaussian integration with
101 C Newton corrections since F is the derivative
107 C Allow for maximum NITMAX more iterations on RADAPT
108 DO 550 IHOME= 1, NITMAX
109 535 XINCR = (TPCTIL-TPART) / MAX(F,FMIN)
112 IF (IHOME .GT. 1 .AND. X2 .EQ. XBEST) THEN
113 WRITE (6,'(A,G12.3)')
114 + ' FUNLUX: WARNING from FUNPCT: insufficient precision at X=',X
118 CALL RADAPT(FUNC,X1,X2,1,RTEPS,0.,TPART2,UNCERT)
119 DTPAR2 = TPART2-TPCTIL
121 IF(ABS(XINCR)/REFX .LT. PRECIS) GOTO 545
122 IF(DTABS .LT. DTBEST) GOTO 545
129 IF(F .LT. 0.) GOTO 900
130 IF(DTABS .LT. RTEPS*TPCTIL) GOTO 580
133 + ' FUNLUX: WARNING from FUNPCT: cannot converge, bin',IBIN
136 XINCR = (TPCTIL-TPART) / MAX(F,FMIN)
140 IF(F .LT. 0.) GOTO 900
142 C END OF LOOP OVER BINS
143 X1 = XFCUM(NLO+NBINS-1)
145 CALL RADAPT(FUNC,X1,X2,1,RTEPS,0.,TPART ,UNCERT)
146 ABERR = ABS(TPART-TPCTIL)/TFTOT
147 C WRITE(6,1001) IFUNC,XLOW,XHIGH
148 IF(ABERR .GT. RTEPS) WRITE(6,1002) ABERR
150 900 WRITE(6,1000) X,F
153 1000 FORMAT(/' FUNLUX fatal error in FUNPCT: function negative:'/
154 + ,' at X=',E15.6,', F=',E15.6/)
155 C 1001 FORMAT(' FUNPCT has prepared USER FUNCTION',I3,
156 C + ' between',G12.3,' and',G12.3,' for FUNLUX.')
157 1002 FORMAT(' WARNING: Relative error in cumulative distribution',
158 + ' may be as big as',F10.7)
160 SUBROUTINE FUNLUX(ARRAY,XRAN,LEN)
161 C Generation of LEN random numbers in any given distribution,
162 C by 4-point interpolation in the inverse cumulative distr.
163 C which was previously generated by FUNLXP
167 C Bin width for main sequence, and its inverse
168 PARAMETER (GAP= 1./99., GAPINV=99.)
169 C Top of left tail, bottom of right tail (each tail replaces 2 bins)
170 PARAMETER (TLEFT= 2./99.,BRIGHT=97./99.)
171 C Bin width for minor sequences (tails), and its inverse
172 PARAMETER (GAPS=TLEFT/49., GAPINS=1./GAPS)
174 C The array ARRAY is assumed to have the following structure:
175 C ARRAY(1-100) contains the 99 bins of the inverse cumulative
176 C distribution of the entire function.
177 C ARRAY(101-150) contains the 49-bin blowup of main bins
178 C 1 and 2 (left tail of distribution)
179 C ARRAY(151-200) contains the 49-bin blowup of main bins
180 C 98 and 99 (right tail of distribution)
182 CALL RANLUX(XRAN,LEN)
186 J = INT( X *GAPINV) + 1
192 P = ( X -GAPS*(J1-1)) * GAPINS
193 A = (P+1.0) * ARRAY(J+2) - (P-2.0)*ARRAY(J-1)
194 B = (P-1.0) * ARRAY(J) - P * ARRAY(J+1)
195 XRAN(IBUF) = A*P*(P-1.0)*0.16666667 + B*(P+1.0)*(P-2.0)*0.5
196 ELSE IF (J .GT. 97) THEN
197 J1 = INT((X-BRIGHT)*GAPINS)
201 P = (X -BRIGHT -GAPS*(J1-1)) * GAPINS
202 A = (P+1.0) * ARRAY(J+2) - (P-2.0)*ARRAY(J-1)
203 B = (P-1.0) * ARRAY(J) - P * ARRAY(J+1)
204 XRAN(IBUF) = A*P*(P-1.0)*0.16666667 + B*(P+1.0)*(P-2.0)*0.5
208 P = ( X -GAP*(J-1)) * GAPINV
209 A = (P+1.0) * ARRAY(J+2) - (P-2.0)*ARRAY(J-1)
210 B = (P-1.0) * ARRAY(J) - P * ARRAY(J+1)
211 XRAN(IBUF) = A*P*(P-1.0)*0.16666667 + B*(P+1.0)*(P-2.0)*0.5
217 SUBROUTINE FUNLZ(FUNC,X2LOW,X2HIGH,XLOW,XHIGH)
218 C FIND RANGE WHERE FUNC IS NON-ZERO.
219 C WRITTEN 1980, F. JAMES
220 C MODIFIED, NOV. 1985, TO FIX BUG AND GENERALIZE
221 C TO FIND SIMPLY-CONNECTED NON-ZERO REGION (XLOW,XHIGH)
222 C ANYWHERE WITHIN THE GIVEN REGION (X2LOW,H2HIGH).
223 C WHERE 'ANYWHERE' MEANS EITHER AT THE LOWER OR UPPER
224 C EDGE OF THE GIVEN REGION, OR, IF IN THE MIDDLE,
225 C COVERING AT LEAST 1% OF THE GIVEN REGION.
226 C OTHERWISE IT IS NOT GUARANTEED TO FIND THE NON-ZERO REGION.
227 C IF FUNCTION EVERYWHERE ZERO, FUNLZ SETS XLOW=XHIGH=0.
231 C FIND OUT IF FUNCTION IS ZERO AT ONE END OR BOTH
233 IF (FUNC(XLOW) .GT. 0.) GO TO 120
235 IF (FUNC(XHIGH) .GT. 0.) GO TO 50
236 C FUNCTION IS ZERO AT BOTH ENDS,
237 C LOOK FOR PLACE WHERE IT IS NON-ZERO.
240 DO 20 I= 1, NSLICE, 2
241 XMID = XLOW + I * (XHIGH-XLOW) / NSLICE
242 IF (FUNC(XMID) .GT. 0.) GO TO 50
245 C FALLING THROUGH LOOP MEANS CANNOT FIND NON-ZERO VALUE
247 WRITE(6,555) XLOW, XHIGH
253 C DELETE 'LEADING' ZERO RANGE
258 IF (FUNC(XNEW) .EQ. 0.) GO TO 68
264 WRITE(6,555) X2LOW,XLOW
266 IF (FUNC(XHIGH) .GT. 0.) GO TO 220
267 C DELETE 'TRAILING' RANGE OF ZEROES
272 IF (FUNC(XNEW) .EQ. 0.) GO TO 168
278 WRITE(6,555) XHIGH, X2HIGH
282 554 FORMAT('0CANNOT FIND NON-ZERO FUNCTION VALUE')
283 555 FORMAT(' FUNCTION IS ZERO FROM X=',E12.5,' TO ',E12.5)