1C$$$$$$
2 SUBROUTINE MIDMOD(DELTS,DT,FX,HCOMP,HD,HG,HJM,HL,HP,HR,HS,HS1,
3C * HS2,HSTOT,HT,LC,LCZ,LFIRSTIT,M,ETA2M,HDM,HGM,HICZ,HIM, ! KC 2025-05-31
4 * * HS2,HSTOT,HT,LC,LFIRSTIT,M,ETA2M,HDM,HGM,HICZ,HIM,
5 * * HLM,HPM,HRM,HSBOT,HSTOP,HTM,IMIN,IMAX,LALLCZ,LCM,
6 * * LCZM,LCZSUR,OMEGAM,R0M,QIWM,MRZONE,MXZONE,NRZONE,
7 * * NZONE,HCOMPS)
8C 10/15/26 MHP via Claude
9C code changed to take JSON from DIMENSIONS_MOD instead of declaring
10C PARAMETER(JSON=5000) here.
11 USE DIMENSIONS_MOD
12C 10/14/26 MHP via Claude
13C code changed to convert COMMON/TEMP/ into TEMP_MOD.
14 USE TEMP_MOD
15C 10/14/26 MHP via Claude
16C code changed to convert COMMON/SCRTCH/ into SCRTCH_MOD.
17 USE SCRTCH_MOD
18C 10/14/26 MHP via Claude
19C code changed to convert COMMON/OLDROT/ into OLDROT_MOD.
20 USE OLDROT_MOD
21C 10/14/26 MHP via Claude
22C code changed to convert COMMON/OLDPHY/ into OLDPHY_MOD.
23 USE OLDPHY_MOD
24C 10/14/26 MHP via Claude
25C code changed to convert COMMON/OLDMOD/ into OLDMOD_MOD.
26 USE OLDMOD_MOD
27C 10/14/26 MHP via Claude
28C code changed to convert COMMON/MDPHY/ into MDPHY_MOD.
29 USE MDPHY_MOD
30C 10/14/26 MHP via Claude
31C code changed to convert COMMON/DEUTER/ into DEUTER_MOD.
32 USE DEUTER_MOD
33C 10/14/26 MHP via Claude
34C code changed to convert COMMON/NMLPAR/ into NMLPAR_MOD.
35 USE NMLPAR_MOD
36C 10/14/26 MHP via Claude
37C code changed to convert COMMON/CONSTANTS/ into CONSTANTS_MOD.
38 USE CONSTANTS_MOD
39C 10/20/26 MHP via Claude
40C code changed to replace implicit typing with IMPLICIT NONE and
41C explicit declarations.
42 IMPLICIT NONE
43 REAL*8 CZI,CZJ,DDELN,DDELP,DELJ,DELTS,DRATEM,DRATEM0,DT,ETA2M,F2,
44 * * FAC2,FX,HCOMP,HCOMPS,HD,HDM,HG,HGM,HICZ,HIM,HJM,HJM2,HL,
45 * * HLM,HP,HPM,HR,HRM,HRP,HRR,HRSH,HS,HS1,HS2,HSBOT,HSTOP,
46 * * HSTOT,HT,HTM,OMEGAM,QIWM,R0M,RATIO,RR,TEMP
47 INTEGER I,I0,I1,IBEGIN,ICZ0,ICZ1,IEND,II,IMAX,IMIN,IND,J,JEND,
48 * * JSTART,K,M,MRZONE,MXZONE,NRZONE,NZONE
49 LOGICAL*4 LALLCZ,LC,LCC,LCM,LCP,LCZM,LCZSUR,LDO,LFIRSTIT,LNEWCZ
50
51C 10/13/26 MHP via Claude
52C HCOMPS is now a dummy argument, formerly COMMON/OLDAB/.
53 DIMENSION HCOMPS(15,JSON)
54C 10/13/26 MHP via Claude: removed the unused COMMON/BURN/ declaration
55C (no member referenced here; residue of the obsolete-option removals).
56C 9/25/26 MHP via Claude
57C code changed to merge COMMON/CONST/, COMMON/CONST1/, COMMON/CONST2/,
58C and COMMON/CONST3/ into a single COMMON/CONSTANTS/
59C MHP 8/17 ADDED EXCEN, C_2 TO COMMON BLOCK FOR MATT ET AL. 2012 CENT. TERM
60C 10/12/26 MHP via Claude
61C code changed to extend COMMON/NMLPAR/ to 234 members, adding the
62C namelist variables that the physics routines read from 27 COMMON
63C blocks which also held derived or working members. Those blocks keep
64C only their non-namelist members; five of them -- NEWMX, VMULT,
65C PMMWIND, CCOUT1 and ENVGEN -- had nothing left and are gone.
66C Derivation-only namelist variables from the same blocks went to
67C COMMON/NMLBYPASS/ instead, not here.
68C
69C Declared identically in all 121 files that hold any of these members.
70C Generated from one member list, so every copy is byte-identical; the
71C linker's 'size of symbol changed' warning is the check that they are.
72C 10/13/26 MHP via Claude: removed the unused COMMON/CWIND/ declaration
73C (no member referenced here; residue of the obsolete-option removals).
74C 10/13/26 MHP via Claude: removed the unused COMMON/DWMAX/ declaration
75C (no member referenced here; residue of the obsolete-option removals).
76C 10/13/26 MHP via Claude
77C code changed to replace COMMON/OLDAB/ with an explicit argument: midmod.f
78C fills HCOMPS and seculr.f reads it, both called only from getw.f, which
79C now owns the storage.
80C MHP 05/02 ADDED FOR DEUTERIUM BURNING
81C 10/13/26 MHP via Claude
82C code changed to drop COMMON/CTLIM/, declared here but never used.
83C MHP 06/02
84C 10/9/26 MHP via Claude
85C code changed to convert COMMON/PREVMID/ to plain local arrays:
86C declared only in this file (confirmed via a codebase-wide scan), so
87C there's nothing to share via COMMON. The existing blanket SAVE
88C statement below already preserves their values across calls, same
89C as COMMON did. LCP keeps its LOGICAL*4 type via the IMPLICIT
90C LOGICAL*4(L) rule already in effect in this file.
91 DIMENSION DDELP(JSON),DDELN(JSON),HRP(JSON),LCP(JSON)
92 DIMENSION HCOMP(15,JSON),HD(JSON),HG(JSON),HJM(JSON),HL(JSON),
93 * * HP(JSON),HR(JSON),HS(JSON),HS1(JSON),HS2(JSON),HT(JSON),
94C * LC(JSON),LCZ(JSON),ETA2M(JSON),HDM(JSON),HGM(JSON), ! KC 2025-05-31
95 * * LC(JSON),ETA2M(JSON),HDM(JSON),HGM(JSON),
96 * * HIM(JSON),HLM(JSON),HPM(JSON),HRM(JSON),HTM(JSON),
97 * * LCM(JSON),LCZM(JSON),OMEGAM(JSON),R0M(JSON),QIWM(JSON),
98 * * MRZONE(13,2),MXZONE(12,2)
99C G Somers 3/17, ADDING NEW TAUCZ COMMON BLOCK
100C 10/13/26 MHP via Claude: removed the unused COMMON/OVRTRN/ declaration
101C (no member referenced here; residue of the obsolete-option removals).
102C MHP 3/09 ADDED FLAG TO ENFORCE SOLID BODY ROTATION AT ALL TIMES.
103C JNT 09/25 FOR 05/15 ADD IMPJMOD
104C MHP 06/02
105 LOGICAL*4 LCHG(JSON)
106C ADDED VECTOR FOR DEUTERIUM BURNING
107 DIMENSION DRATEM(JSON),DRATEM0(JSON)
108 SAVE
109C IN GENERAL A DIFFUSION TIMESTEP IS LESS THAN A MODEL TIMESTEP.
110C SR MIDMOD TAKES THE STRUCTURE AT THE BEGINNING AND END OF THE TIMESTEP
111C AND ASSIGNS AN INTERMEDIATE STRUCTURE USING LINEAR INTERPOLATION IN TIME.
112C NUCLEAR BURNING IS ACCOUNTED FOR HERE, AND THE CHANGES IN ANGULAR
113C VELOCITY DUE TO CHANGES IN RADIUS AND CONSERVATION OF ANGULAR MOMENTUM
114C ARE ALSO COMPUTED.
115C MIDMOD ALSO LOCATES THE OUTER EDGE OF A CENTRAL CONVECTION ZONE AND THE INNER
116C EDGE OF A SURFACE C.Z., AND DETERMINES THE MASS AND MOMENT OF INERTIA OF
117C THE SURFACE C.Z.
118 IEND = 11
119 IF(LEXCOM) IEND = 15
120C INITIALIZE COMPOSITION ARRAY THE FIRST TIME THROUGH.
121C HCOMPM IS THE ARRAY OF CHANGES IN COMPOSITION DUE TO NUCLEAR BURNING
122C DURING THE COURSE OF THE MODEL TIMESTEP.
123C MHP 06/02 SAVE CHANGES IN R, CZ DEPTH, DELAD-DELRAD FROM THE
124C PRIOR STEP.
125 IF(LFIRSTIT)THEN
126 DO 20 J = 1,M
127 LCP(J) = LCO(J)
128 HRP(J) = HRO(J)
129 DDELP(J) = DELAO(J)-DELRO(J)
130 AMUM(J) = AMUO(J)
131 DO 10 I = 1,IEND
132 HCOMP(I,J) = HCOMPP(I,J)
133 10 10 CONTINUE
134 20 20 CONTINUE
135 ELSE
136 DO J = 1,M
137 HRP(J) = HRM(J)
138 DDELP(J) = DDELN(J)
139 LCP(J) = LCM(J)
140 END DO
141 ENDIF
142 LNEWCZ = .FALSE.
143C INTERPOLATE IN THE MODEL VARIABLES AND AUXILLARY PHYSICS.
144 FAC2 = DT/DELTS
145 DO 40 J = 1,M
146 HDM(J) = HDO(J) + FX*(HD(J)-HDO(J))
147 HLM(J) = HLO(J) + FX*(HL(J)-HLO(J))
148 HPM(J) = HPO(J) + FX*(HP(J)-HPO(J))
149 HRM(J) = HRO(J) + FX*(HR(J)-HRO(J))
150 HTM(J) = HTO(J) + FX*(HT(J)-HTO(J))
151C DO 30 I = 1,IEND
152C HCOMP(I,J)=HCOMP(I,J)+FAC2*HCOMPM(I,J)
153C HCOMPP(I,J) = HCOMP(I,J)
154C 30 CONTINUE
155 HGM(J) = HGO(J) + FX*(HG(J) - HGO(J))
156 DELAM(J) = DELAO(J) + FX*(SDEL(3,J)-DELAO(J))
157 DELM(J) = DELO(J) + FX*(SDEL(2,J) - DELO(J))
158 DELRM(J) = DELRO(J) + FX*(SDEL(1,J) - DELRO(J))
159 ESUMM(J) = ESUMO(J) + FX*(SESUM(J) - ESUMO(J))
160 VISCM(J) = VISCO(J) + FX*(VISC(J) - VISCO(J))
161 THDIFM(J) = THDIFO(J) + FX*(THDIF(J) - THDIFO(J))
162 CPM(J) = CPO(J) + FX*(CP(J) - CPO(J))
163 QDTM(J) = QDTO(J) + FX*(SQDT(J) - QDTO(J))
164 OM(J) = OO(J) + FX*(SO(J) - OO(J))
165 AMUM(J) = AMUM(J) + FAC2*(HAMU(J) - AMUO(J))
166C MHP 6/00 ADDED TOTAL ENERGY GENERATION
167 TEMP = SESUM(J)+SEG(6,J)+SEG(7,J)
168 EPSM(J) = EPSO(J)+FX*(TEMP-EPSO(J))
169 40 40 CONTINUE
170C CHECK FOR ADVANCING OR RECEDING CONVECTIVE REGIONS.USE INTERPOLATED
171C RADIATIVE AND ADIABATIC TEMPERATURE GRADIENTS TO DETERMINE WHETHER
172C OR NOT A ZONE IS CONVECTIVE IF IT CHANGES STATE OVER THE COURSE OF A
173C TIMESTEP.
174 DO 50 I = 1,M
175 DDELN(I) = DELAM(I)-DELRM(I)
176 IF(LC(I).EQV.LCP(I))THEN
177 LCM(I) = LC(I)
178 VELM(I) = VELO(I) + FX*(SVEL(I)-VELO(I))
179 LCHG(I) = .FALSE.
180 ELSE
181 LCHG(I) = .TRUE.
182 LNEWCZ = .TRUE.
183 IF(DELAM(I).LT.DELRM(I)) THEN
184 LCM(I) = .TRUE.
185 VELM(I) = MAX(VELO(I),SVEL(I))
186 ELSE
187 LCM(I) = .FALSE.
188 VELM(I) = 0.0D0
189 ENDIF
190 ENDIF
191 50 50 CONTINUE
192 LNEWCZ = .FALSE.
193C MHP 06/02 IF THE CZ DEPTHS HAVE CHANGED, RESOLVE
194C OUT WHEN A GIVEN ZONE "DROPPED OUT" OF THE CONVECTION
195C ZONE OR ENTERED IT. MODIFY THE SPECIFIC ANGULAR MOMENTUM
196C ACCORDINGLY.
197 IF(LNEWCZ)THEN
198 LCC = .FALSE.
199 LDO = .FALSE.
200 DO I = 1,M-1
201 IF(LCHG(I))THEN
202 IF(.NOT.LCC)THEN
203C START OF CHANGED REGION
204 LCC = .TRUE.
205 I0 = I
206 ENDIF
207 ENDIF
208 IF(.NOT.LCHG(I))THEN
209 IF(LCC)THEN
210C END OF CHANGED REGION
211 I1 = I - 1
212 LCC = .FALSE.
213 LDO = .TRUE.
214 WRITE(*,*)I0,I1,DDELN(I0),DDELN(I0-1),
215 * * DDELN(I1+1)
216C ONLY CHANGE IF THERE IS A RECEDING CONVECTION ZONE;
217C WE CAN ASSUME LOCAL CONSERVATION OF J PRIOR TO HAVING
218C A SHELL INCORPORATED INTO A CZ.
219 IF (DDELN(I0).GT.0.0D0)THEN
220 IF(DDELN(I0-1).LT.0.0D0)THEN
221C SUBTRACTED FROM A CORE CZ
222 IND = -1
223 ELSE IF(DDELN(I1+1).LT.0.0D0)THEN
224C SUBTRACTED FROM AN ENVELOPE CZ
225 IND = 1
226 ELSE
227 LDO = .FALSE.
228 ENDIF
229 ELSE
230 LDO = .FALSE.
231 ENDIF
232 ENDIF
233 ENDIF
234 IF(LDO)THEN
235 LDO = .FALSE.
236C CORE CZ
237 IF(IND.LT.0)THEN
238C LOCATE EDGES OF CURRENT LOWER CZ
239 ICZ1 = I0 - 1
240 DO II = I0-1,1,-1
241 IF(.NOT.LCM(II))THEN
242 ICZ0 = II + 1
243 GOTO 11
244 ENDIF
245 END DO
246 ICZ0 = 1
247 11 11 CONTINUE
248 DO J = I1,I0,-1
249 IF(DDELN(J).LT.0.0D0)GOTO 13
250 CZI = 0.0D0
251 CZJ = 0.0D0
252C FRACTION OF THE TIMESTEP SHELL WAS RADIATIVE
253 FX = DDELN(J)/(DDELN(J)-DDELP(J))
254C FRACTION OF THE TIMESTEP THAT THE SHELL WAS CONVECTIVE
255 F2 = 1.0D0 - FX
256 DO II = ICZ0,J-1
257 HRR = HRP(II)+F2*(HR(II)-HRO(II))
258 CZI = CZI+CC23*HS2(II)*10.0D0**(2.0D0*HRR)
259 CZJ = CZJ + HJM(II)*HS2(II)
260 END DO
261C GET THE CZ MOMENT OF INERTIA AND TOTAL J AT THE TIME THE
262C SHELL WAS RELEASED; THIS GIVES A CORRECTED VALUE FOR
263C J/M. REDISTRIBUTE THE DIFFERENCE IN J BACK INTO THE CZ.
264 HRSH = 2.0D0*(HRP(J)+F2*(HR(J)-HRP(J)))
265 HJM2 = CC23*(CZJ/CZI)*10.0D0**HRSH
266 DELJ = (HJM(J)-HJM2)*HS2(J)
267 RATIO = (CZJ-DELJ)/CZJ
268 HJM(J)=HJM2
269 RR = HJM2/HJM(J)
270 WRITE(*,*)J,FX,RR,DELJ,RATIO
271 DO II = ICZ0,J-1
272 HJM(II) = HJM(II)*RATIO
273 END DO
274 END DO
275 ELSE
276C ENVELOPE CZ
277C LOCATE EDGES OF CURRENT LOWER CZ
278 ICZ0 = I1 + 1
279 DO II = I1+2,M
280 IF(.NOT.LCM(II))THEN
281 ICZ1 = II - 1
282 GOTO 12
283 ENDIF
284 END DO
285 ICZ1 = M
286 12 12 CONTINUE
287 DO J = I0,I1
288 IF(DDELN(J).LT.0.0D0)GOTO 13
289 CZI = 0.0D0
290 CZJ = 0.0D0
291C FRACTION OF THE TIMESTEP SHELL WAS RADIATIVE
292 FX = DDELN(J)/(DDELN(J)-DDELP(J))
293C FRACTION OF THE TIMESTEP THAT THE SHELL WAS CONVECTIVE
294 F2 = 1.0D0 - FX
295 DO II = J+1,ICZ1
296 HRR = HRP(II)+F2*(HR(II)-HRO(II))
297 CZI = CZI+CC23*HS2(II)*10.0D0**(2.0D0*HRR)
298 CZJ = CZJ + HJM(II)*HS2(II)
299 END DO
300C GET THE CZ MOMENT OF INERTIA AND TOTAL J AT THE TIME THE
301C SHELL WAS RELEASED; THIS GIVES A CORRECTED VALUE FOR
302C J/M. REDISTRIBUTE THE DIFFERENCE IN J BACK INTO THE CZ.
303 HRSH = 2.0D0*(HRP(J)+F2*(HR(J)-HRP(J)))
304 HJM2 = CC23*(CZJ/CZI)*10.0D0**HRSH
305 DELJ = (HJM(J)-HJM2)*HS2(J)
306 RATIO = (CZJ-DELJ)/CZJ
307 HJM(J)=HJM2
308 RR = HJM2/HJM(J)
309 WRITE(*,*)J,FX,RR,DELJ,RATIO
310 DO II = J+1,M
311 HJM(II) = HJM(II)*RATIO
312 END DO
313 END DO
314 ENDIF
315 13 13 CONTINUE
316 ENDIF
317 END DO
318 ENDIF
319C CONVECTIVE OVERSHOOT APPLIED TO NORMAL CONVECTION ZONES.
320 CALL OVROT(HCOMP,HDM,HPM,HRM,HS,HTM,LCM,M,LCZM,MRZONE,MXZONE,
321 * * NRZONE,NZONE)
322C REBURN THE ORIGINAL MIXTURE FOR THE SMALL DIFFUSION TIME STEP.
323C MHP 6/00 - FOR THERMODYNAMIC CONSISTENCY USE CURRENT T, NOT END OF
324C TIMESTEP T (REPLACED HT IN CALL WITH HTM)
325C CALL ROTMIX(DT,HCOMP,HS2,HTM,5,M,MRZONE,MXZONE, ! KC 2025-05-31
326 CALL ROTMIX(DT,HCOMP,HS2,HTM,M,MRZONE,MXZONE,
327 * * NRZONE,NZONE
328 * * ,HSTOT,HDM,HS,HRM,HPM,LCZM,HS1)
329 DO I = 1,M
330 DO J = 1,IEND
331 HCOMPS(J,I) = HCOMP(J,I)
332 END DO
333 END DO
334C MHP 05/02 ADDED DEUTERIUM BURNING
335 IF(HCOMPP(12,M).GT.1.0D-14)THEN
336C INCREMENT THE TIMESTEP
337 IF(LFIRSTIT) THEN
338 DO I = 1,M
339 DRATEM(I) = DRATE0(I)+FAC2*(DRATE(I)-DRATE0(I))
340 DRATEM0(I) = DRATE0(I)
341 END DO
342 ELSE
343 DO I = 1,M
344 DRATEM0(I) = DRATEM(I)
345 DRATEM(I) = DRATEM(I)+FAC2*(DRATE(I)-DRATE0(I))
346 END DO
347 ENDIF
348C RADIATIVE ZONES.
349C
350 DO K = 1,NRZONE
351 DO J = MRZONE(K,1),MRZONE(K,2)
352C EXIT LOOP ONCE T DROPS BELOW NUCLEAR REACTION T CUTOFF
353 IF(HTM(J).LE.TCUT(1)) GOTO 190
354 IBEGIN = J
355 IEND = J
356 CALL DBURNM(IBEGIN,IEND,M,HS2,HCOMP,DT,DRATEM,DRATEM0,
357 * * FAC2)
358 END DO
359 END DO
360 190 190 CONTINUE
361C
362C CONVECTION ZONES.
363C NOTE KEMCOM ALSO AUTOMATICALLY HOMOGENIZE CONVECTION ZONES.
364C
365 DO K = 1,NZONE
366 IBEGIN = MXZONE(K,1)
367 IEND = MXZONE(K,2)
368 CALL DBURNM(IBEGIN,IEND,M,HS2,HCOMP,DT,DRATEM,DRATEM0,
369 * * FAC2)
370 END DO
371 ENDIF
372C DETERMINE EXTENT OF CENTRAL CONVECTION ZONE.
373C IMIN IS THE FIRST ZONE ABOVE A CENTRAL CONVECTION ZONE, AND THUS THE
374C FIRST ZONE CONSIDERED FOR STABILITY AGAINST ROTATIONAL INSTABILITIES.
375 IF(LCZM(1))THEN
376 DO 60 I = 2,M
377 IF(.NOT.LCZM(I))GOTO 65
378 60 60 CONTINUE
379 I = M + 1
380 65 65 IMIN = MAX(2,I-1)
381 ELSE
382 IMIN = 2
383 ENDIF
384C DETERMINE EXTENT OF SURFACE CONVECTION ZONE.
385 LALLCZ = .FALSE.
386 IF(LCZM(M))THEN
387C SURFACE C.Z. EXISTS. FIND LOWEST SHELL (IMAX), WHICH IS ALSO THE
388C UPPERMOST ZONE CONSIDERED FOR STABILITY AGAINST ROTATIONALLY INDUCED MIXING.
389 DO 70 I = M-1,1,-1
390 IF(.NOT.LCZM(I)) GOTO 80
391 70 70 CONTINUE
392 LALLCZ = .TRUE.
393 I = 0
394 80 80 IMAX = I + 1
395C HSTOP IS THE MASS AT THE TOP OF THE C.Z.
396C HSBOT IS THE MASS AT THE BOTTOM OF THE C.Z.
397 HSTOP = EXP(CLN*HSTOT)
398 IF(IMAX.GT.1)THEN
399 HSBOT = 0.5D0*(HS1(IMAX)+HS1(IMAX-1))
400 ELSE
401 HSBOT = 0.0D0
402 ENDIF
403C LCZSUR=T IF A SURFACE C.Z.DEEP ENOUGH FOR ANGULAR MOMENTUM LOSS EXISTS
404 IF((HSTOP-HSBOT)/CMSUN.GT.0.0D0)THEN
405 LCZSUR = .TRUE.
406 ELSE
407 LCZSUR= .FALSE.
408 ENDIF
409 ELSE
410C NO SURFACE C.Z.
411 IMAX = M
412 LCZSUR = .FALSE.
413 ENDIF
414C MHP 3/09 ADD ABILITY TO COMPUTE THE CONVECTIVE OVERTURN TIMESCALE 'LOCALLY'.
415C THIS IS DEFINED AS HP/V, WHERE HP IS THE PRESSURE SCALE HEIGHT AT THE BASE
416C AND V IS THE CONVECTIVE VELOCITY ONE PRESSURE SCALE HEIGHT ABOVE THE BASE.
417C FOR FULLY CONVECTIVE STARS THE CENTRAL PRESSURE SCALE HEIGHT DIVERGES, SO
418C INSTEAD DEFINE V AT THE POINT WHERE HP = P/RHO*G = P*R^2/RHO*G*M = R.
419C IF(LCZSUR)THEN
420C IF(.NOT.LALLCZ)THEN
421CC PINPOINT RCZ
422C DD2 = DELRM(IMAX-1)-DELAM(IMAX-1)
423C DD1 = DELRM(IMAX)-DELAM(IMAX)
424C FX = DD2/(DD2-DD1)
425CC WRITE(*,911)IMAX,FX,DD2,DD1
426CC 911 FORMAT(I5,1P3E12.3)
427CC INFER HP
428C ENVRL = HRM(IMAX-1)+FX*(HRM(IMAX)-HRM(IMAX-1))
429C ENVR = EXP(CLN*ENVRL)
430C PS2 = EXP(CLN*(HPM(IMAX)-HDM(IMAX)))/HGM(IMAX)
431C PS1 = EXP(CLN*(HPM(IMAX-1)-HDM(IMAX-1)))/HGM(IMAX-1)
432C PSCA = PS1 + FX*(PS2-PS1)
433C RTESTL = DLOG10(ENVR+PSCA)
434CC FIND V
435C DO K = IMAX+1,M
436C IF(HRM(K).GT.RTESTL)THEN
437C FX = (RTESTL-HRM(K-1))/(HRM(K)-HRM(K-1))
438C CVEL = VELM(K-1)+FX*(VELM(K)-VELM(K-1))
439C GOTO 85
440C ENDIF
441C END DO
442C CVEL = VELM(M)
443C 85 CONTINUE
444CC DEFINE TAUCZ
445C TAUCZ = PSCA/CVEL
446CC WRITE(*,911)K,PSCA,CVEL,TAUCZ
447C ELSE
448CC INFER HP
449C PSCA2 = EXP(CLN*(HPM(1)-HDM(1)))/HGM(1)
450C RTEST2 = EXP(CLN*HR(1))
451C IF(PSCA2.LE.RTEST2)THEN
452CC HP < R AT THE FIRST POINT. ASSUME V CONSTANT INSIDE AND HP = K/R FOR
453CC SLOWLY VARYING DENSITY AND PRESSURE NEAR THE CENTER.
454C CVEL = VELM(1)
455C PSCA = (PSCA2*RTEST2)**0.5D0
456C TAUCZ = PSCA/CVEL
457CC WRITE(*,912)PSCA2,RTEST2,PSCA,CVEL,TAUCZ
458CC 912 FORMAT(1P5E12.3)
459C ELSE
460C DO K = 2,M
461C PSCA1 = PSCA2
462C RTEST1 = RTEST2
463C PSCA2 = EXP(CLN*(HPM(K)-HDM(K)))/HGM(K)
464C RTEST2 = EXP(CLN*HR(K))
465CC FIND LOCATION WHERE HP = R
466C IF(PSCA2.LE.RTEST2)THEN
467C FX = (RTEST1-PSCA1)/((PSCA2-RTEST2)-(PSCA1-RTEST1))
468CC FIND V
469C CVEL = VELM(K-1)+FX*(VELM(K)-VELM(K-1))
470C PSCA = PSCA1+FX*(PSCA2-PSCA1)
471CC DEFINE TAUCZ
472C TAUCZ = PSCA/CVEL
473C GOTO 95
474C ENDIF
475C END DO
476C K = M
477C CVEL = VELM(M)
478C PSCA = PSCA2
479C TAUCZ = PSCA/CVEL
480C 95 CONTINUE
481CC WRITE(*,911)K,PSCA,CVEL,TAUCZ
482C ENDIF
483C ENDIF
484C ENDIF
485C JNT 09/25 FOR 05/15 IMPJMOD=1 IS THE SAME AS LSOLID
486 IF(.NOT.LSOLID .AND. (IMPJMOD.NE.1))THEN
487C NOW FIND THE RUN OF ROTATION VARIABLES THAT ARE CONSISTENT WITH THE
488C INTERMEDIATE STRUCTURE AND THE RUN OF SPECIFIC ANGULAR MOMENTUM J/M.
489C J/M = I/M * OMEGA.
490C FIRST GUESS AT MOMENT OF INERTIA OF DISTORTED SPERICAL SHELLS:
491C I/M = 2/3 R**2.
492 DO I = 1,M
493 HIM(I) = CC23*EXP(CLN*2.0D0*HRM(I))
494 OMEGAM(I) = HJM(I)/HIM(I)
495 HIM(I) = HS2(I)*HIM(I)
496 END DO
497C SOLVE FOR THE ANGULAR VELOCITIES OF THE SHELLS GIVEN THE SPECIFIC
498C ANGULAR MOMENTUM (HJM) AND A FIRST GUESS AT THE ANGULAR VELOCITY(OMEGAM)
499C AND MOMENT OF INERTIA (HIM).
500 CALL GETROT(HDM,HJM,HRM,HS,HS2,LCZM,M,ETA2M,HIM,OMEGAM,QIWM,R0M)
501C FIND TOTAL MOMENT OF INERTIA OF THE SURFACE C.Z. IF APPLICABLE.
502 IF(LCZSUR)THEN
503 HICZ = HIM(M)
504 DO I = M-1,1,-1
505 IF(.NOT.LCZM(I))GOTO 110
506 HICZ = HICZ + HIM(I)
507 END DO
508 110 110 CONTINUE
509 ENDIF
510 ELSE
511 JSTART = 1
512 JEND = M
513 CALL SOLID(HDM,HJM,HRM,HS,HS2,JSTART,JEND,ETA2M,HIM,OMEGAM,
514 * * QIWM,R0M,M)
515 IF(LCZSUR)THEN
516 HICZ = HIM(1)
517 DO I = 2,M
518 HICZ = HICZ + HIM(I)
519 END DO
520 ENDIF
521 ENDIF
522 RETURN
523 END
1"""Python version of midmod.f (YREC 7be4133): the structure at an
2intermediate time of a model step, for the angular-momentum transport
3loop."""
4
5import math
6
7import numpy as np
8
9from pyrec import constants_mod
10from pyrec import deuter_mod
11from pyrec import dimensions_mod
12from pyrec import mdphy_mod
13from pyrec import nmlpar_mod
14from pyrec import oldmod_mod
15from pyrec import oldphy_mod
16from pyrec import oldrot_mod
17from pyrec import scrtch_mod
18from pyrec import temp_mod
19from pyrec.dburnm import dburnm
20from pyrec.getrot import getrot
21from pyrec.ovrot import ovrot
22from pyrec.rotmix import rotmix
23from pyrec.solid import solid
24
25JSON = dimensions_mod.json
26
27# The Fortran's local arrays (SAVE): the previous intermediate step's values
28# (DDELP, DDELN, HRP, LCP, formerly COMMON/PREVMID/), the changed-shell flags
29# and the deuterium rates.
30ddelp = np.zeros(JSON + 1)
31ddeln = np.zeros(JSON + 1)
32hrp = np.zeros(JSON + 1)
33lcp = np.zeros(JSON + 1, dtype=bool)
34lchg = np.zeros(JSON + 1, dtype=bool)
35dratem = np.zeros(JSON + 1)
36dratem0 = np.zeros(JSON + 1)
37
38
39def midmod(delts: float, dt: float, fx: float, hcomp: np.ndarray, hd: np.ndarray, hg: np.ndarray, hjm: np.ndarray,
40 hl: np.ndarray, hp: np.ndarray, hr: np.ndarray, hs: np.ndarray, hs1: np.ndarray, hs2: np.ndarray,
41 hstot: float, ht: np.ndarray, lc: np.ndarray, lfirstit: bool, m: int, eta2m: np.ndarray, hdm: np.ndarray,
42 hgm: np.ndarray, hicz: float, him: np.ndarray, hlm: np.ndarray, hpm: np.ndarray, hrm: np.ndarray,
43 hsbot: float, hstop: float, htm: np.ndarray, imin: int, imax: int, lallcz: bool, lcm: np.ndarray,
44 lczm: np.ndarray, lczsur: bool, omegam: np.ndarray, r0m: np.ndarray, qiwm: np.ndarray, mrzone: np.ndarray,
45 mxzone: np.ndarray, nrzone: int, nzone: int, hcomps: np.ndarray) -> tuple[float, float, float, float, int,
46 int, bool, bool, int, int]:
47 """Build the structure at the fraction fx of the model step delts by
48 linear interpolation in time between the old model (the *_mod arrays)
49 and the new one (the arguments); burn and mix the composition over the
50 diffusion step dt; find the convection-zone edges; and solve for the
51 rotation consistent with the specific angular momentum hjm.
52
53 Translates: midmod.f#MIDMOD (7be4133)
54
55 Arguments: the new model (hcomp[k, j], hd, hg, hjm, hl, hp, hr, hs, hs1,
56 hs2, ht, lc; log total mass hstot; m shells); lfirstit, True on the
57 first diffusion step of the model step. Arrays (index 0 unused) set in
58 place: hcomp (reset, burnt and mixed), hjm (only in the dead block),
59 eta2m, hdm, hgm, him, hlm, hpm, hrm, htm, lcm, lczm, omegam, r0m, qiwm,
60 mrzone, mxzone, hcomps (the composition after mixing) and the
61 interpolated physics in mdphy_mod. Scalars set are passed in with any
62 value.
63
64 Returns (fx, hicz, hsbot, hstop, imin, imax, lallcz, lczsur, nrzone,
65 nzone): fx (changed only in the dead block), the moment of inertia of
66 the surface convection zone (unchanged without one), the masses at its
67 bottom and top, the edges imin and imax, whether the star is all
68 convective, whether a surface zone exists, and the numbers of radiative
69 and mixed zones.
70
71 """
72
73 c = constants_mod
74 nml = nmlpar_mod
75 om_ = oldmod_mod
76 op = oldphy_mod
77 md = mdphy_mod
78 sc = scrtch_mod
79 tp = temp_mod
80
81 # The number of species (Fortran lines 118–119).
82 iend = 11
83 if nml.lexcom:
84 iend = 15
85
86 # On the first diffusion step, start from the old composition; save the
87 # radius, convective state and DELA - DELR of the prior step (MHP 06/02)
88 # (Fortran lines 125–141).
89 if lfirstit:
90 for j in range(1, m + 1): # DO 20
91 lcp[j] = om_.lco[j]
92 hrp[j] = om_.hro[j]
93 ddelp[j] = op.delao[j] - op.delro[j]
94 md.amum[j] = op.amuo[j]
95 for i in range(1, iend + 1):
96 hcomp[i, j] = om_.hcompp[i, j]
97 else:
98 for j in range(1, m + 1):
99 hrp[j] = hrm[j]
100 ddelp[j] = ddeln[j]
101 lcp[j] = lcm[j]
102
103 # Interpolate in the model variables and the auxiliary physics; AMUM is
104 # incremented, which comes to the same (see the page) (Fortran lines
105 # 142–169).
106 lnewcz = False
107 fac2 = dt / delts
108 for j in range(1, m + 1): # DO 40
109 hdm[j] = om_.hdo[j] + fx * (hd[j] - om_.hdo[j])
110 hlm[j] = om_.hlo[j] + fx * (hl[j] - om_.hlo[j])
111 hpm[j] = om_.hpo[j] + fx * (hp[j] - om_.hpo[j])
112 hrm[j] = om_.hro[j] + fx * (hr[j] - om_.hro[j])
113 htm[j] = om_.hto[j] + fx * (ht[j] - om_.hto[j])
114 hgm[j] = oldrot_mod.hgo[j] + fx * (hg[j] - oldrot_mod.hgo[j])
115 md.delam[j] = op.delao[j] + fx * (sc.sdel[3, j] - op.delao[j])
116 md.delm[j] = op.delo[j] + fx * (sc.sdel[2, j] - op.delo[j])
117 md.delrm[j] = op.delro[j] + fx * (sc.sdel[1, j] - op.delro[j])
118 md.esumm[j] = op.esumo[j] + fx * (sc.sesum[j] - op.esumo[j])
119 md.viscm[j] = op.visco[j] + fx * (tp.visc[j] - op.visco[j])
120 md.thdifm[j] = op.thdifo[j] + fx * (tp.thdif[j] - op.thdifo[j])
121 md.cpm[j] = op.cpo[j] + fx * (tp.cp[j] - op.cpo[j])
122 md.qdtm[j] = op.qdto[j] + fx * (tp.sqdt[j] - op.qdto[j])
123 md.om[j] = op.oo[j] + fx * (sc.so[j] - op.oo[j])
124 md.amum[j] = md.amum[j] + fac2 * (tp.hamu[j] - op.amuo[j])
125 # The total energy generation: nuclear plus the gravitational terms (MHP 6/00).
126 temp = sc.sesum[j] + sc.seg[6, j] + sc.seg[7, j]
127 md.epsm[j] = op.epso[j] + fx * (temp - op.epso[j])
128
129 # Shells that change state over the step are convective if
130 # DELA < DELR at the intermediate time (Fortran lines 174–191).
131 # Question (see the page): the Schwarzschild criterion here.
132 for i in range(1, m + 1): # DO 50
133 ddeln[i] = md.delam[i] - md.delrm[i]
134 if lc[i] == lcp[i]:
135 lcm[i] = lc[i]
136 md.velm[i] = op.velo[i] + fx * (sc.svel[i] - op.velo[i])
137 lchg[i] = False
138 else:
139 lchg[i] = True
140 lnewcz = True
141 if md.delam[i] < md.delrm[i]:
142 lcm[i] = True
143 md.velm[i] = max(op.velo[i], sc.svel[i])
144 else:
145 lcm[i] = False
146 md.velm[i] = 0.0
147
148 # Receding convection zones: unused? (see the page), since this reset
149 # comes first (Fortran lines 192–318).
150 lnewcz = False
151 if lnewcz:
152 fx = _receding_cz(m, fx, hjm, hr, hs2, lcm)
153
154 # Convective overshoot applied to normal convection zones (Fortran
155 # lines 320–321).
156 nrzone, nzone = ovrot(hcomp, hdm, hpm, hrm, hs, htm, lcm, m, lczm,
157 mrzone, mxzone, nrzone, nzone)
158
159 # Reburn the original mixture for the short step, at the current T
160 # (MHP 6/00), and save the composition (Fortran lines 326–333).
161 rotmix(dt, hcomp, hs2, htm, m, mrzone, mxzone, nrzone, nzone,
162 hstot, hdm, hs, hrm, hpm, lczm, hs1)
163 for i in range(1, m + 1):
164 for j in range(1, iend + 1):
165 hcomps[j, i] = hcomp[j, i]
166
167 # Deuterium burning (MHP 05/02): the rates over the substep (Fortran
168 # lines 335–347).
169 if om_.hcompp[12, m] > 1.0e-14:
170 dr = deuter_mod
171 if lfirstit:
172 for i in range(1, m + 1):
173 dratem[i] = dr.drate0[i] + fac2 * (dr.drate[i] - dr.drate0[i])
174 dratem0[i] = dr.drate0[i]
175 else:
176 for i in range(1, m + 1):
177 dratem0[i] = dratem[i]
178 dratem[i] = dratem[i] + fac2 * (dr.drate[i] - dr.drate0[i])
179
180 # Radiative zones, shell by shell, until T drops below the cutoff;
181 # the zones run outward, so no hotter shell is skipped (Fortran
182 # lines 350–360).
183 done = False
184 for k in range(1, nrzone + 1):
185 for j in range(mrzone[k, 1], mrzone[k, 2] + 1):
186 if htm[j] <= nml.tcut[1]:
187 done = True # GOTO 190
188 break
189 ibegin = j
190 iend = j
191 dburnm(ibegin, iend, m, hs2, hcomp, dt, dratem, dratem0,
192 fac2)
193 if done:
194 break
195
196 # label 190. Convection zones, zone by zone (Fortran lines 365–370).
197 for k in range(1, nzone + 1):
198 ibegin = mxzone[k, 1]
199 iend = mxzone[k, 2]
200 dburnm(ibegin, iend, m, hs2, hcomp, dt, dratem, dratem0, fac2)
201
202 # Extent of a central convection zone (Fortran lines 375–383).
203 # Question (see the page): IMIN is the last convective shell.
204 if lczm[1]:
205 i = m + 1
206 for k in range(2, m + 1): # DO 60
207 if not lczm[k]:
208 i = k
209 break
210 imin = max(2, i - 1) # label 65
211 else:
212 imin = 2
213
214 # Extent of a surface convection zone (Fortran lines 385–413).
215 lallcz = False
216 if lczm[m]:
217 i = 0
218 lallcz = True
219 for k in range(m - 1, 0, -1): # DO 70
220 if not lczm[k]:
221 i = k
222 lallcz = False
223 break
224 imax = i + 1 # label 80
225 # HSTOP, HSBOT: the masses at the top and bottom of the zone.
226 hstop = math.exp(c.cln * hstot)
227 if imax > 1:
228 hsbot = 0.5 * (hs1[imax] + hs1[imax - 1])
229 else:
230 hsbot = 0.0
231 # Question (see the page): true for any surface zone.
232 if (hstop - hsbot) / c.cmsun > 0.0:
233 lczsur = True
234 else:
235 lczsur = False
236 else:
237 imax = m
238 lczsur = False
239
240 # The rotation: a first guess from thin spherical shells, I/M = 2/3 r**2,
241 # Omega = J/I, then GETROT (Fortran lines 486–500). A local convective
242 # overturn time is not computed here (MHP 3/09). IMPJMOD = 1 is the same
243 # as LSOLID (JNT 09/25).
244 if not nml.lsolid and nml.impjmod != 1:
245 for i in range(1, m + 1):
246 him[i] = c.cc23 * math.exp(c.cln * 2.0 * hrm[i])
247 omegam[i] = hjm[i] / him[i]
248 him[i] = hs2[i] * him[i]
249 getrot(hdm, hjm, hrm, hs, hs2, lczm, m, eta2m, him, omegam, qiwm,
250 r0m)
251
252 # Moment of inertia of the surface convection zone (Fortran lines
253 # 502–509).
254 if lczsur:
255 hicz = him[m]
256 for i in range(m - 1, 0, -1):
257 if not lczm[i]:
258 break # GOTO 110
259 hicz = hicz + him[i]
260
261 # Solid rotation (Fortran lines 510–521).
262 else:
263 jstart = 1
264 jend = m
265 solid(hdm, hjm, hrm, hs, hs2, jstart, jend, eta2m, him, omegam,
266 qiwm, r0m, m)
267 # Question (see the page): the whole star for solid rotation.
268 if lczsur:
269 hicz = him[1]
270 for i in range(2, m + 1):
271 hicz = hicz + him[i]
272
273 return (fx, hicz, hsbot, hstop, imin, imax, lallcz, lczsur, nrzone,
274 nzone)
275
276
277def _receding_cz(m: int, fx: float, hjm: np.ndarray, hr: np.ndarray, hs2: np.ndarray, lcm: np.ndarray) -> float:
278 """Correct the specific angular momentum of shells that left a
279 convection zone during the step (MHP 06/02; Fortran lines 197–318).
280 Never run (LNEWCZ is reset first): unused? (see the page); translated
281 as written, its defects included. Returns FX, which the Fortran
282 overwrites.
283
284 """
285
286 c = constants_mod
287 hro = oldmod_mod.hro
288
289 # The changed regions (Fortran lines 198–233).
290 lcc = False
291 ldo = False
292 for i in range(1, m):
293 if lchg[i]:
294 if not lcc:
295 lcc = True # start of a changed region
296 i0 = i
297 if not lchg[i]:
298 if lcc:
299 i1 = i - 1 # end of a changed region
300 lcc = False
301 ldo = True
302 print(i0, i1, ddeln[i0], ddeln[i0 - 1], ddeln[i1 + 1])
303 # Only a receding convection zone changes J.
304 if ddeln[i0] > 0.0:
305 if ddeln[i0 - 1] < 0.0:
306 ind = -1 # subtracted from a core zone
307 elif ddeln[i1 + 1] < 0.0:
308 ind = 1 # subtracted from an envelope zone
309 else:
310 ldo = False
311 else:
312 ldo = False
313
314 # Correct J in a receding zone (Fortran lines 234–316).
315 if ldo:
316 ldo = False
317 if ind < 0:
318 # Core zone: locate its edges.
319 icz1 = i0 - 1
320 icz0 = 1
321 for ii in range(i0 - 1, 0, -1):
322 if not lcm[ii]:
323 icz0 = ii + 1
324 break # GOTO 11
325 js = range(i1, i0 - 1, -1)
326 else:
327 # Envelope zone: locate its edges.
328 icz0 = i1 + 1
329 icz1 = m
330 for ii in range(i1 + 2, m + 1):
331 if not lcm[ii]:
332 icz1 = ii - 1
333 break # GOTO 12
334 js = range(i0, i1 + 1)
335 for j in js:
336 if ddeln[j] < 0.0:
337 break # GOTO 13
338 czi = 0.0
339 czj = 0.0
340 # Fractions of the step the shell was radiative, convective.
341 fx = ddeln[j] / (ddeln[j] - ddelp[j])
342 f2 = 1.0 - fx
343 zone = range(icz0, j) if ind < 0 else range(j + 1, icz1 + 1)
344 for ii in zone:
345 hrr = hrp[ii] + f2 * (hr[ii] - hro[ii])
346 czi = czi + c.cc23 * hs2[ii] * 10.0**(2.0 * hrr)
347 czj = czj + hjm[ii] * hs2[ii]
348 # The zone's J/M when the shell was released; the
349 # difference goes back into the zone.
350 hrsh = 2.0 * (hrp[j] + f2 * (hr[j] - hrp[j]))
351 hjm2 = c.cc23 * (czj / czi) * 10.0**hrsh
352 delj = (hjm[j] - hjm2) * hs2[j]
353 ratio = (czj - delj) / czj
354 hjm[j] = hjm2
355 rr = hjm2 / hjm[j]
356 print(j, fx, rr, delj, ratio)
357 rescale = range(icz0, j) if ind < 0 else range(j + 1, m + 1)
358 for ii in rescale:
359 hjm[ii] = hjm[ii] * ratio
360 # label 13
361 return fx