1C*************************************************************
2C BOOLE: Performs 5-point Newton-Cotes integration of tabulated data
3C X: vector of independent variable values (x)
4C Y: vector dependent variable values ( f(x) )
5C N: number of elements in X
6C NN: number of elements desired in interpolated grid (should be 1+4*A)
7C S: returned, integrated value of the function
8C XI: returned grid in X
9C YI: returned interpolated values of Y
10C
11C Data need to be evenly gridded for the integration formula to work.
12C Data that are not already so are interpolated onto an even grid
13C using spline interpolation (SPLINJ for the second derivatives and
14C SPLINT to evaluate).
15C 10/14/26 MHP via Claude
16C comment corrected: it credited "numerical recipes SPLINE (renamed
17C splinnr)", but this routine calls SPLINJ and SPLINT. splinnr was never
18C reachable and has been deleted; see KNOWN_ISSUES.md issue 24.
19C*************************************************************
20C PARAMETER(NN = 17)
21C PARAMETER(N = 16)
22C DATA Y/6.40,5.041,3.844,2.809,1.936,1.225,0.676,0.289,0.064,0.361,
23C *0.784,1.369,2.116,3.025,4.096,5.329/
24C DATA X/-8.0,-7.1,-6.2,-5.3,-4.4,-3.5,-2.6,-1.7,0.8,1.9,2.8,3.7,
25C *4.6,5.5,6.4,7.3/
26
27
28 SUBROUTINE BOOLE(X,Y,N,NN,S)
29C 10/20/26 MHP via Claude
30C code changed to replace implicit typing with IMPLICIT NONE and
31C explicit declarations.
32 IMPLICIT NONE
33 REAL*8 S,SCALEX,SCALEY,X,XD,XI,Y,YD,YI
34 PARAMETER(SCALEX=1D-11)
35 PARAMETER(SCALEY=1e7)
36 REAL*8 H(1),D2X(N)
37 DIMENSION X(N), Y(N),XI(NN), YI(NN), S(1), XD(N), YD(N)
38 INTEGER I, N, NN, P, KLO, KHI
39
40
41C Rescale radius and cs vectors to have values ~1
42 DO 22 I=1,N
43 XD(I)=X(I)*SCALEX
44 YD(I)=Y(I)*SCALEY
4522 22 CONTINUE
46C Deal with unevenly gridded datasets:
47C IF (.NOT.LEVEN) THEN ! do for all
48 CALL SPLINJ(XD,YD,D2X,N) ! get derivs of interp. fn.
49 DO 20, I=1,NN
50 XI(I)=XD(1)+(I-1)*(XD(N)-XD(1))/(NN-1)
51 CALL SPLINT(XD,YD,N,D2X,XI(I),YI(I),KLO,KHI)
5220 20 CONTINUE
53
54
55C How many sets of four points do we have?
56 P=(NN-1)/4
57 H=(XD(N)-XD(1))/(NN-1)
58C For each set of 4 points before the last, apply formula and add up
59 S=0.0D0
60 DO 21, I=0,P-1
61 S=S+2.0*H*(7*YI(1+4*I)+ 32*YI(2+4*I) + 12*YI(3+4*I) +
62 * * 32*YI(4+4*I) + 7*YI(5+4*I))/45.0
6321 21 CONTINUE
64C Rescale result back to actual units:
65 S=S/(SCALEX*SCALEY)
66C PRINT*, 'Last point in vector:', NN
67C PRINT*, 'Last point integrated:',5+4*(P-1)
68
69C--------------------------------------------------------------
70C OPEN(UNIT=100,FILE='diagnostic3.out',STATUS='OLD')
71C DO 1505 I=1,N
72C WRITE(100,1504), X(I), Y(I), XD(I), YD(I),
73C * XI(I), YI(I), S(1), H(1)
74C1505 CONTINUE
75C1504 FORMAT(1X,8E16.8)
76C CLOSE(100)
77C----------------------------------------------------------------
78
79 END
80
81
82
1"""Python version of boole.f (YREC development, 7be4133)."""
2
3import numpy as np
4
5from pyrec.splinj import splinj
6from pyrec.splint import splint
7
8SCALEX = 1.0e-11
9SCALEY = 1.0e7
10
11
12def boole(x: np.ndarray, y: np.ndarray, n: int, nn: int, s: float) -> float:
13 """Integrate tabulated data with Boole's rule after spline resampling.
14
15 The data are rescaled, fitted with a cubic spline, evaluated at ``nn``
16 evenly spaced points, integrated with Boole's rule (5-point
17 Newton-Cotes) and scaled back. Only use: the acoustic depth in CALCAD.
18
19 Translates: boole.f#BOOLE (7be4133)
20
21 Parameters
22 ----------
23 x, y : ndarray, shape (n + 1,)
24 The tabulated abscissae and values, ``x[1..n]``, ``y[1..n]``.
25 n : int
26 Number of tabulated points.
27 nn : int
28 Number of points of the even grid; should be 1 + 4p.
29 s : float
30 Output only (Fortran declares it ``S(1)``, used as a scalar).
31
32 Returns
33 -------
34 s : float
35 The integral of ``y`` over ``x``.
36
37 """
38
39 # The automatic arrays (Fortran lines 36–37).
40 xd = np.zeros(n + 1)
41 yd = np.zeros(n + 1)
42 d2x = np.zeros(n + 1)
43 xi = np.zeros(nn + 1)
44 yi = np.zeros(nn + 1)
45 klo = khi = 0
46
47 # Rescale radius and sound-speed vectors to values near 1 (label 22,
48 # Fortran lines 41–45).
49 # Question (see the page): are the fixed scales needed?
50 for i in range(1, n + 1):
51 xd[i] = x[i] * SCALEX
52 yd[i] = y[i] * SCALEY
53
54 # Interpolate onto an even grid (done for all data sets; label 20,
55 # Fortran lines 46–52).
56 splinj(xd, yd, d2x, n)
57 for i in range(1, nn + 1):
58 xi[i] = xd[1] + (i - 1) * (xd[n] - xd[1]) / (nn - 1)
59 yi[i], klo, khi = splint(xd, yd, n, d2x, xi[i], yi[i], klo, khi)
60
61 # Boole's rule over each set of four intervals; Fortran's integer
62 # division (Fortran lines 55–63). CALCAD passes nn - 1 a multiple of 4.
63 p = (nn - 1) // 4
64 h = (xd[n] - xd[1]) / (nn - 1)
65 s = 0.0
66 for i in range(0, p): # label 21
67 s = s + 2.0 * h * (7 * yi[1 + 4 * i] + 32 * yi[2 + 4 * i]
68 + 12 * yi[3 + 4 * i] + 32 * yi[4 + 4 * i]
69 + 7 * yi[5 + 4 * i]) / 45.0
70
71 # Rescale the result back to actual units (Fortran line 65).
72 s = s / (SCALEX * SCALEY)
73 return s