chkscal.f
179 lines · 1 definitions · on GitHub (7be4133)
Python version: chkscal.py, 121 lines, on the right (switch to Python above the code).
Variables on this page (12)
c4pi, clsun, crsun, csig, endage, itrack, lendag, rescal, sr, xenv0a, xls, xlstol
Purpose
This file calibrates a track of another star (not the Sun) to a given radius and luminosity: it watches the track for the moment it crosses the target radius $R_*$, compares the luminosity there with the target $L_*$, and adjusts the hydrogen abundance $X$ (thus $Y$) for the next run until the track passes through $(R_*, L_*)$. Then it sets up a final run that stops at the age where the track reaches $R_*$.
How it fits
- Inputs: the arguments
BL($\log L/L_\odot$),TEFFL($\log T_\mathrm{eff}$),DAGE(age, Gyr),NK(kind card) andALRI(the previous model's radius, kept by the main program and started by SETSCAL); inNMLPAR_MOD(set by PARMIN), the targetsSR($R_*/R_\odot$; computed by SETSCAL fromSTEFFwhen the optionLTEFFgives the star's $T_\mathrm{eff}$ instead, so this routine needs onlySR, settled from the code, Nov 9, 2026: setscal.f, lines 102–106↗),XLS($L_*/L_\odot$) and the toleranceXLSTOL; the previous model'sBLI,AGEI, local variables kept bySAVE. - Who calls it: the main program (main.f), for even kind cards, when the option
LCALSTis on and the star has not yet been found (LSTARfalse), from the second model on (main.f, lines 1117–1123↗; the first model only setsTEFFI, which nothing reads: unused?). - Outputs: the arguments
LPASSR(main.f then ends the run),LSTARandALRI;BLR,AGER,BLRPare saved locals; for the next kind cards, the new $X$ (RESCAL(2,·)inRUNLOOP_MOD,XENV0AinNMLPAR_MOD), or the stopping age (LENDAGinRUNLOOP_MOD,ENDAGEinNMLPAR_MOD). Lines to the screen and toITRACK.
The method
-
The radius from $L$ and $T_\mathrm{eff}$, in solar units: $$\frac{R}{R_\odot} = \frac{\sqrt{L/(4\pi\sigma)}}{T_\mathrm{eff}^2\,R_\odot}.$$ If the track has not crossed $R_*$ since the previous model, store $L$, the age and $R$, and return.
The radius is linear, not a logarithm. The comments call
ALRandALRI"log(R/Rsun)" (lines 81–82↗), but the code computes $R/R_\odot$ itself (line 96↗) and compares it withSR, which is $R/R_\odot$ (line 79↗, line 98↗), so the comparison is consistent, the interpolation is linear in $R$, and the comments are stale.
Suspected bugs, checked by running the code
Each bug is marked by what running the code showed: (changes results, large) or (small), the fix moving a run clearly beyond a null change; (stops the run); (wrong output), the fix changing only what is written; (harmless in the runs), within the noise; (never occurred), the code ran but the fault did not; (not reached); (cannot be reached), a guard prevents it; (withdrawn), the suspicion was wrong.
1. (not reached) A false crossing at the start of a run that begins above $R_*$.
(lines 97–103↗; setscal.f, line 107↗; main.f, lines 1119–1123↗) ALRI starts at 0 (setscal.f, line 107↗) and is not updated at a crossing (lines 118–178↗ leave it as it was), and main.f's first call of each run is at its second model (the first only sets TEFFI). If that model's radius is above $R_*$ (a pre-main-sequence start with $R_*$ on the main sequence, say), the test ALR.GT.SR.AND.ALRI.LE.SR (line 98↗) holds at once: LPASSR ends the run at its second model, and $L$ and the age "at $R_*$" are interpolated between this model and BLI, AGEI, which are unset in the first run (saved locals with no DATA). Since ALRI stays 0, every later run stops the same way, and the secant step works on these values. When the track starts below $R_*$, the first comparison of each later run is made against the previous run's last stored model rather than the run's own, which is harmless as long as every run starts on the same side of $R_*$. Only with LCALST (off by default, nmlpar_mod.f, line 160↗) and a track that starts above $R_*$; a track that starts below $R_*$ and expands through it is not affected.
A possible fix (in main.f, then here):
main.f (another file)
@@ lines 1116–1123 @@
C TEST IF MODEL IS NEAR DESIRED Teff AND L. IF NOT RESCALE AND TRY AGAIN.
IF (LCALST .AND. .NOT. LSTAR) THEN
IF(MOD(NK,2).EQ.0)THEN
+C 11/09/26 KC via Claude
+C code changed to mark the first model of each run, so that CHKSCAL
+C starts its search from the run's own models.
IF(MODELN.EQ.1) THEN
TEFFI = 10.0D0**TEFFL
+ ALRI = -1.0D0
ELSE
CALL CHKSCAL(BL, TEFFL, DAGE, NK,ALRI,LSTAR,LPASSR)
IF(LPASSR) GOTO 200
chkscal.f
@@ lines 93–99 @@
C If not store L and age and return.
LPASSR=.FALSE.
TEFF = 10.0D0**TEFFL
+C 11/09/26 KC via Claude
+C code changed to store the first model of a run without testing it.
ALR = SQRT((10.0D0**BL)*CLSUN/(C4PI*CSIG))/(TEFF*TEFF*CRSUN)
+ IF(ALRI.LT.0.0D0) THEN
+ BLI = BL
+ AGEI = DAGE
+ ALRI = ALR
+ RETURN
+ ENDIF
IF(ALR.GT.ALRI) THEN
IF(.NOT.(ALR.GT.SR.AND.ALRI.LE.SR)) THEN
BLI = BL
Checked by running YREC (Nov 9, 2026; a line added at each suspected path counted how often it was taken, the outputs otherwise unchanged). No run reached CHKSCAL in the 34 cases run: LCALST is off by default (nmlpar_mod.f, line 160↗) and in all of YREC's cases, and no user document offers it (docs/archive/F90_CONVERSION_PLAN.md, line 247: "no case sets LCALST"). What would reach it: LCALST on, with a track whose second model lies above $R_*$, such as a pre-main-sequence start with $R_*$ on the main sequence. Intent: none found.
Definitions
subroutineCHKSCAL
Calibrates $X$ (thus $Y$) so that a track passes through a target $(R_*, L_*)$: detects the crossing of $R_*$, interpolates $L$ and the age there, and sets $X$ by a secant step, or sets the final run's stopping age.
Uses modules CONSTANTS_MOD, IOUNITS_MOD, NMLPAR_MOD, RUNLOOP_MOD
Called by (file level)
Change log
The changes since rp_1
Changed since rp_1. /CALSTAR/ retired: ALRI, LSTAR, LPASSR are now arguments (owned by the main program), BLI, AGEI, BLR, AGER, BLRP saved locals, the targets in NMLPAR_MOD; COMMON blocks to modules, IMPLICIT NONE.