1C
2C
3C$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
4C STARIN
5C$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
6C SUBROUTINE STARIN(BL,CFENV,DAGE,DDAGE,DELTS,DELTSH,DELTS0,ETA2,FP, ! KC 2025-05-31
7 SUBROUTINE STARIN(BL,CFENV,DAGE,DDAGE,DELTS,DELTSH,ETA2,FP,
8 * * FT,FTRI,HCOMP,HD,HI,HJM,HKEROT,HL,HP,HR,HS,HS1,HS2,HSTOT,HT,IKUT,
9C * ISTORE,JCORE,JENV,LARGE,LC,LNEW,M,MODEL,NK,OMEGA,PS,QDP,QDT,QIW, ! KC 2025-05-31
10 * * ISTORE,JENV,LARGE,LC,LNEW,M,MODEL,NK,OMEGA,PS,QIW,
11 * * R0,RS,SJTOT,SKEROT,SMASS,TEFFL,TLUMX,TRIL,TRIT,TS,VEL,HG,V,
12 * * CMIXL,COMPMIX)
13C 11/02/26 MHP via Claude
14C code changed to make QDT and QDP locals. MAIN only passed them on to
15C CRRECT, and COEFFT sets them from EQSTAT before every use.
16C 10/15/26 MHP via Claude
17C code changed to take JSON from DIMENSIONS_MOD instead of declaring
18C PARAMETER(JSON=5000) here.
19 USE DIMENSIONS_MOD
20C 10/14/26 MHP via Claude
21C code changed to convert COMMON/NEWOPAC/ into NEWOPAC_MOD.
22 USE NEWOPAC_MOD
23C 10/14/26 MHP via Claude
24C code changed to convert COMMON/OVRTRN/ into OVRTRN_MOD.
25 USE OVRTRN_MOD
26C 10/14/26 MHP via Claude
27C code changed to convert COMMON/OLDROT/ into OLDROT_MOD.
28 USE OLDROT_MOD
29C 10/14/26 MHP via Claude
30C code changed to convert COMMON/OLDMOD/ into OLDMOD_MOD.
31 USE OLDMOD_MOD
32C 10/14/26 MHP via Claude
33C code changed to convert COMMON/ENVSTRUCT/ into ENVSTRUCT_MOD.
34 USE ENVSTRUCT_MOD
35C 10/14/26 MHP via Claude
36C code changed to convert COMMON/DPMIX/ into DPMIX_MOD.
37 USE DPMIX_MOD
38C 10/14/26 MHP via Claude
39C code changed to convert COMMON/DEBHU/ into DEBHU_MOD.
40 USE DEBHU_MOD
41C 10/14/26 MHP via Claude
42C code changed to convert COMMON/COMP2/ into COMP2_MOD.
43 USE COMP2_MOD
44C 10/14/26 MHP via Claude
45C code changed to convert COMMON/COMP/ into COMP_MOD.
46 USE COMP_MOD
47C 10/14/26 MHP via Claude
48C code changed to convert COMMON/CENV/ into CENV_MOD.
49 USE CENV_MOD
50C 10/14/26 MHP via Claude
51C code changed to convert COMMON/NMLBYPASS/ into NMLBYPASS_MOD.
52 USE NMLBYPASS_MOD
53C 10/14/26 MHP via Claude
54C code changed to convert COMMON/NMLPAR/ into NMLPAR_MOD.
55 USE NMLPAR_MOD
56C 10/14/26 MHP via Claude
57C code changed to convert COMMON/CONSTANTS/ into CONSTANTS_MOD.
58 USE CONSTANTS_MOD
59C 10/14/26 MHP via Claude
60C code changed to convert COMMON/IOUNITS/ into IOUNITS_MOD.
61 USE IOUNITS_MOD
62C 10/14/26 MHP via Claude
63C code changed to convert COMMON/RUNLOOP/ into RUNLOOP_MOD. A blanket
64C USE imports exactly the names the COMMON declaration made global here,
65C so it cannot change meaning. See runloop_mod.f for the block history
66C and for why the module declares the types the implicit rules supplied.
67 USE RUNLOOP_MOD
68C 10/20/26 MHP via Claude
69C code changed to replace implicit typing with IMPLICIT NONE and
70C explicit declarations.
71 IMPLICIT NONE
72 REAL*8 AMU,ATEFFL,ATOMWT,B,BETA,BETA14,BETAI,BL,CFENV,CMIXL,
73 * * CMIXL0,D,DAGE,DD,DDAGE,DEL,DELA,DELR,DELTS,DELTSH,DL,DP,DR,
74 * * DS,DS1,DS2,DS3,DT,DUM1,DUM2,DUM3,DUM4,EBEG0,EMAX0,EMIN0,
75 * * EMU,ETA,ETA2,FACD,FP,FPL,FS,FT,FTL,FTRI,FV,FX,FXION,GL,
76 * * HCOMP,HD,HG,HI,HJ,HJM,HKEROT,HL,HLC,HP,HR,HS,HS1,HS2,HSEND,
77 * * HSTOT,HT,O,OL,OMEGA,P,PDISK0,PL,PLIM,PP,PS,QACP,QACR,QACT,
78 * * QAP,QAT,QCP,QCPP,QCPT,QDP,QDT,QDTP,QDTT,QIW,QOD,QOT,R0,
79 * * RAT_C,RAT_N,RAT_O,RHOC,RL,RMU,RS,SENV1,SENVTOL,SJTOT,SKEROT,SL,
80 * * SMASS,SUMJ,SUMKE,SUM_C,SUM_O,T,TDISK0,TEFFL,TEMP,TEST,TL,
81 * * TLUMX,TOT_C,TOT_N,TOT_O,TRIL,TRIT,TS,V,VEL,VSUM,WMAX0,X,X0,
82 * * X1,X2,Z
83 INTEGER I,IDUM,IKUT,IREAD,ISTORE,IXX,J,JCORE0,JEND,JENV,JENV0,JM,
84 * * K,M,MM,MN,MODEL,MP1,MRZONE,MXZONE,NK,NRZONE,NZONE
85 LOGICAL*4 LARGE,LATMO,LC,LCONV,LCZ,LDERIV,LDIFY0,LDIFZ0,LDISK0,
86 * * LEXCOM0,LEXCP0,LINSTB0,LJDOT00,LMIXL,LNEW,LOCOND,LOVSTC0,
87 * * LOVSTE0,LOVSTM0,LPRT,LPULPT,LPUREZ0,LROT0,LSBC0,LSEMIC0
88
89C DBGLAOL
90 INTEGER*4 KATM, KENV, KSAHA
91C CHARACTER*256 OPECALEX(7)
92 CHARACTER*4 ATEMP
93 CHARACTER*6 EOS
94 CHARACTER*4 ATM, LOK, HIK, COMPMIX
95C MHP 8/25 Removed unused character strings
96C CHARACTER*256 FLAOL, FPUREZ
97C CHARACTER*256 FLAST, FFIRST, FRUN, FSTAND, FFERMI,
98C 1 FDEBUG, FTRACK, FSHORT, FMILNE, FMODPT,
99C 2 FSTOR, FPMOD, FPENV, FPATM, FDYN,
100C 3 FLLDAT, FSNU, FSCOMP, FKUR,
101C 4 FMHD1, FMHD2, FMHD3, FMHD4, FMHD5, FMHD6, FMHD7, FMHD8
102C 9/24/26 MHP via Claude
103C code changed to remove dead ILLDAT, IKUR from COMMON/LUNUM/
104C 9/24/26 MHP via Claude
105C code changed to remove dead IDYN from COMMON/LUNUM/
106C 9/25/26 MHP via Claude
107C code changed to consolidate all I/O logical unit numbers, previously
108C scattered across COMMON/LUOUT/, COMMON/LUNUM/, COMMON/ALEX06/,
109C COMMON/ACDPTH/, COMMON/NEWOPAC/, COMMON/LOPAL95/, COMMON/ATMOS2/,
110C COMMON/ALATM03/, COMMON/OPALEOS/, and COMMON/SCV2/, into a single
111C COMMON/IOUNITS/
112C 9/25/26 MHP via Claude
113C code changed to remove dead COMMON/LUNUM/ISCOMP (declared,
114C assigned a unit number, but never opened or read anywhere)
115C COMMON/LUFNM/ FLAST, FFIRST, FRUN, FSTAND, FFERMI,
116C 1 FDEBUG, FTRACK, FSHORT, FMILNE, FMODPT,
117C 2 FSTOR, FPMOD, FPENV, FPATM, FDYN,
118C 3 FLLDAT, FSNU, FSCOMP, FKUR,
119C 4 FMHD1, FMHD2, FMHD3, FMHD4, FMHD5, FMHD6, FMHD7, FMHD8
120C DBGLAOL
121C MHP 8/25 Removed all character strings from common blocks
122C 10/12/26 MHP via Claude
123C code changed to extend COMMON/NMLPAR/ to 234 members, adding the
124C namelist variables that the physics routines read from 27 COMMON
125C blocks which also held derived or working members. Those blocks keep
126C only their non-namelist members; five of them -- NEWMX, VMULT,
127C PMMWIND, CCOUT1 and ENVGEN -- had nothing left and are gone.
128C Derivation-only namelist variables from the same blocks went to
129C COMMON/NMLBYPASS/ instead, not here.
130C
131C Declared identically in all 121 files that hold any of these members.
132C Generated from one member list, so every copy is byte-identical; the
133C linker's 'size of symbol changed' warning is the check that they are.
134C 9/25/26 MHP via Claude
135C code changed to merge COMMON/CONST/, COMMON/CONST1/, COMMON/CONST2/,
136C and COMMON/CONST3/ into a single COMMON/CONSTANTS/
137C 9/24/26 MHP via Claude
138C code changed to pass CMIXL as an explicit argument instead of via
139C common block, to reduce implicit global state ahead of the F90
140C module conversion
141C 10/13/26 MHP via Claude: removed the unused COMMON/ENVPRT/ declaration
142C (no member referenced here; residue of the obsolete-option removals).
143C 10/12/26 MHP via Claude
144C code changed to remove COMMON/OPTAB/ entirely. Once OPTOL moved to the
145C consolidated namelist block, every remaining member was write-only:
146C ZSI appeared only in a DATA statement in parmin.f, and IDT and IDD were
147C assigned the constants 15 and 5 in coefft.f, envint.f, physic.f and
148C starin.f and read nowhere in the code. They are leftovers from the
149C removed opacity-table interpolation schemes.
150C DBG 7/92 COMMON BLOCK ADDED TO COMPUTE DEBYE-HUCKEL CORRECTION.
151 DIMENSION TLUMX(8),TRIL(3),TRIT(3),PS(3),TS(3),RS(3),CFENV(9),
152 * *HS(JSON),HL(JSON),HR(JSON),HP(JSON),HT(JSON),HD(JSON),LC(JSON),
153 * *HCOMP(15,JSON),OMEGA(JSON),HS1(JSON),HS2(JSON),QIW(JSON),
154 * *ETA2(JSON),FP(JSON),FT(JSON),HI(JSON),HJM(JSON),R0(JSON),
155 * * HKEROT(JSON),HG(JSON),ATOMWT(12),V(12),DUM1(4),
156 * * DUM2(3),DUM3(3),DUM4(3),FXION(3)
157C MHP 10/24 ENSURE THAT ONLY HOMOGENEOUS MODELS HAVE THE MIXTURE ALTERED
158 REAL*8 TESTMIX(15)
159C OPACITY COMMON BLOCKS - modified 3/09
160C 9/23/26 MHP via Claude
161C code changed to remove the OPAL92 opacity tables
162C 9/23/26 MHP via Claude
163C code changed to remove the Kurucz 1990 opacity tables
164C 9/23/26 MHP via Claude
165C code changed to remove the LAOL89 opacity tables
166C 9/24/26 MHP via Claude
167C code changed to remove the Alexander 1995 opacity tables
168C 9/24/26 MHP via Claude
169C code changed to remove dead opacity-table Z-value inputs
170C 9/24/26 MHP via Claude
171C code changed to merge COMMON /MISCOPAC/ and COMMON/NWLAOL/ into
172C COMMON /NEWOPAC/
173C 10/13/26 MHP via Claude: removed the unused COMMON/SCVEOS/ declaration
174C (no member referenced here; residue of the obsolete-option removals).
175C MHP 10/98 ADDED HPTTOL FOR CHANGING CORE FITTING POINT
176C 10/13/26 MHP via Claude: removed the unused COMMON/CTOL/ declaration
177C (no member referenced here; residue of the obsolete-option removals).
178C MHP 07/02 ADDED FOR ENVELOPE INTEGRATION WHEN CHANGING THE
179C OUTER FITTING POINT
180C MHP 07/02 STORE CONTENTS OF ENVELOPE INTEGRATION INTO A
181C SET OF VECTORS, WHICH ARE FLIPPED AND CONVERTED INTO AN ASCENDING
182C SERIES AFTER THE INTEGRATION IS DONE.
183C KC 2025-05-30 reordered common block elements
184C JvS 08/25 Updated with new elements
185C LLP 3/19/03 Add COMMON block /I2O/ for info directly transferred from
186C input to output model - starting with a code for th initial model
187C compostion (COMPMIX)
188C 10/13/26 MHP via Claude
189C code changed to replace COMMON/I2O/ with an explicit argument. COMPMIX
190C is CHARACTER, which does not belong in a COMMON block. GETMODEL2,
191C GETYREC7 and PUTMODEL2 already took it as an argument; only these three
192C files shared it through the block.
193C G Somers 10/14, Add spot common block
194C G Somers END
195C MHP 10/24 ADDED NEW CONTROLS FOR ALTERING THE CNO MASS FRACTIONS
196C ISOTOPIC RATIOS(C,N,O) AND D/HE3/LI/BE/B ABUNDANCES.
197C THESE CONTROLS ONLY ALTER THE MIXTURE IN THE STARTING MODEL AND ONLY
198C IF THE MODEL IS CHEMICALLY UNEVOLVED. POSTPROCESSING TOOLS SHOULD BE USED FOR THE
199C CORE HE BURNING PHASE.
200c COMMON/NEWCMP/XNEWCP,INEWCP,LNEWCP,LREL,ANEWCP
201C 10/12/26 MHP via Claude
202C code changed to merge COMMON/NEWPARAM/, COMMON/NEWCROSS/ and
203C COMMON/XSECT/ into a single COMMON/NMLBYPASS/, declared here, in
204C remap.f and in starin.f.
205C
206C These are namelist variables that exist only to set other quantities,
207C or that are reserved for future development; none is read by the wider
208C code. Keeping them in their own block keeps them OUT of the single
209C consolidated namelist block being built, so that block holds only
210C variables the physics routines actually consume. starin.f declares it
211C although it uses none of them yet, so the isotope and cross-section
212C machinery there can reach them without reopening this layout.
213C
214C Member order is NEWPARAM, then NEWCROSS, then XSECT, and the three
215C declarations are generated from one list so all files agree.
216 DATA ATOMWT/23.0D0,26.99D0,24.32D0,55.86D0,28.1D0,12.015D0,
217 * * 1.008D0,16.0D0,14.01D0,39.96D0,20.19D0,4.004D0/
218C 10/13/26 MHP via Claude: removed the unused COMMON/SCRTCH/ declaration
219C (no member referenced here; residue of the obsolete-option removals).
220
221C DIMENSION MXZONE(12,2),MXZON0(12,2),MRZONE(13,2) ! KC 2025-07-22
222 DIMENSION MXZONE(12,2),MRZONE(13,2)
223 DIMENSION LCZ(JSON)
224 SAVE
225
226
227C If flag LARGE is set, model has failed to converge. Terminate the run.
228 IF(LARGE) THEN
229 WRITE(ISHORT,1000)
230 1000 1000 FORMAT(1X,39('>'),40('<')/,
231 * * "STARIN: ***** RUN STOPPED *****")
232 WRITE(ISHORT,1010)
233 1010 1010 FORMAT("STARIN: ***** MODEL FAILED TO CONVERGE *****")
234C 10/30/26 MHP via Claude: bare STOP -> STOP 1, the run-time error code (issue 38).
235 STOP 1
236 ENDIF
237
238C THIS SUBROUTINE READS IN THE INITIAL STELLAR MODEL
239C INITIAL MODEL IS STORED IN LOGICAL UNIT IFIRST
240
241C Set flags for reading an input model
242 IKUT = 0
243 IREAD = IFIRST
244
245C INITIALIZE VARIABLES
246 VEL = 0.0D0
247 QDT = -1.0D0
248 QDP = 1.0D0
249
250C Flag LFIRST(NK) tells where to get the starting stellar model for the current
251C step (step NK). If LFIRST(NK) is true, read in the starting stellarmodel from
252C the file specified by LU IFIRST. If LFIRST(NK) is false, as starting model use
253C the stellar model currently stored in memory.
254
255 IF(.NOT.LFIRST(NK)) THEN
256C Use the model currently in memory as the starting model.
257C DBG 2/92 CHANGED SO WILL RESCALE ENVELOPE MASS ON EACH NEW RUN
258C 10/30/26 MHP via Claude
259C code changed to drop this RSCALE call. The jump to 3000 reaches the
260C call after the core extension, so a reused model was rescaled twice.
261C Now skip over the reading and processing of an input model file
262 GOTO 3000
263 ENDIF
264
265
266C Read in the starting model from LU IFIRST and process it.
267
268C Get file format of input model
269
270 REWIND IREAD
271 READ(IREAD,10) ATEMP
272 10 10 FORMAT(A4)
273
274C ATEMP now contains a keyword describing the format of the input stellar
275C model. We decide what kind of model format it has and process accordingly.
276
277 IF(ATEMP .EQ. 'NMOD') THEN
278 WRITE(ISHORT,12)
279 12 12 FORMAT('STARIN: Input model has YREC7 format')
280 CALL GETYREC7(BL,CFENV,CMIXL0,DAGE,DDAGE,FTRI,HCOMP,HD,HL,
281 * * HP,HR,HS,HSTOT,HT,IREAD,ISHORT,JCORE0,JENV0,LC,LEXCOM0,
282 * * LROT0,M,MODEL,OMEGA,PS,RS,SMASS,TEFFL,TLUMX,TRIL,TRIT,TS,
283 & & ATM,EOS,HIK,LDIFY0,LDIFZ0,LDISK0,LINSTB0,LJDOT00,LOK,
284 & & LOVSTC0,LOVSTE0,LOVSTM0,LPUREZ0,LSEMIC0,COMPMIX,PDISK0,
285 & & TDISK0,WMAX0)
286C First three lines above are YREC7 inputs
287C Last three lines are MODEL2 add-ons
288
289 ELSE IF(ATEMP .EQ. 'MOD2 ') THEN
290 WRITE(ISHORT,16)
291 16 16 FORMAT('STARIN: Input model has MODEL2 format')
292 CALL GETMODEL2(BL,CFENV,CMIXL0,DAGE,DDAGE,FTRI,HCOMP,HD,HL,
293C * HP,HR,HS,HSTOT,HT,IREAD,ISHORT,JCORE0,JENV0,LC,LEXCOM0, ! KC 2025-05-31
294 * * HP,HR,HS,HSTOT,HT,IREAD,JCORE0,JENV0,LC,LEXCOM0,
295 * * LROT0,M,MODEL,OMEGA,PS,RS,SMASS,TEFFL,TLUMX,TRIL,TRIT,TS,
296 & & ATM,EOS,HIK,LDIFY0,LDIFZ0,LDISK0,LINSTB0,LJDOT00,LOK,
297 & & LOVSTC0,LOVSTE0,LOVSTM0,LPUREZ0,LSEMIC0,COMPMIX,PDISK0,
298 & & TDISK0,WMAX0)
299C First three lines above are YREC7 inputs
300C Last three lines are MODEL2 add-ons
301
302 ELSE
303 WRITE(ISHORT,20)
304 20 20 FORMAT('STARIN: ***** RUN TERMINATED, INVALID INPUT',
305 * * ' MODEL FILE. *****')
306C 10/30/26 MHP via Claude: bare STOP -> STOP 3, the input-error code (issue 38).
307 STOP 3
308 ENDIF
309
310C Model has now been read in. Some post-processing is required.
311
312 DELTS = CSECYR*DDAGE
313 DELTSH = DABS(DELTS)
314 STOTAL = HSTOT
315
316C CHECK TO ENSURE THAT MIX LENGTH, SURFACE B.C. AND CONVECTION ZONE
317C THEORY OF THE MODEL ARE THE SAME AS USER PARAMETERS
318C CHECKED ONLY FOR EVOLVED MODELS(MODEL NUMBER > 0)
319C 1/92 Changed to not stop just give warning.
320 IF(MODEL.GT.0) THEN
321 LMIXL = .TRUE.
322C Jan 12, 1989 : in STARIN changed test to see if model has correct mixing
323C length from 1.0e-6 to 2.0e-3 because models only store
324C mixing length to four sig digits.
325 IF(CMIXL0.GT.0.0D0) LMIXL = (DABS(CMIXL-CMIXL0).LT.2.0D-3)
326C MHP 9/03 FIXED TYPO
327 IF(.NOT.LMIXL .OR. LEXCOM0.NEQV.LEXCOM) THEN
328 WRITE(ISHORT,1040) CMIXL,CMIXL0,LEXCOM,LEXCP0
329 WRITE(IOWR,1040) CMIXL,CMIXL0,LEXCOM,LEXCP0
330 1040 1040 FORMAT(1X,'ERROR IN SUBROUTINE STARIN'/1X,'USER PARAMETERS',
331 * * ' OF WRONG TYPE FOR INITIAL MODEL'/1X,'MIXING LENGTH - USER'
332 * * ,' DESIRES',F7.3,' MODEL MIX LENGTH',F7.3/1X,
333 * * 'EXTENDED COMP-USER DESIRES ',L1,' MODEL USED ',L1)
334C =>RUN STOPPED DUE TO INCONSISTENCY BETWEEN MODEL AND RUN PARMS
335c STOP
336 ENDIF
337 ENDIF
338
339C ENVELOPE DATA (Now bypassed)
340C LNEW0 HAS BEEN READ IN, IF TRUE THEN RECOMPUTE ENVELOPE EVERY MODEL
341C STORED ENVELOPE RECORDS ONLY USED FOR HE FLASH CALCS
342c IF(LNEW0) THEN
343c LNEW = .TRUE.
344c ELSE
345c LNEW = .NOT.LKUTHE
346c ENDIF
347c DO 80 I = 1,3
348c IF((.NOT.LNEW).AND.IABS(IO).NE.I) LNEW = .TRUE.
349c 80 CONTINUE
350
351 ISTORE = 0
352 FTRI = 1.0D0
353c Require recompute of envelope. No assurance of reliable
354c input triangle
355 LNEW = .TRUE.
356
357
358C GET XNEW AND ZNEW FROM HENYEY POINTS
359
360 XNEW = HCOMP(1,M)
361 ZNEW = HCOMP(3,M)
362
363C FOURTH PART: - LOG J/M STORED
364
365 IF(LROT) THEN
366 IF(LWNEW) THEN
367C GENERATE A SOLID BODY ROTATION CURVE WITH OMEGA = WNEW;
368C THIS IS DONE TO CONVERT A NON-ROTATING MODEL TO A ROTATING ONE.
369 DO 540 I = 1,M
370 OMEGA(I) = WNEW
371 540 540 CONTINUE
372 ENDIF
373 ELSE
374 DO 570 I = 1,JSON
375 FP(I) = 1.0D0
376 FT(I) = 1.0D0
377 570 570 CONTINUE
378 ENDIF
379C KEEP IREAD OPEN
380 REWIND IREAD
381C End of the reading and processing of an input model file.
382 IF(.NOT.LFIRST(NK))GOTO 3000
383C IF(.NOT.LFIRST(NK).OR.NK.GT.1)GOTO 3000
384C MHP 10/24 MACHINERY TO ALTER THE HEAVY ELEMENT MIXTURE
385C THIS IS ONLY DONE if the first MODEL IS being READ IN, AND ONLY FOR A
386C CHEMICALLY HOMOGENEOUS MODEL. IT CAN OVER-WRITE MASS FRACTIONS 4-15 WITH USER-SPECIFIED VALUES
387C ISETMIX=1 -> CAN ADJUST CNO FRACTIONS ISETISO=1-> CHANGE ISOTOPE RATIOS
388 IF(LMIXTURE .OR. LISOTOPE)THEN
389C ENSURE STARTING MODEL IS HOMOGENEOUS BEFORE EITHER IS CHANGED
390 DO I = 1,15
391 TESTMIX(I)=HCOMP(I,1)
392 END DO
393 DO J = 2,M
394 DO I = 1,15
395 TEST = ABS(HCOMP(I,J)-TESTMIX(I))
396 IF(TEST.GT.1.0D-6)THEN
397 WRITE(*,592)I,J,TEST
398 WRITE(ISHORT,592)I,J,TEST
399 592 592 FORMAT('SPECIES ',I3,' IN SHELL ',I5,
400 * * ' DIFFERS FROM CENTER BY ',E12.4,
401 * * ' MIX NOT MODIFIED IN EVOLVED MODEL')
402 GOTO 602
403 ENDIF
404 END DO
405 END DO
406 ENDIF
407C LOOP FOR CHANGING CNO MIX
408 IF(LMIXTURE)THEN
409C INFER CURRENT TOTAL CNO FRACTIONS AND SCALE ALL ISOTOPES BY THE RATIO BETWEEN
410C DESIRED AND CURRENT FRACTIONS. RELATIVE ISOTOPES ARE ADJUSTED IN THE ISOTOPE SECTION BELOW.
411 TOT_C = (TESTMIX(5)+TESTMIX(6))/TESTMIX(3)
412 TOT_N = (TESTMIX(7)+TESTMIX(8))/TESTMIX(3)
413 TOT_O = (TESTMIX(9)+TESTMIX(10)+TESTMIX(11))/TESTMIX(3)
414 RAT_C = FRAC_C/TOT_C
415 RAT_N = FRAC_N/TOT_N
416 RAT_O = FRAC_O/TOT_O
417 WRITE(*,*)FRAC_C,FRAC_N,FRAC_O
418 DO I = 5,6
419 DO J = 1,M
420 HCOMP(I,J)=RAT_C*HCOMP(I,J)
421 END DO
422 END DO
423 DO I = 7,8
424 DO J = 1,M
425 HCOMP(I,J)=RAT_N*HCOMP(I,J)
426 END DO
427 END DO
428 DO I = 9,11
429 DO J = 1,M
430 HCOMP(I,J)=RAT_O*HCOMP(I,J)
431 END DO
432 END DO
433 WRITE(*,594)(TESTMIX(K),K=5,11),(HCOMP(K,1),K=5,11)
434 WRITE(ISHORT,594)(TESTMIX(K),K=5,11),(HCOMP(K,1),K=5,11)
435 594 594 FORMAT('CNO MIX CHANGED IN STARIN. OLD C12 C13 N14'
436 * * ' N15 O16 O17 O18 ',7E12.4,' NEW ',7E12.4)
437 ENDIF
438C DESIRED ISOTOPE RATIOS AND LIGHT ELEMENT ABUNDANCES ASSIGNED.
439C AT PRESENT B10,B11,N15,O17 ARE NOT USED AND THUS NOT ALTERED.
440C START WITH LIGHT ELEMENTS
441 IF(LISOTOPE)THEN
442 SUM_C = HCOMP(5,1)+HCOMP(6,1)
443 SUM_O = HCOMP(9,1)+HCOMP(11,1)
444 DO J = 1,M
445 HCOMP(4,J)=XHE3_INI
446 HCOMP(5,J)= R12_13*SUM_C/(1.0D0+R12_13)
447 HCOMP(6,J)= SUM_C/(1.0D0+R12_13)
448 HCOMP(9,J)= R16_18*SUM_O/(1.0D0+R16_18)
449 HCOMP(11,J)= SUM_O/(1.0D0+R16_18)
450 HCOMP(12,J)=XH2_INI
451 HCOMP(13,J)=XLI6_INI
452 HCOMP(14,J)=XLI7_INI
453 HCOMP(15,J)=XBE9_INI
454 END DO
455 WRITE(*,593)(TESTMIX(K),K=4,15),(HCOMP(K,1),K=4,15)
456 WRITE(ISHORT,593)(TESTMIX(K),K=4,15),(HCOMP(K,1),K=4,15)
457 593 593 FORMAT('CNO ISOTOPES AND LIGHT ELEMENTS CHANGED IN ',
458 * * 'STARIN. OLD HE3 C12 C13 N14 N15 O16 O17 O18 H2 LI6 ',
459 * * 'LI7 BE9',12E12.4,' NEW ',12E12.4)
460 ENDIF
461 602 602 CONTINUE
462 3000 3000 CONTINUE
463
464C The following code enables us to extend the model from the current
465C inner most shell to a point ncloser to center, if flag LCORE is set.
466C 9/98 MHP REPLACE AS FOLLOWS:
467C ADD INTEGER NUMBER OF POINTS USING THE DESIRED SPACING IN MASS,HPTTOL.
468C USE STELLAR STRUCTURE EQUATIONS CONSISTENT WITH THE ASSUMPTIONS
469C IN THE MODEL, NAMELY CONSTANT ENERGY GENERATION RATE AND DENSITY
470C INTERIOR TO THE LOCATION OF THE CENTRAL FITTING POINT.
471C MHP 9/14 CHANGED SO THAT MOVING THE CORE FITTING IS ATTACHED TO ANY RUN
472C WHICH READS IN THE STARTING MODEL; THIS AVOIDS OVER-WRITING THE CHANGE
473C IN AUTO-CALIBRATED SOLAR MODELS
474 IF(LCORE .AND. LFIRST(NK)) THEN
475C IF(LCORE .AND. NK .EQ. 1) THEN
476C AVOID SHUFFLING POINTS BY ASSIGNING NEW CENTRAL POINTS IN INTEGER
477C MULTIPLES OF THE CENTRAL POINT SPACING.
478C MCORE is number of shells to extrapolate to new core.
479C FCORE is factor to reduce inner mass shell.
480 MCORE = INT(DLOG10(FCORE)/HPTTOL(2))+1
481 FCORE = DBLE(MCORE)*HPTTOL(2)
482 MN = M + MCORE
483 IF(MN .GT. JSON) THEN
484 WRITE(ISHORT,476)"STARIN: Unable to extend core inward ",
485 * * "- JSON too small"
486 WRITE(ISHORT,477) "STARIN: Required size =", MN,
487 * * ", JSON = ", JSON
488 WRITE(ISHORT,478) "STARIN: ***** RUN TERMINATED *****"
489 476 476 FORMAT(2A)
490 477 477 FORMAT(A, I8, A, I8)
491 478 478 FORMAT(A)
492C 10/30/26 MHP via Claude
493C code changed to stop here, as the message says. The run went on and
494C shifted the model past JSON. STOP 3: the input asks for too many points.
495 STOP 3
496 ENDIF
497 DS = HPTTOL(2)
498c shift data for remaining points by the required number
499 DO I=M,1, -1
500 HS(I+MCORE) = HS(I)
501 HR(I+MCORE) = HR(I)
502 HL(I+MCORE) = HL(I)
503 HP(I+MCORE) = HP(I)
504 HT(I+MCORE) = HT(I)
505 LC(I+MCORE) = LC(I)
506 DO J=1, 15
507 HCOMP(J,I+MCORE) = HCOMP(J,I)
508 END DO
509 OMEGA(I+MCORE) = OMEGA(I)
510 END DO
511 MP1 = MCORE+1
512C MARCH INWARD IN MASS FROM THE INNERMOST MODEL POINT.
513C ASSUME EPSILON=CONSTANT AND DEL=CONSTANT
514 RHOC = HD(1)
515 DEL = (HT(2)-HT(1))/(HP(2)-HP(1))
516 HLC = HL(1)
517C MHP 4/12 FACTOR FOR ESTIMATING RHO FROM P AND T
518 FACD = HP(MP1)-HD(MP1)-HT(MP1)
519 DO I = MCORE,1,-1
520 HS(I) = HS(I+1)-DS
521C USE M = 4PI/3*RHOC*R**3 TO GET R AS A FUNCTION OF M
522 HR(I) = CC13*(HS(I)-C4PI3L-RHOC)
523C USE EPSILON=CONSTANT TO GET L
524 HL(I) = EXP(CLN*(HS(I)-HS(MP1)))*HLC
525C USE HYDROSTATIC EQUILIBRIUM TO GET P
526 PP = HP(I+1)
527 TEMP = EXP(CLN*(CGL+2.0D0*HS(I)-C4PIL-PP-4.0D0*HR(I)))
528 PP = PP+0.5D0*TEMP*DS
529 TEMP = EXP(CLN*(CGL+2.0D0*HS(I)-C4PIL-PP-4.0D0*HR(I)))
530 HP(I) = HP(I+1)+TEMP*DS
531C ASSUME R/C FLAG IS THE SAME AS FOR THE FIRST POINT
532 LC(I) = LC(MP1)
533C ASSUME DEL= CONSTANT IN THE CORE
534 HT(I) = HT(I+1)+TEMP*DEL*DS
535C ASSUME OMEGA = CONSTANT
536 OMEGA(I) = OMEGA(MP1)
537C ASSUME COMPOSITION IS UNIFORM
538 DO J=1, 15
539 HCOMP(J,I) = HCOMP(J,MP1)
540 END DO
541C CALL EQUATION OF STATE TO GET CONSISTENT DENSITY
542C LDERIV = .FALSE.
543C LOCOND = .FALSE.
544C LATMO = .FALSE.
545C KSAHA = 0
546C X = HCOMP(1,I)
547C Z = HCOMP(3,I)
548C PL = HP(I)
549C P = EXP(CLN*PL)
550C TL = HT(I)
551C T = EXP(CLN*TL)
552C DL = HD(I+1)
553C D = EXP(CLN*DL)
554C FPL = 1.0D0
555C FTL = 1.0D0
556C CALL EQSTAT(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,FXION,
557C * RMU,AMU,EMU,ETA,QDT,QDP,QCP,DELA,QDTT,QDTP,
558C * QAT,QAP,QCPT,QCPP,LDERIV,LATMO,KSAHA)
559C HD(I) = DL
560C MHP 4/12 REPLACED (BROKEN) CALL TO EQSTAT WITH LOCAL ESTIMATE FOR RHO
561 HD(I) = HP(I) - HT(I) - FACD
562 END DO
563 M = MN
564 END IF
565C End of code to extend core inward
566
567C PERFORM RESCALING OF FIRST MODEL IF REQUIRED
568 IF(IRESCA(NK).NE.1) CALL RSCALE(HL,HCOMP,HS,HSTOT,M,NK,
569 * * SMASS,LC)
570
571C What is the metallicity of your model? (surface X and Z)
572C put in SETUPOPAC here, and take out of setups.
573C DBG 2/92 CHANGED SO THAT WORKS ON FIRST MODEL OF EACH NEW RUN
574C CHANGE FITTING POINT OF THE ENVELOPE INTEGRATION IF REQUESTED;
575C PROCEDURE IS:
576C IF THE REQUESTED ENVELOPE MASS(SENV0) IS GREATER THAN THE
577C CURRENT ONE, DELETE POINTS UNTIL THE MASS IS EQUAL.
578C LINEAR INTERPOLATION BETWEEN THE LAST POINT ABOVE THE FITTING
579C MASS AND THE FIRST POINT BELOW IT IS USED;COMPOSITION IS
580C ASSUMED EQUAL TO THE LAST OLD POINT BELOW THE NEW FITTING POINT.
581C IF THE REQUESTED ENVELOPE MASS IS SMALLER THAN THE CURRENT ONE,
582C AN ENVELOPE WITH TEFF AND L EQUAL TO THE STORED MODEL VALUE
583C IS INTEGRATED FROM THE SURFACE TO THE DESIRED FITTING POINT.
584C 1 NEW POINT IS ADDED, AND THE COMPOSITION OF THE NEW POINT
585C IS ASSUMED EQUAL TO THAT OF THE LAST OLD POINT.
586 IF(LSENV0) THEN
587 IF(SENV0.GT.0.0D0) SENV0 = -SENV0
588C DBG 2/92 CHANGED MINIMUM FROM 1.0D-10 TO 1.0D-12
589C RESTRICT MIMIMUM ENVELOPE MASS;1.0D-12 CORRESPONDS TO TAU=2/3
590C FOR THIS PURPOSE(BASE OF ATMOSPHERE).
591 IF(SENV0.GT.-1.0D-12) SENV0 = -1.D-12
592 SENV = HS(M) - HSTOT
593 SENV1 = SENV
594C 10/28/26 MHP via Claude
595C code changed to leave the fitting point alone when the requested one
596C matches the current one to within roundoff, not only when it is exactly
597C equal. SENV = HS(M) - HSTOT is a difference of two log masses near 33,
598C so it carries roundoff of order 1D-14. A request such as SENV0 = -1D-4
599C on a model whose SENV is -1.0000000000332D-4 used to pass the exact
600C test, and the shallower-envelope branch below then added a point with
601C FX = 0, a copy of point M; SPLINT stopped on the duplicate abscissa.
602C The tolerance is 100 ulps of HSTOT, about 7D-13, below the 1D-12
603C minimum envelope mass imposed above.
604 SENVTOL = 1.0D2*EPSILON(HSTOT)*ABS(HSTOT)
605 IF(ABS(SENV-SENV0).LE.SENVTOL) GOTO 599
606 JEND = 11
607 IF(LEXCOM) JEND = 15
608 IF(SENV0.LT.SENV) THEN
609C NEW ENVELOPE DEEPER THAN THE OLD ONE
610 HSEND = HSTOT + SENV0
611 DO 575 I = M-1,1,-1
612 IF(HS(I).LT.HSEND)GOTO 580
613 575 575 CONTINUE
614C ENVELOPE MASS DESIRED WITHIN FIRST POINT;PRINT NASTY MESSAGE
615C AND ABORT.
616 WRITE(ISHORT,576)SENV0
617 576 576 FORMAT(5X,'ERROR IN SUBROUTINE STARIN'/5X,'DESIRED',
618 * * ' ENVELOPE MASS',1PE22.13,' TOO LARGE'/5X,'ENVELOPE',
619 * * ' MASS NOT CHANGED')
620 GOTO 599
621 580 580 M = I + 1
622 SENV = SENV0
623 FS = (HSEND - HS(I))/(HS(I+1) - HS(I))
624 HS(M) = HSEND
625 HD(M) = HD(I) + FS*(HD(I+1) - HD(I))
626 HL(M) = HL(I) + FS*(HL(I+1) - HL(I))
627 HP(M) = HP(I) + FS*(HP(I+1) - HP(I))
628 HR(M) = HR(I) + FS*(HR(I+1) - HR(I))
629 HT(M) = HT(I) + FS*(HT(I+1) - HT(I))
630 DO 585 J = 1,JEND
631 HCOMP(J,M) = HCOMP(J,I)
632 585 585 CONTINUE
633 XNEW = HCOMP(1,M)
634 ZNEW = HCOMP(3,M)
635 IF(LROT) OMEGA(M) = OMEGA(I) + FS*(OMEGA(I+1)-OMEGA(I))
636 IF(LC(I).AND.LC(I+1))THEN
637 LC(M) = .TRUE.
638 ELSE IF(.NOT.LC(I).AND. .NOT.LC(I+1))THEN
639 LC(M) = .FALSE.
640 ELSE
641C CALL BASIC PHYSICS ROUTINES TO DETERMINE IF THE NEW LAST SHELL IS
642C CONVECTIVE OR RADIATIVE.
643 LDERIV = .FALSE.
644 LOCOND = .FALSE.
645 LATMO = .TRUE.
646 KSAHA = 0
647 X = HCOMP(1,M)
648 Z = HCOMP(3,M)
649 PL = HP(M)
650 TL = HT(M)
651 DL = HD(M)
652 B = HL(M)
653 RL = HR(M)
654 SL = HS(M)
655 FPL = 1.0D0
656 FTL = 1.0D0
657C 9/22/26 MHP via Claude
658C code changed to remove the MHD equation of state
659C 9/23/26 MHP via Claude
660C this EQSTAT call was previously only reached when LMHD was TRUE
661C (there was no ELSE branch calling it otherwise, unlike every other
662C LMHD site in the code), so with the default LMHD=.FALSE. it never
663C executed. Identified as an unintended bug and fixed by calling it
664C unconditionally, matching every other EQSTAT call site.
665 IF (LDH) THEN
666 XXDH = HCOMP(1,M)
667 YYDH = HCOMP(2,M)+HCOMP(4,M)
668 ZZDH = HCOMP(3,M)
669 ZDH(1) = HCOMP(5,M)+HCOMP(6,M)
670 ZDH(2) = HCOMP(7,M)+HCOMP(8,M)
671 ZDH(3) = HCOMP(9,M)+HCOMP(10,M)+HCOMP(11,M)
672 END IF
673 CALL EQSTAT(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,
674 * * FXION,RMU,AMU,EMU,ETA,QDT,QDP,QCP,DELA,QDTT,
675 * * QDTP,QAT,QAP,QCPT,QCPP,LDERIV,LATMO,KSAHA)
676 CALL GETOPAC(DL, TL, X, Z, O, OL, QOD, QOT, FXION)
677 IOVIM = -1
678 CALL TPGRAD(TL,T,PL,P,D,RL,SL,B,O,QDT,QDP,QOT,QOD,
679 * * QCP,DEL,DELR,DELA,QDTT,QDTP,QAT,QAP,QACT,QACP,
680 * * QACR,QCPT,QCPP,VEL,LDERIV,LCONV,FPL,FTL,TEFFL,
681 * * CMIXL)
682 HD(M) = DL
683 LC(M) = LCONV
684 ENDIF
685 ELSE
686C DESIRED ENVELOPE MASS LESS THAN CURRENT VALUE.
687 MM = M
688 EMAX0 = ENVMAX
689 EMIN0 = ENVMIN
690 EBEG0 = ENVBEG
691 ENVMAX = HPTTOL(8)
692 ENVMIN = HPTTOL(8)
693 ENVBEG = HPTTOL(8)
694C SENV = SENV0
695 LSBC0 = .FALSE.
696 LPRT = .TRUE.
697 KATM = 0
698 KENV = 0
699 KSAHA = 0
700 B = DEXP(CLN*BL)
701 RL = 0.5D0*(BL + CLSUNL - 4.0D0*TEFFL - C4PIL - CSIGL)
702 GL = CGL + STOTAL - RL - RL
703 X = HCOMP(1,M)
704 Z = HCOMP(3,M)
705 FPL = 1.0D0
706 FTL = 1.0D0
707 IXX=0
708 PLIM = HP(M)
709C DBG PULSE: DO NOT DO PULSE OUTPUT
710 LPULPT = .FALSE.
711 IF (LDH) THEN
712 XXDH = HCOMP(1,M)
713 YYDH = HCOMP(2,M)+HCOMP(4,M)
714 ZZDH = HCOMP(3,M)
715 ZDH(1) = HCOMP(5,M)+HCOMP(6,M)
716 ZDH(2) = HCOMP(7,M)+HCOMP(8,M)
717 ZDH(3) = HCOMP(9,M)+HCOMP(10,M)+HCOMP(11,M)
718 END IF
719C MHP 10/02 define ISTORE - used in ENVINT
720 IDUM = 0
721C G Somers 10/14, FOR SPOTTED RUNS, FIND THE
722C PRESSURE AT THE AMBIENT TEMPERATURE ATEFFL
723 IF(JENV.EQ.M.AND.SPOTF.NE.0.0.AND.SPOTX.NE.1.0)THEN
724 ATEFFL = TEFFL - 0.25*LOG10(SPOTF * SPOTX**4.0 + 1.0 - SPOTF)
725 ELSE
726 ATEFFL = TEFFL
727 ENDIF
728 CALL ENVINT(B,FPL,FTL,GL,HSTOT,IXX,LPRT,LSBC0,PLIM,RL,
729 * * ATEFFL,X,Z,DUM1,IDUM,KATM,KENV,KSAHA,DUM2,
730 * * DUM3,DUM4,LPULPT,CMIXL)
731C G Somers END
732 ENVMAX = EMAX0
733 ENVMIN = EMIN0
734 ENVBEG = EBEG0
735 SENV = SENV0
736 IF(M+NUMENV.GE.JSON) STOP 9999
737C ENFORCE CONSISTENCY WITH THE INTERIOR SOLUTION;
738C ADJUST THE (P, RHO, T, R) POINTS TO BE CONSISTENT
739C WITH THE LAST MODEL POINT.
740 DP = HP(M) - ENVP(1)
741 DD = HD(M) - ENVD(1)
742 DT = HT(M) - ENVT(1)
743 DR = HR(M) - ENVR(1)
744 DO J = 1,NUMENV - 1
745 ENVD(J) = ENVD(J+1)+DD
746 ENVP(J) = ENVP(J+1)+DP
747 ENVR(J) = ENVR(J+1)+DR
748 ENVS(J) = ENVS(J+1)
749 ENVT(J) = ENVT(J+1)+DT
750 ENVX(J) = ENVX(J+1)
751 ENVZ(J) = ENVZ(J+1)
752C 10/30/26 MHP via Claude: shift the convective flag with the rest; it
753C was left in place, so LC(J) = LCENV(JM) below read it one point off.
754 LCENV(J) = LCENV(J+1)
755 END DO
756 NUMENV = NUMENV - 1
757 DO J = M+1,M+NUMENV
758 JM = J-M
759C LUMINOSITY ASSUMED CONSTANT
760 HL(J) = HL(M)
761C INCLUDE NEW POINTS UP TO THE DIFFERENT DESIRED FITTING POINT
762 IF(ENVS(JM).LE.SENV)THEN
763 HD(J) = ENVD(JM)
764 HP(J) = ENVP(JM)
765 HR(J) = ENVR(JM)
766 HS(J) = ENVS(JM) + STOTAL
767 HT(J) = ENVT(JM)
768 HCOMP(1,J) = ENVX(JM)
769 HCOMP(3,J) = ENVZ(JM)
770 DO K = 4,JEND
771 HCOMP(K,J) = HCOMP(K,M)
772 END DO
773 HCOMP(2,J)=1.0D0-HCOMP(1,J)-HCOMP(3,J)-HCOMP(4,J)
774 LC(J) = LCENV(JM)
775 ELSE
776C POINTS BEYOND THIS ARE ABOVE THE NEW DESIRED FITTING POINT;
777C INTERPOLATE LINEARLY, SET NEW NUMBER OF TOTAL POINTS, AND EXIT
778 IF(JM.EQ.1)THEN
779C INTERPOLATE BETWEEN THE LAST INTERIOR POINT AND THE FIRST ENVELOPE POINT
780 X0 = HS(M)
781 X1 = STOTAL + SENV
782 X2 = ENVS(JM) + STOTAL
783 IF(X2-X0.LT.1.0D-14) STOP 9998
784 FX = (X1-X0)/(X2-X0)
785 HD(J) = HD(M)+FX*(ENVD(JM)-HD(M))
786 HP(J) = HP(M)+FX*(ENVP(JM)-HP(M))
787 HR(J) = HR(M)+FX*(ENVR(JM)-HR(M))
788 HS(J) = X1
789 HT(J) = HT(M)+FX*(ENVT(JM)-HT(M))
790 HCOMP(1,J) = HCOMP(1,M)+FX*(HCOMP(1,M)-ENVX(JM))
791 HCOMP(3,J) = HCOMP(3,M)+FX*(HCOMP(3,M)-ENVZ(JM))
792 DO K = 4,JEND
793 HCOMP(K,J) = HCOMP(K,M)
794 END DO
795 HCOMP(2,J)=1.0D0-HCOMP(1,J)-HCOMP(3,J)-HCOMP(4,J)
796 IF(LCENV(JM).OR.LC(M))THEN
797 LC(J) = .TRUE.
798 ELSE
799 LC(J) = .FALSE.
800 ENDIF
801 ELSE
802C INTERPOLATE BETWEEN THE LAST 2 ENVELOPE POINTS
803 X0 = ENVS(JM-1) + STOTAL
804 X1 = STOTAL + SENV
805 X2 = ENVS(JM) + STOTAL
806 IF(X2-X0.LT.1.0D-14) STOP 9998
807 FX = (X1-X0)/(X2-X0)
808 HD(J) = ENVD(JM-1)+FX*(ENVD(JM)-ENVD(JM-1))
809 HP(J) = ENVP(JM-1)+FX*(ENVP(JM)-ENVP(JM-1))
810 HR(J) = ENVR(JM-1)+FX*(ENVR(JM)-ENVR(JM-1))
811 HS(J) = X1
812 HT(J) = ENVT(JM-1)+FX*(ENVT(JM)-ENVT(JM-1))
813 HCOMP(1,J) = ENVX(JM-1)+FX*(ENVX(JM)-ENVX(JM-1))
814 HCOMP(3,J) = ENVZ(JM-1)+FX*(ENVZ(JM)-ENVZ(JM-1))
815 DO K = 4,JEND
816 HCOMP(K,J) = HCOMP(K,M)
817 END DO
818 HCOMP(2,J)=1.0D0-HCOMP(1,J)-HCOMP(3,J)-HCOMP(4,J)
819 IF(LCENV(JM).OR.LCENV(JM-1))THEN
820 LC(J) = .TRUE.
821 ELSE
822 LC(J) = .FALSE.
823 ENDIF
824 ENDIF
825 M = J
826 GOTO 587
827 ENDIF
828 END DO
829C ASSIGN THE BOUNDARY AT THE PHOTOSPHERE FOR ENVELOPE MASS BELOW 1.0D-12.
830 M = M + NUMENV
831 587 587 CONTINUE
832 IF(LROT)THEN
833 DO J = MM+1,M
834 OMEGA(J) = OMEGA(MM)
835 HJM(J) = CC23*OMEGA(MM)*10.0D0**(2.0D0*HR(J))
836 END DO
837 ENDIF
838 WRITE(*,910)
839 910 910 FORMAT(1X,'NEW INTERIOR POINTS FROM CHANGE IN ENVELOPE MASS'/
840 * * ' J,LOG RHO, LOG L, LOG P, LOG R, LOG M, LOG T, CONV T/F')
841 WRITE(*,911)(J,HD(J),HL(J),HP(J),HR(J),HS(J)-STOTAL,
842 * * HT(J),LC(J), J = MM,M)
843 911 911 FORMAT(I5,1P6E16.8,L2)
844C M = M + 1
845C HS(M) = HSTOT + SENV
846C HD(M) = ED
847C HL(M) = HL(M-1)
848C HP(M) = EP
849C HR(M) = ER
850C HT(M) = ET
851C LC(M) = EVEL.GT.0.0D0
852C DO 590 J = 1,JEND
853C HCOMP(J,M) = HCOMP(J,M-1)
854C 590 CONTINUE
855C XNEW = HCOMP(1,M)
856C ZNEW = HCOMP(3,M)
857C IF(LROT) OMEGA(M) = OMEGA(I) + FS*(OMEGA(I+1)-OMEGA(I))
858 ENDIF
859 LNEW = .TRUE.
860 WRITE(ISHORT,597)SENV1,SENV
861 597 597 FORMAT(5X,'***** NEW ENVELOPE MASS CALCULATED *****'/8X,
862 * * 'OLD SENV ',1PE22.13,' NEW SENV',E22.13)
863 599 599 CONTINUE
864 ENDIF
865
866C SET UP WEIGHTS AND MASSES
867C HS1 IS THE UNLOGGED HS; HS2 IS THE MASS OF THE SHELL(ALSO NOT LOG).
868 DS3 = DEXP(CLN*HS(1))
869 DS2 = - DS3
870 DO 120 I = 2,M
871 DS1 = DS2
872 DS2 = DS3
873 DS3 = DEXP(CLN*HS(I))
874 HS1(I-1) = DS2
875 HS2(I-1) = 0.5D0*(DS3-DS1)
876 120 120 CONTINUE
877 HS1(M) = DS3
878 HS2(M) = DEXP(CLN*HSTOT) - 0.5D0*(DS2+DS3)
879
880 IF(LROT) THEN
881C CALCULATE FP,FT,R0 AND ETA2 GIVEN OMEGA
882 CALL FPFT(HD,HR,HS,M,OMEGA,ETA2,FP,FT,HG,R0)
883C FIND MOMENT OF INERTIA(HI)
884C CALL MOMI(ETA2,HD,HR,HS,HS2,1,M,OMEGA,R0,HI,QIW,M) ! KC 2025-05-31
885 CALL MOMI(ETA2,HR,HS,HS2,1,M,OMEGA,R0,HI,QIW)
886C GIVEN OMEGA AND I, FIND ANGULAR MOMENTUM AND ROTATIONAL K.E.
887 SUMJ = 0.0D0
888 SUMKE = 0.0D0
889 DO 550 I = 1,M
890 HJ = OMEGA(I)*HI(I)
891 HJM(I) = HJ/HS2(I)
892 HKEROT(I) = 0.5D0*OMEGA(I)*HJ
893 SUMJ = SUMJ + HJ
894 SUMKE = SUMKE + HKEROT(I)
895 550 550 CONTINUE
896 WRITE(ISHORT,560)SJTOT,SUMJ,SKEROT,SUMKE
897 560 560 FORMAT(1X,'TOTAL J OF STAR - PREVIOUS ',1PE21.13,' NEW ',
898 * * 1PE21.13/1X,'TOTAL ROTATIONAL K.E. OF STAR - PREVIOUS ',
899 * * 1PE21.13,' NEW ',1PE21.13)
900 SJTOT = SUMJ
901 SKEROT = SUMKE
902 ENDIF
903
904 IF(NK.GT.1) GOTO 630
905C SET UP MASS FRACTIONS AND NUMBER FRACTIONS OF ELEMENTS IN
906C ENVELOPE.
907C DBG 1/96 V (ENVELOPE MASS FRACTIONS WAS NORMALLY READ IN VIA
908C RDLAOL. NOW THAT THESE OPACITIES ARE OBSOLETE VNEW IS INTRODUCED
909C HOLD THE RELATIVE MASS FRACTIONS OF THE ELEMENTS (SEE PARMIN).
910C TO MAINTAIN BACKWARD COMPATIBILITY IF LLAOL=T THEN USE V READ IN
911C VIA RDLAOL OTHERWISE USE VNEW.
912 IF (.NOT.LLAOL) THEN
913 DO I=1, 12
914 V(I)=VNEW(I)
915 END DO
916 END IF
917
918C COMPUTE SURFACE MIX VALUES.
919C ZENVM = Z OTHER THAN CNO CYCLE ELEMENTS;
920C AMUENV = MEAN ATOMIC WEIGHT OF SURFACE Z;
921C FXENV = NUMBER DENSITY OF SPECIES .
922 XENV = XNEW
923 ZENV = ZNEW
924 YENV = 1.0D0 - XENV - ZENV - HCOMP(4,M)
925 Y3ENV = HCOMP(4,M)
926C EVERYTHING BUT V(7)=H, AND V(12)=HE
927 VSUM = V(1)+V(2)+V(3)+V(4)+V(5)+V(6)+V(8)+V(9)+V(10)+V(11)
928 ZENVM = ZENV*(VSUM -V(6)-V(8)-V(9))/VSUM
929 FV = ZENV/VSUM
930 V(7) = XENV/FV
931 V(12) = (1.0D0-XENV-ZENV)/FV
932 VSUM = 0.0D0
933 DO 610 I = 1,12
934 V(I) = FV*V(I)/ATOMWT(I)
935 VSUM = VSUM + V(I)
936 610 610 CONTINUE
937 AMUENV = VSUM
938 FV = 1.0D0/AMUENV
939C DBG 1/96 FXENV ARE NUMBER FRACTIONS OF ELEMENTS REQURIED
940C BY EOS ROUTINES (SEE EQSTAT AND EQSAHA)
941 DO 620 I = 1,12
942 FXENV(I) = V(I)*FV
943 620 620 CONTINUE
944C FIND SURFACE COMPOSITION OPACITY TABLE
945C FIRST FIND INTERPOLATING FACTOR FOR COMPOSITION
946 630 630 CONTINUE
947C DBG 11/95 GENERATE NEW SURFACE OPACITY TABLES
948 CALL SURFOPAC(XENV)
949 IF(LSCV)THEN
950 CALL SETSCV
951 ENDIF
952
953C CLONE P,T,R,L ARRAY TO DUMMY ARRAY HPOLD.
954C HPOLD IS USED TO LIMIT THE TIMESTEP BASED ON CHANGES FROM
955C MODEL TO MODEL IN P,T,R,L.
956 DO 710 I = 1,M
957 HPO(I) = HP(I)
958 HTO(I) = HT(I)
959 HRO(I) = HR(I)
960 HLO(I) = HL(I)
961C JVS 04/14 Added Teff to the list of saved values
962 TEFFLO = TEFFL
963C 10/29/26 MHP via Claude
964C code changed to save the surface luminosity, HLSURO, in place of the
965C point count MO. HPOINT re-splines HLO onto the new mesh, so ENTIME's
966C HLO(MO) read an interior point or a stale entry whenever the count
967C changed.
968 HLSURO = HL(M)
969 710 710 CONTINUE
970 IF(LROT) THEN
971 DO 720 I = 1,M
972 WOLD(I) = OMEGA(I)
973 720 720 CONTINUE
974 ENDIF
975
976C 8/17 G Somers
977C FIND BASIC PHYSICAL QUANTITIES. THIS CODE STOLEN FROM PHYSIC
978C FIND ACTUAL AND ADIABATIC TEMPERATURE GRADIENTS,OPACITY,AND
979C MEAN MOLECULAR WEIGHT FOR ALL RADIATIVE SHELLS.
980C if(.False.)then
981C LDERIV = .FALSE.
982C LOCOND = .FALSE.
983C LATMO = .FALSE.
984C IDT = 15
985C DO 725 I = 1,4
986C IDD(I) = 5
987C 725 CONTINUE
988C DO 730 IM = 1,M
989C SL = HS(IM)
990C TL = HT(IM)
991C PL = HP(IM)
992C RL = HR(IM)
993C B = HL(IM)
994C X = HCOMP(1,IM)
995C Z = HCOMP(3,IM)
996C DL = HD(IM)
997C FPL = FP(IM)
998C FTL = FT(IM)
999C
1000C IF(LMHD) THEN
1001C CALL MEQOS(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,FXION,RMU,
1002C * AMU,EMU,ETA,QDT,QDP,QCP,DELA,QDTT,QDTP,QAT,QAP,QCPT,
1003C * QCPP,LDERIV,LATMO,KSAHA)
1004C ELSE
1005C IF (LDH) THEN
1006C XXDH = HCOMP(1,IM)
1007C YYDH = HCOMP(2,IM)+HCOMP(4,IM)
1008C ZZDH = HCOMP(3,IM)
1009C ZDH(1) = HCOMP(5,IM)+HCOMP(6,IM)
1010C ZDH(2) = HCOMP(7,IM)+HCOMP(8,IM)
1011C ZDH(3) = HCOMP(9,IM)+HCOMP(10,IM)+HCOMP(11,IM)
1012C END IF
1013C CALL EQSTAT(TL,T,PL,P,DL,D,X,Z,BETA,BETAI,BETA14,FXION,RMU,
1014C * AMU,EMU,ETA,QDT,QDP,QCP,DELA,QDTT,QDTP,QAT,QAP,QCPT,
1015C * QCPP,LDERIV,LATMO,KSAHA)
1016C ENDIF
1017C CALL GETOPAC (DL,TL,X,Z,O,OL,QOD,QOT,FXION)
1018C IOVIM=IM
1019C CALL TPGRAD(TL,T,PL,P,D,RL,SL,B,O,QDT,QDP,QOT,QOD,QCP,DEL,
1020C * DELR,DELA,QDTT,QDTP,QAT,QAP,QACT,QACP,QACR,QCPT,QCPP,
1021C * VEL,LDERIV,LCONV,FPL,FTL,TEFFL)
1022C SDEL(1,IM) = DELR
1023C SDEL(2,IM) = DEL
1024C SDEL(3,IM) = DELA
1025CC JVS 10/13 Always want SVEL
1026C SVEL(IM) = VEL
1027C 730 CONTINUE
1028C endif
1029
1030C CALL PHYSIC(FP,FT,HCOMP,HD,HG,HL,HP,HR,HS,HT,LC,LCZ,M,TEFFL) ! KC 2025-05-31
1031 CALL PHYSIC(FP,FT,HCOMP,HD,HG,HL,HP,HR,HS,HT,LC,M,TEFFL,CMIXL)
1032 CALL OVROT(HCOMP,HD,HP,HR,HS,HT,LC,M,LCZ,MRZONE,MXZONE,NRZONE,
1033 * * NZONE)
1034C 10/29/26 MHP via Claude
1035C Keep the starting model's rotation convective flags for CRRECT's
1036C GETROT, as HPOINT does after each rezone.
1037 DO I = 1,M
1038 LCZO(I) = LCZ(I)
1039 END DO
1040C INITIALIZE TAUCZ, PPHOT, AND FRACSTEP
1041C CALL GETTAU(HCOMP,HR,HP,HD,HG,HS1,HT,FP,FT,TEFFL, ! KC 2025-05-31
1042 CALL GETTAU(HCOMP,HR,HP,HD,HS1,HT,FP,FT,TEFFL,
1043 * * HSTOT,BL,M,LC,ENVR,CMIXL)
1044 TAUCZ0 = TAUCZ
1045 PPHOT0 = PPHOT
1046 FRACSTEP = 0.5
1047
1048 RETURN
1049 END1"""Python version of starin.f (YREC 7be4133): the starting model of a run,
2read from file or kept, and prepared for evolution."""
3
4import math
5
6import numpy as np
7
8from pyrec import cenv_mod
9from pyrec import comp2_mod
10from pyrec import comp_mod
11from pyrec import constants_mod
12from pyrec import debhu_mod
13from pyrec import dimensions_mod
14from pyrec import dpmix_mod
15from pyrec import envstruct_mod
16from pyrec import iounits_mod
17from pyrec import newopac_mod
18from pyrec import nmlbypass_mod # noqa: F401 (USEd; no member read here)
19from pyrec import nmlpar_mod
20from pyrec import oldmod_mod
21from pyrec import oldrot_mod
22from pyrec import ovrtrn_mod
23from pyrec import runloop_mod
24from pyrec.envint import envint
25from pyrec.eqstat import eqstat
26from pyrec.fpft import fpft
27from pyrec.getmodel2 import getmodel2
28from pyrec.getopac import getopac
29from pyrec.gettau import gettau
30from pyrec.getyrec7 import getyrec7
31from pyrec.momi import momi
32from pyrec.ovrot import ovrot
33from pyrec.physic import physic
34from pyrec.rscale import rscale
35from pyrec.setscv import setscv
36from pyrec.surfopac import surfopac
37from pyrec.tpgrad import tpgrad
38
39JSON = dimensions_mod.json
40
41# DATA ATOMWT: atomic weights of the 12 elements of V (index 0 unused).
42ATOMWT = np.array([0.0, 23.0, 26.99, 24.32, 55.86, 28.1, 12.015, 1.008,
43 16.0, 14.01, 39.96, 20.19, 4.004])
44
45# Local arrays kept between calls (SAVE).
46mxzone = np.zeros((13, 3), dtype=int)
47mrzone = np.zeros((14, 3), dtype=int)
48lcz = np.zeros(JSON + 1, dtype=bool)
49
50
51def _set_debhu(hcomp, m):
52 # The composition for the Debye-Hueckel correction, at shell m.
53 debhu_mod.xxdh = hcomp[1, m]
54 debhu_mod.yydh = hcomp[2, m] + hcomp[4, m]
55 debhu_mod.zzdh = hcomp[3, m]
56 debhu_mod.zdh[1] = hcomp[5, m] + hcomp[6, m]
57 debhu_mod.zdh[2] = hcomp[7, m] + hcomp[8, m]
58 debhu_mod.zdh[3] = hcomp[9, m] + hcomp[10, m] + hcomp[11, m]
59
60
61def _e(x, w, d):
62 # Fortran's 0PEw.d: a mantissa in [0.1, 1).
63 if x == 0.0:
64 return f"{'0.' + '0' * d + 'E+00':>{w}}"
65 e = math.floor(math.log10(abs(x))) + 1
66 mant = x / 10.0**e
67 if round(abs(mant), d) >= 1.0:
68 mant /= 10.0
69 e += 1
70 s = ("-" if x < 0 else "") + "0" + f"{abs(mant):.{d}f}"[1:]
71 return f"{s + f'E{e:+03d}':>{w}}"
72
73
74def starin(bl: float, cfenv: np.ndarray, dage: float, ddage: float, delts: float, deltsh: float, eta2: np.ndarray,
75 fp: np.ndarray, ft: np.ndarray, ftri: float, hcomp: np.ndarray, hd: np.ndarray, hi: np.ndarray,
76 hjm: np.ndarray, hkerot: np.ndarray, hl: np.ndarray, hp: np.ndarray, hr: np.ndarray, hs: np.ndarray,
77 hs1: np.ndarray, hs2: np.ndarray, hstot: float, ht: np.ndarray, ikut: int, istore: int, jenv: int,
78 large: bool, lc: np.ndarray, lnew: bool, m: int, model: int, nk: int, omega: np.ndarray, ps: np.ndarray,
79 qiw: np.ndarray, r0: np.ndarray, rs: np.ndarray, sjtot: float, skerot: float, smass: float, teffl: float,
80 tlumx: np.ndarray, tril: np.ndarray, trit: np.ndarray, ts: np.ndarray, vel: float, hg: np.ndarray,
81 v: np.ndarray, cmixl: float, compmix: str) -> tuple[float, float, float, float, float, float, float, int,
82 int, bool, int, int, float, float, float, float, float, str]:
83 """Provide the starting model of run nk: read it from the unit IFIRST
84 (YREC7 or MODEL2 format) or keep the one in memory, then prepare it:
85 change the mixture of a homogeneous model, extend the core inward,
86 rescale, move the envelope's fitting point, compute the shell masses,
87 the rotation quantities, the surface composition, and the first
88 physics, convection zones and overturn time.
89
90 Translates: starin.f#STARIN (7be4133)
91
92 Arguments: the model (hs, hr, hl, hp, ht, hd, hcomp[species, shell],
93 lc, omega, m points, index 0 unused) and its rotation arrays (eta2, fp,
94 ft, hi, hjm, hkerot, qiw, r0, hg), the envelope triangle (trit, tril,
95 ps, ts, rs, cfenv, ftri, istore), bl, teffl, hstot, smass, dage, ddage,
96 model, tlumx, the run number nk, jenv (read only, for the spots), large
97 (the previous model failed: stop), the totals sjtot, skerot, v (the
98 surface mixture's relative mass fractions), cmixl (the run's mixing
99 length) and compmix (set by the readers). delts, deltsh, ikut, lnew
100 and vel are output only. Arrays are changed in place.
101
102 Returns (bl, dage, ddage, delts, deltsh, ftri, hstot, ikut, istore,
103 lnew, m, model, sjtot, skerot, smass, teffl, vel, compmix).
104
105 """
106
107 c = constants_mod
108 nml = nmlpar_mod
109 es = envstruct_mod
110 ishort = iounits_mod.ishort
111
112 # A failed previous model stops the run (Fortran lines 227–236).
113 if large:
114 iounits_mod.write(ishort, " " + ">" * 39 + "<" * 40 + "\n"
115 "STARIN: ***** RUN STOPPED *****")
116 iounits_mod.write(ishort,
117 "STARIN: ***** MODEL FAILED TO CONVERGE *****")
118 raise SystemExit(1)
119
120 # Fortran lines 241–248.
121 ikut = 0
122 iread = iounits_mod.ifirst
123 vel = 0.0
124 qdt = -1.0
125 qdp = 1.0
126
127 # Without LFIRST, the model in memory is kept (GOTO 3000), and rescaled
128 # below (Fortran lines 250–263).
129 if nml.lfirst[nk]:
130 # Read the starting model; its first four characters give the
131 # format (Fortran lines 266–308).
132 iounits_mod.rewind(iread)
133 atemp = iounits_mod.read(iread)[:4] # format 10, A4
134 # The readers return every scalar argument except the units, in
135 # argument order.
136 if atemp == "NMOD":
137 iounits_mod.write(ishort, "STARIN: Input model has YREC7 format")
138 (bl, cmixl0, dage, ddage, ftri, hstot, jcore0, jenv0, lexcom0,
139 lrot0, m, model, smass, teffl, atm, eos, hik, ldify0, ldifz0,
140 ldisk0, linstb0, ljdot00, lok, lovstc0, lovste0, lovstm0,
141 lpurez0, lsemic0, compmix, pdisk0, tdisk0, wmax0) = getyrec7(
142 bl, cfenv, 0.0, dage, ddage, ftri, hcomp, hd, hl, hp, hr, hs,
143 hstot, ht, iread, ishort, 0, 0, lc, False, False, m, model,
144 omega, ps, rs, smass, teffl, tlumx, tril, trit, ts, "", "",
145 "", False, False, False, False, False, "", False, False,
146 False, False, False, compmix, 0.0, 0.0, 0.0)
147 elif atemp == "MOD2":
148 iounits_mod.write(ishort,
149 "STARIN: Input model has MODEL2 format")
150 (bl, cmixl0, dage, ddage, ftri, hstot, jcore0, jenv0, lexcom0,
151 lrot0, m, model, smass, teffl, atm, eos, hik, ldify0, ldifz0,
152 ldisk0, linstb0, ljdot00, lok, lovstc0, lovste0, lovstm0,
153 lpurez0, lsemic0, compmix, pdisk0, tdisk0, wmax0) = getmodel2(
154 bl, cfenv, 0.0, dage, ddage, ftri, hcomp, hd, hl, hp, hr, hs,
155 hstot, ht, iread, 0, 0, lc, False, False, m, model, omega,
156 ps, rs, smass, teffl, tlumx, tril, trit, ts, "", "", "",
157 False, False, False, False, False, "", False, False, False,
158 False, False, compmix, 0.0, 0.0, 0.0)
159 else:
160 iounits_mod.write(ishort, "STARIN: ***** RUN TERMINATED, "
161 "INVALID INPUT MODEL FILE. *****")
162 raise SystemExit(3)
163
164 # The step in seconds (ddage in years) (Fortran lines 310–314).
165 delts = c.csecyr * ddage
166 deltsh = abs(delts)
167 comp_mod.stotal = hstot
168
169 # An evolved model: warn if its mixing length or composition switch
170 # differs from the run's (the run is no longer stopped) (Fortran
171 # lines 316–337).
172 # Question (see the page): should a mismatch still stop the run?
173 if model > 0:
174 lmixl = True
175 if cmixl0 > 0.0:
176 lmixl = abs(cmixl - cmixl0) < 2.0e-3
177 if not lmixl or lexcom0 != nml.lexcom:
178 # Suspected bug (see the page): LEXCP0 is never set; the
179 # model's value is LEXCOM0. False stands for the undefined
180 # value.
181 lexcp0 = False
182 text = (" ERROR IN SUBROUTINE STARIN\n USER PARAMETERS"
183 " OF WRONG TYPE FOR INITIAL MODEL\n MIXING LENGTH -"
184 f" USER DESIRES{cmixl:7.3f} MODEL MIX LENGTH"
185 f"{cmixl0:7.3f}\n EXTENDED COMP-USER DESIRES "
186 f"{'T' if nml.lexcom else 'F'} MODEL USED "
187 f"{'T' if lexcp0 else 'F'}") # format 1040
188 iounits_mod.write(ishort, text)
189 iounits_mod.write(iounits_mod.iowr, text)
190
191 # A new envelope, the surface X and Z, and rotation (Fortran lines
192 # 339–380).
193 istore = 0
194 ftri = 1.0
195 lnew = True # the envelope is always recomputed
196 comp_mod.xnew = hcomp[1, m]
197 comp_mod.znew = hcomp[3, m]
198
199 if nml.lrot:
200 if nml.lwnew:
201 for i in range(1, m + 1): # loop 540
202 omega[i] = nml.wnew
203 else:
204 for i in range(1, JSON + 1): # loop 570
205 fp[i] = 1.0
206 ft[i] = 1.0
207 iounits_mod.rewind(iread)
208
209 # Change the mixture, only of a homogeneous model (MHP 10/24)
210 # (Fortran lines 383–461).
211 testmix = np.zeros(16)
212 homogeneous = True
213 if nml.lmixture or nml.lisotope:
214 for i in range(1, 16):
215 testmix[i] = hcomp[i, 1]
216 for j in range(2, m + 1):
217 for i in range(1, 16):
218 test = abs(hcomp[i, j] - testmix[i])
219 if test > 1.0e-6:
220 text = (f"SPECIES {i:3d} IN SHELL {j:5d} DIFFERS FROM"
221 f" CENTER BY {_e(test, 12, 4)} MIX NOT"
222 f" MODIFIED IN EVOLVED MODEL") # format 592
223 print(text)
224 iounits_mod.write(ishort, text)
225 homogeneous = False
226 break
227 if not homogeneous:
228 break # GOTO 602
229 if homogeneous:
230 if nml.lmixture:
231 # Scale C, N and O so that each element's share of Z is
232 # FRAC_C, FRAC_N, FRAC_O.
233 tot_c = (testmix[5] + testmix[6]) / testmix[3]
234 tot_n = (testmix[7] + testmix[8]) / testmix[3]
235 tot_o = (testmix[9] + testmix[10] + testmix[11]) / testmix[3]
236 rat_c = nml.frac_c / tot_c
237 rat_n = nml.frac_n / tot_n
238 rat_o = nml.frac_o / tot_o
239 print(nml.frac_c, nml.frac_n, nml.frac_o)
240 for i in range(5, 7):
241 for j in range(1, m + 1):
242 hcomp[i, j] = rat_c * hcomp[i, j]
243 for i in range(7, 9):
244 for j in range(1, m + 1):
245 hcomp[i, j] = rat_n * hcomp[i, j]
246 for i in range(9, 12):
247 for j in range(1, m + 1):
248 hcomp[i, j] = rat_o * hcomp[i, j]
249 text = ("CNO MIX CHANGED IN STARIN. OLD C12 C13 N14"
250 " N15 O16 O17 O18 "
251 + "".join(_e(testmix[k], 12, 4) for k in range(5, 12))
252 + " NEW "
253 + "".join(_e(hcomp[k, 1], 12, 4)
254 for k in range(5, 12))) # format 594
255 print(text)
256 iounits_mod.write(ishort, text)
257 if nml.lisotope:
258 # Impose 12C/13C and 16O/18O at fixed sums, and the light
259 # elements' initial values.
260 # R14_15, R16_17 are not applied (unused?).
261 # Suspected bug (see the page): the defaults of R16_18 and
262 # R16_17 look swapped.
263 sum_c = hcomp[5, 1] + hcomp[6, 1]
264 sum_o = hcomp[9, 1] + hcomp[11, 1]
265 for j in range(1, m + 1):
266 hcomp[4, j] = nml.xhe3_ini
267 hcomp[5, j] = nml.r12_13 * sum_c / (1.0 + nml.r12_13)
268 hcomp[6, j] = sum_c / (1.0 + nml.r12_13)
269 hcomp[9, j] = nml.r16_18 * sum_o / (1.0 + nml.r16_18)
270 hcomp[11, j] = sum_o / (1.0 + nml.r16_18)
271 hcomp[12, j] = nml.xh2_ini
272 hcomp[13, j] = nml.xli6_ini
273 hcomp[14, j] = nml.xli7_ini
274 hcomp[15, j] = nml.xbe9_ini
275 text = ("CNO ISOTOPES AND LIGHT ELEMENTS CHANGED IN "
276 "STARIN. OLD HE3 C12 C13 N14 N15 O16 O17 O18 H2 LI6 "
277 "LI7 BE9"
278 + "".join(_e(testmix[k], 12, 4) for k in range(4, 16))
279 + " NEW "
280 + "".join(_e(hcomp[k, 1], 12, 4)
281 for k in range(4, 16))) # format 593
282 print(text)
283 iounits_mod.write(ishort, text)
284 # label 602
285
286 # label 3000
287 # Extend the model inward by MCORE points (MHP 9/98, 9/14) (Fortran
288 # lines 462–565).
289 if nml.lcore and nml.lfirst[nk]:
290 nml.mcore = int(math.log10(nml.fcore) / nml.hpttol[2]) + 1
291 nml.fcore = float(nml.mcore) * nml.hpttol[2] # now a log offset
292 mn = m + nml.mcore
293 if mn > JSON:
294 iounits_mod.write(ishort, "STARIN: Unable to extend core inward "
295 "- JSON too small")
296 iounits_mod.write(ishort, f"STARIN: Required size ={mn:8d}"
297 f", JSON = {JSON:8d}")
298 iounits_mod.write(ishort, "STARIN: ***** RUN TERMINATED *****")
299 raise SystemExit(3)
300 ds = nml.hpttol[2]
301 mcore = nml.mcore
302 # Shift the old points outward.
303 # Suspected bug (see the page): hd is not shifted.
304 for i in range(m, 0, -1):
305 hs[i + mcore] = hs[i]
306 hr[i + mcore] = hr[i]
307 hl[i + mcore] = hl[i]
308 hp[i + mcore] = hp[i]
309 ht[i + mcore] = ht[i]
310 lc[i + mcore] = lc[i]
311 for j in range(1, 16):
312 hcomp[j, i + mcore] = hcomp[j, i]
313 omega[i + mcore] = omega[i]
314 mp1 = mcore + 1
315 rhoc = hd[1]
316 # Suspected bug (see the page): with mcore = 1 this is 0/0.
317 dele = (ht[2] - ht[1]) / (hp[2] - hp[1])
318 hlc = hl[1]
319 facd = hp[mp1] - hd[mp1] - ht[mp1]
320 # Inward at constant density, energy generation and gradient.
321 for i in range(mcore, 0, -1):
322 hs[i] = hs[i + 1] - ds
323 hr[i] = c.cc13 * (hs[i] - c.c4pi3l - rhoc)
324 hl[i] = math.exp(c.cln * (hs[i] - hs[mp1])) * hlc
325 pp = hp[i + 1]
326 temp = math.exp(c.cln * (c.cgl + 2.0 * hs[i] - c.c4pil - pp
327 - 4.0 * hr[i]))
328 pp = pp + 0.5 * temp * ds
329 temp = math.exp(c.cln * (c.cgl + 2.0 * hs[i] - c.c4pil - pp
330 - 4.0 * hr[i]))
331 hp[i] = hp[i + 1] + temp * ds
332 lc[i] = lc[mp1]
333 ht[i] = ht[i + 1] + temp * dele * ds
334 omega[i] = omega[mp1]
335 for j in range(1, 16):
336 hcomp[j, i] = hcomp[j, mp1]
337 hd[i] = hp[i] - ht[i] - facd
338 m = mn
339
340 # Rescale (Fortran lines 567–569).
341 if runloop_mod.iresca[nk] != 1:
342 hstot, smass = rscale(hl, hcomp, hs, hstot, m, nk, smass, lc)
343
344 # Move the envelope's fitting point to SENV0 (Fortran lines 571–864).
345 if cenv_mod.lsenv0:
346 # (In one branch EQSTAT and TPGRAD set STARIN's qdt, qdp and vel.)
347 m, lnew, qdt, qdp, vel = _new_fitting_point(
348 hcomp, hd, hjm, hl, hp, hr, hs, ht, lc, omega, m, bl, teffl,
349 hstot, jenv, lnew, qdt, qdp, vel, cmixl)
350
351 # Shell masses (Fortran lines 866–876).
352 ds3 = math.exp(c.cln * hs[1])
353 ds2 = -ds3
354 for i in range(2, m + 1): # loop 120
355 ds1 = ds2
356 ds2 = ds3
357 ds3 = math.exp(c.cln * hs[i])
358 hs1[i - 1] = ds2
359 hs2[i - 1] = 0.5 * (ds3 - ds1)
360 hs1[m] = ds3
361 hs2[m] = math.exp(c.cln * hstot) - 0.5 * (ds2 + ds3)
362
363 # Rotation: distortion, moments of inertia, J and kinetic energy
364 # (Fortran lines 878–902).
365 if nml.lrot:
366 fpft(hd, hr, hs, m, omega, eta2, fp, ft, hg, r0)
367 momi(eta2, hr, hs, hs2, 1, m, omega, r0, hi, qiw)
368 sumj = 0.0
369 sumke = 0.0
370 for i in range(1, m + 1): # loop 550
371 hj = omega[i] * hi[i]
372 hjm[i] = hj / hs2[i]
373 hkerot[i] = 0.5 * omega[i] * hj
374 sumj = sumj + hj
375 sumke = sumke + hkerot[i]
376 iounits_mod.write(ishort,
377 f" TOTAL J OF STAR - PREVIOUS {sjtot:21.13E} NEW "
378 f"{sumj:21.13E}\n TOTAL ROTATIONAL K.E. OF STAR - "
379 f"PREVIOUS {skerot:21.13E} NEW {sumke:21.13E}")
380 sjtot = sumj
381 skerot = sumke
382
383 # The surface composition, for the first run only (Fortran lines
384 # 904–943).
385 # Question (see the page): skipped for later runs.
386 if nk <= 1:
387 if not newopac_mod.llaol:
388 for i in range(1, 13):
389 v[i] = nml.vnew[i]
390 comp_mod.xenv = comp_mod.xnew
391 comp_mod.zenv = comp_mod.znew
392 comp2_mod.yenv = 1.0 - comp_mod.xenv - comp_mod.zenv - hcomp[4, m]
393 comp2_mod.y3env = hcomp[4, m]
394 vsum = v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[8] + v[9] + v[10] \
395 + v[11]
396 comp_mod.zenvm = comp_mod.zenv * (vsum - v[6] - v[8] - v[9]) / vsum
397 fv = comp_mod.zenv / vsum
398 v[7] = comp_mod.xenv / fv
399 v[12] = (1.0 - comp_mod.xenv - comp_mod.zenv) / fv
400 vsum = 0.0
401 for i in range(1, 13): # loop 610
402 v[i] = fv * v[i] / ATOMWT[i]
403 vsum = vsum + v[i]
404 # The inverse mean atomic weight per ion (the Fortran's comment
405 # says the mean atomic weight of the surface Z).
406 comp_mod.amuenv = vsum
407 fv = 1.0 / comp_mod.amuenv
408 for i in range(1, 13): # loop 620
409 comp_mod.fxenv[i] = v[i] * fv
410
411 # label 630: the surface opacities and the SCV EOS (Fortran lines
412 # 944–951).
413 surfopac(comp_mod.xenv)
414 if nml.lscv:
415 setscv()
416
417 # Save the old model (Fortran lines 953–974).
418 om = oldmod_mod
419 for i in range(1, m + 1): # loop 710
420 om.hpo[i] = hp[i]
421 om.hto[i] = ht[i]
422 om.hro[i] = hr[i]
423 om.hlo[i] = hl[i]
424 # Loop-invariant, as in the Fortran.
425 om.tefflo = teffl
426 om.hlsuro = hl[m]
427 if nml.lrot:
428 for i in range(1, m + 1): # loop 720
429 oldrot_mod.wold[i] = omega[i]
430
431 # The first physics and convection zones (Fortran lines 976–1033).
432 physic(fp, ft, hcomp, hd, hg, hl, hp, hr, hs, ht, lc, m, teffl, cmixl)
433 nrzone, nzone = ovrot(hcomp, hd, hp, hr, hs, ht, lc, m, lcz, mrzone,
434 mxzone, 0, 0)
435
436 # Keep the starting model's rotation convective flags for CRRECT's
437 # GETROT (Fortran lines 1034–1039).
438 for i in range(1, m + 1):
439 om.lczo[i] = lcz[i]
440
441 # The overturn time and photospheric pressure (Fortran lines 1040–1046).
442 # The module array ENVR is passed as GETTAU's scalar RBCZ, so ENVR(1)
443 # receives the base's radius (KNOWN_ISSUES.md lists it).
444 es.envr[1] = gettau(hcomp, hr, hp, hd, hs1, ht, fp, ft, teffl, hstot,
445 bl, m, lc, es.envr[1], cmixl)
446 ovrtrn_mod.taucz0 = ovrtrn_mod.taucz
447 ovrtrn_mod.pphot0 = ovrtrn_mod.pphot
448 ovrtrn_mod.fracstep = 0.5
449
450 return (bl, dage, ddage, delts, deltsh, ftri, hstot, ikut, istore, lnew,
451 m, model, sjtot, skerot, smass, teffl, vel, compmix)
452
453
454def _new_fitting_point(hcomp, hd, hjm, hl, hp, hr, hs, ht, lc, omega, m, bl,
455 teffl, hstot, jenv, lnew, qdt, qdp, vel, cmixl):
456 """STARIN's block for LSENV0 (labels 575-599): move the envelope's
457 fitting point to SENV0, deeper (drop shells, interpolate the new last
458 one) or shallower (integrate an envelope and take its points down to
459 the new fitting mass as interior shells). Returns (m, lnew, qdt, qdp,
460 vel): STARIN's arguments, which the physics of one branch sets
461 (Fortran lines 586–864)."""
462
463 c = constants_mod
464 nml = nmlpar_mod
465 ce = cenv_mod
466 es = envstruct_mod
467 ishort = iounits_mod.ishort
468
469 # The sign and the minimum of SENV0 (Fortran lines 587–591).
470 # Question (see the page): the smallest envelope.
471 if ce.senv0 > 0.0:
472 ce.senv0 = -ce.senv0
473 if ce.senv0 > -1.0e-12:
474 ce.senv0 = -1.0e-12
475 comp_mod.senv = hs[m] - hstot
476 senv1 = comp_mod.senv
477
478 # Leave the fitting point alone when the request matches the current
479 # one to within roundoff (SENV is a difference of two log masses near
480 # 33): 100 ulps of HSTOT, Fortran's EPSILON for REAL*8 (Fortran lines
481 # 594–607).
482 senvtol = 1.0e2 * np.finfo(np.float64).eps * abs(hstot)
483 if abs(comp_mod.senv - ce.senv0) <= senvtol:
484 return m, lnew, qdt, qdp, vel # GOTO 599
485 jend = 11
486 if nml.lexcom:
487 jend = 15
488
489 if ce.senv0 < comp_mod.senv:
490 # A deeper fitting point: drop the shells beyond it (Fortran lines
491 # 608–685).
492 hsend = hstot + ce.senv0
493 i = 0
494 for ii in range(m - 1, 0, -1): # loop 575
495 if hs[ii] < hsend:
496 i = ii
497 break # to label 580
498 else:
499 iounits_mod.write(ishort,
500 f" ERROR IN SUBROUTINE STARIN\n DESIRED"
501 f" ENVELOPE MASS{ce.senv0:22.13E} TOO LARGE\n"
502 f" ENVELOPE MASS NOT CHANGED") # format 576
503 return m, lnew, qdt, qdp, vel # GOTO 599
504
505 # label 580: the new last shell.
506 m = i + 1
507 comp_mod.senv = ce.senv0
508 fs = (hsend - hs[i]) / (hs[i + 1] - hs[i])
509 hs[m] = hsend
510 hd[m] = hd[i] + fs * (hd[i + 1] - hd[i])
511 hl[m] = hl[i] + fs * (hl[i + 1] - hl[i])
512 hp[m] = hp[i] + fs * (hp[i + 1] - hp[i])
513 hr[m] = hr[i] + fs * (hr[i + 1] - hr[i])
514 ht[m] = ht[i] + fs * (ht[i + 1] - ht[i])
515 for j in range(1, jend + 1): # loop 585
516 hcomp[j, m] = hcomp[j, i]
517 comp_mod.xnew = hcomp[1, m]
518 comp_mod.znew = hcomp[3, m]
519 if nml.lrot:
520 omega[m] = omega[i] + fs * (omega[i + 1] - omega[i])
521 if lc[i] and lc[i + 1]:
522 lc[m] = True
523 elif not lc[i] and not lc[i + 1]:
524 lc[m] = False
525 else:
526 # Between a convective and a radiative shell: let the physics
527 # decide (EQSTAT is always called for such a shell).
528 lderiv = False
529 latmo = True
530 ksaha = 0
531 x = hcomp[1, m]
532 z = hcomp[3, m]
533 pl = hp[m]
534 tl = ht[m]
535 dl = hd[m]
536 b = hl[m]
537 rl = hr[m]
538 sl = hs[m]
539 fpl = 1.0
540 ftl = 1.0
541 if nml.ldh:
542 _set_debhu(hcomp, m)
543 fxion = np.zeros(4)
544 (t, p, dl, d, beta, betai, beta14, rmu, amu, emu, eta, qdt, qdp,
545 qcp, dela, qdtt, qdtp, qat, qap, qcpt, qcpp, ksaha) = eqstat(
546 tl, 0.0, pl, 0.0, dl, 0.0, x, z, 0.0, 0.0, 0.0, fxion, 0.0,
547 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
548 0.0, lderiv, latmo, ksaha)
549 o, ol, qod, qot = getopac(dl, tl, x, z, 0.0, 0.0, 0.0, 0.0, fxion)
550 dpmix_mod.iovim = -1
551 (dele, delr, qact, qacp, qacr, vel, lconv) = tpgrad(
552 tl, t, pl, p, d, rl, sl, b, o, qdt, qdp, qot, qod, qcp, 0.0,
553 0.0, dela, qdtt, qdtp, qat, qap, 0.0, 0.0, 0.0, qcpt, qcpp,
554 vel, lderiv, False, fpl, ftl, teffl, cmixl)
555 hd[m] = dl
556 lc[m] = lconv
557 else:
558 # A shallower fitting point: integrate an envelope from the surface
559 # at fixed steps HPTTOL(8), and take its points down to SENV0
560 # (Fortran lines 686–736).
561 mm = m
562 emax0 = nml.envmax
563 emin0 = nml.envmin
564 ebeg0 = nml.envbeg
565 nml.envmax = nml.hpttol[8]
566 nml.envmin = nml.hpttol[8]
567 nml.envbeg = nml.hpttol[8]
568 lsbc0 = False
569 lprt = True
570 katm = 0
571 kenv = 0
572 ksaha = 0
573 b = math.exp(c.cln * bl)
574 rl = 0.5 * (bl + c.clsunl - 4.0 * teffl - c.c4pil - c.csigl)
575 gl = c.cgl + comp_mod.stotal - rl - rl
576 x = hcomp[1, m]
577 z = hcomp[3, m]
578 fpl = 1.0
579 ftl = 1.0
580 ixx = 0
581 plim = hp[m]
582 lpulpt = False
583 if nml.ldh:
584 _set_debhu(hcomp, m)
585 idum = 0
586 # For spotted stars, the ambient temperature (G Somers 10/14).
587 if jenv == m and nml.spotf != 0.0 and nml.spotx != 1.0:
588 ateffl = teffl - 0.25 * math.log10(
589 nml.spotf * nml.spotx**4.0 + 1.0 - nml.spotf)
590 else:
591 ateffl = teffl
592 dum1 = np.zeros(5)
593 dum2 = np.zeros(4)
594 dum3 = np.zeros(4)
595 dum4 = np.zeros(4)
596 rl, idum, katm, kenv, ksaha = envint(
597 b, fpl, ftl, gl, hstot, ixx, lprt, lsbc0, plim, rl, ateffl, x, z,
598 dum1, idum, katm, kenv, ksaha, dum2, dum3, dum4, lpulpt, cmixl)
599 nml.envmax = emax0
600 nml.envmin = emin0
601 nml.envbeg = ebeg0
602 comp_mod.senv = ce.senv0
603 if m + es.numenv >= JSON:
604 raise SystemExit(9999)
605
606 # Shift the envelope to match the last interior point, dropping its
607 # first point (Fortran lines 737–756).
608 dp = hp[m] - es.envp[1]
609 dd = hd[m] - es.envd[1]
610 dt = ht[m] - es.envt[1]
611 dr = hr[m] - es.envr[1]
612 for j in range(1, es.numenv):
613 es.envd[j] = es.envd[j + 1] + dd
614 es.envp[j] = es.envp[j + 1] + dp
615 es.envr[j] = es.envr[j + 1] + dr
616 es.envs[j] = es.envs[j + 1]
617 es.envt[j] = es.envt[j + 1] + dt
618 es.envx[j] = es.envx[j + 1]
619 es.envz[j] = es.envz[j + 1]
620 es.lcenv[j] = es.lcenv[j + 1]
621 es.numenv = es.numenv - 1
622
623 # The envelope's points down to the fitting mass become shells
624 # (Fortran lines 757–830).
625 senv = comp_mod.senv
626 stotal = comp_mod.stotal
627 reached = False
628 for j in range(m + 1, m + es.numenv + 1):
629 jm = j - m
630 hl[j] = hl[m]
631 if es.envs[jm] <= senv:
632 hd[j] = es.envd[jm]
633 hp[j] = es.envp[jm]
634 hr[j] = es.envr[jm]
635 hs[j] = es.envs[jm] + stotal
636 ht[j] = es.envt[jm]
637 hcomp[1, j] = es.envx[jm]
638 hcomp[3, j] = es.envz[jm]
639 for k in range(4, jend + 1):
640 hcomp[k, j] = hcomp[k, m]
641 hcomp[2, j] = 1.0 - hcomp[1, j] - hcomp[3, j] - hcomp[4, j]
642 lc[j] = es.lcenv[jm]
643 else:
644 # The last new point, interpolated to the fitting mass.
645 if jm == 1:
646 x0 = hs[m]
647 x1 = stotal + senv
648 x2 = es.envs[jm] + stotal
649 if x2 - x0 < 1.0e-14:
650 raise SystemExit(9998)
651 fx = (x1 - x0) / (x2 - x0)
652 hd[j] = hd[m] + fx * (es.envd[jm] - hd[m])
653 hp[j] = hp[m] + fx * (es.envp[jm] - hp[m])
654 hr[j] = hr[m] + fx * (es.envr[jm] - hr[m])
655 hs[j] = x1
656 ht[j] = ht[m] + fx * (es.envt[jm] - ht[m])
657 # Suspected bug (see the page): the sign is reversed here.
658 hcomp[1, j] = hcomp[1, m] + fx * (hcomp[1, m]
659 - es.envx[jm])
660 hcomp[3, j] = hcomp[3, m] + fx * (hcomp[3, m]
661 - es.envz[jm])
662 for k in range(4, jend + 1):
663 hcomp[k, j] = hcomp[k, m]
664 hcomp[2, j] = (1.0 - hcomp[1, j] - hcomp[3, j]
665 - hcomp[4, j])
666 lc[j] = bool(es.lcenv[jm] or lc[m])
667 else:
668 x0 = es.envs[jm - 1] + stotal
669 x1 = stotal + senv
670 x2 = es.envs[jm] + stotal
671 if x2 - x0 < 1.0e-14:
672 raise SystemExit(9998)
673 fx = (x1 - x0) / (x2 - x0)
674 hd[j] = es.envd[jm - 1] + fx * (es.envd[jm]
675 - es.envd[jm - 1])
676 hp[j] = es.envp[jm - 1] + fx * (es.envp[jm]
677 - es.envp[jm - 1])
678 hr[j] = es.envr[jm - 1] + fx * (es.envr[jm]
679 - es.envr[jm - 1])
680 hs[j] = x1
681 ht[j] = es.envt[jm - 1] + fx * (es.envt[jm]
682 - es.envt[jm - 1])
683 hcomp[1, j] = es.envx[jm - 1] + fx * (es.envx[jm]
684 - es.envx[jm - 1])
685 hcomp[3, j] = es.envz[jm - 1] + fx * (es.envz[jm]
686 - es.envz[jm - 1])
687 for k in range(4, jend + 1):
688 hcomp[k, j] = hcomp[k, m]
689 hcomp[2, j] = (1.0 - hcomp[1, j] - hcomp[3, j]
690 - hcomp[4, j])
691 lc[j] = bool(es.lcenv[jm] or es.lcenv[jm - 1])
692 m = j
693 reached = True
694 break # GOTO 587
695 if not reached:
696 m = m + es.numenv
697
698 # label 587: the new shells rotate at the old surface rate (Fortran
699 # lines 831–843).
700 if nml.lrot:
701 for j in range(mm + 1, m + 1):
702 omega[j] = omega[mm]
703 hjm[j] = c.cc23 * omega[mm] * 10.0**(2.0 * hr[j])
704 print(" NEW INTERIOR POINTS FROM CHANGE IN ENVELOPE MASS\n"
705 " J,LOG RHO, LOG L, LOG P, LOG R, LOG M, LOG T, CONV T/F")
706 for j in range(mm, m + 1): # format 911
707 print(f"{j:5d}" + "".join(
708 f"{q:16.8E}" for q in (hd[j], hl[j], hp[j], hr[j],
709 hs[j] - stotal, ht[j]))
710 + f" {'T' if lc[j] else 'F'}")
711
712 # Fortran lines 859–863.
713 lnew = True
714 iounits_mod.write(ishort,
715 f" ***** NEW ENVELOPE MASS CALCULATED *****\n"
716 f" OLD SENV {senv1:22.13E} NEW SENV"
717 f"{comp_mod.senv:22.13E}") # format 597
718 return m, lnew, qdt, qdp, vel