Ejemplo n.º 1
0
def test_quantity_linspace(start, stop, num, expected):
    obtained = quantity_linspace(start, stop, num)
    assert obtained.unit == expected.unit
    assert obtained.value.all() == expected.value.all()

    with pytest.raises(ValueError):
        quantity_linspace(u.Quantity(0.5, 'eV'), '0.6 eV', 3)
Ejemplo n.º 2
0
def test_quantity_linspace(start, stop, num, expected):
    obtained = quantity_linspace(start, stop, num)
    assert obtained.unit == expected.unit
    assert obtained.value.all() == expected.value.all()

    with pytest.raises(ValueError):
        quantity_linspace(u.Quantity(0.5, 'eV'), '0.6 eV', 3)
Ejemplo n.º 3
0
def parse_spectrum_list2dict(spectrum_list):
    """
    Parse the spectrum list [start, stop, num] to a list
    """
    if 'start' in spectrum_list and 'stop' in spectrum_list \
            and 'num' in spectrum_list:
        spectrum_list = [
            spectrum_list['start'], spectrum_list['stop'], spectrum_list['num']
        ]
    if spectrum_list[0].unit.physical_type != 'length' and \
                    spectrum_list[1].unit.physical_type != 'length':
        raise ValueError('start and end of spectrum need to be a length')

    spectrum_config_dict = {}
    spectrum_config_dict['start'] = spectrum_list[0]
    spectrum_config_dict['end'] = spectrum_list[1]
    spectrum_config_dict['bins'] = spectrum_list[2]

    spectrum_frequency = quantity_linspace(
        spectrum_config_dict['end'].to('Hz', u.spectral()),
        spectrum_config_dict['start'].to('Hz', u.spectral()),
        num=spectrum_config_dict['bins'] + 1)

    spectrum_config_dict['frequency'] = spectrum_frequency

    return spectrum_config_dict
Ejemplo n.º 4
0
    def from_config(cls, config):
        """
        Create a new MontecarloRunner instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        MontecarloRunner

        """
        if config.plasma.disable_electron_scattering:
            logger.warn('Disabling electron scattering - this is not physical')
            sigma_thomson = 1e-200 / (u.cm ** 2)
        else:
            logger.debug("Electron scattering switched on")
            sigma_thomson = 6.652486e-25 / (u.cm ** 2)

        spectrum_frequency = quantity_linspace(
            config.spectrum.stop.to('Hz', u.spectral()),
            config.spectrum.start.to('Hz', u.spectral()),
            num=config.spectrum.num + 1)

        return cls(seed=config.montecarlo.seed,
                   spectrum_frequency=spectrum_frequency,
                   virtual_spectrum_range=config.montecarlo.virtual_spectrum_range,
                   sigma_thomson=sigma_thomson,
                   enable_reflective_inner_boundary=config.montecarlo.enable_reflective_inner_boundary,
                   inner_boundary_albedo=config.montecarlo.inner_boundary_albedo,
                   line_interaction_type=config.plasma.line_interaction_type,
                   distance=config.supernova.get('distance', None))
Ejemplo n.º 5
0
def parse_spectrum_list2dict(spectrum_list):
    """
    Parse the spectrum list [start, stop, num] to a list
    """
    if 'start' in spectrum_list and 'stop' in spectrum_list \
            and 'num' in spectrum_list:
        spectrum_list = [spectrum_list['start'], spectrum_list['stop'],
                         spectrum_list['num']]
    if spectrum_list[0].unit.physical_type != 'length' and \
                    spectrum_list[1].unit.physical_type != 'length':
        raise ValueError('start and end of spectrum need to be a length')


    spectrum_config_dict = {}
    spectrum_config_dict['start'] = spectrum_list[0]
    spectrum_config_dict['end'] = spectrum_list[1]
    spectrum_config_dict['bins'] = spectrum_list[2]

    spectrum_frequency = quantity_linspace(
        spectrum_config_dict['end'].to('Hz', u.spectral()),
        spectrum_config_dict['start'].to('Hz', u.spectral()),
        num=spectrum_config_dict['bins'] + 1)

    spectrum_config_dict['frequency'] = spectrum_frequency

    return spectrum_config_dict
Ejemplo n.º 6
0
    def from_config(cls, config):
        """
        Create a new MontecarloRunner instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        MontecarloRunner

        """
        if config.plasma.disable_electron_scattering:
            logger.warn('Disabling electron scattering - this is not physical')
            sigma_thomson = 1e-200 / (u.cm**2)
        else:
            logger.debug("Electron scattering switched on")
            sigma_thomson = 6.652486e-25 / (u.cm**2)

        spectrum_frequency = quantity_linspace(
            config.spectrum.stop.to('Hz', u.spectral()),
            config.spectrum.start.to('Hz', u.spectral()),
            num=config.spectrum.num + 1)

        return cls(
            seed=config.montecarlo.seed,
            spectrum_frequency=spectrum_frequency,
            virtual_spectrum_range=config.montecarlo.virtual_spectrum_range,
            sigma_thomson=sigma_thomson,
            enable_reflective_inner_boundary=config.montecarlo.
            enable_reflective_inner_boundary,
            inner_boundary_albedo=config.montecarlo.inner_boundary_albedo,
            line_interaction_type=config.plasma.line_interaction_type,
            distance=config.supernova.get('distance', None))
Ejemplo n.º 7
0
    def from_config(cls, config):
        """
        Create a new HomologousDensity instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        HomologousDensity

        """
        d_conf = config.model.structure.density
        velocity = quantity_linspace(config.model.structure.velocity.start,
                                     config.model.structure.velocity.stop,
                                     config.model.structure.velocity.num + 1).cgs

        adjusted_velocity = velocity.insert(0, 0)
        v_middle = (adjusted_velocity[1:] * 0.5 +
                    adjusted_velocity[:-1] * 0.5)
        no_of_shells = len(adjusted_velocity) - 1
        time_explosion = config.supernova.time_explosion.cgs

        if d_conf.type == 'branch85_w7':
            density_0 = calculate_power_law_density(v_middle, d_conf.w7_v_0,
                                                    d_conf.w7_rho_0, -7)
            time_0 = d_conf.w7_time_0
        elif d_conf.type == 'uniform':
            density_0 = (d_conf.value.to('g cm^-3') *
                         np.ones(no_of_shells))
            time_0 = d_conf.get('time_0', time_explosion)
        elif d_conf.type == 'power_law':
            density_0 = calculate_power_law_density(v_middle, d_conf.v_0,
                                                    d_conf.rho_0,
                                                    d_conf.exponent)
            time_0 = d_conf.get('time_0', time_explosion)
        elif d_conf.type == 'exponential':
            density_0 = calculate_exponential_density(v_middle, d_conf.v_0,
                                                      d_conf.rho_0)
            time_0 = d_conf.get('time_0', time_explosion)
        else:
            raise ValueError("Unrecognized density type "
                             "'{}'".format(d_conf.type))
        return cls(density_0, time_0)
Ejemplo n.º 8
0
    def from_config(cls, config):
        """
        Create a new HomologousDensity instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        HomologousDensity

        """
        d_conf = config.model.structure.density
        velocity = quantity_linspace(config.model.structure.velocity.start,
                                     config.model.structure.velocity.stop,
                                     config.model.structure.velocity.num +
                                     1).cgs

        adjusted_velocity = velocity.insert(0, 0)
        v_middle = (adjusted_velocity[1:] * 0.5 + adjusted_velocity[:-1] * 0.5)
        no_of_shells = len(adjusted_velocity) - 1
        time_explosion = config.supernova.time_explosion.cgs

        if d_conf.type == 'branch85_w7':
            density_0 = calculate_power_law_density(v_middle, d_conf.w7_v_0,
                                                    d_conf.w7_rho_0, -7)
            time_0 = d_conf.w7_time_0
        elif d_conf.type == 'uniform':
            density_0 = (d_conf.value.to('g cm^-3') * np.ones(no_of_shells))
            time_0 = d_conf.get('time_0', time_explosion)
        elif d_conf.type == 'power_law':
            density_0 = calculate_power_law_density(v_middle, d_conf.v_0,
                                                    d_conf.rho_0,
                                                    d_conf.exponent)
            time_0 = d_conf.get('time_0', time_explosion)
        elif d_conf.type == 'exponential':
            density_0 = calculate_exponential_density(v_middle, d_conf.v_0,
                                                      d_conf.rho_0)
            time_0 = d_conf.get('time_0', time_explosion)
        else:
            raise ValueError("Unrecognized density type "
                             "'{}'".format(d_conf.type))
        return cls(density_0, time_0)
Ejemplo n.º 9
0
    def from_config_dict(cls,
                         config_dict,
                         atom_data=None,
                         test_parser=False,
                         validate=True,
                         config_dirname=''):
        """
        Validating and subsequently parsing a config file.


        Parameters
        ----------

        config_dict : ~dict
            dictionary of a raw unvalidated config file

        atom_data: ~tardis.atomic.AtomData
            atom data object. if `None` will be tried to be read from
            atom data file path in the config_dict [default=None]

        test_parser: ~bool
            switch on to ignore a working atom_data, mainly useful for
            testing this reader

        validate: ~bool
            Turn validation on or off.


        Returns
        -------

        `tardis.config_reader.Configuration`

        """

        if validate:
            validated_config_dict = config_validator.validate_dict(config_dict)
        else:
            validated_config_dict = config_dict

        #First let's see if we can find an atom_db anywhere:
        if test_parser:
            atom_data = None
        elif 'atom_data' in validated_config_dict.keys():
            if os.path.isabs(validated_config_dict['atom_data']):
                atom_data_fname = validated_config_dict['atom_data']
            else:
                atom_data_fname = os.path.join(
                    config_dirname, validated_config_dict['atom_data'])
            validated_config_dict['atom_data_fname'] = atom_data_fname
        else:
            raise ConfigurationError(
                'No atom_data key found in config or command line')

        if atom_data is None and not test_parser:
            logger.info('Reading Atomic Data from %s', atom_data_fname)
            atom_data = atomic.AtomData.from_hdf5(atom_data_fname)
        else:
            atom_data = atom_data

        #Parsing supernova dictionary
        validated_config_dict['supernova']['luminosity_nu_start'] = \
            validated_config_dict['supernova']['luminosity_wavelength_end'].to(
                u.Hz, u.spectral())
        try:
            validated_config_dict['supernova']['luminosity_nu_end'] = \
                (validated_config_dict['supernova']
                 ['luminosity_wavelength_start'].to(u.Hz, u.spectral()))
        except ZeroDivisionError:
            validated_config_dict['supernova']['luminosity_nu_end'] = (np.inf *
                                                                       u.Hz)

        validated_config_dict['supernova']['time_explosion'] = (
            validated_config_dict['supernova']['time_explosion'].cgs)

        validated_config_dict['supernova']['luminosity_requested'] = (
            validated_config_dict['supernova']['luminosity_requested'].cgs)

        #Parsing the model section

        model_section = validated_config_dict['model']
        v_inner = None
        v_outer = None
        mean_densities = None
        abundances = None

        structure_section = model_section['structure']

        if structure_section['type'] == 'specific':
            velocity = model_section['structure']['velocity']
            start, stop, num = velocity['start'], velocity['stop'], \
                               velocity['num']
            num += 1
            velocities = quantity_linspace(start, stop, num)

            v_inner, v_outer = velocities[:-1], velocities[1:]
            mean_densities = parse_density_section(
                model_section['structure']['density'], v_inner, v_outer,
                validated_config_dict['supernova']['time_explosion']).cgs

        elif structure_section['type'] == 'file':
            if os.path.isabs(structure_section['filename']):
                structure_fname = structure_section['filename']
            else:
                structure_fname = os.path.join(config_dirname,
                                               structure_section['filename'])

            v_inner, v_outer, mean_densities, inner_boundary_index, \
            outer_boundary_index = read_density_file(
                structure_fname, structure_section['filetype'],
                validated_config_dict['supernova']['time_explosion'],
                structure_section['v_inner_boundary'],
                structure_section['v_outer_boundary'])

        r_inner = validated_config_dict['supernova']['time_explosion'] * v_inner
        r_outer = validated_config_dict['supernova']['time_explosion'] * v_outer
        r_middle = 0.5 * (r_inner + r_outer)

        structure_section['v_inner'] = v_inner.cgs
        structure_section['v_outer'] = v_outer.cgs
        structure_section['mean_densities'] = mean_densities.cgs
        no_of_shells = len(v_inner)
        structure_section['no_of_shells'] = no_of_shells
        structure_section['r_inner'] = r_inner.cgs
        structure_section['r_outer'] = r_outer.cgs
        structure_section['r_middle'] = r_middle.cgs
        structure_section['volumes'] = ((4. / 3) * np.pi * \
                                       (r_outer ** 3 -
                                        r_inner ** 3)).cgs

        #### TODO the following is legacy code and should be removed
        validated_config_dict['structure'] = \
            validated_config_dict['model']['structure']
        # ^^^^^^^^^^^^^^^^

        abundances_section = model_section['abundances']

        if abundances_section['type'] == 'uniform':
            abundances = pd.DataFrame(columns=np.arange(no_of_shells),
                                      index=pd.Index(np.arange(1, 120),
                                                     name='atomic_number'),
                                      dtype=np.float64)

            for element_symbol_string in abundances_section:
                if element_symbol_string == 'type': continue
                z = element_symbol2atomic_number(element_symbol_string)
                abundances.ix[z] = float(
                    abundances_section[element_symbol_string])

        elif abundances_section['type'] == 'file':
            if os.path.isabs(abundances_section['filename']):
                abundances_fname = abundances_section['filename']
            else:
                abundances_fname = os.path.join(config_dirname,
                                                abundances_section['filename'])

            index, abundances = read_abundances_file(
                abundances_fname, abundances_section['filetype'],
                inner_boundary_index, outer_boundary_index)
            if len(index) != no_of_shells:
                raise ConfigurationError(
                    'The abundance file specified has not the same number of cells'
                    'as the specified density profile')

        abundances = abundances.replace(np.nan, 0.0)

        abundances = abundances[abundances.sum(axis=1) > 0]

        norm_factor = abundances.sum(axis=0)

        if np.any(np.abs(norm_factor - 1) > 1e-12):
            logger.warning(
                "Abundances have not been normalized to 1. - normalizing")
            abundances /= norm_factor

        validated_config_dict['abundances'] = abundances

        ########### DOING PLASMA SECTION ###############
        plasma_section = validated_config_dict['plasma']

        if plasma_section['initial_t_inner'] < 0.0 * u.K:
            luminosity_requested = validated_config_dict['supernova'][
                'luminosity_requested']
            plasma_section['t_inner'] = ((
                luminosity_requested /
                (4 * np.pi * r_inner[0]**2 * constants.sigma_sb))**.25).to('K')
            logger.info(
                '"initial_t_inner" is not specified in the plasma '
                'section - initializing to %s with given luminosity',
                plasma_section['t_inner'])
        else:
            plasma_section['t_inner'] = plasma_section['initial_t_inner']

        if plasma_section['initial_t_rad'] > 0 * u.K:
            plasma_section['t_rads'] = np.ones(no_of_shells) * \
                                       plasma_section['initial_t_rad']
        else:
            plasma_section['t_rads'] = None

        if plasma_section['disable_electron_scattering'] is False:
            logger.debug("Electron scattering switched on")
            validated_config_dict['montecarlo'][
                'sigma_thomson'] = 6.652486e-25 / (u.cm**2)
        else:
            logger.warn('Disabling electron scattering - this is not physical')
            validated_config_dict['montecarlo']['sigma_thomson'] = 1e-200 / (
                u.cm**2)

        if plasma_section['helium_treatment'] == 'recomb-nlte':
            validated_config_dict['plasma'][
                'helium_treatment'] == 'recomb-nlte'
        else:
            validated_config_dict['plasma']['helium_treatment'] == 'dilute-lte'

        ##### NLTE subsection of Plasma start
        nlte_validated_config_dict = {}
        nlte_species = []
        nlte_section = plasma_section['nlte']

        nlte_species_list = nlte_section.pop('species')
        for species_string in nlte_species_list:
            nlte_species.append(species_string_to_tuple(species_string))

        nlte_validated_config_dict['species'] = nlte_species
        nlte_validated_config_dict['species_string'] = nlte_species_list
        nlte_validated_config_dict.update(nlte_section)

        if 'coronal_approximation' not in nlte_section:
            logger.debug(
                'NLTE "coronal_approximation" not specified in NLTE section - defaulting to False'
            )
            nlte_validated_config_dict['coronal_approximation'] = False

        if 'classical_nebular' not in nlte_section:
            logger.debug(
                'NLTE "classical_nebular" not specified in NLTE section - defaulting to False'
            )
            nlte_validated_config_dict['classical_nebular'] = False

        elif nlte_section:  #checks that the dictionary is not empty
            logger.warn(
                'No "species" given - ignoring other NLTE options given:\n%s',
                pp.pformat(nlte_section))

        if not nlte_validated_config_dict:
            nlte_validated_config_dict['species'] = []

        plasma_section['nlte'] = nlte_validated_config_dict

        #^^^^^^^^^^^^^^ End of Plasma Section

        ##### Monte Carlo Section

        montecarlo_section = validated_config_dict['montecarlo']
        montecarlo_section['no_of_packets'] = \
            int(montecarlo_section['no_of_packets'])
        montecarlo_section['last_no_of_packets'] = \
            int(montecarlo_section['last_no_of_packets'])
        if montecarlo_section['last_no_of_packets'] < 0:
            montecarlo_section['last_no_of_packets'] = \
                montecarlo_section['no_of_packets']

        montecarlo_section['convergence_strategy'] = (
            parse_convergence_section(
                montecarlo_section['convergence_strategy']))

        black_body_section = montecarlo_section['black_body_sampling']
        montecarlo_section['black_body_sampling'] = {}
        montecarlo_section['black_body_sampling']['start'] = \
            black_body_section['start']
        montecarlo_section['black_body_sampling']['end'] = \
            black_body_section['stop']
        montecarlo_section['black_body_sampling']['samples'] = \
            black_body_section['num']
        virtual_spectrum_section = montecarlo_section['virtual_spectrum_range']
        montecarlo_section['virtual_spectrum_range'] = {}
        montecarlo_section['virtual_spectrum_range']['start'] = \
            virtual_spectrum_section['start']
        montecarlo_section['virtual_spectrum_range']['end'] = \
            virtual_spectrum_section['stop']
        montecarlo_section['virtual_spectrum_range']['samples'] = \
            virtual_spectrum_section['num']

        ###### END of convergence section reading

        validated_config_dict['spectrum'] = parse_spectrum_list2dict(
            validated_config_dict['spectrum'])

        return cls(validated_config_dict, atom_data)
Ejemplo n.º 10
0
    def parse_artis_model_setup_files(model_file_section_dict, time_explosion):

        ###### Reading the structure part of the ARTIS file pair
        structure_fname = model_file_section_dict['structure_fname']

        for i, line in enumerate(file(structure_fname)):
            if i == 0:
                no_of_shells = np.int64(line.strip())
            elif i == 1:
                time_of_model = u.Quantity(float(line.strip()), 'day').to('s')
            elif i == 2:
                break

        artis_model_columns = [
            'velocities', 'mean_densities_0', 'ni56_fraction', 'co56_fraction',
            'fe52_fraction', 'cr48_fraction'
        ]
        artis_model = np.recfromtxt(structure_fname,
                                    skip_header=2,
                                    usecols=(1, 2, 4, 5, 6, 7),
                                    unpack=True,
                                    dtype=[(item, np.float64)
                                           for item in artis_model_columns])
        #converting densities from log(g/cm^3) to g/cm^3 and stretching it to the current ti
        velocities = u.Quantity(np.append([0], artis_model['velocities']),
                                'km/s').to('cm/s')
        mean_densities_0 = u.Quantity(10**artis_model['mean_densities_0'],
                                      'g/cm^3')

        mean_densities = calculate_density_after_time(mean_densities_0,
                                                      time_of_model,
                                                      time_explosion)

        #Verifying information
        if len(mean_densities) == no_of_shells:
            logger.debug(
                'Verified ARTIS model structure file %s (no_of_shells=length of dataset)',
                structure_fname)
        else:
            raise ConfigurationError(
                'Error in ARTIS file %s - Number of shells not the same as dataset length'
                % structure_fname)

        v_inner = velocities[:-1]
        v_outer = velocities[1:]

        volumes = (4 * np.pi / 3) * (time_of_model**
                                     3) * (v_outer**3 - v_inner**3)
        masses = (volumes * mean_densities_0 / constants.M_sun).to(1)

        logger.info(
            'Read ARTIS configuration file %s - found %d zones with total mass %g Msun',
            structure_fname, no_of_shells, sum(masses.value))

        if 'v_lowest' in model_file_section_dict:
            v_lowest = parse_quantity(
                model_file_section_dict['v_lowest']).to('cm/s').value
            min_shell = v_inner.value.searchsorted(v_lowest)
        else:
            min_shell = 1

        if 'v_highest' in model_file_section_dict:
            v_highest = parse_quantity(
                model_file_section_dict['v_highest']).to('cm/s').value
            max_shell = v_outer.value.searchsorted(v_highest)
        else:
            max_shell = no_of_shells
        artis_model = artis_model[min_shell:max_shell]
        v_inner = v_inner[min_shell:max_shell]
        v_outer = v_outer[min_shell:max_shell]
        mean_densities = mean_densities[min_shell:max_shell]

        ###### Reading the abundance part of the ARTIS file pair
        abundances_fname = model_file_section_dict['abundances_fname']
        abundances = pd.DataFrame(
            np.loadtxt(abundances_fname)[min_shell:max_shell, 1:].transpose(),
            index=np.arange(1, 31))

        ni_stable = abundances.ix[28] - artis_model['ni56_fraction']
        co_stable = abundances.ix[27] - artis_model['co56_fraction']
        fe_stable = abundances.ix[26] - artis_model['fe52_fraction']
        mn_stable = abundances.ix[25] - 0.0
        cr_stable = abundances.ix[24] - artis_model['cr48_fraction']
        v_stable = abundances.ix[23] - 0.0
        ti_stable = abundances.ix[22] - 0.0

        abundances.ix[28] = ni_stable
        abundances.ix[28] += artis_model['ni56_fraction'] * np.exp(
            -(time_explosion * inv_ni56_efolding_time).to(1).value)

        abundances.ix[27] = co_stable
        abundances.ix[27] += artis_model['co56_fraction'] * np.exp(
            -(time_explosion * inv_co56_efolding_time).to(1).value)
        abundances.ix[27] += (inv_ni56_efolding_time * artis_model['ni56_fraction'] /
                              (inv_ni56_efolding_time - inv_co56_efolding_time)) * \
                             (np.exp(-(inv_co56_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_ni56_efolding_time * time_explosion).to(1).value))

        abundances.ix[26] = fe_stable
        abundances.ix[26] += artis_model['fe52_fraction'] * np.exp(
            -(time_explosion * inv_fe52_efolding_time).to(1).value)
        abundances.ix[26] += (
            (artis_model['co56_fraction'] * inv_ni56_efolding_time -
             artis_model['co56_fraction'] * inv_co56_efolding_time +
             artis_model['ni56_fraction'] * inv_ni56_efolding_time -
             artis_model['ni56_fraction'] * inv_co56_efolding_time -
             artis_model['co56_fraction'] * inv_ni56_efolding_time *
             np.exp(-(inv_co56_efolding_time * time_explosion).to(1).value) +
             artis_model['co56_fraction'] * inv_co56_efolding_time *
             np.exp(-(inv_co56_efolding_time * time_explosion).to(1).value) -
             artis_model['ni56_fraction'] * inv_ni56_efolding_time *
             np.exp(-(inv_co56_efolding_time * time_explosion).to(1).value) +
             artis_model['ni56_fraction'] * inv_co56_efolding_time *
             np.exp(-(inv_ni56_efolding_time * time_explosion).to(1).value)) /
            (inv_ni56_efolding_time - inv_co56_efolding_time))

        abundances.ix[25] = mn_stable
        abundances.ix[25] += (inv_fe52_efolding_time * artis_model['fe52_fraction'] /
                              (inv_fe52_efolding_time - inv_mn52_efolding_time)) * \
                             (np.exp(-(inv_mn52_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_fe52_efolding_time * time_explosion).to(1).value))

        abundances.ix[24] = cr_stable
        abundances.ix[24] += artis_model['cr48_fraction'] * np.exp(
            -(time_explosion * inv_cr48_efolding_time).to(1).value)
        abundances.ix[24] += (
            (artis_model['fe52_fraction'] * inv_fe52_efolding_time -
             artis_model['fe52_fraction'] * inv_mn52_efolding_time -
             artis_model['fe52_fraction'] * inv_fe52_efolding_time *
             np.exp(-(inv_mn52_efolding_time * time_explosion).to(1).value) +
             artis_model['fe52_fraction'] * inv_mn52_efolding_time *
             np.exp(-(inv_fe52_efolding_time * time_explosion).to(1).value)) /
            (inv_fe52_efolding_time - inv_mn52_efolding_time))

        abundances.ix[23] = v_stable
        abundances.ix[23] += (inv_cr48_efolding_time * artis_model['cr48_fraction'] /
                              (inv_cr48_efolding_time - inv_v48_efolding_time)) * \
                             (np.exp(-(inv_v48_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_cr48_efolding_time * time_explosion).to(1).value))

        abundances.ix[22] = ti_stable
        abundances.ix[22] += (
            (artis_model['cr48_fraction'] * inv_cr48_efolding_time -
             artis_model['cr48_fraction'] * inv_v48_efolding_time -
             artis_model['cr48_fraction'] * inv_cr48_efolding_time *
             np.exp(-(inv_v48_efolding_time * time_explosion).to(1).value) +
             artis_model['cr48_fraction'] * inv_v48_efolding_time *
             np.exp(-(inv_cr48_efolding_time * time_explosion).to(1).value)) /
            (inv_cr48_efolding_time - inv_v48_efolding_time))

        if 'split_shells' in model_file_section_dict:
            split_shells = int(model_file_section_dict['split_shells'])
        else:
            split_shells = 1

        if split_shells > 1:
            logger.info('Increasing the number of shells by a factor of %s' %
                        split_shells)
            no_of_shells = len(v_inner)
            velocities = quantity_linspace(v_inner[0], v_outer[-1],
                                           no_of_shells * split_shells + 1)
            v_inner = velocities[:-1]
            v_outer = velocities[1:]
            old_mean_densities = mean_densities
            mean_densities = np.empty(
                no_of_shells * split_shells) * old_mean_densities.unit
            new_abundance_data = np.empty(
                (abundances.values.shape[0], no_of_shells * split_shells))
            for i in xrange(split_shells):
                mean_densities[i::split_shells] = old_mean_densities
                new_abundance_data[:, i::split_shells] = abundances.values

            abundances = pd.DataFrame(new_abundance_data,
                                      index=abundances.index)

            #def parser_simple_ascii_model

        return v_inner, v_outer, mean_densities, abundances
Ejemplo n.º 11
0
    def from_config(cls, config):
        """
        Create a new Radial1DModel instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        Radial1DModel

        """
        time_explosion = config.supernova.time_explosion.cgs

        structure = config.model.structure
        if structure.type == 'specific':
            velocity = quantity_linspace(structure.velocity.start,
                                         structure.velocity.stop,
                                         structure.velocity.num + 1).cgs
            homologous_density = HomologousDensity.from_config(config)
        elif structure.type == 'file':
            if os.path.isabs(structure.filename):
                structure_fname = structure.filename
            else:
                structure_fname = os.path.join(config.config_dirname,
                                               structure.filename)

            time_0, velocity, density_0 = read_density_file(
                structure_fname, structure.filetype)
            density_0 = density_0.insert(0, 0)
            homologous_density = HomologousDensity(density_0, time_0)
        else:
            raise NotImplementedError
        # Note: This is the number of shells *without* taking in mind the
        #       v boundaries.
        no_of_shells = len(velocity) - 1

        if config.plasma.initial_t_rad > 0 * u.K:
            t_radiative = np.ones(no_of_shells) * config.plasma.initial_t_rad
        else:
            t_radiative = None

        if config.plasma.initial_t_inner < 0.0 * u.K:
            luminosity_requested = config.supernova.luminosity_requested
            t_inner = None
        else:
            luminosity_requested = None
            t_inner = config.plasma.initial_t_inner

        abundances_section = config.model.abundances
        if abundances_section.type == 'uniform':
            abundance = pd.DataFrame(columns=np.arange(no_of_shells),
                                     index=pd.Index(np.arange(1, 120),
                                                    name='atomic_number'),
                                     dtype=np.float64)

            for element_symbol_string in abundances_section:
                if element_symbol_string == 'type':
                    continue
                z = element_symbol2atomic_number(element_symbol_string)
                abundance.ix[z] = float(
                    abundances_section[element_symbol_string])

        elif abundances_section.type == 'file':
            if os.path.isabs(abundances_section.filename):
                abundances_fname = abundances_section.filename
            else:
                abundances_fname = os.path.join(config.config_dirname,
                                                abundances_section.filename)

            index, abundance = read_abundances_file(
                abundances_fname, abundances_section.filetype)

        abundance = abundance.replace(np.nan, 0.0)
        abundance = abundance[abundance.sum(axis=1) > 0]

        norm_factor = abundance.sum(axis=0)

        if np.any(np.abs(norm_factor - 1) > 1e-12):
            logger.warning("Abundances have not been normalized to 1."
                           " - normalizing")
            abundance /= norm_factor

        return cls(velocity=velocity,
                   homologous_density=homologous_density,
                   abundance=abundance,
                   time_explosion=time_explosion,
                   t_radiative=t_radiative,
                   t_inner=t_inner,
                   luminosity_requested=luminosity_requested,
                   dilution_factor=None,
                   v_boundary_inner=structure.get('v_inner_boundary', None),
                   v_boundary_outer=structure.get('v_outer_boundary', None))
Ejemplo n.º 12
0
    def from_config_dict(cls, config_dict, atom_data=None, test_parser=False,
                         config_definition_file=None, validate=True):
        """
        Validating and subsequently parsing a config file.


        Parameters
        ----------

        config_dict : ~dict
            dictionary of a raw unvalidated config file

        atom_data: ~tardis.atomic.AtomData
            atom data object. if `None` will be tried to be read from
            atom data file path in the config_dict [default=None]

        test_parser: ~bool
            switch on to ignore a working atom_data, mainly useful for
            testing this reader

        config_definition_file: ~str
            path to config definition file, if `None` will be set to the default
            in the `data` directory that ships with TARDIS

        validate: ~bool
            Turn validation on or off. 


        Returns
        -------

        `tardis.config_reader.Configuration`

        """

        if config_definition_file is None:
            config_definition_file = default_config_definition_file

        config_definition = yaml.load(open(config_definition_file))
        if validate:
            validated_config_dict = ConfigurationValidator(config_definition,
                                       config_dict).get_config()
        else:
            validated_config_dict = config_dict

        #First let's see if we can find an atom_db anywhere:
        if test_parser:
            atom_data = None
        elif 'atom_data' in validated_config_dict.keys():
            atom_data_fname = validated_config_dict['atom_data']
            validated_config_dict['atom_data_fname'] = atom_data_fname
        else:
            raise ConfigurationError('No atom_data key found in config or command line')

        if atom_data is None and not test_parser:
            logger.info('Reading Atomic Data from %s', atom_data_fname)
            atom_data = atomic.AtomData.from_hdf5(atom_data_fname)
        else:
            atom_data = atom_data



        #Parsing supernova dictionary
        validated_config_dict['supernova']['luminosity_nu_start'] = \
            validated_config_dict['supernova']['luminosity_wavelength_end'].to(
                u.Hz, u.spectral())
        try:
            validated_config_dict['supernova']['luminosity_nu_end'] = \
                (validated_config_dict['supernova']
                 ['luminosity_wavelength_start'].to(u.Hz, u.spectral()))
        except ZeroDivisionError:
            validated_config_dict['supernova']['luminosity_nu_end'] = (
                np.inf * u.Hz)

        validated_config_dict['supernova']['time_explosion'] = (
            validated_config_dict['supernova']['time_explosion'].cgs)

        validated_config_dict['supernova']['luminosity_requested'] = (
            validated_config_dict['supernova']['luminosity_requested'].cgs)

        #Parsing the model section

        model_section = validated_config_dict['model']
        v_inner = None
        v_outer = None
        mean_densities = None
        abundances = None



        structure_section = model_section['structure']

        if structure_section['type'] == 'specific':
            start, stop, num = model_section['structure']['velocity']
            num += 1
            velocities = quantity_linspace(start, stop, num)

            v_inner, v_outer = velocities[:-1], velocities[1:]
            mean_densities = parse_density_section(
                model_section['structure']['density'], v_inner, v_outer,
                validated_config_dict['supernova']['time_explosion']).cgs

        elif structure_section['type'] == 'file':
            v_inner, v_outer, mean_densities, inner_boundary_index, \
            outer_boundary_index = read_density_file(
                structure_section['filename'], structure_section['filetype'],
                validated_config_dict['supernova']['time_explosion'],
                structure_section['v_inner_boundary'],
                structure_section['v_outer_boundary'])

        r_inner = validated_config_dict['supernova']['time_explosion'] * v_inner
        r_outer = validated_config_dict['supernova']['time_explosion'] * v_outer
        r_middle = 0.5 * (r_inner + r_outer)

        structure_section['v_inner'] = v_inner.cgs
        structure_section['v_outer'] = v_outer.cgs
        structure_section['mean_densities'] = mean_densities.cgs
        no_of_shells = len(v_inner)
        structure_section['no_of_shells'] = no_of_shells
        structure_section['r_inner'] = r_inner.cgs
        structure_section['r_outer'] = r_outer.cgs
        structure_section['r_middle'] = r_middle.cgs
        structure_section['volumes'] = ((4. / 3) * np.pi * \
                                       (r_outer ** 3 -
                                        r_inner ** 3)).cgs


        #### TODO the following is legacy code and should be removed
        validated_config_dict['structure'] = \
            validated_config_dict['model']['structure']
        # ^^^^^^^^^^^^^^^^


        abundances_section = model_section['abundances']

        if abundances_section['type'] == 'uniform':
            abundances = pd.DataFrame(columns=np.arange(no_of_shells),
                                      index=pd.Index(np.arange(1, 120), name='atomic_number'), dtype=np.float64)

            for element_symbol_string in abundances_section:
                if element_symbol_string == 'type': continue
                z = element_symbol2atomic_number(element_symbol_string)
                abundances.ix[z] = float(abundances_section[element_symbol_string])

        elif abundances_section['type'] == 'file':
            index, abundances = read_abundances_file(abundances_section['filename'], abundances_section['filetype'],
                                                     inner_boundary_index, outer_boundary_index)
            if len(index) != no_of_shells:
                raise ConfigurationError('The abundance file specified has not the same number of cells'
                                         'as the specified density profile')

        abundances = abundances.replace(np.nan, 0.0)

        abundances = abundances[abundances.sum(axis=1) > 0]

        norm_factor = abundances.sum(axis=0)

        if np.any(np.abs(norm_factor - 1) > 1e-12):
            logger.warning("Abundances have not been normalized to 1. - normalizing")
            abundances /= norm_factor

        validated_config_dict['abundances'] = abundances



        ########### DOING PLASMA SECTION ###############
        plasma_section = validated_config_dict['plasma']

        if plasma_section['initial_t_inner'] < 0.0 * u.K:
            luminosity_requested = validated_config_dict['supernova']['luminosity_requested']
            plasma_section['t_inner'] = ((luminosity_requested /
                                          (4 * np.pi * r_inner[0] ** 2 *
                                           constants.sigma_sb)) ** .25).to('K')
            logger.info('"initial_t_inner" is not specified in the plasma '
                        'section - initializing to %s with given luminosity',
                        plasma_section['t_inner'])
        else:
            plasma_section['t_inner'] = plasma_section['initial_t_inner']

        if plasma_section['initial_t_rad'] > 0 * u.K:
            plasma_section['t_rads'] = np.ones(no_of_shells) * \
                                       plasma_section['initial_t_rad']
        else:
            plasma_section['t_rads'] = None

        if plasma_section['disable_electron_scattering'] is False:
            logger.debug("Electron scattering switched on")
            validated_config_dict['montecarlo']['sigma_thomson'] = 6.652486e-25 / (u.cm ** 2)
        else:
            logger.warn('Disabling electron scattering - this is not physical')
            validated_config_dict['montecarlo']['sigma_thomson'] = 1e-200 / (u.cm ** 2)

        if plasma_section['helium_treatment'] == 'recomb-nlte':
            validated_config_dict['plasma']['helium_treatment'] == 'recomb-nlte'
        else:
            validated_config_dict['plasma']['helium_treatment'] == 'dilute-lte'





        ##### NLTE subsection of Plasma start
        nlte_validated_config_dict = {}
        nlte_species = []
        nlte_section = plasma_section['nlte']

        nlte_species_list = nlte_section.pop('species')
        for species_string in nlte_species_list:
            nlte_species.append(species_string_to_tuple(species_string))

        nlte_validated_config_dict['species'] = nlte_species
        nlte_validated_config_dict['species_string'] = nlte_species_list
        nlte_validated_config_dict.update(nlte_section)

        if 'coronal_approximation' not in nlte_section:
            logger.debug('NLTE "coronal_approximation" not specified in NLTE section - defaulting to False')
            nlte_validated_config_dict['coronal_approximation'] = False

        if 'classical_nebular' not in nlte_section:
            logger.debug('NLTE "classical_nebular" not specified in NLTE section - defaulting to False')
            nlte_validated_config_dict['classical_nebular'] = False


        elif nlte_section:  #checks that the dictionary is not empty
            logger.warn('No "species" given - ignoring other NLTE options given:\n%s',
                        pp.pformat(nlte_section))

        if not nlte_validated_config_dict:
            nlte_validated_config_dict['species'] = []

        plasma_section['nlte'] = nlte_validated_config_dict

        #^^^^^^^^^^^^^^ End of Plasma Section

        ##### Monte Carlo Section

        montecarlo_section = validated_config_dict['montecarlo']
        if montecarlo_section['last_no_of_packets'] < 0:
            montecarlo_section['last_no_of_packets'] = \
                montecarlo_section['no_of_packets']

        default_convergence_section = {'type': 'damped',
                                      'lock_t_inner_cycles': 1,
                                      't_inner_update_exponent': -0.5,
                                      'damping_constant': 0.5}



        if montecarlo_section['convergence_strategy'] is None:
            logger.warning('No convergence criteria selected - '
                           'just damping by 0.5 for w, t_rad and t_inner')
            montecarlo_section['convergence_strategy'] = (
                parse_convergence_section(default_convergence_section))
        else:
            montecarlo_section['convergence_strategy'] = (
                parse_convergence_section(
                    montecarlo_section['convergence_strategy']))

        black_body_section = montecarlo_section['black_body_sampling']
        montecarlo_section['black_body_sampling'] = {}
        montecarlo_section['black_body_sampling']['start'] = \
            black_body_section[0]
        montecarlo_section['black_body_sampling']['end'] = \
            black_body_section[1]
        montecarlo_section['black_body_sampling']['samples'] = \
            black_body_section[2]
        virtual_spectrum_section = montecarlo_section['virtual_spectrum_range']
        montecarlo_section['virtual_spectrum_range'] = {}
        montecarlo_section['virtual_spectrum_range']['start'] = \
            virtual_spectrum_section[0]
        montecarlo_section['virtual_spectrum_range']['end'] = \
            virtual_spectrum_section[1]
        montecarlo_section['virtual_spectrum_range']['samples'] = \
            virtual_spectrum_section[2]

        ###### END of convergence section reading


        validated_config_dict['spectrum'] = parse_spectrum_list2dict(
            validated_config_dict['spectrum'])

        return cls(validated_config_dict, atom_data)
Ejemplo n.º 13
0
    def parse_artis_model_setup_files(model_file_section_dict, time_explosion):

        ###### Reading the structure part of the ARTIS file pair
        structure_fname = model_file_section_dict['structure_fname']

        for i, line in enumerate(file(structure_fname)):
            if i == 0:
                no_of_shells = np.int64(line.strip())
            elif i == 1:
                time_of_model = u.Quantity(float(line.strip()), 'day').to('s')
            elif i == 2:
                break

        artis_model_columns = ['velocities', 'mean_densities_0', 'ni56_fraction', 'co56_fraction', 'fe52_fraction',
                               'cr48_fraction']
        artis_model = np.recfromtxt(structure_fname, skip_header=2, usecols=(1, 2, 4, 5, 6, 7), unpack=True,
                                    dtype=[(item, np.float64) for item in artis_model_columns])
        #converting densities from log(g/cm^3) to g/cm^3 and stretching it to the current ti
        velocities = u.Quantity(np.append([0], artis_model['velocities']), 'km/s').to('cm/s')
        mean_densities_0 = u.Quantity(10 ** artis_model['mean_densities_0'], 'g/cm^3')

        mean_densities = calculate_density_after_time(mean_densities_0, time_of_model, time_explosion)


        #Verifying information
        if len(mean_densities) == no_of_shells:
            logger.debug('Verified ARTIS model structure file %s (no_of_shells=length of dataset)', structure_fname)
        else:
            raise ConfigurationError(
                'Error in ARTIS file %s - Number of shells not the same as dataset length' % structure_fname)

        v_inner = velocities[:-1]
        v_outer = velocities[1:]

        volumes = (4 * np.pi / 3) * (time_of_model ** 3) * ( v_outer ** 3 - v_inner ** 3)
        masses = (volumes * mean_densities_0 / constants.M_sun).to(1)

        logger.info('Read ARTIS configuration file %s - found %d zones with total mass %g Msun', structure_fname,
                    no_of_shells, sum(masses.value))

        if 'v_lowest' in model_file_section_dict:
            v_lowest = parse_quantity(model_file_section_dict['v_lowest']).to('cm/s').value
            min_shell = v_inner.value.searchsorted(v_lowest)
        else:
            min_shell = 1

        if 'v_highest' in model_file_section_dict:
            v_highest = parse_quantity(model_file_section_dict['v_highest']).to('cm/s').value
            max_shell = v_outer.value.searchsorted(v_highest)
        else:
            max_shell = no_of_shells
        artis_model = artis_model[min_shell:max_shell]
        v_inner = v_inner[min_shell:max_shell]
        v_outer = v_outer[min_shell:max_shell]
        mean_densities = mean_densities[min_shell:max_shell]

        ###### Reading the abundance part of the ARTIS file pair
        abundances_fname = model_file_section_dict['abundances_fname']
        abundances = pd.DataFrame(np.loadtxt(abundances_fname)[min_shell:max_shell, 1:].transpose(),
                                  index=np.arange(1, 31))

        ni_stable = abundances.ix[28] - artis_model['ni56_fraction']
        co_stable = abundances.ix[27] - artis_model['co56_fraction']
        fe_stable = abundances.ix[26] - artis_model['fe52_fraction']
        mn_stable = abundances.ix[25] - 0.0
        cr_stable = abundances.ix[24] - artis_model['cr48_fraction']
        v_stable = abundances.ix[23] - 0.0
        ti_stable = abundances.ix[22] - 0.0

        abundances.ix[28] = ni_stable
        abundances.ix[28] += artis_model['ni56_fraction'] * np.exp(
            -(time_explosion * inv_ni56_efolding_time).to(1).value)

        abundances.ix[27] = co_stable
        abundances.ix[27] += artis_model['co56_fraction'] * np.exp(
            -(time_explosion * inv_co56_efolding_time).to(1).value)
        abundances.ix[27] += (inv_ni56_efolding_time * artis_model['ni56_fraction'] /
                              (inv_ni56_efolding_time - inv_co56_efolding_time)) * \
                             (np.exp(-(inv_co56_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_ni56_efolding_time * time_explosion).to(1).value))

        abundances.ix[26] = fe_stable
        abundances.ix[26] += artis_model['fe52_fraction'] * np.exp(
            -(time_explosion * inv_fe52_efolding_time).to(1).value)
        abundances.ix[26] += ((artis_model['co56_fraction'] * inv_ni56_efolding_time
                               - artis_model['co56_fraction'] * inv_co56_efolding_time
                               + artis_model['ni56_fraction'] * inv_ni56_efolding_time
                               - artis_model['ni56_fraction'] * inv_co56_efolding_time
                               - artis_model['co56_fraction'] * inv_ni56_efolding_time * np.exp(
            -(inv_co56_efolding_time * time_explosion).to(1).value)
                               + artis_model['co56_fraction'] * inv_co56_efolding_time * np.exp(
            -(inv_co56_efolding_time * time_explosion).to(1).value)
                               - artis_model['ni56_fraction'] * inv_ni56_efolding_time * np.exp(
            -(inv_co56_efolding_time * time_explosion).to(1).value)
                               + artis_model['ni56_fraction'] * inv_co56_efolding_time * np.exp(
            -(inv_ni56_efolding_time * time_explosion).to(1).value))
                              / (inv_ni56_efolding_time - inv_co56_efolding_time))

        abundances.ix[25] = mn_stable
        abundances.ix[25] += (inv_fe52_efolding_time * artis_model['fe52_fraction'] /
                              (inv_fe52_efolding_time - inv_mn52_efolding_time)) * \
                             (np.exp(-(inv_mn52_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_fe52_efolding_time * time_explosion).to(1).value))

        abundances.ix[24] = cr_stable
        abundances.ix[24] += artis_model['cr48_fraction'] * np.exp(
            -(time_explosion * inv_cr48_efolding_time).to(1).value)
        abundances.ix[24] += ((artis_model['fe52_fraction'] * inv_fe52_efolding_time
                               - artis_model['fe52_fraction'] * inv_mn52_efolding_time
                               - artis_model['fe52_fraction'] * inv_fe52_efolding_time * np.exp(
            -(inv_mn52_efolding_time * time_explosion).to(1).value)
                               + artis_model['fe52_fraction'] * inv_mn52_efolding_time * np.exp(
            -(inv_fe52_efolding_time * time_explosion).to(1).value))
                              / (inv_fe52_efolding_time - inv_mn52_efolding_time))

        abundances.ix[23] = v_stable
        abundances.ix[23] += (inv_cr48_efolding_time * artis_model['cr48_fraction'] /
                              (inv_cr48_efolding_time - inv_v48_efolding_time)) * \
                             (np.exp(-(inv_v48_efolding_time * time_explosion).to(1).value) - np.exp(
                                 -(inv_cr48_efolding_time * time_explosion).to(1).value))

        abundances.ix[22] = ti_stable
        abundances.ix[22] += ((artis_model['cr48_fraction'] * inv_cr48_efolding_time
                               - artis_model['cr48_fraction'] * inv_v48_efolding_time
                               - artis_model['cr48_fraction'] * inv_cr48_efolding_time * np.exp(
            -(inv_v48_efolding_time * time_explosion).to(1).value)
                               + artis_model['cr48_fraction'] * inv_v48_efolding_time * np.exp(
            -(inv_cr48_efolding_time * time_explosion).to(1).value))
                              / (inv_cr48_efolding_time - inv_v48_efolding_time))

        if 'split_shells' in model_file_section_dict:
            split_shells = int(model_file_section_dict['split_shells'])
        else:
            split_shells = 1

        if split_shells > 1:
            logger.info('Increasing the number of shells by a factor of %s' % split_shells)
            no_of_shells = len(v_inner)
            velocities = quantity_linspace(
                v_inner[0], v_outer[-1], no_of_shells * split_shells + 1)
            v_inner = velocities[:-1]
            v_outer = velocities[1:]
            old_mean_densities = mean_densities
            mean_densities = np.empty(no_of_shells * split_shells) * old_mean_densities.unit
            new_abundance_data = np.empty((abundances.values.shape[0], no_of_shells * split_shells))
            for i in xrange(split_shells):
                mean_densities[i::split_shells] = old_mean_densities
                new_abundance_data[:, i::split_shells] = abundances.values

            abundances = pd.DataFrame(new_abundance_data, index=abundances.index)




            #def parser_simple_ascii_model

        return v_inner, v_outer, mean_densities, abundances
Ejemplo n.º 14
0
    def from_config(cls, config):
        """
        Create a new Radial1DModel instance from a Configuration object.

        Parameters
        ----------
        config : tardis.io.config_reader.Configuration

        Returns
        -------
        Radial1DModel

        """
        time_explosion = config.supernova.time_explosion.cgs

        structure = config.model.structure
        if structure.type == 'specific':
            velocity = quantity_linspace(structure.velocity.start,
                                         structure.velocity.stop,
                                         structure.velocity.num + 1).cgs
            homologous_density = HomologousDensity.from_config(config)
        elif structure.type == 'file':
            if os.path.isabs(structure.filename):
                structure_fname = structure.filename
            else:
                structure_fname = os.path.join(config.config_dirname,
                                               structure.filename)

            time_0, velocity, density_0 = read_density_file(
                structure_fname, structure.filetype)
            density_0 = density_0.insert(0, 0)
            homologous_density = HomologousDensity(density_0, time_0)
        else:
            raise NotImplementedError
        # Note: This is the number of shells *without* taking in mind the
        #       v boundaries.
        no_of_shells = len(velocity) - 1

        if config.plasma.initial_t_rad > 0 * u.K:
            t_radiative = np.ones(no_of_shells) * config.plasma.initial_t_rad
        else:
            t_radiative = None

        if config.plasma.initial_t_inner < 0.0 * u.K:
            luminosity_requested = config.supernova.luminosity_requested
            t_inner = None
        else:
            luminosity_requested = None
            t_inner = config.plasma.initial_t_inner

        abundances_section = config.model.abundances
        if abundances_section.type == 'uniform':
            abundance = pd.DataFrame(columns=np.arange(no_of_shells),
                                     index=pd.Index(np.arange(1, 120),
                                                    name='atomic_number'),
                                     dtype=np.float64)

            for element_symbol_string in abundances_section:
                if element_symbol_string == 'type':
                    continue
                z = element_symbol2atomic_number(element_symbol_string)
                abundance.ix[z] = float(abundances_section[element_symbol_string])

        elif abundances_section.type == 'file':
            if os.path.isabs(abundances_section.filename):
                abundances_fname = abundances_section.filename
            else:
                abundances_fname = os.path.join(config.config_dirname,
                                                abundances_section.filename)

            index, abundance = read_abundances_file(abundances_fname,
                                                    abundances_section.filetype)

        abundance = abundance.replace(np.nan, 0.0)
        abundance = abundance[abundance.sum(axis=1) > 0]

        norm_factor = abundance.sum(axis=0)

        if np.any(np.abs(norm_factor - 1) > 1e-12):
            logger.warning("Abundances have not been normalized to 1."
                           " - normalizing")
            abundance /= norm_factor


        return cls(velocity=velocity,
                   homologous_density=homologous_density,
                   abundance=abundance,
                   time_explosion=time_explosion,
                   t_radiative=t_radiative,
                   t_inner=t_inner,
                   luminosity_requested=luminosity_requested,
                   dilution_factor=None,
                   v_boundary_inner=structure.get('v_inner_boundary', None),
                   v_boundary_outer=structure.get('v_outer_boundary', None))