1C SUBROUTINE FOR INTERPOLATING IN THE GENERAL ABUNDANCE TABLES OF THE SCV
2C EQUATION OF STATE.
3C SUBROUTINE EQSCVG(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,FXION,RMU,
4C *AMU,EMU,ETA,QDT,QDP,QCP,DELA,LCALC) ! KC 2025-05-31
5 SUBROUTINE EQSCVG(TL,T,P,DL,D,X,Z,BETA,FXION,QDT,QDP,QCP,DELA,LCALC)
6C 10/14/26 MHP via Claude
7C code changed to convert COMMON/SCVEOS/ into SCVEOS_MOD.
8 USE SCVEOS_MOD
9C 10/14/26 MHP via Claude
10C code changed to convert COMMON/CONSTANTS/ into CONSTANTS_MOD.
11 USE CONSTANTS_MOD
12C 10/20/26 MHP via Claude
13C code changed to replace implicit typing with IMPLICIT NONE and
14C explicit declarations.
15 IMPLICIT NONE
16 REAL*8 BETA,BETM1,D,DDX,DDY,DDZ,DELA,DENX,DENXL,DENY,DENYL,DENZ,
17 * * DENZL,DL,FP,FPD,FT,FTD,FXION,P,PGAS,PP,PRAD,QCP,QCP0,QDP,
18 * * QDP0,QDPX,QDPY,QDPZ,QDT,QDT0,QDTX,QDTY,QDTZ,QPT,QPT0,QR,
19 * * QSMT,QST0,QSTX,QSTY,QUT,QUTZ,QUTZL,S0,SM,SX,SXL,SY,SYL,T,
20 * * TEMP,TL,UR,X,XHEP,XHEPP,XHP,XTF_H1,XTF_H2,XTF_HE,XTF_HEP,
21 * * XTF_HEPP,XTF_HE_E,XTF_HP,XTF_H_E,Y,Z
22 INTEGER I,II,J,JJ,JJJ,K,NTS
23 LOGICAL*4 LCALC
24
25 PARAMETER (NTS=63)
26C 9/25/26 MHP via Claude
27C code changed to merge COMMON/CONST/, COMMON/CONST1/, COMMON/CONST2/,
28C and COMMON/CONST3/ into a single COMMON/CONSTANTS/
29C 10/13/26 MHP via Claude: removed the unused COMMON/NMLPAR/ declaration
30C (no member referenced here; residue of the obsolete-option removals).
31C 10/13/26 MHP via Claude: removed the unused COMMON/COMP/ declaration
32C (no member referenced here; residue of the obsolete-option removals).
33C DIMENSION ATOMWT(4),QR(4),FT(4),FTD(4), ! KC 2025-05-31
34 DIMENSION QR(4),FT(4),FTD(4),
35 * * FP(4),FPD(4),TEMP(4,3),FXION(3)
36C DATA ATOMWT/0.9921D0,0.24975D0,0.08322D0,0.4995D0/
37C DATA CMH,CMHE,CBOLTZ/1.67357D-24,6.646442D-24,1.380658D-16/
38 SAVE
39
40C FIND GAS PRESSURE (WHICH IS THE QUANTITY WHICH IS TABULATED).
41 BETM1 = 1.0D0 - BETA
42 PP = DLOG10(BETA*P)
43C CHECK IF THE POINT IS WITHIN THE TABLE
44 IF(TL.LT.TLOGX(1) .OR. TL.GT.TLOGX(NTS) .OR. PP.LT.4.0D0)THEN
45 LCALC = .FALSE.
46 RETURN
47 ENDIF
48C FIND NEAREST POINTS IN TEMPERATURE.
49 IF(TL.LT.TLOGX(IDTSCV+1))THEN
50C SEARCH DOWN TO FIND NEAREST 4 TABLE ELEMENTS
51 DO I = IDTSCV,1,-1
52 IF(TL.GT.TLOGX(I))THEN
53 II = I - 1
54 GOTO 10
55 ENDIF
56 END DO
57 II = 1
58 10 10 CONTINUE
59 IDTSCV = MAX(1,II)
60 IDTSCV = MIN(NTS-3,IDTSCV)
61 ELSE
62C SEARCH UP FOR NEAREST 4 TABLE ELEMENTS
63 DO I = IDTSCV+2,NTS
64 IF(TL.LT.TLOGX(I))THEN
65 II = I - 2
66 GOTO 20
67 ENDIF
68 END DO
69 II = NTS - 3
70 20 20 CONTINUE
71 IDTSCV = MAX(1,II)
72 IDTSCV = MIN(NTS-3,IDTSCV)
73 ENDIF
74C FIND NEAREST POINTS IN PRESSURE.
75 JJJ = MIN(NPTSX(IDTSCV)-3,IDP)
76 IF(PP.LT.TABLENV(IDTSCV,JJJ+1,1))THEN
77C SEARCH DOWN TO FIND NEAREST 4 TABLE ELEMENTS
78 DO J = JJJ,1,-1
79 IF(PP.GT.TABLENV(IDTSCV,J,1))THEN
80 JJ = J - 1
81 GOTO 30
82 ENDIF
83 END DO
84 JJ = 1
85 30 30 CONTINUE
86 IDP = MAX(1,JJ)
87 IDP = MIN(NPTSX(IDTSCV)-3,IDP)
88 ELSE
89C SEARCH UP FOR NEAREST 4 TABLE ELEMENTS. NOTE SEARCH IS DONE AT LOWEST
90C TEMPERATURE POINT (WITH THE MINIMUM RANGE IN P).
91 DO J = JJJ+2,NPTSX(IDTSCV)
92 IF(PP.LT.TABLENV(IDTSCV,J,1))THEN
93 JJ = J - 2
94 GOTO 40
95 ENDIF
96 END DO
97C POINT IS OUTSIDE TABLE; RETURN.
98c WRITE(*,5)TL,PL
99 LCALC = .FALSE.
100 RETURN
101 40 40 CONTINUE
102 IDP = MIN(NPTSX(IDTSCV)-3,JJ)
103 ENDIF
104 LCALC = .TRUE.
105 DO K = 1,4
106 QR(K) = TLOGX(K+IDTSCV-1)
107 END DO
108 CALL INTERP(QR,FT,FTD,TL)
109 DO K = 1,4
110 QR(K) = TABLENV(IDTSCV,IDP+K-1,1)
111 END DO
112 CALL INTERP(QR,FP,FPD,PP)
113 Y = 1.0D0 - X - Z
114C INCLUDE RADIATION PRESSURE IN THE EQUATION OF STATE.
115 PRAD = BETM1*P
116 PGAS = BETA*P
117C DENSITY FOR X=1, Y=1, Z=1
118C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
119 DO I = 1,4
120 II = IDTSCV+I-1
121 TEMP(I,1)=FP(1)*TABLEX(II,IDP,4) +
122 * * FP(2)*TABLEX(II,IDP+1,4) + FP(3)*TABLEX(II,IDP+2,4)
123 * * + FP(4)*TABLEX(II,IDP+3,4)
124 TEMP(I,2)=FP(1)*TABLEY(II,IDP,4) +
125 * * FP(2)*TABLEY(II,IDP+1,4) + FP(3)*TABLEY(II,IDP+2,4)
126 * * + FP(4)*TABLEY(II,IDP+3,4)
127 TEMP(I,3)=FP(1)*TABLEZ(II,IDP,4) +
128 * * FP(2)*TABLEZ(II,IDP+1,4) + FP(3)*TABLEZ(II,IDP+2,4)
129 * * + FP(4)*TABLEZ(II,IDP+3,4)
130 END DO
131C INTERPOLATE IN TEMPERATURE
132 DENXL= FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
133 * * + FT(4)*TEMP(4,1)
134 DENX = EXP(CLN*DENXL)
135 DENYL= FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
136 * * + FT(4)*TEMP(4,2)
137 DENY = EXP(CLN*DENYL)
138 DENZL= FT(1)*TEMP(1,3) + FT(2)*TEMP(2,3) + FT(3)*TEMP(3,3)
139 * * + FT(4)*TEMP(4,3)
140 DENZ = EXP(CLN*DENZL)
141C DENSITY
142 D = 1.0D0/(X/DENX + Y/DENY + Z/DENZ)
143 DL = LOG10(D)
144 DDX = X*D/DENX
145 DDY = Y*D/DENY
146 DDZ = Z*D/DENZ
147C D LN RHO/ D LN P = QDP
148C FOR GAS PRESSURE QDP(TOT) = QDP(X)*X*RHO/RHO(X)+QDP(Y)*Y*RHO/RHO(Y)
149C FOR RADIATION PRESSURE QDP = 0, SO QDP(TOT) = QDP(GAS)*P/PGAS
150C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
151 DO I = 1,4
152 II = IDTSCV+I-1
153 TEMP(I,1)=FP(1)*TABLEX(II,IDP,8) +
154 * * FP(2)*TABLEX(II,IDP+1,8) + FP(3)*TABLEX(II,IDP+2,8)
155 * * + FP(4)*TABLEX(II,IDP+3,8)
156 TEMP(I,2)=FP(1)*TABLEY(II,IDP,8) +
157 * * FP(2)*TABLEY(II,IDP+1,8) + FP(3)*TABLEY(II,IDP+2,8)
158 * * + FP(4)*TABLEY(II,IDP+3,8)
159 TEMP(I,3)=FP(1)*TABLEZ(II,IDP,13) +
160 * * FP(2)*TABLEZ(II,IDP+1,13) + FP(3)*TABLEZ(II,IDP+2,13)
161 * * + FP(4)*TABLEZ(II,IDP+3,13)
162 END DO
163C INTERPOLATE IN TEMPERATURE
164 QDPX= FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
165 * * + FT(4)*TEMP(4,1)
166 QDPY= FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
167 * * + FT(4)*TEMP(4,2)
168 QDPZ= FT(1)*TEMP(1,3) + FT(2)*TEMP(2,3) + FT(3)*TEMP(3,3)
169 * * + FT(4)*TEMP(4,3)
170 QDP0 = QDPX*DDX + QDPY*DDY + QDPZ*DDZ
171 QDP = QDP0/BETA
172C D LN RHO/ D LN T = QDT (NOTE : D LN P/ D LN T = QPT)
173C FOR GAS PRESSURE, CORRECT AS PER QDP
174C FOR RADIATION PRESSURE, USE QDT = -QDP*QPT. CORRECT QPT FOR
175C RADIATION PRESSURE AND USE THE CORRECTED QDP, QPT TO GET QDT.
176C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.zdiffOPEOSfinalewkop95zscv1.full
177 DO I = 1,4
178 II = IDTSCV+I-1
179 TEMP(I,1)=FP(1)*TABLEX(II,IDP,7) +
180 * * FP(2)*TABLEX(II,IDP+1,7) + FP(3)*TABLEX(II,IDP+2,7)
181 * * + FP(4)*TABLEX(II,IDP+3,7)
182 TEMP(I,2)=FP(1)*TABLEY(II,IDP,7) +
183 * * FP(2)*TABLEY(II,IDP+1,7) + FP(3)*TABLEY(II,IDP+2,7)
184 * * + FP(4)*TABLEY(II,IDP+3,7)
185 TEMP(I,3)=FP(1)*TABLEZ(II,IDP,10) +
186 * * FP(2)*TABLEZ(II,IDP+1,10) + FP(3)*TABLEZ(II,IDP+2,10)
187 * * + FP(4)*TABLEZ(II,IDP+3,10)
188 END DO
189C INTERPOLATE IN TEMPERATURE
190 QDTX= FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
191 * * + FT(4)*TEMP(4,1)
192 QDTY= FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
193 * * + FT(4)*TEMP(4,2)
194 QDTZ= FT(1)*TEMP(1,3) + FT(2)*TEMP(2,3) + FT(3)*TEMP(3,3)
195 * * + FT(4)*TEMP(4,3)
196 QDT0 = QDTX*DDX + QDTY*DDY + QDTZ*DDZ
197 QPT0 = -QDT0/QDP0
198 QPT = QPT0*BETA + 4.0D0*BETM1
199 QDT = -QPT*QDP
200C CP = S*(D LN S/ D LN T)|P IS TABULATED. USE
201C CP = DU/DT + P*(D LN RHO/D LN T)**2/RHO/T/(D LN RHO/ D LN P)
202C TO FIND DU/DT. THEN INCLUDE THE EFFECTS OF RADIATION PRESSURE
203C ON DU/DT AND THE OTHER TERMS AND GET A CORRECTED CP.
204C CP (GAS PRESSURE ONLY).
205C NOTE THAT UNLIKE THE ENVELOPE TABLE, WE NEED TO INTERPOLATE IN
206C ENTROPY S, D LN S/D LNT, AND ENTROPY OF MIXING, THEN CALCULATE
207C DU/DT
208C ENTROPY AND ENTROPY OF MIXING
209C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
210 DO I = 1,4
211 II = IDTSCV+I-1
212 TEMP(I,1)=FP(1)*TABLEX(II,IDP,5) +
213 * * FP(2)*TABLEX(II,IDP+1,5) + FP(3)*TABLEX(II,IDP+2,5)
214 * * + FP(4)*TABLEX(II,IDP+3,5)
215 TEMP(I,2)=FP(1)*TABLEY(II,IDP,5) +
216 * * FP(2)*TABLEY(II,IDP+1,5) + FP(3)*TABLEY(II,IDP+2,5)
217 * * + FP(4)*TABLEY(II,IDP+3,5)
218 TEMP(I,3)=FP(1)*SMIX(II,IDP) +
219 * * FP(2)*SMIX(II,IDP+1) + FP(3)*SMIX(II,IDP+2)
220 * * + FP(4)*SMIX(II,IDP+3)
221 END DO
222C INTERPOLATE IN TEMPERATURE
223 SXL= FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
224 * * + FT(4)*TEMP(4,1)
225 SX = EXP(CLN*SXL)
226 SYL= FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
227 * * + FT(4)*TEMP(4,2)
228 SY = EXP(CLN*SYL)
229 SM= FT(1)*TEMP(1,3) + FT(2)*TEMP(2,3) + FT(3)*TEMP(3,3)
230 * * + FT(4)*TEMP(4,3)
231 QSMT = FTD(1)*LOG10(TEMP(1,3)) + FTD(2)*LOG10(TEMP(2,3))
232 * * + FTD(3)*LOG10(TEMP(3,3))
233 * * + FTD(4)*LOG10(TEMP(4,3))
234 S0 = X*SX + Y*SY + SM
235C D LN S/ D LN T (X AND Y) AND DU/DT (Z)
236C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
237 DO I = 1,4
238 II = IDTSCV+I-1
239 TEMP(I,1)=FP(1)*TABLEX(II,IDP,9) +
240 * * FP(2)*TABLEX(II,IDP+1,9) + FP(3)*TABLEX(II,IDP+2,9)
241 * * + FP(4)*TABLEX(II,IDP+3,9)
242 TEMP(I,2)=FP(1)*TABLEY(II,IDP,9) +
243 * * FP(2)*TABLEY(II,IDP+1,9) + FP(3)*TABLEY(II,IDP+2,9)
244 * * + FP(4)*TABLEY(II,IDP+3,9)
245 TEMP(I,3)=FP(1)*TABLEZ(II,IDP,7) +
246 * * FP(2)*TABLEZ(II,IDP+1,7) + FP(3)*TABLEZ(II,IDP+2,7)
247 * * + FP(4)*TABLEZ(II,IDP+3,7)
248 END DO
249C INTERPOLATE IN TEMPERATURE
250 QSTX= FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
251 * * + FT(4)*TEMP(4,1)
252 QSTY= FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
253 * * + FT(4)*TEMP(4,2)
254 QUTZL= FT(1)*TEMP(1,3) + FT(2)*TEMP(2,3) + FT(3)*TEMP(3,3)
255 * * + FT(4)*TEMP(4,3)
256 QUTZ = EXP(CLN*QUTZL)
257 QST0 = X*SX*QSTX + Y*SY*QSTY + SM*QSMT
258 QCP0 = QST0 + Z*(QUTZ + PGAS*QDTZ**2/QDPZ/DENZ/T)
259C NOW FIND DU/DT FROM THE ORIGINAL TABLE.
260 QUT = QCP0 - PGAS*QDT0**2/QDP0/D/T
261C CORRECT DU/DT FOR RADIATION
262 UR = 3.0D0*PRAD/D
263 QUT = QUT + 4.0D0*UR/T
264C CORRECT CP FOR RADIATION PRESSURE
265 QCP = QUT + P*QDT**2/QDP/D/T
266C ADIABATIC TEMPERATURE GRADIENT
267 DELA = -P*QDT/D/T/QCP
268
269C Get fractions of total particles (including electrons), as follows:
270C XTF_H2 the fraction that is neutral hydrogen molecules, and
271C XTF_He the fraction thst is neutral helium).
272C These are in column 2 respectively of the SCV hydrogen and
273C Helium tables.
274C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
275 DO I = 1,4
276 II = IDTSCV+I-1
277 TEMP(I,1)=FP(1)*TABLEX(II,IDP,2) +
278 * * FP(2)*TABLEX(II,IDP+1,2) + FP(3)*TABLEX(II,IDP+2,2)
279 * * + FP(4)*TABLEX(II,IDP+3,2)
280 TEMP(I,2)=FP(1)*TABLEY(II,IDP,2) +
281 * * FP(2)*TABLEY(II,IDP+1,2) + FP(3)*TABLEY(II,IDP+2,2)
282 * * + FP(4)*TABLEY(II,IDP+3,2)
283 END DO
284C INTERPOLATE IN TEMPERATURE
285 XTF_H2 = FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
286 * * + FT(4)*TEMP(4,1)
287 XTF_He = FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
288 * * + FT(4)*TEMP(4,2)
289
290C Get more fractions of total particles (including electrons), as follows:
291C XTF_H1 the fraction that is neutral hydrogen atoms, and
292C XTF_HeP the fraction thst is singly ionized helium).
293C These are in column 3 respectively of the SCV hydrogen and
294C Helium tables.
295C INTERPOLATE IN PRESSURE AT 4 DIFFERENT TEMPERATURE POINTS.
296 DO I = 1,4
297 II = IDTSCV+I-1
298 TEMP(I,1)=FP(1)*TABLEX(II,IDP,3) +
299 * * FP(2)*TABLEX(II,IDP+1,3) + FP(3)*TABLEX(II,IDP+2,3)
300 * * + FP(4)*TABLEX(II,IDP+3,3)
301 TEMP(I,2)=FP(1)*TABLEY(II,IDP,3) +
302 * * FP(2)*TABLEY(II,IDP+1,3) + FP(3)*TABLEY(II,IDP+2,3)
303 * * + FP(4)*TABLEY(II,IDP+3,3)
304 END DO
305C INTERPOLATE IN TEMPERATURE
306 XTF_H1 = FT(1)*TEMP(1,1) + FT(2)*TEMP(2,1) + FT(3)*TEMP(3,1)
307 * * + FT(4)*TEMP(4,1)
308 XTF_HeP = FT(1)*TEMP(1,2) + FT(2)*TEMP(2,2) + FT(3)*TEMP(3,2)
309 * * + FT(4)*TEMP(4,2)
310
311C At tis time we can calculate the ramaining particles fractions using conservation
312C of particles and coservation of charge. The variable names are:
313C XTF_H_e the hycrogen related fraction that is electrons
314C XTF_HP the hydrogen ralated fraction that is H+ ions
315C XTF_He_e the helium related fraction that is electrons
316C XTF_HePP the helium related fraction that is doubly ionized helium (He++)
317C Particle and charge conservation yields:
318 XTF_H_e = .5D0*(1D0 - XTF_H2 - XTF_H1)
319 XTF_HP = XTF_H_e
320 XTF_He_e = (1D0/3D0)*(2D0 - 2D0*XTF_He - XTF_HeP)
321 XTF_HePP = 1D0 - XTF_He - XTF_HeP - XTF_He_e
322
323C We are seeking the fraction XHP of hydrogen nuclei that are singly ionized,
324C the fraction XHeP of helium huclei that are singly ionized and XHePP, the
325C helium fraction that is doubly ionized.
326 XHP = XTF_HP / (XTF_H2 + XTF_H1 + XTF_HP)
327 XHeP = XTF_HeP / (XTF_He + XTF_HeP + XTF_HePP)
328 XHePP = XTF_HePP / (XTF_He + XTF_HeP + XTF_HePP)
329
330C In the same order, these are the desired elements of array XION(3)
331 FXION(1) = XHP
332 FXION(2) = XHeP
333 FXION(3) = XHePP
334
335 RETURN ! Primay exit. Success. LCALC is true.
336
337 END
1"""Python version of eqscvg.f (YREC development, 7be4133): the SCV
2equation of state for a general composition, from the pure-H, pure-He
3and metal tables."""
4
5import math
6
7import numpy as np
8
9from pyrec import constants_mod
10from pyrec import scveos_mod
11from pyrec.interp import interp
12
13NTS = 63 # temperatures in the SCV tables
14
15# Locals kept between calls (SAVE).
16qr = np.zeros(5)
17ft = np.zeros(5)
18ftd = np.zeros(5)
19fp = np.zeros(5)
20fpd = np.zeros(5)
21temp = np.zeros((5, 4))
22
23
24def _rows(table, col, ncol=3):
25 """The block the Fortran writes out for each quantity: Lagrange
26 interpolation in log Pgas (weights fp) of column col of a table, at
27 the 4 temperatures of the stencil. Returns the values at rows 1-4.
28 ncol=2 for a table with no column index (SMIX)."""
29
30 scv = scveos_mod
31 out = np.zeros(5)
32 for i in range(1, 5):
33 ii = scv.idtscv + i - 1
34 idp = scv.idp
35 if ncol == 2:
36 out[i] = sum(fp[k] * table[ii, idp + k - 1] for k in range(1, 5))
37 else:
38 out[i] = sum(fp[k] * table[ii, idp + k - 1, col]
39 for k in range(1, 5))
40 return out
41
42
43def _in_t(vals, w=None):
44 """Interpolate in temperature: sum of the weights ft (or w) times the
45 values at the 4 temperatures."""
46
47 w = ft if w is None else w
48 return w[1] * vals[1] + w[2] * vals[2] + w[3] * vals[3] + w[4] * vals[4]
49
50
51def eqscvg(tl: float, t: float, p: float, dl: float, d: float, x: float, z: float, beta: float, fxion: np.ndarray,
52 qdt: float, qdp: float, qcp: float, dela: float, lcalc: bool) -> tuple[float, float, float, float, float,
53 float, bool]:
54 """The SCV equation of state for any X, Z: density by additive volumes
55 of the H, He and metal tables, derivatives as volume-weighted means,
56 c_P from the tabulated entropies, then radiation and the H and He
57 ionization fractions (equations on the page). Called by eqscve.
58
59 Translates: eqscvg.f#EQSCVG (7be4133)
60
61 Arguments: tl, t (log T, T), p (total pressure), x, z, beta (Pgas/P);
62 dl, d, qdt, qdp, qcp, dela and lcalc are only set. Array changed in
63 place: fxion (H+, He+, He++ fractions, index 0 unused).
64
65 Returns (dl, d, qdt, qdp, qcp, dela, lcalc). Outside the table, lcalc
66 is False and the others are returned as passed in.
67
68 """
69
70 c = constants_mod
71 scv = scveos_mod
72
73 # The gas pressure is the tabulated quantity (Fortran lines 41–47).
74 betm1 = 1.0 - beta
75 pp = math.log10(beta * p)
76 # Is the point within the table?
77 if tl < scv.tlogx[1] or tl > scv.tlogx[NTS] or pp < 4.0:
78 lcalc = False
79 return dl, d, qdt, qdp, qcp, dela, lcalc
80
81 # Nearest 4 points in temperature, searching from the last stencil
82 # (left by this routine or eqscve; Fortran lines 49–73).
83 # Question (see the page): no smoothing when the stencil changes.
84 if tl < scv.tlogx[scv.idtscv + 1]:
85 for i in range(scv.idtscv, 0, -1):
86 if tl > scv.tlogx[i]:
87 ii = i - 1
88 break # go to 10
89 else:
90 ii = 1
91 else:
92 for i in range(scv.idtscv + 2, NTS + 1):
93 if tl < scv.tlogx[i]:
94 ii = i - 2
95 break # go to 20
96 else:
97 ii = NTS - 3
98 scv.idtscv = max(1, ii)
99 scv.idtscv = min(NTS - 3, scv.idtscv)
100 idt = scv.idtscv
101
102 # Nearest 4 points in pressure, searched in the row idt (the lowest
103 # temperature of the stencil, with the smallest range in P; Fortran
104 # lines 75–104).
105 nptsx = scv.nptsx[idt]
106 jjj = min(nptsx - 3, scv.idp)
107 if pp < scv.tablenv[idt, jjj + 1, 1]:
108 for j in range(jjj, 0, -1):
109 if pp > scv.tablenv[idt, j, 1]:
110 jj = j - 1
111 break # go to 30
112 else:
113 jj = 1
114 scv.idp = max(1, jj)
115 scv.idp = min(nptsx - 3, scv.idp)
116 else:
117 for j in range(jjj + 2, nptsx + 1):
118 if pp < scv.tablenv[idt, j, 1]:
119 jj = j - 2
120 break # go to 40
121 else:
122 # The point is above the table: return.
123 lcalc = False
124 return dl, d, qdt, qdp, qcp, dela, lcalc
125 scv.idp = min(nptsx - 3, jj) # label 40
126 idp = scv.idp
127 lcalc = True
128
129 # Lagrange weights in log T and log Pgas (Fortran lines 105–112).
130 for k in range(1, 5):
131 qr[k] = scv.tlogx[k + idt - 1]
132 interp(qr, ft, ftd, tl)
133 for k in range(1, 5):
134 # Question (see the page): row idt's pressures for all 4 rows.
135 qr[k] = scv.tablenv[idt, idp + k - 1, 1]
136 interp(qr, fp, fpd, pp)
137
138 # Radiation pressure (Fortran lines 113–116).
139 y = 1.0 - x - z
140 prad = betm1 * p
141 pgas = beta * p
142
143 # Densities for X=1, Y=1, Z=1 (column 4; log10 in the tables; Fortran
144 # lines 119–140).
145 denxl = _in_t(_rows(scv.tablex, 4))
146 denx = math.exp(c.cln * denxl)
147 denyl = _in_t(_rows(scv.tabley, 4))
148 deny = math.exp(c.cln * denyl)
149 denzl = _in_t(_rows(scv.tablez, 4))
150 denz = math.exp(c.cln * denzl)
151
152 # Density by additive volumes, and the volume weights (Fortran lines
153 # 142–146).
154 d = 1.0 / (x / denx + y / deny + z / denz)
155 dl = math.log10(d)
156 ddx = x * d / denx
157 ddy = y * d / deny
158 ddz = z * d / denz
159
160 # d ln rho / d ln P (gas): columns 8, 8 and 13 (Fortran lines
161 # 151–171).
162 qdpx = _in_t(_rows(scv.tablex, 8))
163 qdpy = _in_t(_rows(scv.tabley, 8))
164 qdpz = _in_t(_rows(scv.tablez, 13))
165 qdp0 = qdpx * ddx + qdpy * ddy + qdpz * ddz
166 qdp = qdp0 / beta
167
168 # d ln rho / d ln T (gas): columns 7, 7 and 10; then radiation
169 # (Fortran lines 177–199).
170 qdtx = _in_t(_rows(scv.tablex, 7))
171 qdty = _in_t(_rows(scv.tabley, 7))
172 qdtz = _in_t(_rows(scv.tablez, 10))
173 qdt0 = qdtx * ddx + qdty * ddy + qdtz * ddz
174 qpt0 = -qdt0 / qdp0
175 qpt = qpt0 * beta + 4.0 * betm1
176 qdt = -qpt * qdp
177
178 # Entropies (column 5, log10) and the entropy of mixing (Fortran lines
179 # 210–234).
180 # Question (see the page): SMIX is the envelope's.
181 temp[:, 1] = _rows(scv.tablex, 5)
182 temp[:, 2] = _rows(scv.tabley, 5)
183 temp[:, 3] = _rows(scv.smix, None, ncol=2)
184 sxl = _in_t(temp[:, 1])
185 sx = math.exp(c.cln * sxl)
186 syl = _in_t(temp[:, 2])
187 sy = math.exp(c.cln * syl)
188 sm = _in_t(temp[:, 3])
189 # Suspected bug (see the page): log10 of SMIX fails if it is <= 0.
190 qsmt = (ftd[1] * math.log10(temp[1, 3]) + ftd[2] * math.log10(temp[2, 3])
191 + ftd[3] * math.log10(temp[3, 3])
192 + ftd[4] * math.log10(temp[4, 3]))
193 s0 = x * sx + y * sy + sm # noqa: F841 (unused in the Fortran too)
194
195 # d ln S / d ln T for X and Y (column 9), dU/dT for Z (column 7,
196 # log10; Fortran lines 237–258).
197 qstx = _in_t(_rows(scv.tablex, 9))
198 qsty = _in_t(_rows(scv.tabley, 9))
199 qutzl = _in_t(_rows(scv.tablez, 7))
200 qutz = math.exp(c.cln * qutzl)
201 qst0 = x * sx * qstx + y * sy * qsty + sm * qsmt
202 qcp0 = qst0 + z * (qutz + pgas * qdtz ** 2 / qdpz / denz / t)
203
204 # dU/dT for the gas, then corrected for radiation (Fortran lines
205 # 260–263).
206 qut = qcp0 - pgas * qdt0 ** 2 / qdp0 / d / t
207 ur = 3.0 * prad / d
208 qut = qut + 4.0 * ur / t
209 # c_P with radiation pressure, and the adiabatic gradient (Fortran
210 # lines 265–267).
211 qcp = qut + p * qdt ** 2 / qdp / d / t
212 dela = -p * qdt / d / t / qcp
213
214 # Fractions of all particles (electrons included): neutral H2 and
215 # neutral He (column 2), neutral H atoms and He+ (column 3; Fortran
216 # lines 275–309).
217 xtf_h2 = _in_t(_rows(scv.tablex, 2))
218 xtf_he = _in_t(_rows(scv.tabley, 2))
219 xtf_h1 = _in_t(_rows(scv.tablex, 3))
220 xtf_hep = _in_t(_rows(scv.tabley, 3))
221
222 # The rest from conservation of particles and of charge (Fortran lines
223 # 318–321).
224 xtf_h_e = 0.5 * (1.0 - xtf_h2 - xtf_h1)
225 xtf_hp = xtf_h_e
226 xtf_he_e = (1.0 / 3.0) * (2.0 - 2.0 * xtf_he - xtf_hep)
227 xtf_hepp = 1.0 - xtf_he - xtf_hep - xtf_he_e
228
229 # Fractions of H nuclei singly ionized, of He nuclei singly and doubly
230 # (Fortran lines 326–333).
231 # Suspected bug (see the page): H2 counted once among the H nuclei.
232 xhp = xtf_hp / (xtf_h2 + xtf_h1 + xtf_hp)
233 xhep = xtf_hep / (xtf_he + xtf_hep + xtf_hepp)
234 xhepp = xtf_hepp / (xtf_he + xtf_hep + xtf_hepp)
235 fxion[1] = xhp
236 fxion[2] = xhep
237 fxion[3] = xhepp
238 return dl, d, qdt, qdp, qcp, dela, lcalc