Source code for snewpy.models.ccsn

# -*- coding: utf-8 -*-
"""
The submodule ``snewpy.models.ccsn`` contains models of core-collapse supernovae
derived from the :class:`SupernovaModel` base class.

Since SNEWPY v1.3, the prefered method is to initialise a model based on its physics parameters.
Initialisation from a file name is deprecated.

Use the ``param`` class property to view all physics parameters and their possible values:

>>> from snewpy.models.ccsn import Nakazato_2013
>>> Nakazato_2013.param
{'progenitor_mass': <Quantity [13., 20., 30., 50.] solMass>,
 'revival_time': <Quantity [  0., 100., 200., 300.] ms>,
 'metallicity': [0.02, 0.004],
 'eos': ['LS220', 'shen', 'togashi']}

For some models, not all combinations of parameters are valid. Use the ``get_param_combinations()``
class method to get a list of all valid combinations and filter it:

>>> list(params for params in Nakazato_2013.get_param_combinations() if params['eos'] != 'shen')
[{'progenitor_mass': <Quantity 30. solMass>, 'revival_time': <Quantity 0. ms>,
  'metallicity': 0.004, 'eos': 'LS220'},
 {'progenitor_mass': <Quantity 30. solMass>, 'revival_time': <Quantity 0. ms>,
  'metallicity': 0.004, 'eos': 'togashi'}]

.. _Garching Supernova Archive: https://wwwmpa.mpa-garching.mpg.de/ccsnarchive/
"""
import logging
import os
import re
import tarfile

import numpy as np
from astropy import units as u
from astropy.table import Table

from snewpy.models import loaders
from .base import PinchedModel, _RegistryModel

from warnings import warn
from functools import wraps


def _warn_deprecated_filename_argument(func):
    """Decorator for model.__new__ methods, causing them to issue a deprecation warning
     if argument `filename` is used. Initialization by filename will be moved to
     snewpy.models.init_model, and model classes are initialized from physical parameters.
    """
    @wraps(func)  # Ensures docstrings are preserved
    def decorator(cls, *args, **kwargs):
        filename = args[0] if len(args) > 0 else None  # Assumes filename is first pos. arg if provided
        if filename is not None:
            msg = ''.join(['Initializing this model with a filename is deprecated. ',
                           f'Instead, use keyword arguments {list(cls.param.keys())}. ',
                           f'See `{cls.__name__}.param`, `{cls.__name__}.get_param_combinations()` for more info.'])
            warn(FutureWarning(msg), stacklevel=2)
        return func(cls, *args, **kwargs)
    return decorator


[docs]class Analytic3Species(PinchedModel): """An analytical model calculating spectra given total luminosity, average energy, and rms or pinch, for each species. """ param = "There are no input files available for this class. Use `doc/scripts/Analytic.py` in the SNEWPY GitHub repo to create a custom input file." def get_param_combinations(cls): print(cls.param) return [] def __init__(self, filename): """ Parameters ---------- filename : str Absolute or relative path to file with model data. """ simtab = Table.read(filename,format='ascii') self.filename = filename super().__init__(simtab, metadata={})
[docs]class Nakazato_2013(_RegistryModel): """Model based on simulations from Nakazato et al., ApJ S 205:2 (2013), ApJ 804:75 (2015), PASJ 73:639 (2021). See also http://asphwww.ph.noda.tus.ac.jp/snn/. """ param = {'progenitor_mass': [13, 20, 30, 50] * u.Msun, 'revival_time': [0, 100, 200, 300] * u.ms, 'metallicity': [0.02, 0.004], 'eos': ['LS220', 'shen', 'togashi']} _param_validator = lambda p: (p['revival_time'] == 0 * u.ms and p['progenitor_mass'] == 30 * u.Msun and p['metallicity'] == 0.004) or \ (p['revival_time'] != 0 * u.ms and p['eos'] == 'shen' and not (p['progenitor_mass'] == 30 * u.Msun and p['metallicity'] == 0.004)) @_warn_deprecated_filename_argument def __new__(cls, filename=None, *, progenitor_mass=None, revival_time=None, metallicity=None, eos=None): """Model initialization. Parameters ---------- filename : str Absolute or relative path to FITS file with model data. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. revival_time: astropy.units.Quantity Time of shock revival in model in units ms. Valid values are {revival_time}. Selecting 0 ms will load a black hole formation model metallicity: float Progenitor metallicity. Valid values are {metallicity}. eos: str Equation of state. Valid values are {eos}. Raises ------ ValueError If a combination of parameters is invalid when loading from parameters Examples -------- >>> from snewpy.models.ccsn import Nakazato_2013; import astropy.units as u >>> Nakazato_2013(progenitor_mass=30*u.Msun, metallicity=0.004, revival_time=0*u.s, eos='togashi') Nakazato_2013 Model: nakazato-togashi-BH-z0.004-s30.0.fits Progenitor mass : 30.0 solMass EOS : togashi Metallicity : 0.004 Revival time : 0.0 ms """ # Attempt to load model from parameters if filename is not None: metadata = {'Progenitor mass': float(filename.split('-')[-1].strip('s%.fits')) * u.Msun} if 't_rev' in filename: metadata.update({ 'EOS': filename.split('-')[-4].upper(), 'Metallicity': float(filename.split('-')[-3].strip('z%')), 'Revival time': float(filename.split('-')[-2].strip('t_rev%ms')) * u.ms }) # No revival time because the explosion "failed" (BH formation). else: metadata.update({ 'EOS': filename.split('-')[-4].upper(), 'Metallicity': float(filename.split('-')[-2].strip('z%')), 'Revival time': 0 * u.ms }) return loaders.Nakazato_2013(os.path.abspath(filename), metadata) # Load from model parameters user_params = dict(zip(cls.param.keys(), (progenitor_mass, revival_time, metallicity, eos))) cls.check_valid_params(cls, **user_params) # Store model metadata. metadata = { 'Progenitor mass': progenitor_mass, 'EOS': eos, 'Metallicity': metallicity, 'Revival time': revival_time } # Strip units for filename construction progenitor_mass = progenitor_mass.to(u.Msun).value revival_time = revival_time.to(u.ms).value if revival_time != 0: filename = f"nakazato-{eos}-z{metallicity}-t_rev{int(revival_time)}ms-s{progenitor_mass:3.1f}.fits" else: filename = f"nakazato-{eos}-BH-z{metallicity}-s{progenitor_mass:3.1f}.fits" return loaders.Nakazato_2013(filename, metadata) # Populate Docstring with param values __new__.__doc__ = __new__.__doc__.format(**param)
[docs]class Sukhbold_2015(_RegistryModel): """Model based on simulations from Sukhbold et al., ApJ 821:38,2016. Models were shared privately by email. """ param = {'progenitor_mass': [27., 9.6] * u.Msun, 'eos': ['LS220', 'SFHo']} @_warn_deprecated_filename_argument def __new__(cls, filename=None, *, progenitor_mass=None, eos=None): """Model Initialization Parameters ---------- filename : str Absolute or relative path to FITS file with model data. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. eos: str Equation of state. Valid values are {eos}. Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ if filename is not None: metadata = { 'Progenitor mass': float(filename.split('-')[-1].strip('z%.fits')) * u.Msun, 'EOS': filename.split('-')[-2] } return loaders.Sukhbold_2015(os.path.abspath(filename), metadata) user_params = dict(zip(cls.param.keys(), (progenitor_mass, eos))) cls.check_valid_params(cls, **user_params) if progenitor_mass.value == 9.6: filename = f'sukhbold-{eos}-z{progenitor_mass.value:3.1f}.fits' else: filename = f'sukhbold-{eos}-s{progenitor_mass.value:3.1f}.fits' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': eos } return loaders.Sukhbold_2015(filename, metadata) # Populate Docstring with param values __new__.__doc__ = __new__.__doc__.format(**param)
[docs]class Tamborra_2014(_RegistryModel): """Model based on 3D simulations from `Tamborra et al., PRD 90:045032, 2014 <https://arxiv.org/abs/1406.0006>`_. Data files are from the `Garching Supernova Archive`_. """ param = {'progenitor_mass': [20., 27.] * u.Msun} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='LS220', *, progenitor_mass=None): if filename is not None: # Metadata creation is implemented in snewpy.models.base._GarchingArchiveModel return loaders.Tamborra_2014(os.path.abspath(filename)) cls.check_valid_params(cls, progenitor_mass=progenitor_mass) filename = f's{progenitor_mass.value:3.1f}c_3D_dir1' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': 'LS220' } # Metadata is handled by __init__ in _GarchingArchiveModel return loaders.Tamborra_2014(filename=filename, metadata=metadata) # Populate Docstring with param values __new__.__doc__ = loaders.Tamborra_2014.__init__.__doc__.format(**param)
[docs]class Bollig_2016(_RegistryModel): """Model based on simulations from `Bollig et al. (2016) <https://arxiv.org/abs/1508.00785>`_. Models were taken, with permission, from the `Garching Supernova Archive`_. """ param = {'progenitor_mass': [11.2, 27.] * u.Msun} def __new__(cls, filename=None, eos='LS220', *, progenitor_mass=None): if filename is not None: # Metadata creation is implemented in snewpy.models.base._GarchingArchiveModel return loaders.Bollig_2016(os.path.abspath(filename)) cls.check_valid_params(cls, progenitor_mass=progenitor_mass) filename = f's{progenitor_mass.value:3.1f}c' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': 'LS220' } return loaders.Bollig_2016(filename=filename, metadata=metadata) # Populate Docstring with param values (Docstring is inherited from base._GarchingArchiveModel.__init__) __new__.__doc__ = loaders.Bollig_2016.__init__.__doc__.format(**param)
[docs]class Walk_2018(_RegistryModel): """Model based on SASI-dominated simulations from `Walk et al., PRD 98:123001, 2018 <https://arxiv.org/abs/1807.02366>`_. Data files are from the `Garching Supernova Archive`_. """ param = {'progenitor_mass': 15. * u.Msun} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='LS220', *, progenitor_mass=None): if filename is not None: # Metadata creation is implemented in snewpy.models.base._GarchingArchiveModel return loaders.Walk_2018(os.path.abspath(filename)) cls.check_valid_params(cls, progenitor_mass=progenitor_mass) filename = f's{progenitor_mass.value:3.1f}c_3D_nonrot_dir1' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': 'LS220' } return loaders.Walk_2018(filename=filename, metadata=metadata) # Populate Docstring with param values (Docstring is inherited from base._GarchingArchiveModel.__init__) __new__.__doc__ = loaders.Walk_2018.__init__.__doc__.format(**param)
[docs]class Walk_2019(_RegistryModel): """Model based on SASI-dominated simulations from `Walk et al., PRD 101:123013, 2019 <https://arxiv.org/abs/1910.12971>`_. Data files are from the `Garching Supernova Archive`_. """ param = {'progenitor_mass': 40 * u.Msun} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='LS220', *, progenitor_mass=None): if filename is not None: # Metadata creation is implemented in snewpy.models.base._GarchingArchiveModel return loaders.Walk_2019(os.path.abspath(filename)) cls.check_valid_params(cls, progenitor_mass=progenitor_mass) filename = f's{progenitor_mass.value:3.1f}c_3DBH_dir1' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': 'LS220' } return loaders.Walk_2019(filename=filename, metadata=metadata) # Populate Docstring with param values (Docstring is inherited from base._GarchingArchiveModel.__init__) __new__.__doc__ = loaders.Walk_2019.__init__.__doc__.format(**param)
[docs]class OConnor_2013(_RegistryModel): """Model based on the black hole formation simulation in `O'Connor & Ott (2013) <https://arxiv.org/abs/1207.1100>`_. """ param = {'progenitor_mass': (list(range(12, 34)) + list(range(35, 61, 5)) + [70, 80, 100, 120]) * u.Msun, 'eos': ['HShen', 'LS220']} _param_abbrv = {'progenitor_mass': '[12..33, 35..5..60, 70, 80, 100, 120] solMass', 'eos': ['HShen', 'LS220']} @_warn_deprecated_filename_argument def __new__(cls, base=None, mass=None, eos='LS220', *, progenitor_mass=None): """Model Initialization. Parameters ---------- base : str Absolute or relative path folder with model data. This argument is deprecated. mass: int Mass of model progenitor in units Msun. This argument is deprecated. eos: str Equation of state. Valid values are {eos}. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ # TODO: (For v2.0) Change `base` to filename, move compressed model files to OConnor_2013 model folder if mass is not None: warn(f'Argument `mass` of type int is deprecated. To initialize this model, use keyword arguments ' f'{list(cls.param.keys())}. See {cls.__name__}.param, {cls.__name__}.get_param_combinations() for more info', category=DeprecationWarning, stacklevel=2) else: mass = 15 # Default Value, this is handled this way for backwards compatibility -- TODO (For V2.0) Remove if base is not None: # If base is provided, do not attempt to load from param. if mass * u.Msun not in cls.param['progenitor_mass']: raise ValueError(f'Invalid value for argument `progenitor mass` or `mass`, see {cls.__name__}.param' f' for allowed values') metadata = {'Progenitor mass': progenitor_mass if progenitor_mass is not None else mass * u.Msun, 'EOS': eos} filename = os.path.join(base, f"{eos}_timeseries.tar.gz") return loaders.OConnor_2013(os.path.abspath(filename), metadata) # Load from Parameters cls.check_valid_params(cls, progenitor_mass=progenitor_mass, eos=eos) filename = f'{eos}_timeseries.tar.gz' metadata = { 'Progenitor mass': progenitor_mass, 'EOS': eos, } return loaders.OConnor_2013(filename=filename, metadata=metadata) # Populate Docstring with param values __new__.__doc__ = __new__.__doc__.format(**_param_abbrv)
[docs]class OConnor_2015(_RegistryModel): """Model based on the black hole formation simulation in `O'Connor (2015) <https://arxiv.org/abs/1411.7058>`_. """ param = {'progenitor_mass': 40 * u.Msun} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='LS220', *, progenitor_mass=None): """Model Initialization. Parameters ---------- filename : str Absolute or relative path to tar.gz file with model data. This argument is deprecated. eos: str Equation of state. Valid value is 'LS220'. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ metadata = { 'Progenitor mass': 40*u.Msun, 'EOS': 'LS220', } if filename is not None: return loaders.OConnor_2015(os.path.abspath(filename), metadata) # Load from Parameters cls.check_valid_params(cls, progenitor_mass=progenitor_mass) # Filename is currently the same regardless of parameters filename = 'M1_neutrinos.dat' return loaders.OConnor_2015(filename, metadata) # Populate Docstring with param values __new__.__doc__ = __new__.__doc__.format(**param)
[docs]class Zha_2021(_RegistryModel): """Model based on the hadron-quark phse transition models from `Zha et al. 2021 <https://arxiv.org/abs/2103.02268>`_. """ param = {'progenitor_mass': (list(range(16, 27)) + [19.89, 22.39, 30, 33]) * u.Msun} _param_abbrv = {'progenitor_mass': '[16..26, 19.89, 22.39, 30, 33] solMass'} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='ST0S_B145', *, progenitor_mass=None): """Model Initialization. Parameters ---------- filename : str Absolute or relative path to file with model data. This argument is deprecated. eos : str Equation of state. Valid value is 'ST0S_B145'. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ if filename is not None: metadata = {'Progenitor mass': float(os.path.splitext(os.path.basename(filename))[0][1:]) * u.Msun, 'EOS': 'STOS_B145'} return loaders.Zha_2021(os.path.abspath(filename), metadata) # Load from Parameters cls.check_valid_params(cls, progenitor_mass=progenitor_mass) metadata = { 'Progenitor mass': progenitor_mass, 'EOS': 'STOS_B145', } filename = f's{progenitor_mass.value:g}.dat' return loaders.Zha_2021(filename, metadata) # Populate Docstring with abbreviated param values __new__.__doc__ = __new__.__doc__.format(**_param_abbrv)
[docs]class Warren_2020(_RegistryModel): """Model based on simulations from Warren et al., ApJ 898:139, 2020. Neutrino fluxes available at https://doi.org/10.5281/zenodo.3667908.""" # TODO: (For v2.0) Resolve Zenodo issues (Missing files) # np.arange with decimal increments can produce floating point errors # Though it may be more intuitive to use np.arange, these fp-errors quickly become troublesome param = {'progenitor_mass': np.concatenate((np.linspace(9.0, 12.75, 16), np.linspace(13, 30., 171), np.linspace(31., 33., 3), np.linspace(35, 55, 5), np.linspace(60, 80, 3), np.linspace(100, 120, 2))) * u.Msun, 'turbmixing_param': [1.23, 1.25, 1.27]} _param_abbrv = {'progenitor_mass': '[9..0.25..13, 13..0.1..30, 31..35, 35..5..60, 70..10..90, 100, 120] solMass', 'turbmixing_param': [1.23, 1.25, 1.27]} @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='SFHo', *, progenitor_mass=None, turbmixing_param=None): """ Parameters ---------- filename : str Absolute or relative path to file with model data. This argument is deprecated. eos : str Equation of state. Valid value is 'SFHo'. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. turbmixing_param: float Turbulent mixing parameter alpha_lambda. Valid Values are {turbmixing_param} Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ if filename is not None: _, _, turbmixing_param, progenitor_mass = os.path.splitext(os.path.basename(filename))[0].split('_') metadata = {'Progenitor mass': float(progenitor_mass[1:]) * u.Msun, 'Turb. mixing param.': float(turbmixing_param[1:]), 'EOS': 'SFHo'} return loaders.Warren_2020(os.path.abspath(filename), metadata) # Load from Parameters user_params = dict(zip(cls.param.keys(), (progenitor_mass, turbmixing_param))) cls.check_valid_params(cls, **user_params) if progenitor_mass.value.is_integer() and progenitor_mass.value <= 30.: fname = os.path.join(f'stir_a{turbmixing_param:3.2f}', f'stir_multimessenger_a{turbmixing_param:3.2f}_m{progenitor_mass.value:.1f}.h5') else: fname = os.path.join(f'stir_a{turbmixing_param:3.2f}', f'stir_multimessenger_a{turbmixing_param:3.2f}_m{progenitor_mass.value:g}.h5') # Set model metadata. metadata = { 'Progenitor mass': progenitor_mass, 'Turb. mixing param.': turbmixing_param, 'EOS': 'SFHo', } return loaders.Warren_2020(fname, metadata) # Populate Docstring with abbreviated param values __new__.__doc__ = __new__.__doc__.format(**_param_abbrv)
[docs]class Kuroda_2020(_RegistryModel): """Model based on simulations from `Kuroda et al. (2020) <https://arxiv.org/abs/2009.07733>`_.""" param = {'rotational_velocity': [0, 1] * u.rad / u.s, 'magnetic_field_exponent': [0, 12, 13]} _param_validator = lambda p: (p['rotational_velocity'].value == 1 and p['magnetic_field_exponent'] in (12, 13)) or \ (p['rotational_velocity'].value == 0 and p['magnetic_field_exponent'] == 0) @_warn_deprecated_filename_argument def __new__(cls, filename=None, eos='LS220', mass=20*u.Msun, *, rotational_velocity=None, magnetic_field_exponent=None): """ Parameters ---------- filename : str Absolute or relative path to file with model data. This argument is deprecated. eos : str Equation of state. Valid value is 'LS220'. This argument is deprecated. mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid value is 20 * u.Msun. This argument is deprecated. Other Parameters ---------------- rotational_velocity: astropy.units.Quantity Rotational velocity of progenitor. Valid values are {rotational_velocity} magnetic_field_exponent: int Exponent of magnetic field (See Eq. 46). Valid Values are {magnetic_field_exponent} Raises ------ FileNotFoundError If a file for the chosen model parameters cannot be found ValueError If a combination of parameters is invalid when loading from parameters """ if filename is not None: _, rotational_velocity, magnetic_field_exponent = re.split('R|B', os.path.splitext(os.path.basename(filename))[0]) metadata = { 'Progenitor mass': 20 * u.Msun, 'Rotational Velocity': int(rotational_velocity[0]), 'B_0 Exponent': int(magnetic_field_exponent), 'EOS': 'LS220' } return loaders.Kuroda_2020(os.path.abspath(filename), metadata) # Load from Parameters cls.check_valid_params(cls, rotational_velocity=rotational_velocity, magnetic_field_exponent=magnetic_field_exponent) filename = f'LnuR{int(rotational_velocity.value):1d}0B{int(magnetic_field_exponent):02d}.dat' metadata = { 'Progenitor mass': 20 * u.Msun, 'Rotational Velocity': rotational_velocity, 'B_0 Exponent': magnetic_field_exponent, 'EOS': 'LS220', } return loaders.Kuroda_2020(filename, metadata) __new__.__doc__ = __new__.__doc__.format(**param)
[docs]class Fornax_2019(_RegistryModel): """Model based on 3D simulations from D. Vartanyan, A. Burrows, D. Radice, M. A. Skinner and J. Dolence, MNRAS 482(1):351, 2019. Data available at https://www.astro.princeton.edu/~burrows/nu-emissions.3d/ """ param = {'progenitor_mass': [9, 10, 12, 13, 14, 15, 16, 19, 25, 60] * u.Msun} @_warn_deprecated_filename_argument def __new__(cls, filename=None, cache_flux=False, *, progenitor_mass=None, ): """Model Initialization. Parameters ---------- filename : str Absolute or relative path to file with model data. This argument is deprecated. cache_flux : bool If true, pre-compute the flux on a fixed angular grid and store the values in a FITS file. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. """ if filename is not None: progenitor_mass = os.path.splitext(os.path.basename(filename))[0].split('_')[2] metadata = {'Progenitor mass': int(progenitor_mass[:-1]) * u.Msun} return loaders.Fornax_2019(os.path.abspath(filename), metadata, cache_flux=cache_flux) # Load from Parameters metadata = {'Progenitor mass': progenitor_mass} cls.check_valid_params(cls, progenitor_mass=progenitor_mass) if progenitor_mass.value == 16: filename = f'lum_spec_{int(progenitor_mass.value):d}M_r250.h5' else: filename = f'lum_spec_{int(progenitor_mass.value):d}M.h5' return loaders.Fornax_2019(filename, metadata, cache_flux=cache_flux) # Populate Docstring with abbreviated param values __new__.__doc__ = __new__.__doc__.format(**param)
[docs]class Fornax_2021(_RegistryModel): """Model based on 3D simulations from D. Vartanyan, A. Burrows, D. Radice, M. A. Skinner and J. Dolence, MNRAS 482(1):351, 2019. Data available at https://www.astro.princeton.edu/~burrows/nu-emissions.3d/ """ param = {'progenitor_mass': (list(range(12, 24)) + [25, 26, 26.99]) * u.Msun} _param_abbrv = {'progenitor_mass': '[12..26, 26.99] solMass'} @_warn_deprecated_filename_argument def __new__(cls, filename=None, *, progenitor_mass=None): """Model Initialization. Parameters ---------- filename : str Absolute or relative path to file with model data. This argument is deprecated. Other Parameters ---------------- progenitor_mass: astropy.units.Quantity Mass of model progenitor in units Msun. Valid values are {progenitor_mass}. """ if filename is not None: progenitor_mass = os.path.splitext(os.path.basename(filename))[0].split('_')[2] metadata = {'Progenitor mass': float(progenitor_mass[:-1]) * u.Msun} return loaders.Fornax_2021(os.path.abspath(filename), metadata) # Load from Parameters cls.check_valid_params(cls, progenitor_mass=progenitor_mass) if progenitor_mass.value.is_integer(): filename = f'lum_spec_{int(progenitor_mass.value):2d}M_r10000_dat.h5' else: filename = f'lum_spec_{progenitor_mass.value:.2f}M_r10000_dat.h5' metadata = {'Progenitor mass': progenitor_mass} return loaders.Fornax_2021(filename, metadata) # Populate Docstring with abbreviated param values __new__.__doc__ = __new__.__doc__.format(**_param_abbrv)
[docs]class SNOwGLoBES: """A model that does not inherit from SupernovaModel (yet) and imports a group of SNOwGLoBES files.""" def __init__(self, tarfilename): """ Parameters ---------- tarfilename: str Absolute or relative path to tar archive with SNOwGLoBES files. """ self.tfname = tarfilename tf = tarfile.open(self.tfname) # For now just pull out the "NoOsc" files. datafiles = sorted([f.name for f in tf if '.dat' in f.name]) noosc = [df for df in datafiles if 'NoOsc' in df] noosc.sort(key=len) # Loop through the noosc files and pull out the number fluxes. self.time = [] self.energy = None self.flux = {} self.fmin = 1e99 self.fmax = -1e99 for nooscfile in noosc: with tf.extractfile(nooscfile) as f: logging.debug('Reading {}'.format(nooscfile)) meta = f.readline() metatext = meta.decode('utf-8') t = float(metatext.split('TBinMid=')[-1].split('sec')[0]) dt = float(metatext.split('tBinWidth=')[-1].split('s')[0]) dE = float(metatext.split('eBinWidth=')[-1].split('MeV')[0]) data = Table.read(f, format='ascii.commented_header', header_start=-1) data.meta['t'] = t data.meta['dt'] = dt data.meta['dE'] = dE self.time.append(t) if self.energy is None: self.energy = (data['E(GeV)'].data*1000).tolist() for flavor in ['NuE', 'NuMu', 'NuTau', 'aNuE', 'aNuMu', 'aNuTau']: if flavor in self.flux: self.flux[flavor].append(data[flavor].data.tolist()) else: self.flux[flavor] = [data[flavor].data.tolist()] # We now have a table with rows=times and columns=energies. Transpose # so that rows=energy and cols=time. for k, v in self.flux.items(): self.flux[k] = np.transpose(self.flux[k]) self.fmin = np.minimum(self.fmin, np.min(self.flux[k])) self.fmax = np.maximum(self.fmax, np.max(self.flux[k]))
[docs] def get_fluence(self, t): """Return the fluence at a given time t. Parameters ---------- t : float Time in seconds. Returns ------- fluence : dict A dictionary giving fluence at time t, keyed by flavor. """ # Get index of closest element in the array idx = np.abs(np.asarray(self.time) - t).argmin() fluence = {} for k, fl in self.flux.items(): fluence[k] = fl[:,idx] return fluence