Skip to content

Commit 495ff9f

Browse files
DebraheemVincentVanlaer
authored andcommitted
fix fallback paths, add bolometric flux BB comparison test, add changelog entries and known bugs
1 parent 8f3d214 commit 495ff9f

6 files changed

Lines changed: 195 additions & 38 deletions

File tree

colors/defaults/colors.defaults

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@
9191
! then MESA uses the nearest metallicity in the table for the atmosphere
9292
! interpolation. If the photospheric hydrogen mass fraction or metal mass
9393
! fraction is not positive, then MESA cannot form
94-
! log10((Z/X)/z_over_x_ref), so it uses the lowest metallicity in the
95-
! table instead. This is a fallback safeguard and not a dedicated treatment
96-
! for H-free atmospheres.
94+
! log10((Z/X)/z_over_x_ref). In that case the module still returns colors
95+
! and SEDs, but it does so by using the lowest metallicity in the table.
96+
! This is a fallback safeguard and not a dedicated treatment for H-free
97+
! atmospheres.
9798

9899
! For the shipped Kurucz2003all table in this checkout, the
99100
! metallicity range is [Fe/H] = -2.5 to [Fe/H] = 4.0. With the

colors/private/colors_utils.f90

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ function basename(path) result(name)
487487
name = path(i + 1:)
488488
end function basename
489489

490+
! resolve a path relative to mesa_dir unless it is already explicit.
491+
! legacy colors defaults used '/data/...'; if that absolute-looking path
492+
! does not exist on disk, warn and retry relative to mesa_dir.
490493
function resolve_path(path) result(full_path)
491494
use const_def, only: mesa_dir
492495
character(len=*), intent(in) :: path
@@ -511,10 +514,8 @@ function resolve_path(path) result(full_path)
511514
if (exists) then
512515
full_path = p
513516
else
514-
!it might be nice to warn the user that their filepath implies absolute
515-
!silently correcting this WILL lead to confusion
516-
!warning every step seems a smidge over the top though
517-
!write (*, *) trim(p), " not found. Trying ", trim(mesa_dir)//trim(p)
517+
write (*, '(5a)') 'colors: path ', trim(p), &
518+
' not found; trying ', trim(mesa_dir)//trim(p), ' instead'
518519
full_path = trim(mesa_dir)//trim(p)
519520
end if
520521

@@ -559,17 +560,19 @@ subroutine read_strings_from_file(colors_settings, strings, n, ierr)
559560
end subroutine read_strings_from_file
560561

561562
! load flux cube from binary file into handle at initialization.
562-
! if the file cannot be opened or the large flux_cube array cannot be
563-
! allocated, sets cube_loaded = .false. so the runtime will fall back to
564-
! loading individual SED files via the lookup table.
565-
! grids and wavelengths are always loaded (small); only the 4-D cube
566-
! allocation is treated as the fallback trigger.
563+
! if the cube is missing, malformed, or too large to allocate, keep
564+
! cube_loaded = .false. and fall back to loading individual SED files.
565+
! validate the header and on-disk size before reading the large 4-D payload
566+
! so a stale or truncated cube reports a clear message instead of failing
567+
! later inside the Fortran runtime.
567568
subroutine load_flux_cube(rq, stellar_model_dir)
569+
use iso_fortran_env, only: int64
568570
type(Colors_General_Info), intent(inout) :: rq
569571
character(len=*), intent(in) :: stellar_model_dir
570572

571573
character(len=512) :: bin_filename
572574
integer :: unit, status, n_teff, n_logg, n_meta, n_lambda
575+
integer(int64) :: file_bytes, expected_bytes, header_bytes, real_bytes
573576
real(dp) :: cube_mb
574577

575578
rq%cube_loaded = .false.
@@ -580,16 +583,40 @@ subroutine load_flux_cube(rq, stellar_model_dir)
580583
access='STREAM', form='UNFORMATTED', iostat=status)
581584
if (status /= 0) then
582585
! no binary cube available -- will use individual SED files
583-
write (*, '(a)') 'colors: no flux_cube.bin found; using per-file SED loading'
586+
write (*, '(a)') 'colors: no flux_cube.bin found; using slower per-file SED loading'
584587
return
585588
end if
586589

587590
read (unit, iostat=status) n_teff, n_logg, n_meta, n_lambda
588591
if (status /= 0) then
592+
write (*, '(a)') 'colors: could not read flux_cube.bin header; falling back to slower per-file SED loading'
589593
close (unit)
590594
return
591595
end if
592596

597+
if (n_teff <= 0 .or. n_logg <= 0 .or. n_meta <= 0 .or. n_lambda <= 0) then
598+
write (*, '(a)') 'colors: invalid flux_cube.bin header; falling back to slower per-file SED loading'
599+
close (unit)
600+
return
601+
end if
602+
603+
inquire (file=trim(bin_filename), size=file_bytes, iostat=status)
604+
if (status == 0) then
605+
header_bytes = 4_int64*int(storage_size(n_teff)/8, int64)
606+
real_bytes = int(storage_size(1.0_dp)/8, int64)
607+
expected_bytes = header_bytes + real_bytes*( &
608+
int(n_teff, int64) + int(n_logg, int64) + int(n_meta, int64) + int(n_lambda, int64) + &
609+
int(n_teff, int64)*int(n_logg, int64)*int(n_meta, int64)*int(n_lambda, int64))
610+
if (file_bytes /= expected_bytes) then
611+
write (*, '(a,i0,a,i0,a)') &
612+
'colors: flux_cube.bin size mismatch (', file_bytes, &
613+
' bytes, expected ', expected_bytes, &
614+
'); falling back to slower per-file SED loading'
615+
close (unit)
616+
return
617+
end if
618+
end if
619+
593620
! attempt the large allocation first -- this is the one that may fail.
594621
! doing it before the small grid allocations avoids partial cleanup.
595622
allocate (rq%cube_flux(n_teff, n_logg, n_meta, n_lambda), stat=status)
@@ -598,7 +625,7 @@ subroutine load_flux_cube(rq, stellar_model_dir)
598625
cube_mb = real(n_teff, dp)*n_logg*n_meta*n_lambda*8.0_dp/(1024.0_dp**2)
599626
write (*, '(a,f0.1,a)') &
600627
'colors: flux cube allocation failed (', cube_mb, &
601-
' MB); falling back to per-file SED loading'
628+
' MB); falling back to slower per-file SED loading'
602629
close (unit)
603630
return
604631
end if
@@ -643,7 +670,7 @@ subroutine load_flux_cube(rq, stellar_model_dir)
643670

644671
! error cleanup -- deallocate everything that may have been allocated
645672
900 continue
646-
write (*, '(a)') 'colors: error reading flux_cube.bin; falling back to per-file SED loading'
673+
write (*, '(a)') 'colors: error reading flux_cube.bin; falling back to slower per-file SED loading'
647674
if (allocated(rq%cube_flux)) deallocate (rq%cube_flux)
648675
if (allocated(rq%cube_teff_grid)) deallocate (rq%cube_teff_grid)
649676
if (allocated(rq%cube_logg_grid)) deallocate (rq%cube_logg_grid)
@@ -1081,4 +1108,4 @@ subroutine interp_linear_internal(x_out, x_in, y_in, y_out)
10811108
end do
10821109

10831110
end subroutine interp_linear_internal
1084-
end module colors_utils
1111+
end module colors_utils

colors/test/src/test_colors.f90

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ program test_colors
4444
how_many_colors_history_columns, data_for_colors_history_columns, &
4545
calculate_bolometric
4646
use colors_def, only: Colors_General_Info
47-
use const_def, only: dp, rsun, mesa_dir
47+
use const_def, only: dp, rsun, boltz_sigma
4848
use utils_lib, only: mesa_error
49+
use colors_utils, only: resolve_path
4950

5051
implicit none
5152

@@ -97,6 +98,11 @@ program test_colors
9798
! number of sampled SED points printed for the SED comparison
9899
integer, parameter :: n_sed_samples = 20
99100

101+
! require the integrated SED flux to stay close to sigma*T^4 scaled to
102+
! the test distance. large deficits usually mean the wavelength coverage
103+
! is missing too much UV or IR flux.
104+
real(dp), parameter :: bol_flux_rel_tol = 5d-3
105+
100106
character(len=32) :: my_mesa_dir
101107
integer :: handle, ierr, n_cols, i, j, k
102108
integer :: model_num
@@ -160,7 +166,7 @@ program test_colors
160166
! group 1: representative stellar types
161167
! -----------------------------------------------------------------------
162168

163-
write(*,'(a)') '# group1 system=Vega grid=Kurucz2003 filters=Johnson'
169+
call write_section_header('# Group1 system=Vega grid=Kurucz2003 filters=Johnson')
164170
do j = 1, n_cases
165171
model_num = model_num + 1
166172
call data_for_colors_history_columns( &
@@ -180,7 +186,7 @@ program test_colors
180186
! group 2a: vary [M/H]
181187
! -----------------------------------------------------------------------
182188

183-
write(*,'(a)') '# group2a vary_MH Teff=5778 logg=4.44'
189+
call write_section_header('# Group2a vary_MH Teff=5778 logg=4.44')
184190
do j = 1, n_meta
185191
model_num = model_num + 1
186192
call data_for_colors_history_columns( &
@@ -200,7 +206,7 @@ program test_colors
200206
! group 2b: vary log g
201207
! -----------------------------------------------------------------------
202208

203-
write(*,'(a)') '# group2b vary_logg Teff=5778 MH=0.0'
209+
call write_section_header('# Group2b vary_logg Teff=5778 MH=0.0')
204210
do j = 1, n_logg
205211
model_num = model_num + 1
206212
call data_for_colors_history_columns( &
@@ -220,7 +226,7 @@ program test_colors
220226
! group 2c: vary Teff
221227
! -----------------------------------------------------------------------
222228

223-
write(*,'(a)') '# group2c vary_Teff logg=4.0 MH=0.0'
229+
call write_section_header('# Group2c vary_Teff logg=4.0 MH=0.0')
224230
do j = 1, n_teff
225231
model_num = model_num + 1
226232
call data_for_colors_history_columns( &
@@ -236,23 +242,32 @@ program test_colors
236242
end do
237243
end do
238244

245+
sed_filepath = trim(resolve_path(cs%stellar_atm))
246+
239247
! -----------------------------------------------------------------------
240-
! SED comparison: solar case, n_sed_samples evenly spaced wavelength/flux
248+
! group 3: solar SED sample plus wavelength-coverage sanity checks
241249
! -----------------------------------------------------------------------
242250

243-
sed_filepath = trim(mesa_dir)//trim(cs%stellar_atm)
251+
call write_section_header('# Group3 SED sample + wavelength_coverage_sanity')
252+
write(*,'(a)') '# SED sample case=solar Teff=5778 logg=4.44 FeH=0.0 columns=wavelength_AA flux_erg_s_cm2_AA'
244253
call calculate_bolometric( &
245254
cs, test_teff(1), test_logg(1), test_meta(1), test_R(1), d_10pc, &
246255
bol_mag, bol_flux, wavelengths, fluxes, sed_filepath, interp_rad)
247256

248257
n_wav = size(wavelengths)
249258
stride = max(1, n_wav / n_sed_samples)
250259

251-
write(*,'(a)') '# SED sample case=solar columns=wavelength_AA flux_erg_s_cm2_AA'
252260
do i = 1, n_wav, stride
253261
write(*,'(1pe23.13, 1x, 1pe23.13)') wavelengths(i), fluxes(i)
254262
end do
255263

264+
write(*,'(a)') ''
265+
write(*,'(a, 1pe10.2)') '# wavelength_coverage_sanity logg=4.0 FeH=0.0 rel_tol=', bol_flux_rel_tol
266+
do j = 1, n_teff
267+
call check_bolometric_coverage( &
268+
cs, sed_filepath, 'Teff', sweep_teff(j), 4.0d0, 0.0d0, rsun, bol_flux_rel_tol)
269+
end do
270+
256271
! -----------------------------------------------------------------------
257272
! cleanup
258273
! -----------------------------------------------------------------------
@@ -266,4 +281,46 @@ program test_colors
266281

267282
write(*,*) 'test_colors: passed'
268283

284+
contains
285+
286+
subroutine write_section_header(title)
287+
character(len=*), intent(in) :: title
288+
289+
write(*,'(a)') ''
290+
write(*,'(a)') trim(title)
291+
write(*,'(a)') ''
292+
end subroutine write_section_header
293+
294+
subroutine check_bolometric_coverage(rq, sed_path, label, teff, log_g, metallicity, radius, rel_tol)
295+
type(Colors_General_Info), intent(inout) :: rq
296+
character(len=*), intent(in) :: sed_path, label
297+
real(dp), intent(in) :: teff, log_g, metallicity, radius, rel_tol
298+
299+
real(dp), allocatable :: local_wavelengths(:), local_fluxes(:)
300+
real(dp) :: local_mag, local_flux, local_interp_rad
301+
real(dp) :: expected_flux, abs_err, rel_err
302+
303+
call calculate_bolometric( &
304+
rq, teff, log_g, metallicity, radius, d_10pc, &
305+
local_mag, local_flux, local_wavelengths, local_fluxes, sed_path, local_interp_rad)
306+
307+
expected_flux = boltz_sigma*teff**4*(radius/d_10pc)**2
308+
abs_err = abs(local_flux - expected_flux)
309+
rel_err = abs(local_flux - expected_flux)/expected_flux
310+
311+
write(*,'(a, a, a, f10.1)') '# case: ', trim(label), '=', teff
312+
write(*,'(a40, 1pe23.13)') 'Wav_min_AA', minval(local_wavelengths)
313+
write(*,'(a40, 1pe23.13)') 'Wav_max_AA', maxval(local_wavelengths)
314+
write(*,'(a40, 1pe23.13)') 'Flux_actual', local_flux
315+
write(*,'(a40, 1pe23.13)') 'Flux_expected', expected_flux
316+
write(*,'(a40, 1pe23.13)') 'Flux_abserr', abs_err
317+
write(*,'(a40, 1pe23.13)') 'Flux_relerr', rel_err
318+
319+
if (rel_err > rel_tol) then
320+
write(*,'(a, a, a, 1pe11.3, a, 1pe11.3)') &
321+
'wavelength coverage sanity check failed for ', trim(label), &
322+
': rel_err=', rel_err, ' > rel_tol=', rel_tol
323+
stop 1
324+
end if
325+
end subroutine check_bolometric_coverage
269326
end program test_colors

colors/test/test_output

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
2-
# group1 system=Vega grid=Kurucz2003 filters=Johnson
2+
3+
# Group1 system=Vega grid=Kurucz2003 filters=Johnson
4+
35
# case: solar
46
Mag_bol 1.6233783742415E+01
57
Flux_bol 3.2098630468165E-07
@@ -33,7 +35,9 @@ colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
3335
R -2.0538595855424E-01
3436
U 3.9598722643568E+00
3537
V 7.5454159459472E-01
36-
# group2a vary_MH Teff=5778 logg=4.44
38+
39+
# Group2a vary_MH Teff=5778 logg=4.44
40+
3741
# MH= -2.00
3842
Mag_bol 1.6233121880603E+01
3943
Flux_bol 3.2118203670543E-07
@@ -78,7 +82,9 @@ colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
7882
R 4.2891305098437E+00
7983
U 5.7511450514938E+00
8084
V 4.7518221763185E+00
81-
# group2b vary_logg Teff=5778 MH=0.0
85+
86+
# Group2b vary_logg Teff=5778 MH=0.0
87+
8288
# logg= 1.00
8389
Mag_bol 1.6233777481775E+01
8490
Flux_bol 3.2098815557824E-07
@@ -123,7 +129,9 @@ colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
123129
R 4.3286664694765E+00
124130
U 5.5395103794726E+00
125131
V 4.7780378683469E+00
126-
# group2c vary_Teff logg=4.0 MH=0.0
132+
133+
# Group2c vary_Teff logg=4.0 MH=0.0
134+
127135
# Teff= 3500.0
128136
Mag_bol 1.8411335119795E+01
129137
Flux_bol 4.3198229964375E-08
@@ -168,7 +176,10 @@ colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
168176
R 1.3843911085916E+00
169177
U 1.0937345701750E-01
170178
V 1.2754965059690E+00
171-
# SED sample case=solar columns=wavelength_AA flux_erg_s_cm2_AA
179+
180+
# Group3 SED sample + wavelength_coverage_sanity
181+
182+
# SED sample case=solar Teff=5778 logg=4.44 FeH=0.0 columns=wavelength_AA flux_erg_s_cm2_AA
172183
1.4720000000000E+02 2.1385116423739E-41
173184
5.1200000000000E+02 1.2669686045439E-39
174185
1.0950000000000E+03 5.5890114496366E-21
@@ -190,4 +201,34 @@ colors: flux cube loaded (76 x 11 x 8 x 1199, 61.2 MB)
190201
5.6500000000000E+04 5.2911476520239E-14
191202
7.2600000000000E+04 2.0114488666486E-14
192203
9.6200000000000E+04 6.6589153670475E-15
204+
205+
# wavelength_coverage_sanity logg=4.0 FeH=0.0 rel_tol= 5.00E-03
206+
# case: Teff= 3500.0
207+
Wav_min_AA 1.4720000000000E+02
208+
Wav_max_AA 1.6000000000000E+06
209+
Flux_actual 4.3198229964375E-08
210+
Flux_expected 4.3253426712080E-08
211+
Flux_abserr 5.5196747704715E-11
212+
Flux_relerr 1.2761242726995E-03
213+
# case: Teff= 6000.0
214+
Wav_min_AA 1.4720000000000E+02
215+
Wav_max_AA 1.6000000000000E+06
216+
Flux_actual 3.7325163050257E-07
217+
Flux_expected 3.7355395930932E-07
218+
Flux_abserr 3.0232880675309E-10
219+
Flux_relerr 8.0933101957231E-04
220+
# case: Teff= 10000.0
221+
Wav_min_AA 1.4720000000000E+02
222+
Wav_max_AA 1.6000000000000E+06
223+
Flux_actual 2.8809769255562E-06
224+
Flux_expected 2.8823607971398E-06
225+
Flux_abserr 1.3838715836804E-09
226+
Flux_relerr 4.8011740412706E-04
227+
# case: Teff= 20000.0
228+
Wav_min_AA 1.4720000000000E+02
229+
Wav_max_AA 1.6000000000000E+06
230+
Flux_actual 4.6160109853289E-05
231+
Flux_expected 4.6117772754238E-05
232+
Flux_abserr 4.2337099051924E-08
233+
Flux_relerr 9.1802132938073E-04
193234
test_colors: passed

0 commit comments

Comments
 (0)