1
2
3C$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
4C CHOOSE
5C$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
6 SUBROUTINE CHOOSE(P1,P2,M1,M2,Q1,Q2,EPS,NCASE)
7C 10/20/26 MHP via Claude
8C code changed to replace implicit typing with IMPLICIT NONE and
9C explicit declarations.
10 IMPLICIT NONE
11 INTEGER NCASE
12C
13C SHAPE PRESERVING QUADRATIC SPLINES
14C BY D.F.MCALLISTER & J.A. ROULIER
15C CODED BY S.L.DODD & M.ROULIER
16C
17 REAL*8 P1,P2,M1,M2,Q1,Q2,MREF,MREF1,MREF2,SPQ,PROD,
18 * * PROD1,PROD2,EPS
19C
20C CHOOSE DETERMINES THE CASE NEEDED FOR THE COMPUTATION OF THE PARAME-
21C TERS OF THE QUADRATIC SPLINE AND RETURNS THE VALUE IN THE VARIABLE
22C NCASE.
23C
24C ON INPUT--
25C
26C (P1,P2) GIVES THE COORDINATES OF ONE OF THE POINTS OF INTERPOLATION.
27C
28C M1 SPECIFIES THE DERIVATIVE CONDITION AT (P1,P2).
29C
30C (Q1,Q2) GIVES THE COORDINATES OF ONE OF THE POINTS OF INTERPOLATION.
31C
32C M2 SPECIFIES THE DERIVATIVE CONDITION AT (Q1,Q2).
33C
34C EPS IS AN ERROR TOLERANCE USED TO DISTINGUISH CASES WHEN M1 OR M2 IS
35C RELATIVELY CLOSE TO THE SLOPE OR TWICE THE SLOPE OF THE LINE
36C SEGMENT JOINING (P1,P2) AND (Q1,Q2). IF EPS IS NOT EQUAL TO ZERO,
37C THEN EPS SHOULD BE GREATER THAN OR EQUAL TO MACHINE EPSILON.
38C
39C
40C ON OUTPUT--
41C
42C NCASE CONTAINS THE VALUE WHICH CONTROLS HOW THE PARAMETERS OF THE
43C QUADRATIC SPLINE ARE EVALUATED.
44C
45C AND
46C
47C CHOOSE DOES NOT ALTER P1,P2,Q1,Q2,M1,M2,EPS.
48C
49C----------------------------------------------------------------------
50C
51C CALCULATE THE SLOPE SPQ OF THE LINE JOINING (P1,P2),(Q1,Q2).
52 SPQ=(Q2-P2)/(Q1-P1)
53C
54C CHECK WHETHER OR NOT SPQ IS 0.
55C ******MODIFICATION BY MARC PINSONNEAULT TO AVOID DIVISION BY ZERO
56C ******IN SR CASES
57 IF(M1.EQ.0.0D0.OR.M2.EQ.0.0D0) GOTO 9
58C ******
59 IF (SPQ .NE. 0.D0) GO TO 20
60 IF ((M1*M2) .GE. 0.D0) GO TO 10
61 NCASE=1
62 RETURN
63 9 9 CONTINUE
64 10 10 NCASE=2
65 RETURN
66C
67 20 20 PROD1=SPQ*M1
68 PROD2=SPQ*M2
69C
70C FIND THE ABSOLUTE VALUES OF THE SLOPES SPQ,M1,AND M2.
71 MREF=ABS(SPQ)
72 MREF1=ABS(M1)
73 MREF2=ABS(M2)
74C
75C IF THE RELATIVE DEVIATION OF M1 OR M2 FROM SPQ IS LESS THAN EPS, THEN
76C CHOOSE CASE 2 OR CASE 3.
77 IF ((ABS(SPQ-M1).LE.EPS*MREF) .OR. (ABS(SPQ-M2).LE.EPS*MREF))
78 * * GO TO 30
79C
80C COMPARE THE SIGNS OF THE SLOPES SPQ,M1, AND M2.
81 IF ((PROD1 .LT. 0.D0).OR.(PROD2 .LT. 0.D0)) GO TO 80
82 PROD=(MREF-MREF1)*(MREF-MREF2)
83 IF (PROD .GE. 0.D0) GO TO 40
84C
85C L1, THE LINE THROUGH (P1,P2) WITH SLOPE M1, AND L2, THE LINE THROUGH
86C (Q1,Q2) WITH SLOPE M2, INTERSECT AT A POINT WHOSE ABSCISSA IS BETWEEN
87C P1 AND Q1. THE ABSCISSA BECOMES A KNOT OF THE SPLINE.
88 NCASE=1
89 RETURN
90C
91 30 30 IF ((PROD1 .LT. 0.D0).OR.(PROD2 .LT. 0.D0)) GO TO 80
92 40 40 IF (MREF1 .GT. (2.D0*MREF)) GO TO 50
93 IF (MREF2 .GT. (2.D0*MREF)) GO TO 60
94C
95C BOTH L1 AND L2 CROSS THE LINE THROUGH (P1+Q1/2.,P2) AND (P1+Q1/2.,Q2),
96C WHICH IS THE MIDLINE OF THE RECTANGLE FORMED BY (P1,P2),(Q1,P2),
97C (Q1,Q2), AND (P1,Q2), OR BOTH M1 AND M2 HAVE SIGNS DIFFERENT THAN THE
98C SIGN OF SPQ, OR ONE OF M1 AND M2 HAS OPPOSITE SIGN FROM SPQ AND L1
99C AND L2 INTERSECT TO THE LEFT OF P1 OR TO THE RIGHT OF Q1. THE POINT
100C (P1+Q1)/2. IS A KNOT OF THE SPLINE.
101 NCASE=2
102 RETURN
103C
104C CHOOSE CASE 4 IF MREF2 IS GREATER THAN (2.-EPS)*MREF; OTHERWISE,
105C CHOOSE CASE 3.
106 50 50 IF (MREF2 .GT. (2.D0-EPS)*MREF) GO TO 70
107 NCASE=3
108 RETURN
109C
110C IN CASES 3 AND 4, SIGN(M1)=SIGN(M2)=SIGN(SPQ).
111C
112C EITHER L1 OR L2 CROSSES THE MIDLINE, BUT NOT BOTH.
113C CHOOSE CASE 4 IF MREF1 IS GREATER THAN (2.-EPS)*MREF; OTHERWISE,
114C CHOOSE CASE 3.
115 60 60 IF (MREF1 .GT. (2.D0-EPS)*MREF) GO TO 70
116 NCASE=3
117 RETURN
118C
119C IF NEITHER L1 NOR L2 CROSSES THE MIDLINE, THE SPLINE REQUIRES TWO
120C KNOTS BETWEEN P1 AND Q1.
121 70 70 NCASE=4
122 RETURN
123C
124C THE SIGN OF AT LEAST ONE OF THE SLOPES M1,M2 DOES NOT AGREE WITH THE
125C SIGN OF THE SLOPE SPQ.
126 80 80 IF ((PROD1 .LT. 0.D0).AND.(PROD2 .LT. 0.D0)) GO TO 130
127C
128 IF (PROD1 .LT. 0.D0) GO TO 90
129 GO TO 110
130C
131 90 90 IF (MREF2 .GT. ((1.D0+EPS)*MREF)) GO TO 100
132 NCASE=2
133 RETURN
134C
135 100 100 NCASE=1
136 RETURN
137C
138 110 110 IF (MREF1 .GT. ((1.D0+EPS)*MREF)) GO TO 120
139 NCASE=2
140 RETURN
141C
142 120 120 NCASE=1
143 RETURN
144C
145 130 130 NCASE=2
146 RETURN
147C
148 END
1"""Python version of choose.f (YREC 7be4133): the case of the shape-
2preserving quadratic spline (McAllister and Roulier) for one interval."""
3
4
5def choose(p1: float, p2: float, m1: float, m2: float, q1: float, q2: float, eps: float, ncase: int) -> int:
6 """Choose which of the four cases of McAllister and Roulier's
7 quadratic spline the interval needs, from the end slopes and the
8 slope of the chord.
9
10 Translates: choose.f#CHOOSE (7be4133)
11
12 Arguments: (p1, p2), (q1, q2), the points of interpolation; m1, m2,
13 the slopes there; eps, the tolerance for slopes close to the chord's
14 slope or twice it; ncase, passed in (with any value).
15
16 Returns ncase, 1 to 4.
17
18 """
19
20 # The slope of the chord (Fortran line 52).
21 # Question (see the page): no check that q1 != p1.
22 spq = (q2 - p2) / (q1 - p1)
23
24 # Modification by Marc Pinsonneault, to avoid a division by zero in
25 # CASES: a zero end slope gives case 2 at once (Fortran line 57).
26 if m1 == 0.0 or m2 == 0.0:
27 return 2 # labels 9, 10
28
29 # A flat chord (Fortran lines 59–65).
30 if spq == 0.0:
31 if m1 * m2 >= 0.0:
32 return 2 # label 10
33 return 1
34
35 # Label 20: the end slopes against the chord's (Fortran lines 67–91).
36 prod1 = spq * m1
37 prod2 = spq * m2
38 mref = abs(spq)
39 mref1 = abs(m1)
40 mref2 = abs(m2)
41 if abs(spq - m1) <= eps * mref or abs(spq - m2) <= eps * mref:
42 # label 30: an end slope close to the chord's: case 2 or 3.
43 if prod1 < 0.0 or prod2 < 0.0:
44 return _opposite_signs(prod1, prod2, mref, mref1, mref2, eps)
45 else:
46 if prod1 < 0.0 or prod2 < 0.0:
47 return _opposite_signs(prod1, prod2, mref, mref1, mref2, eps)
48 prod = (mref - mref1) * (mref - mref2)
49 if prod < 0.0:
50 # The two tangent lines meet between p1 and q1.
51 return 1
52
53 # Label 40: all three slopes have the same sign (Fortran lines
54 # 92–122).
55 if mref1 > 2.0 * mref:
56 # label 50
57 if mref2 > (2.0 - eps) * mref:
58 return 4 # label 70
59 return 3
60 if mref2 > 2.0 * mref:
61 # label 60
62 if mref1 > (2.0 - eps) * mref:
63 return 4 # label 70
64 return 3
65 # Both tangents cross the midline: a knot at (p1 + q1)/2.
66 return 2
67
68
69def _opposite_signs(prod1: float, prod2: float, mref: float, mref1: float, mref2: float, eps: float) -> int:
70 """Label 80 of CHOOSE: at least one end slope has the sign opposite to
71 the chord's (Fortran lines 126–146). Returns ncase.
72
73 """
74
75 if prod1 < 0.0 and prod2 < 0.0:
76 return 2 # label 130
77 if prod1 < 0.0:
78 # label 90
79 if mref2 > (1.0 + eps) * mref:
80 return 1 # label 100
81 return 2
82 # label 110
83 if mref1 > (1.0 + eps) * mref:
84 return 1 # label 120
85 return 2