1C
2C
3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
4C OP954D
5CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
6 SUBROUTINE OP954D(O,OL,QOD,QOT)
7C 10/14/26 MHP via Claude
8C code changed to convert COMMON/OP95INTERP/ into OP95INTERP_MOD.
9 USE OP95INTERP_MOD
10C 10/14/26 MHP via Claude
11C code changed to convert COMMON/LLOT95A/ into LLOT95A_MOD.
12 USE LLOT95A_MOD
13C 10/20/26 MHP via Claude
14C code changed to replace implicit typing with IMPLICIT NONE and
15C explicit declarations.
16 IMPLICIT NONE
17 REAL*8 C,CC,CCD,CCT,CZ,CZD,CZT,DELTAR,O,OL,QC,QOD,QOT
18 INTEGER I,ID,IT,IXZ,IZ,J,K
19C MHP 7/98 GET OPAL95 OPACITY FROM FULL SET OF OPACITY TABLES.
20C FULL SET OF TABLES: OPACITY AS A FUNCTION OF Z AND X, T, RHO/T6**3
21C TABLES ARE INCREMENTED IN SETS OF NZ*NX. SO THE TABLES FOR THE
22C THIRD METAL ABUNDANCE (3 X 10**-4)BEGIN AT TABLE 21 AND END AT TABLE 30.
23C FOR THE HIGH VALUES OF Z, THE NUMBER OF X TABLES IS NOT THE SAME (I.E.
24C X<0.9 FOR Z=0.1).
25C FOR EACH COMPOSITION A FULL GRID IN (T,RHO/T6**3) IS RETAINED.
26C INDICES FOR INTERPOLATION IN Z,X,T, AND R; INTERPOLATION FACTORS FOR
27C Z,X,T, AND R (AND DERIVATIVE FACTORS FOR T AND RHO); AND DATA FOR
28C LINEAR EXTRAPOLATION WHEN OUTSIDE THE TABLE IN RHO.
29C 10/9/26 MHP via Claude
30C code changed to merge COMMON/OP95INDX/, COMMON/OP95FACT/, and
31C COMMON/OP95EXT/ into COMMON/OP95INTERP/ (see getopal95.f for the
32C full rationale).
33C 10/13/26 MHP via Claude
34C code changed to rename COMMON/OP95INTERP/'s RL and RLL to RHO_T63L and
35C RHO_T63LL. RL is log(rho/T6**3), set here as RL = DL - 3*(TL-6); the
36C old names clash with RL and RLL as used for radius throughout the rest
37C of the code, which is why main.f declared only a 10-member prefix of
38C this block to avoid importing them. With the clash gone main.f can
39C declare the full block, which a USE statement will require once this
40C becomes a module.
41 DIMENSION C(4),QC(4),CC(4),CCT(4),CCD(4),CZ(4),CZT(4),CZD(4)
42 SAVE
43C FIND OPACITY AT EACH OF THE 4 NEARBY VALUES OF Z
44 DO K = 1,4
45 IZ = NZ(JZ+K-1)
46C FIND OPACITY AT EACH OF THE 4 NEARBY VALUES OF X
47 DO J = 1,4
48 IXZ = JX(K,J)+IZ
49C FOR EACH X, GET CAPPA FOR 4 VALUES OF T
50 DO I = 1,4
51 IT = JT + I - 1
52C FOR EACH T, GET CAPPA FOR 4 VALUES OF R
53 ID = JD(I)
54C LOG CAPPA AT DESIRED RHO FOR EACH OF THE 4 DESIRED T.
55 C(I) = BD(I,1)*CAPPA2(IXZ,IT,ID) +
56 * * BD(I,2)*CAPPA2(IXZ,IT,ID+1)
57 * * + BD(I,3)*CAPPA2(IXZ,IT,ID+2)
58 * * + BD(I,4)*CAPPA2(IXZ,IT,ID+3)
59C D LOG CAPPA/D LOG R FOR EACH OF THE 4 DESIRED T.
60 QC(I) = BDD(I,1)*CAPPA2(IXZ,IT,ID)
61 * * + BDD(I,2)*CAPPA2(IXZ,IT,ID+1)
62 * * + BDD(I,3)*CAPPA2(IXZ,IT,ID+2)
63 * * + BDD(I,4)*CAPPA2(IXZ,IT,ID+3)
64 END DO
65C CHECK ON WHETHER RHO IS OUTSIDE OF THE TABLE AND NEEDS EXTRAPOLATION
66 IF(LEXTL)THEN
67C FACTOR IN R
68 DELTAR = RHO_T63L-RHO_T63LL
69C CORRECT CAPPA BY USING THE DERIVATIVE AT THE BOUNDARY.
70 DO I = 1,4
71 C(I) = C(I)+DELTAR*QC(I)
72 END DO
73 ELSE IF(LEXTH)THEN
74 DO I = 1,4
75 IF(LEXH(I))THEN
76 DELTAR = RHO_T63L - RLH(I)
77 C(I) = C(I)+DELTAR*QC(I)
78 ENDIF
79 END DO
80 ENDIF
81C INTERPOLATE FOR LOG CAPPA IN T.
82 CC(J) = BT(1)*C(1) + BT(2)*C(2) + BT(3)*C(3)
83 * * + BT(4)*C(4)
84C D LOG CAPPA/D LOG T
85 CCT(J) = BTT(1)*C(1) + BTT(2)*C(2) + BTT(3)*C(3)
86 * * + BTT(4)*C(4)
87C D LOG CAPPA/D LOG R
88 CCD(J) = BT(1)*QC(1) + BT(2)*QC(2) + BT(3)*QC(3)
89 * * + BT(4)*QC(4)
90 END DO
91C INTERPOLATE FOR LOG CAPPA IN X.
92 CZ(K) = BX(K,1)*CC(1) + BX(K,2)*CC(2) + BX(K,3)*CC(3) +
93 * * BX(K,4)*CC(4)
94C INTERPOLATE FOR QOT IN X.
95 CZT(K) = BX(K,1)*CCT(1) + BX(K,2)*CCT(2) + BX(K,3)*CCT(3) +
96 * * BX(K,4)*CCT(4)
97C INTERPOLATE FOR QOD IN X.
98 CZD(K) = BX(K,1)*CCD(1) + BX(K,2)*CCD(2) + BX(K,3)*CCD(3) +
99 * * BX(K,4)*CCD(4)
100 END DO
101C INTERPOLATE FOR LOG CAPPA IN Z.
102 OL = BZ(1)*CZ(1) + BZ(2)*CZ(2) + BZ(3)*CZ(3) +
103 * * BZ(4)*CZ(4)
104C INTERPOLATE FOR QOT IN Z.
105 QOT = BZ(1)*CZT(1) + BZ(2)*CZT(2) + BZ(3)*CZT(3) +
106 * * BZ(4)*CZT(4)
107C INTERPOLATE FOR QOD IN Z.
108 QOD = BZ(1)*CZD(1) + BZ(2)*CZD(2) + BZ(3)*CZD(3) +
109 * * BZ(4)*CZD(4)
110C CORRECT FROM DERIVATE AT FIXED R TO DERIVATIVE AT FIXED RHO.
111 QOT = QOT - 3.0D0*QOD
112 O = 1.0D1**OL
113 RETURN
114 END
1"""Python version of op954d.f (YREC development, 7be4133): the OPAL 1995
2opacity from the full set of tables, by interpolation in Z, X, T and R."""
3
4import numpy as np
5
6from pyrec import llot95a_mod
7from pyrec import op95interp_mod
8
9# OP954D has SAVE: its work arrays are kept between calls.
10c = np.zeros(5)
11qc = np.zeros(5)
12cc = np.zeros(5)
13cct = np.zeros(5)
14ccd = np.zeros(5)
15cz = np.zeros(5)
16czt = np.zeros(5)
17czd = np.zeros(5)
18
19
20def op954d(o: float, ol: float, qod: float, qot: float) -> tuple[float, float, float, float]:
21 """The OPAL95 opacity at the current point from the full set of tables
22 (MHP 7/98): the log R and log T interpolation of OP952D for each of the
23 4 x 4 nearest (Z, X) tables, then four-point interpolation in X and in
24 Z, with the indices and weights GETOPAL95 left in OP95INTERP_MOD.
25
26 Translates: op954d.f#OP954D (7be4133)
27
28 Arguments: o, ol, qod, qot (set only; any value).
29
30 Returns (o, ol, qod, qot): the opacity kappa, log10 kappa, and
31 dlog kappa/dlog rho and dlog kappa/dlog T at constant rho.
32
33 """
34
35 tab = llot95a_mod
36 ip = op95interp_mod
37 cappa2 = tab.cappa2
38 bd, bdd, bt, btt = ip.bd, ip.bdd, ip.bt, ip.btt
39
40 # Find the opacity at each of the 4 nearby values of Z (Fortran lines 44–100).
41 for k in range(1, 5):
42 # Suspected bug (see LL95TBL's page): at Z = 0.08 and 0.1 the slot
43 # of X = 0 holds a table at X = 1-Z of the previous Z.
44 iz = tab.nz[ip.jz + k - 1]
45 # Find the opacity at each of the 4 nearby values of X (Fortran lines 47–90).
46 for j in range(1, 5):
47 ixz = ip.jx[k, j] + iz
48 # For each X, kappa at 4 values of T (Fortran lines 50–64).
49 for i in range(1, 5):
50 it = ip.jt + i - 1
51 # For each T, kappa at 4 values of R.
52 id_ = ip.jd[i]
53 # log kappa at the desired rho for each of the 4 T.
54 c[i] = (bd[i, 1] * cappa2[ixz, it, id_]
55 + bd[i, 2] * cappa2[ixz, it, id_ + 1]
56 + bd[i, 3] * cappa2[ixz, it, id_ + 2]
57 + bd[i, 4] * cappa2[ixz, it, id_ + 3])
58 # dlog kappa/dlog R for each of the 4 T.
59 qc[i] = (bdd[i, 1] * cappa2[ixz, it, id_]
60 + bdd[i, 2] * cappa2[ixz, it, id_ + 1]
61 + bdd[i, 3] * cappa2[ixz, it, id_ + 2]
62 + bdd[i, 4] * cappa2[ixz, it, id_ + 3])
63
64 # Rho outside the table: extrapolate linearly with the
65 # derivative at the boundary (Fortran lines 66–80).
66 if ip.lextl:
67 deltar = ip.rho_t63l - ip.rho_t63ll
68 for i in range(1, 5):
69 c[i] = c[i] + deltar * qc[i]
70 elif ip.lexth:
71 for i in range(1, 5):
72 if ip.lexh[i]:
73 deltar = ip.rho_t63l - ip.rlh[i]
74 c[i] = c[i] + deltar * qc[i]
75
76 # Interpolate in T: log kappa, dlog kappa/dlog T, and
77 # dlog kappa/dlog R (Fortran lines 82–89).
78 cc[j] = bt[1] * c[1] + bt[2] * c[2] + bt[3] * c[3] + bt[4] * c[4]
79 cct[j] = (btt[1] * c[1] + btt[2] * c[2] + btt[3] * c[3]
80 + btt[4] * c[4])
81 ccd[j] = (bt[1] * qc[1] + bt[2] * qc[2] + bt[3] * qc[3]
82 + bt[4] * qc[4])
83
84 # Interpolate in X: log kappa, QOT and QOD (Fortran lines 92–99).
85 bx = ip.bx
86 cz[k] = (bx[k, 1] * cc[1] + bx[k, 2] * cc[2] + bx[k, 3] * cc[3]
87 + bx[k, 4] * cc[4])
88 czt[k] = (bx[k, 1] * cct[1] + bx[k, 2] * cct[2] + bx[k, 3] * cct[3]
89 + bx[k, 4] * cct[4])
90 czd[k] = (bx[k, 1] * ccd[1] + bx[k, 2] * ccd[2] + bx[k, 3] * ccd[3]
91 + bx[k, 4] * ccd[4])
92
93 # Interpolate in Z (Fortran lines 102–109).
94 bz = ip.bz
95 ol = bz[1] * cz[1] + bz[2] * cz[2] + bz[3] * cz[3] + bz[4] * cz[4]
96 qot = bz[1] * czt[1] + bz[2] * czt[2] + bz[3] * czt[3] + bz[4] * czt[4]
97 qod = bz[1] * czd[1] + bz[2] * czd[2] + bz[3] * czd[3] + bz[4] * czd[4]
98
99 # From the derivative at fixed R to the derivative at fixed rho
100 # (Fortran lines 111–112).
101 qot = qot - 3.0 * qod
102 o = 10.0**ol
103 return o, ol, qod, qot