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)
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
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))
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
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))
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)
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)
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
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))
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)
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
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))