LCOV - code coverage report
Current view: top level - colors/public - colors_lib.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 54.5 % 101 55
Test Date: 2026-01-29 18:28:55 Functions: 38.9 % 18 7

            Line data    Source code
       1              : ! ***********************************************************************
       2              : !
       3              : !   Copyright (C) 2025  Niall Miller & The MESA Team
       4              : !
       5              : !   This program is free software: you can redistribute it and/or modify
       6              : !   it under the terms of the GNU Lesser General Public License
       7              : !   as published by the Free Software Foundation,
       8              : !   either version 3 of the License, or (at your option) any later version.
       9              : !
      10              : !   This program is distributed in the hope that it will be useful,
      11              : !   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              : !   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13              : !   See the GNU Lesser General Public License for more details.
      14              : !
      15              : !   You should have received a copy of the GNU Lesser General Public License
      16              : !   along with this program. If not, see <https://www.gnu.org/licenses/>.
      17              : !
      18              : ! ***********************************************************************
      19              : 
      20              : module colors_lib
      21              : 
      22              :    use const_def, only: dp, strlen, mesa_dir
      23              :    use bolometric, only: calculate_bolometric
      24              :    use synthetic, only: calculate_synthetic
      25              :    use colors_utils, only: read_strings_from_file, load_lookup_table, load_filter, load_vega_sed
      26              :    use colors_history, only: how_many_colors_history_columns, data_for_colors_history_columns
      27              : 
      28              :    implicit none
      29              : 
      30              :    private
      31              : 
      32              :    public :: colors_init, colors_shutdown
      33              :    public :: alloc_colors_handle, alloc_colors_handle_using_inlist, free_colors_handle
      34              :    public :: colors_ptr
      35              :    public :: colors_setup_tables, colors_setup_hooks
      36              :    ! Main functions
      37              :    public :: calculate_bolometric, calculate_synthetic
      38              :    public :: how_many_colors_history_columns, data_for_colors_history_columns
      39              :    ! Old bolometric correction functions that MESA expects (stub implementations, remove later):
      40              :    public :: get_bc_id_by_name, get_lum_band_by_id, get_abs_mag_by_id
      41              :    public :: get_bc_by_id, get_bc_name_by_id, get_bc_by_name
      42              :    public :: get_abs_bolometric_mag, get_abs_mag_by_name, get_bcs_all
      43              :    public :: get_lum_band_by_name
      44              : contains
      45              : 
      46              :    ! call this routine to initialize the colors module.
      47              :    ! only needs to be done once at start of run.
      48              :    ! Reads data from the 'colors' directory in the data_dir.
      49              :    ! If use_cache is true and there is a 'colors/cache' directory, it will try that first.
      50              :    ! If it doesn't find what it needs in the cache,
      51              :    ! it reads the data and writes the cache for next time.
      52            1 :    subroutine colors_init(use_cache, colors_cache_dir, ierr)
      53              :       use colors_def, only: colors_def_init, colors_use_cache, colors_is_initialized
      54              :       logical, intent(in) :: use_cache
      55              :       character(len=*), intent(in) :: colors_cache_dir  ! blank means use default
      56              :       integer, intent(out) :: ierr  ! 0 means AOK.
      57            1 :       ierr = 0
      58            1 :       if (colors_is_initialized) return
      59            1 :       call colors_def_init(colors_cache_dir)
      60            1 :       colors_use_cache = use_cache
      61            1 :       colors_is_initialized = .true.
      62              :    end subroutine colors_init
      63              : 
      64            1 :    subroutine colors_shutdown
      65              :       use colors_def, only: do_free_colors_tables, colors_is_initialized
      66            1 :       call do_free_colors_tables()
      67            1 :       colors_is_initialized = .false.
      68            1 :    end subroutine colors_shutdown
      69              : 
      70              :    ! after colors_init has finished, you can allocate a "handle".
      71            0 :    integer function alloc_colors_handle(ierr) result(handle)
      72              :       integer, intent(out) :: ierr  ! 0 means AOK.
      73              :       character(len=0) :: inlist
      74            0 :       handle = alloc_colors_handle_using_inlist(inlist, ierr)
      75            0 :    end function alloc_colors_handle
      76              : 
      77            4 :    integer function alloc_colors_handle_using_inlist(inlist, ierr) result(handle)
      78              :       use colors_def, only: do_alloc_colors, colors_is_initialized
      79              :       use colors_ctrls_io, only: read_namelist
      80              :       character(len=*), intent(in) :: inlist  ! empty means just use defaults.
      81              :       integer, intent(out) :: ierr  ! 0 means AOK.
      82              :       ierr = 0
      83            1 :       if (.not. colors_is_initialized) then
      84            0 :          ierr = -1
      85            0 :          return
      86              :       end if
      87            1 :       handle = do_alloc_colors(ierr)
      88            1 :       if (ierr /= 0) return
      89            1 :       call read_namelist(handle, inlist, ierr)
      90            1 :       if (ierr /= 0) return
      91            1 :       call colors_setup_tables(handle, ierr)
      92            1 :       call colors_setup_hooks(handle, ierr)
      93            1 :    end function alloc_colors_handle_using_inlist
      94              : 
      95            1 :    subroutine free_colors_handle(handle)
      96              :       ! frees the handle and all associated data
      97              :       use colors_def, only: colors_General_Info, do_free_colors
      98              :       integer, intent(in) :: handle
      99            1 :       call do_free_colors(handle)
     100            1 :    end subroutine free_colors_handle
     101              : 
     102            2 :    subroutine colors_ptr(handle, rq, ierr)
     103              : 
     104              :       use colors_def, only: Colors_General_Info, get_colors_ptr, colors_is_initialized
     105              : 
     106              :       type(colors_General_Info), pointer, intent(out) :: rq
     107              :       integer, intent(in) :: handle
     108              :       integer, intent(out):: ierr
     109              : 
     110            1 :       if (.not. colors_is_initialized) then
     111            0 :          ierr = -1
     112            0 :          return
     113              :       end if
     114              : 
     115            1 :       call get_colors_ptr(handle, rq, ierr)
     116              : 
     117              :    end subroutine colors_ptr
     118              : 
     119            1 :    subroutine colors_setup_tables(handle, ierr)
     120              :       use colors_def, only: Colors_General_Info, get_colors_ptr, color_filter_names, num_color_filters
     121              :       use synthetic, only: compute_vega_zero_point, compute_ab_zero_point, compute_st_zero_point
     122              :       integer, intent(in) :: handle
     123              :       integer, intent(out):: ierr
     124              : 
     125              :       type(Colors_General_Info), pointer :: rq
     126              :       character(len=256) :: lookup_file, filter_dir, filter_filepath, vega_filepath
     127            1 :       REAL, allocatable :: lookup_table(:,:)  ! unused but required by load_lookup_table
     128              :       integer :: i
     129              : 
     130              :       ierr = 0
     131            1 :       call get_colors_ptr(handle, rq, ierr)
     132            1 :       if (ierr /= 0) return
     133              : 
     134              :       ! Read filter names from instrument directory
     135            1 :       call read_strings_from_file(rq, color_filter_names, num_color_filters, ierr)
     136            1 :       if (ierr /= 0) return
     137              : 
     138              :       ! =========================================
     139              :       ! Load lookup table (stellar atmosphere grid)
     140              :       ! =========================================
     141            1 :       if (.not. rq%lookup_loaded) then
     142            1 :          lookup_file = trim(mesa_dir)//trim(rq%stellar_atm)//'/lookup_table.csv'
     143              :          call load_lookup_table(lookup_file, lookup_table, &
     144            1 :                                 rq%lu_file_names, rq%lu_logg, rq%lu_meta, rq%lu_teff)
     145            1 :          rq%lookup_loaded = .true.
     146            1 :          if (allocated(lookup_table)) deallocate(lookup_table)
     147              :       end if
     148              : 
     149              :       ! =========================================
     150              :       ! Load Vega SED (needed for Vega mag system)
     151              :       ! =========================================
     152            1 :       if (.not. rq%vega_loaded) then
     153            1 :          vega_filepath = trim(mesa_dir)//trim(rq%vega_sed)
     154            1 :          call load_vega_sed(vega_filepath, rq%vega_wavelengths, rq%vega_fluxes)
     155            1 :          rq%vega_loaded = .true.
     156              :       end if
     157              : 
     158              :       ! =========================================
     159              :       ! Load all filter transmission curves and precompute zero-points
     160              :       ! =========================================
     161            1 :       if (.not. rq%filters_loaded) then
     162            1 :          filter_dir = trim(mesa_dir)//trim(rq%instrument)
     163              : 
     164            8 :          allocate(rq%filters(num_color_filters))
     165              : 
     166            8 :          do i = 1, num_color_filters
     167            7 :             rq%filters(i)%name = color_filter_names(i)
     168            7 :             filter_filepath = trim(filter_dir)//'/'//trim(color_filter_names(i))
     169            7 :             call load_filter(filter_filepath, rq%filters(i)%wavelengths, rq%filters(i)%transmission)
     170              : 
     171              :             ! Precompute zero-points for all magnitude systems
     172              :             ! These are constant for each filter and never need recalculation
     173              :             rq%filters(i)%vega_zero_point = compute_vega_zero_point( &
     174              :                rq%vega_wavelengths, rq%vega_fluxes, &
     175            7 :                rq%filters(i)%wavelengths, rq%filters(i)%transmission)
     176              : 
     177              :             rq%filters(i)%ab_zero_point = compute_ab_zero_point( &
     178            7 :                rq%filters(i)%wavelengths, rq%filters(i)%transmission)
     179              : 
     180              :             rq%filters(i)%st_zero_point = compute_st_zero_point( &
     181           15 :                rq%filters(i)%wavelengths, rq%filters(i)%transmission)
     182              :          end do
     183              : 
     184            1 :          rq%filters_loaded = .true.
     185              :       end if
     186              : 
     187            1 :    end subroutine colors_setup_tables
     188              : 
     189            1 :    subroutine colors_setup_hooks(handle, ierr)
     190              :       use colors_def, only: colors_General_Info, get_colors_ptr
     191              :       integer, intent(in) :: handle
     192              :       integer, intent(out):: ierr
     193              : 
     194              :       type(colors_General_Info), pointer :: rq
     195              : 
     196              :       ierr = 0
     197            1 :       call get_colors_ptr(handle, rq, ierr)
     198              : 
     199              :       ! TODO: currently does nothing. See kap if this feature is needed
     200              : 
     201            1 :    end subroutine colors_setup_hooks
     202              : 
     203              :    !-----------------------------------------------------------------------
     204              :    ! Bolometric correction interface (stub implementations)
     205              :    !-----------------------------------------------------------------------
     206              : 
     207            0 :    real(dp) function get_bc_by_name(name, log_Teff, log_g, M_div_h, ierr)
     208              :       character(len=*), intent(in) :: name
     209              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     210              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     211              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     212              :       integer, intent(inout) :: ierr
     213              : 
     214            0 :       get_bc_by_name = -99.9d0
     215            0 :       ierr = 0
     216            0 :    end function get_bc_by_name
     217              : 
     218            0 :    real(dp) function get_bc_by_id(id, log_Teff, log_g, M_div_h, ierr)
     219              :       integer, intent(in) :: id
     220              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     221              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     222              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     223              :       integer, intent(inout) :: ierr
     224              : 
     225            0 :       get_bc_by_id = -99.9d0
     226            0 :       ierr = 0
     227            0 :    end function get_bc_by_id
     228              : 
     229            0 :    integer function get_bc_id_by_name(name, ierr)
     230              :       character(len=*), intent(in) :: name
     231              :       integer, intent(inout) :: ierr
     232              : 
     233            0 :       get_bc_id_by_name = -1
     234            0 :       ierr = 0
     235            0 :    end function get_bc_id_by_name
     236              : 
     237            0 :    character(len=strlen) function get_bc_name_by_id(id, ierr)
     238              :       integer, intent(in) :: id
     239              :       integer, intent(inout) :: ierr
     240              : 
     241            0 :       get_bc_name_by_id = ''
     242            0 :       ierr = 0
     243            0 :    end function get_bc_name_by_id
     244              : 
     245            0 :    real(dp) function get_abs_bolometric_mag(lum)
     246              :       use const_def, only: dp
     247              :       real(dp), intent(in) :: lum  ! Luminosity in lsun units
     248              : 
     249            0 :       get_abs_bolometric_mag = -99.9d0
     250            0 :    end function get_abs_bolometric_mag
     251              : 
     252            0 :    real(dp) function get_abs_mag_by_name(name, log_Teff, log_g, M_div_h, lum, ierr)
     253              :       character(len=*), intent(in) :: name
     254              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     255              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     256              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     257              :       real(dp), intent(in) :: lum  ! Luminosity in lsun units
     258              :       integer, intent(inout) :: ierr
     259              : 
     260            0 :       ierr = 0
     261            0 :       get_abs_mag_by_name = -99.9d0
     262            0 :    end function get_abs_mag_by_name
     263              : 
     264            0 :    real(dp) function get_abs_mag_by_id(id, log_Teff, log_g, M_div_h, lum, ierr)
     265              :       integer, intent(in) :: id
     266              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     267              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     268              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     269              :       real(dp), intent(in) :: lum  ! Luminosity in lsun units
     270              :       integer, intent(inout) :: ierr
     271              : 
     272            0 :       ierr = 0
     273            0 :       get_abs_mag_by_id = -99.9d0
     274            0 :    end function get_abs_mag_by_id
     275              : 
     276            0 :    subroutine get_bcs_all(log_Teff, log_g, M_div_h, results, ierr)
     277              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     278              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     279              :       real(dp), dimension(:), intent(out) :: results
     280              :       real(dp), intent(in) :: log_g
     281              :       integer, intent(inout) :: ierr
     282              : 
     283            0 :       ierr = 0
     284            0 :       results(:) = -99.d0
     285            0 :    end subroutine get_bcs_all
     286              : 
     287            0 :    real(dp) function get_lum_band_by_name(name, log_Teff, log_g, M_div_h, lum, ierr)
     288              :       character(len=*), intent(in) :: name
     289              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     290              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     291              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     292              :       real(dp), intent(in) :: lum  ! Total luminosity in lsun units
     293              :       integer, intent(inout) :: ierr
     294              : 
     295            0 :       ierr = 0
     296            0 :       get_lum_band_by_name = -99.d0
     297            0 :    end function get_lum_band_by_name
     298              : 
     299            0 :    real(dp) function get_lum_band_by_id(id, log_Teff, log_g, M_div_h, lum, ierr)
     300              :       integer, intent(in) :: id
     301              :       real(dp), intent(in) :: log_Teff  ! log10 of surface temp
     302              :       real(dp), intent(in) :: log_g  ! log_10 of surface gravity
     303              :       real(dp), intent(in) :: M_div_h  ! [M/H]
     304              :       real(dp), intent(in) :: lum  ! Total luminosity in lsun units
     305              :       integer, intent(inout) :: ierr
     306              : 
     307            0 :       ierr = 0
     308            0 :       get_lum_band_by_id = -99.d0
     309            0 :    end function get_lum_band_by_id
     310              : 
     311              : end module colors_lib
        

Generated by: LCOV version 2.0-1