1C $$$$$$
2C SUBROUTINE PHYSIC(FP,FT,HCOMP,HD,HG,HL,HP,HR,HS,HT,LC,LCZ,M,TEFFL) ! KC 2025-05-31
3 SUBROUTINE PHYSIC(FP,FT,HCOMP,HD,HG,HL,HP,HR,HS,HT,LC,M,TEFFL,
4 * * CMIXL)
5C 10/15/26 MHP via Claude
6C code changed to take JSON from DIMENSIONS_MOD instead of declaring
7C PARAMETER(JSON=5000) here.
8 USE DIMENSIONS_MOD
9C 10/14/26 MHP via Claude
10C code changed to convert COMMON/TEMP/ into TEMP_MOD.
11 USE TEMP_MOD
12C 10/14/26 MHP via Claude
13C code changed to convert COMMON/SCRTCH/ into SCRTCH_MOD.
14 USE SCRTCH_MOD
15C 10/14/26 MHP via Claude
16C code changed to convert COMMON/DWMAX/ into DWMAX_MOD.
17 USE DWMAX_MOD
18C 10/14/26 MHP via Claude
19C code changed to convert COMMON/DPMIX/ into DPMIX_MOD.
20 USE DPMIX_MOD
21C 10/14/26 MHP via Claude
22C code changed to convert COMMON/DEBHU/ into DEBHU_MOD.
23 USE DEBHU_MOD
24C 10/14/26 MHP via Claude
25C code changed to convert COMMON/COMP2/ into COMP2_MOD.
26 USE COMP2_MOD
27C 10/14/26 MHP via Claude
28C code changed to convert COMMON/COMP/ into COMP_MOD.
29 USE COMP_MOD
30C 10/14/26 MHP via Claude
31C code changed to convert COMMON/NMLPAR/ into NMLPAR_MOD.
32 USE NMLPAR_MOD
33C 10/14/26 MHP via Claude
34C code changed to convert COMMON/CONSTANTS/ into CONSTANTS_MOD.
35 USE CONSTANTS_MOD
36C 10/20/26 MHP via Claude
37C code changed to replace implicit typing with IMPLICIT NONE and
38C explicit declarations.
39 IMPLICIT NONE
40 REAL*8 AMU,AMU2,ATOMWT,B,BETA,BETA14,BETAI,CMIXL,D,DEL,DELA,
41 * * DELAMD,DELMID,DELR,DFX1,DFX2,DFX3,DFX4,DL,DMID,EMU,EMU2,
42 * * ETA,FP,FPL,FT,FTL,FXION,GMID,HCOMP,HD,HF,HG,HL,HOLD,HP,HR,
43 * * HS,HSMID,HT,O,OL,P,PL,PMID,QACP,QACR,QACT,QAP,QAT,QCP,QCPP,
44 * * QCPT,QDP,QDT,QDTP,QDTT,QOD,QOT,RL,RMU,SL,T,TEFFL,TEMP,TL,
45 * * VEL,X,Z
46 INTEGER I,IM,K,KSAHA,M
47 LOGICAL*4 LATMO,LC,LCONV,LDERIV,LOCOND
48
49
50C 9/25/26 MHP via Claude
51C code changed to merge COMMON/CONST/, COMMON/CONST1/, COMMON/CONST2/,
52C and COMMON/CONST3/ into a single COMMON/CONSTANTS/
53C 10/12/26 MHP via Claude
54C code changed to extend COMMON/NMLPAR/ to 234 members, adding the
55C namelist variables that the physics routines read from 27 COMMON
56C blocks which also held derived or working members. Those blocks keep
57C only their non-namelist members; five of them -- NEWMX, VMULT,
58C PMMWIND, CCOUT1 and ENVGEN -- had nothing left and are gone.
59C Derivation-only namelist variables from the same blocks went to
60C COMMON/NMLBYPASS/ instead, not here.
61C
62C Declared identically in all 121 files that hold any of these members.
63C Generated from one member list, so every copy is byte-identical; the
64C linker's 'size of symbol changed' warning is the check that they are.
65C 10/12/26 MHP via Claude
66C code changed to remove COMMON/OPTAB/ entirely. Once OPTOL moved to the
67C consolidated namelist block, every remaining member was write-only:
68C ZSI appeared only in a DATA statement in parmin.f, and IDT and IDD were
69C assigned the constants 15 and 5 in coefft.f, envint.f, physic.f and
70C starin.f and read nowhere in the code. They are leftovers from the
71C removed opacity-table interpolation schemes.
72C DBG 7/92 COMMON BLOCK ADDED TO COMPUTE DEBYE-HUCKEL CORRECTION.
73 DIMENSION HCOMP(15,JSON),HD(JSON),HL(JSON),HG(JSON),
74 * * HP(JSON),HR(JSON),HS(JSON),HT(JSON),LC(JSON),
75C * FXION(3),FP(JSON),FT(JSON),ATOMWT(4),LCZ(JSON), ! KC 2025-05-31
76 * * FXION(3),FP(JSON),FT(JSON),ATOMWT(4),
77 * * HF(4),HOLD(4)
78 DATA ATOMWT/1.007825D0,4.002603D0,12.0D0,3.01603D0/
79 SAVE
80
81C FIND ACTUAL AND ADIABATIC TEMPERATURE GRADIENTS,OPACITY,AND
82C MEAN MOLECULAR WEIGHT FOR ALL RADIATIVE SHELLS.
83 LDERIV = .FALSE.
84 LOCOND = .FALSE.
85 LATMO = .FALSE.
86 DO 30 IM = 1,M
87 SL = HS(IM)
88 TL = HT(IM)
89 PL = HP(IM)
90 RL = HR(IM)
91 B = HL(IM)
92 X = HCOMP(1,IM)
93 Z = HCOMP(3,IM)
94 DL = HD(IM)
95 FPL = FP(IM)
96 FTL = FT(IM)
97
98C 9/22/26 MHP via Claude
99C code changed to remove the MHD equation of state
100 IF (LDH) THEN
101 XXDH = HCOMP(1,IM)
102 YYDH = HCOMP(2,IM)+HCOMP(4,IM)
103 ZZDH = HCOMP(3,IM)
104 ZDH(1) = HCOMP(5,IM)+HCOMP(6,IM)
105 ZDH(2) = HCOMP(7,IM)+HCOMP(8,IM)
106 ZDH(3) = HCOMP(9,IM)+HCOMP(10,IM)+HCOMP(11,IM)
107 END IF
108 CALL EQSTAT(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,FXION,RMU,
109 * * AMU,EMU,ETA,QDT,QDP,QCP,DELA,QDTT,QDTP,QAT,QAP,QCPT,
110 * * QCPP,LDERIV,LATMO,KSAHA)
111 CALL GETOPAC (DL,TL,X,Z,O,OL,QOD,QOT,FXION)
112 IOVIM=IM
113 CALL TPGRAD(TL,T,PL,P,D,RL,SL,B,O,QDT,QDP,QOT,QOD,QCP,DEL,
114 * * DELR,DELA,QDTT,QDTP,QAT,QAP,QACT,QACP,QACR,QCPT,QCPP,
115 * * VEL,LDERIV,LCONV,FPL,FTL,TEFFL,CMIXL)
116 LC(IM) = LCONV
117 SDEL(1,IM) = DELR
118 SDEL(2,IM) = DEL
119 SDEL(3,IM) = DELA
120C FIND NEW RUN OF MEAN MOLECULAR WEIGHT ASSUMING FULLY IONIZED GAS.
121C AMUENV IS(1/MEAN MOLECULAR WEIGHT PER ION OF THE SURFACE MIXTURE.)
122 DFX1 = HCOMP(1,IM) - XENV
123 DFX2 = HCOMP(2,IM) - YENV
124 DFX3 = HCOMP(3,IM) - ZENV
125 DFX4 = HCOMP(4,IM) - Y3ENV
126 TEMP = AMUENV + DFX1/ATOMWT(1) + DFX2/ATOMWT(2) +
127 * * DFX3/ATOMWT(3) + DFX4/ATOMWT(4)
128 AMU2 = 1.0D0/TEMP
129 TEMP = HCOMP(1,IM)/ATOMWT(1) + 2.0D0*(HCOMP(4,IM)/ATOMWT(4)
130 * * + HCOMP(2,IM)/ATOMWT(2)) + 0.5D0*HCOMP(3,IM)
131 EMU2 = 1.0D0/TEMP
132 HAMU(IM) = AMU2*EMU2/(AMU2+EMU2)
133 SO(IM) = O
134 CP(IM) = QCP
135 SQDT(IM) = QDT
136C JVS 10/13 Always want SVEL
137 SVEL(IM) = VEL
138C IF(LC(IM))THEN
139C SVEL(IM) = VEL
140C ELSE
141C SVEL(IM) = 0.0D0
142C ENDIF
143 30 30 CONTINUE
144C FIND THE THERMOMETRIC DIFFUSIVITY AND KINEMATIC VISCOSITY.
145C CALL VISCOS(HCOMP,HD,HT,LC,M) ! KC 2025-05-31
146 CALL VISCOS(HCOMP,HD,HT,M)
147C FIND THE RUN OF MAXIMUM ALLOWABLE D OMEGA/D LNR AND THE RUN OF ACTUAL
148C D OMEGA/D LN R FOR ALL RADIATIVE ZONES.
149C IF THE GRADIENT OF OMEGA EXCEEDS THE CRITICAL VALUE FOR THE SHEAR
150C INSTABILITY, A SHORT TIMESCALE INSTABILITY OCCURS. MIX ALL ADJACENT
151C UNSTABLE ZONES TO A MARGINALLY STABLE STATE.
152 DO 100 IM = 2,M
153C SKIP CONVECTIVE REGIONS
154 IF(LC(IM).AND.LC(IM-1))THEN
155 QWRMAX(IM) = 0.0D0
156 GOTO 100
157 ENDIF
158C NOW CHECK FOR SHEAR INSTABILITY -REF.ENDAL&SOFIA APJ 220:279(1978)
159C THERMODYNAMIC QUANTITIES ARE CALCULATED AT THE SHELL MIDPOINT BY
160C 4-POINT LAGRANGIAN INTERPOLATION.
161 IF(IM.LE.2) THEN
162 K = 1
163 ELSE IF(IM.EQ.M) THEN
164 K = M - 3
165 ELSE
166 K = IM - 2
167 ENDIF
168 DO 90 I = 1, 4
169 HOLD(I) = HS(I+K-1)
170 90 90 CONTINUE
171C USE 4-POINT LAGRANGIAN INTERPOLATION TO FIND PHYSICAL VARIABLES
172C AT THE INTERFACE BEING TESTED.
173 HSMID = 0.5D0*(HS(IM) + HS(IM-1))
174 CALL INTRP2(HOLD,HF,HSMID)
175 PMID=HP(K)*HF(1) + HP(K+1)*HF(2) + HP(K+2)*HF(3) +HP(K+3)*HF(4)
176 DMID=HD(K)*HF(1) + HD(K+1)*HF(2) + HD(K+2)*HF(3) +HD(K+3)*HF(4)
177 DELMID=SDEL(2,K)*HF(1) + SDEL(2,K+1)*HF(2) + SDEL(2,K+2)*HF(3)
178 * * + SDEL(2,K+3)*HF(4)
179 DELAMD=SDEL(3,K)*HF(1) + SDEL(3,K+1)*HF(2) + SDEL(3,K+2)*HF(3)
180 * * + SDEL(3,K+3)*HF(4)
181 GMID=HG(K)*HF(1) + HG(K+1)*HF(2) + HG(K+2)*HF(3) +HG(K+3)*HF(4)
182 TEMP = DEXP(CLN*(DMID - PMID))*(DELAMD - DELMID)*GMID**2
183 IF(TEMP.GT.0.0D0) THEN
184 QWRMAX(IM) = 2.0D0*DSQRT(TEMP)
185 ELSE
186 QWRMAX(IM) = 0.0D0
187 ENDIF
188 100 100 CONTINUE
189
190 RETURN
191 END
1"""Python version of physic.f (YREC development, 7be4133): the auxiliary
2physics at every shell, and the shear-stability limit on dOmega/dln r."""
3
4import math
5
6import numpy as np
7
8from pyrec import comp2_mod
9from pyrec import comp_mod
10from pyrec import constants_mod
11from pyrec import debhu_mod
12from pyrec import dpmix_mod
13from pyrec import dwmax_mod
14from pyrec import nmlpar_mod
15from pyrec import scrtch_mod
16from pyrec import temp_mod
17from pyrec.eqstat import eqstat
18from pyrec.getopac import getopac
19from pyrec.intrp2 import intrp2
20from pyrec.tpgrad import tpgrad
21from pyrec.viscos import viscos
22
23# DATA ATOMWT: atomic weights of H, He4, the metals (as C12) and He3.
24atomwt = np.array([0.0, 1.007825, 4.002603, 12.0, 3.01603])
25
26# PHYSIC has SAVE: its locals are kept between calls. KSAHA, which EQSTAT
27# updates, is never initialized or read here (unused?, see the page).
28ksaha = 0
29fxion = np.zeros(4)
30hf = np.zeros(5)
31hold = np.zeros(5)
32
33
34def physic(fp: np.ndarray, ft: np.ndarray, hcomp: np.ndarray, hd: np.ndarray, hg: np.ndarray, hl: np.ndarray,
35 hp: np.ndarray, hr: np.ndarray, hs: np.ndarray, ht: np.ndarray, lc: np.ndarray, m: int, teffl: float,
36 cmixl: float) -> None:
37 """Recompute, at every shell, the equation of state, opacity,
38 temperature gradients and convective velocity, and the mean molecular
39 weight; then the thermal diffusivity and viscosity (VISCOS), and the
40 largest dOmega/dln r stable against the shear instability.
41
42 Translates: physic.f#PHYSIC (7be4133)
43
44 Arguments: fp, ft, the rotational distortion factors; the model hcomp
45 [species, shell], hd, hg, hl, hp, hr, hs, ht (arrays, index 0 unused);
46 lc, the convection flags (changed in place); m, the number of shells;
47 teffl, log Teff; cmixl, the mixing length.
48
49 Returns nothing; sets lc and, in the modules, SDEL, SO, SVEL
50 (scrtch_mod), CP, HAMU, SQDT (temp_mod; THDIF and VISC through VISCOS),
51 QWRMAX (dwmax_mod) and IOVIM (dpmix_mod).
52
53 """
54
55 global ksaha
56 c = constants_mod
57 sdel = scrtch_mod.sdel
58
59 # Actual and adiabatic temperature gradients, opacity and mean
60 # molecular weight for all shells (Fortran lines 81–97; the Fortran
61 # comment says "radiative shells": Question, see the page).
62 lderiv = False
63 locond = False # noqa: F841 (unused in the Fortran too)
64 latmo = False
65 for im in range(1, m + 1):
66 sl = hs[im]
67 tl = ht[im]
68 pl = hp[im]
69 rl = hr[im]
70 b = hl[im]
71 x = hcomp[1, im]
72 z = hcomp[3, im]
73 dl = hd[im]
74 fpl = fp[im]
75 ftl = ft[im]
76
77 # The Debye-Hueckel correction, if chosen; the MHD equation of state is
78 # removed (9/22/26 MHP via Claude) (Fortran lines 98–107).
79 if nmlpar_mod.ldh:
80 debhu_mod.xxdh = hcomp[1, im]
81 debhu_mod.yydh = hcomp[2, im] + hcomp[4, im]
82 debhu_mod.zzdh = hcomp[3, im]
83 debhu_mod.zdh[1] = hcomp[5, im] + hcomp[6, im]
84 debhu_mod.zdh[2] = hcomp[7, im] + hcomp[8, im]
85 debhu_mod.zdh[3] = hcomp[9, im] + hcomp[10, im] + hcomp[11, im]
86
87 # The equation of state, the opacity and the gradients (Fortran
88 # lines 108–119).
89 (t, p, dl, d, beta, betai, beta14, rmu, amu, emu, eta, qdt, qdp,
90 qcp, dela, qdtt, qdtp, qat, qap, qcpt, qcpp, ksaha) = eqstat(
91 tl, 0.0, pl, 0.0, dl, 0.0, x, z, 0.0, 0.0, 0.0, fxion, 0.0, 0.0,
92 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
93 lderiv, latmo, ksaha)
94 o, ol, qod, qot = getopac(dl, tl, x, z, 0.0, 0.0, 0.0, 0.0, fxion)
95 dpmix_mod.iovim = im
96 (dele, delr, qact, qacp, qacr, vel, lconv) = tpgrad(
97 tl, t, pl, p, d, rl, sl, b, o, qdt, qdp, qot, qod, qcp, 0.0,
98 0.0, dela, qdtt, qdtp, qat, qap, 0.0, 0.0, 0.0, qcpt, qcpp,
99 0.0, lderiv, False, fpl, ftl, teffl, cmixl)
100 lc[im] = lconv
101 sdel[1, im] = delr
102 sdel[2, im] = dele
103 sdel[3, im] = dela
104
105 # Mean molecular weight of a fully ionized gas. AMUENV is 1/(mean
106 # molecular weight per ion) of the surface mixture (Fortran lines
107 # 120–132).
108 dfx1 = hcomp[1, im] - comp_mod.xenv
109 dfx2 = hcomp[2, im] - comp2_mod.yenv
110 dfx3 = hcomp[3, im] - comp_mod.zenv
111 dfx4 = hcomp[4, im] - comp2_mod.y3env
112 temp = (comp_mod.amuenv + dfx1 / atomwt[1] + dfx2 / atomwt[2]
113 + dfx3 / atomwt[3] + dfx4 / atomwt[4])
114 amu2 = 1.0 / temp
115 temp = (hcomp[1, im] / atomwt[1]
116 + 2.0 * (hcomp[4, im] / atomwt[4] + hcomp[2, im] / atomwt[2])
117 + 0.5 * hcomp[3, im])
118 emu2 = 1.0 / temp
119 temp_mod.hamu[im] = amu2 * emu2 / (amu2 + emu2)
120
121 # The opacity, c_P, dlnrho/dlnT and the convective velocity, stored
122 # (Fortran lines 133–142); SVEL is always kept (JVS 10/13).
123 scrtch_mod.so[im] = o
124 temp_mod.cp[im] = qcp
125 temp_mod.sqdt[im] = qdt
126 scrtch_mod.svel[im] = vel
127 # label 30
128
129 # Thermometric diffusivity and kinematic viscosity (Fortran lines
130 # 144–146).
131 viscos(hcomp, hd, ht, m)
132
133 # The largest stable dOmega/dln r at each interface (Endal & Sofia
134 # 1978), from quantities interpolated to the midpoint in HS (Fortran
135 # lines 147–188).
136 qwrmax = dwmax_mod.qwrmax
137 for im in range(2, m + 1):
138 # Skip convective regions.
139 if lc[im] and lc[im - 1]:
140 qwrmax[im] = 0.0
141 continue # label 100
142
143 # The four points for the interpolation (Fortran lines 158–170).
144 if im <= 2:
145 k = 1
146 elif im == m:
147 k = m - 3
148 else:
149 k = im - 2
150 for i in range(1, 5):
151 hold[i] = hs[i + k - 1]
152
153 # Interpolated to the interface, and the limit (Fortran lines
154 # 171–187).
155 hsmid = 0.5 * (hs[im] + hs[im - 1])
156 intrp2(hold, hf, hsmid)
157 pmid = (hp[k] * hf[1] + hp[k + 1] * hf[2] + hp[k + 2] * hf[3]
158 + hp[k + 3] * hf[4])
159 dmid = (hd[k] * hf[1] + hd[k + 1] * hf[2] + hd[k + 2] * hf[3]
160 + hd[k + 3] * hf[4])
161 delmid = (sdel[2, k] * hf[1] + sdel[2, k + 1] * hf[2]
162 + sdel[2, k + 2] * hf[3] + sdel[2, k + 3] * hf[4])
163 delamd = (sdel[3, k] * hf[1] + sdel[3, k + 1] * hf[2]
164 + sdel[3, k + 2] * hf[3] + sdel[3, k + 3] * hf[4])
165 gmid = (hg[k] * hf[1] + hg[k + 1] * hf[2] + hg[k + 2] * hf[3]
166 + hg[k + 3] * hf[4])
167 temp = math.exp(c.cln * (dmid - pmid)) * (delamd - delmid) * gmid**2
168 if temp > 0.0:
169 qwrmax[im] = 2.0 * math.sqrt(temp)
170 else:
171 qwrmax[im] = 0.0