LCOV - code coverage report
Current view: top level - colors/public - colors_def.f90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.9 % 130 113
Test Date: 2026-05-14 09:58:24 Functions: 60.0 % 10 6

            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_def
      21              : 
      22              :    use const_def, only: dp
      23              : 
      24              :    implicit none
      25              : 
      26              :    public
      27              : 
      28              :    ! max number of SEDs to keep in the memory cache
      29              :    ! each slot holds one wavelength array (~1200 doubles ~ 10 KB),
      30              :    ! so 256 slots ~ 2.5 MB -- negligible even when the full cube
      31              :    ! cannot be allocated
      32              :    integer, parameter :: sed_mem_cache_cap = 256
      33              : 
      34              :    type :: filter_data
      35              :       character(len=100) :: name
      36              :       real(dp), allocatable :: wavelengths(:)
      37              :       real(dp), allocatable :: transmission(:)
      38              :       ! precomputed zero-point fluxes, computed once at init
      39              :       real(dp) :: vega_zero_point = -1.0_dp
      40              :       real(dp) :: ab_zero_point = -1.0_dp
      41              :       real(dp) :: st_zero_point = -1.0_dp
      42              :    end type filter_data
      43              : 
      44              :    type :: Colors_General_Info
      45              :       character(len=256) :: instrument
      46              :       character(len=256) :: vega_sed
      47              :       character(len=256) :: stellar_atm
      48              :       character(len=256) :: colors_results_directory
      49              :       character(len=256) :: mag_system
      50              :       real(dp) :: metallicity
      51              :       real(dp) :: distance
      52              :       real(dp) :: z_over_x_ref
      53              :       logical :: make_csv
      54              :       logical :: sed_per_model
      55              :       logical :: use_colors
      56              :       integer :: handle
      57              :       logical :: in_use
      58              : 
      59              :       ! cached lookup table data
      60              :       logical :: lookup_loaded = .false.
      61              :       character(len=100), allocatable :: lu_file_names(:)
      62              :       real(dp), allocatable :: lu_logg(:)
      63              :       real(dp), allocatable :: lu_meta(:)
      64              :       real(dp), allocatable :: lu_teff(:)
      65              : 
      66              :       ! cached vega SED
      67              :       logical :: vega_loaded = .false.
      68              :       real(dp), allocatable :: vega_wavelengths(:)
      69              :       real(dp), allocatable :: vega_fluxes(:)
      70              : 
      71              :       ! cached filter data (includes precomputed zero-points)
      72              :       logical :: filters_loaded = .false.
      73              :       type(filter_data), allocatable :: filters(:)
      74              : 
      75              :       ! cached flux cube
      76              :       logical :: cube_loaded = .false.
      77              :       real(dp), allocatable :: cube_flux(:, :, :, :)    ! (n_teff, n_logg, n_meta, n_lambda)
      78              :       real(dp), allocatable :: cube_teff_grid(:)
      79              :       real(dp), allocatable :: cube_logg_grid(:)
      80              :       real(dp), allocatable :: cube_meta_grid(:)
      81              :       real(dp), allocatable :: cube_wavelengths(:)
      82              : 
      83              :       ! unique sorted grids (built once from lookup table at init)
      84              :       logical :: unique_grids_built = .false.
      85              :       real(dp), allocatable :: u_teff(:), u_logg(:), u_meta(:)
      86              : 
      87              :       ! grid_to_lu(i_t, i_g, i_m) gives the lookup-table row index for
      88              :       ! (u_teff(i_t), u_logg(i_g), u_meta(i_m)) -- avoids O(n_lu)
      89              :       ! nearest-neighbour searches at runtime
      90              :       logical :: grid_map_built = .false.
      91              :       integer, allocatable :: grid_to_lu(:, :, :)
      92              : 
      93              :       ! fallback-path caches (used only when cube_loaded == .false.)
      94              : 
      95              :       ! stencil cache: the extended neighbourhood around the current
      96              :       ! interpolation cell, includes derivative-context points
      97              :       ! (i-1 .. i+2 per axis, clamped to boundaries) so that
      98              :       ! hermite_tensor_interp3d gives the same result as the cube path
      99              :       logical :: stencil_valid = .false.
     100              :       integer :: stencil_i_t = -1, stencil_i_g = -1, stencil_i_m = -1
     101              :       real(dp), allocatable :: stencil_fluxes(:, :, :, :)   ! (st, sg, sm, n_lambda)
     102              :       real(dp), allocatable :: stencil_wavelengths(:)     ! (n_lambda)
     103              :       real(dp), allocatable :: stencil_teff(:)            ! subgrid values (st)
     104              :       real(dp), allocatable :: stencil_logg(:)            ! subgrid values (sg)
     105              :       real(dp), allocatable :: stencil_meta(:)            ! subgrid values (sm)
     106              : 
     107              :       ! canonical wavelength grid for fallback SEDs (set once on first disk
     108              :       ! read -- all SEDs in a given atmosphere grid share the same wavelengths)
     109              :       logical :: fallback_wavelengths_set = .false.
     110              :       real(dp), allocatable :: fallback_wavelengths(:)    ! (n_lambda)
     111              : 
     112              :       ! bounded SED memory cache (circular buffer, keyed by lu index)
     113              :       ! avoids re-reading text files for SEDs we've already parsed
     114              :       logical :: sed_mcache_init = .false.
     115              :       integer :: sed_mcache_count = 0
     116              :       integer :: sed_mcache_next = 1
     117              :       integer :: sed_mcache_nlam = 0
     118              :       integer, allocatable :: sed_mcache_keys(:)          ! (sed_mem_cache_cap)
     119              :       real(dp), allocatable :: sed_mcache_data(:, :)       ! (n_lambda, sed_mem_cache_cap)
     120              : 
     121              :    end type Colors_General_Info
     122              : 
     123              :    ! Global filter name list (shared across handles)
     124              :    integer :: num_color_filters
     125              :    character(len=100), allocatable :: color_filter_names(:)
     126              : 
     127              :    integer, parameter :: max_colors_handles = 10
     128              :    type(Colors_General_Info), target :: colors_handles(max_colors_handles)
     129              : 
     130              :    logical :: colors_is_initialized = .false.
     131              : 
     132              :    character(len=1000) :: colors_dir, colors_cache_dir, colors_temp_cache_dir
     133              :    logical :: colors_use_cache = .true.
     134              : 
     135              : contains
     136              : 
     137            2 :    subroutine colors_def_init(colors_cache_dir_in)
     138              :       use utils_lib, only: mkdir
     139              :       use const_def, only: mesa_data_dir, mesa_caches_dir, mesa_temp_caches_dir, use_mesa_temp_cache
     140              :       character(*), intent(in) :: colors_cache_dir_in
     141              :       integer :: i
     142              : 
     143            2 :       if (len_trim(colors_cache_dir_in) > 0) then
     144            0 :          colors_cache_dir = colors_cache_dir_in
     145            2 :       else if (len_trim(mesa_caches_dir) > 0) then
     146            0 :          colors_cache_dir = trim(mesa_caches_dir)//'/colors_cache'
     147              :       else
     148            2 :          colors_cache_dir = trim(mesa_data_dir)//'/colors_data/cache'
     149              :       end if
     150            2 :       call mkdir(colors_cache_dir)
     151              : 
     152           22 :       do i = 1, max_colors_handles
     153           20 :          colors_handles(i)%handle = i
     154           20 :          colors_handles(i)%in_use = .false.
     155           20 :          colors_handles(i)%lookup_loaded = .false.
     156           20 :          colors_handles(i)%vega_loaded = .false.
     157           20 :          colors_handles(i)%filters_loaded = .false.
     158           20 :          colors_handles(i)%cube_loaded = .false.
     159           20 :          colors_handles(i)%unique_grids_built = .false.
     160           20 :          colors_handles(i)%grid_map_built = .false.
     161           20 :          colors_handles(i)%stencil_valid = .false.
     162           20 :          colors_handles(i)%stencil_i_t = -1
     163           20 :          colors_handles(i)%stencil_i_g = -1
     164           20 :          colors_handles(i)%stencil_i_m = -1
     165           20 :          colors_handles(i)%sed_mcache_init = .false.
     166           20 :          colors_handles(i)%sed_mcache_count = 0
     167           20 :          colors_handles(i)%sed_mcache_next = 1
     168           20 :          colors_handles(i)%sed_mcache_nlam = 0
     169           22 :          colors_handles(i)%fallback_wavelengths_set = .false.
     170              :       end do
     171              : 
     172            2 :       colors_temp_cache_dir = trim(mesa_temp_caches_dir)//'/colors_cache'
     173            2 :       if (use_mesa_temp_cache) call mkdir(colors_temp_cache_dir)
     174              : 
     175            2 :    end subroutine colors_def_init
     176              : 
     177            2 :    integer function do_alloc_colors(ierr)
     178              :       integer, intent(out) :: ierr
     179              :       integer :: i
     180            2 :       ierr = 0
     181            2 :       do_alloc_colors = -1
     182            4 :       !$omp critical (colors_handle)
     183            2 :       do i = 1, max_colors_handles
     184            2 :          if (.not. colors_handles(i)%in_use) then
     185            2 :             colors_handles(i)%in_use = .true.
     186            2 :             do_alloc_colors = i
     187            2 :             exit
     188              :          end if
     189              :       end do
     190              :       !$omp end critical (colors_handle)
     191            2 :       if (do_alloc_colors == -1) then
     192            0 :          ierr = -1
     193            0 :          return
     194              :       end if
     195            2 :       if (colors_handles(do_alloc_colors)%handle /= do_alloc_colors) then
     196            0 :          ierr = -1
     197            0 :          return
     198              :       end if
     199              :    end function do_alloc_colors
     200              : 
     201            2 :    subroutine do_free_colors(handle)
     202              :       integer, intent(in) :: handle
     203            2 :       if (handle >= 1 .and. handle <= max_colors_handles) then
     204            2 :          colors_handles(handle)%in_use = .false.
     205            2 :          call free_colors_cache(handle)
     206              :       end if
     207            2 :    end subroutine do_free_colors
     208              : 
     209           22 :    subroutine free_colors_cache(handle)
     210              :       integer, intent(in) :: handle
     211              :       integer :: i
     212              : 
     213           22 :       if (handle < 1 .or. handle > max_colors_handles) return
     214              : 
     215           22 :       if (allocated(colors_handles(handle)%lu_file_names)) &
     216            1 :          deallocate (colors_handles(handle)%lu_file_names)
     217           22 :       if (allocated(colors_handles(handle)%lu_logg)) &
     218            1 :          deallocate (colors_handles(handle)%lu_logg)
     219           22 :       if (allocated(colors_handles(handle)%lu_meta)) &
     220            1 :          deallocate (colors_handles(handle)%lu_meta)
     221           22 :       if (allocated(colors_handles(handle)%lu_teff)) &
     222            1 :          deallocate (colors_handles(handle)%lu_teff)
     223           22 :       colors_handles(handle)%lookup_loaded = .false.
     224              : 
     225           22 :       if (allocated(colors_handles(handle)%vega_wavelengths)) &
     226            1 :          deallocate (colors_handles(handle)%vega_wavelengths)
     227           22 :       if (allocated(colors_handles(handle)%vega_fluxes)) &
     228            1 :          deallocate (colors_handles(handle)%vega_fluxes)
     229           22 :       colors_handles(handle)%vega_loaded = .false.
     230              : 
     231           22 :       if (allocated(colors_handles(handle)%filters)) then
     232            8 :          do i = 1, size(colors_handles(handle)%filters)
     233            7 :             if (allocated(colors_handles(handle)%filters(i)%wavelengths)) &
     234            7 :                deallocate (colors_handles(handle)%filters(i)%wavelengths)
     235            7 :             if (allocated(colors_handles(handle)%filters(i)%transmission)) &
     236            8 :                deallocate (colors_handles(handle)%filters(i)%transmission)
     237              :          end do
     238            8 :          deallocate (colors_handles(handle)%filters)
     239              :       end if
     240           22 :       colors_handles(handle)%filters_loaded = .false.
     241              : 
     242           22 :       if (allocated(colors_handles(handle)%cube_flux)) &
     243            1 :          deallocate (colors_handles(handle)%cube_flux)
     244           22 :       if (allocated(colors_handles(handle)%cube_teff_grid)) &
     245            1 :          deallocate (colors_handles(handle)%cube_teff_grid)
     246           22 :       if (allocated(colors_handles(handle)%cube_logg_grid)) &
     247            1 :          deallocate (colors_handles(handle)%cube_logg_grid)
     248           22 :       if (allocated(colors_handles(handle)%cube_meta_grid)) &
     249            1 :          deallocate (colors_handles(handle)%cube_meta_grid)
     250           22 :       if (allocated(colors_handles(handle)%cube_wavelengths)) &
     251            1 :          deallocate (colors_handles(handle)%cube_wavelengths)
     252           22 :       colors_handles(handle)%cube_loaded = .false.
     253              : 
     254           22 :       if (allocated(colors_handles(handle)%u_teff)) &
     255            1 :          deallocate (colors_handles(handle)%u_teff)
     256           22 :       if (allocated(colors_handles(handle)%u_logg)) &
     257            1 :          deallocate (colors_handles(handle)%u_logg)
     258           22 :       if (allocated(colors_handles(handle)%u_meta)) &
     259            1 :          deallocate (colors_handles(handle)%u_meta)
     260           22 :       colors_handles(handle)%unique_grids_built = .false.
     261              : 
     262           22 :       if (allocated(colors_handles(handle)%grid_to_lu)) &
     263            1 :          deallocate (colors_handles(handle)%grid_to_lu)
     264           22 :       colors_handles(handle)%grid_map_built = .false.
     265              : 
     266           22 :       if (allocated(colors_handles(handle)%stencil_fluxes)) &
     267            0 :          deallocate (colors_handles(handle)%stencil_fluxes)
     268           22 :       if (allocated(colors_handles(handle)%stencil_wavelengths)) &
     269            0 :          deallocate (colors_handles(handle)%stencil_wavelengths)
     270           22 :       if (allocated(colors_handles(handle)%stencil_teff)) &
     271            0 :          deallocate (colors_handles(handle)%stencil_teff)
     272           22 :       if (allocated(colors_handles(handle)%stencil_logg)) &
     273            0 :          deallocate (colors_handles(handle)%stencil_logg)
     274           22 :       if (allocated(colors_handles(handle)%stencil_meta)) &
     275            0 :          deallocate (colors_handles(handle)%stencil_meta)
     276           22 :       colors_handles(handle)%stencil_valid = .false.
     277           22 :       colors_handles(handle)%stencil_i_t = -1
     278           22 :       colors_handles(handle)%stencil_i_g = -1
     279           22 :       colors_handles(handle)%stencil_i_m = -1
     280              : 
     281           22 :       if (allocated(colors_handles(handle)%sed_mcache_keys)) &
     282            0 :          deallocate (colors_handles(handle)%sed_mcache_keys)
     283           22 :       if (allocated(colors_handles(handle)%sed_mcache_data)) &
     284            0 :          deallocate (colors_handles(handle)%sed_mcache_data)
     285           22 :       colors_handles(handle)%sed_mcache_init = .false.
     286           22 :       colors_handles(handle)%sed_mcache_count = 0
     287           22 :       colors_handles(handle)%sed_mcache_next = 1
     288           22 :       colors_handles(handle)%sed_mcache_nlam = 0
     289              : 
     290           22 :       if (allocated(colors_handles(handle)%fallback_wavelengths)) &
     291            0 :          deallocate (colors_handles(handle)%fallback_wavelengths)
     292           22 :       colors_handles(handle)%fallback_wavelengths_set = .false.
     293              : 
     294              :    end subroutine free_colors_cache
     295              : 
     296           28 :    subroutine get_colors_ptr(handle, rq, ierr)
     297              :       integer, intent(in) :: handle
     298              :       type(Colors_General_Info), pointer, intent(out) :: rq
     299              :       integer, intent(out):: ierr
     300           28 :       if (handle < 1 .or. handle > max_colors_handles) then
     301            0 :          ierr = -1
     302            0 :          return
     303              :       end if
     304           28 :       rq => colors_handles(handle)
     305           28 :       ierr = 0
     306              :    end subroutine get_colors_ptr
     307              : 
     308            2 :    subroutine do_free_colors_tables
     309              :       integer :: i
     310              : 
     311            2 :       if (allocated(color_filter_names)) deallocate (color_filter_names)
     312              : 
     313           22 :       do i = 1, max_colors_handles
     314           22 :          call free_colors_cache(i)
     315              :       end do
     316              : 
     317            2 :    end subroutine do_free_colors_tables
     318              : 
     319            0 : end module colors_def
        

Generated by: LCOV version 2.0-1