def _read_particle_header(self): if not self.ds.parameters["particles.write_in_plotfile"]: self.pgrid_info = np.zeros((self.num_grids, 3), dtype='int64') return for fn in ['particle_position_%s' % ax for ax in 'xyz'] + \ ['particle_mass'] + \ ['particle_velocity_%s' % ax for ax in 'xyz']: self.field_list.append(("io", fn)) header = open(os.path.join(self.ds.output_dir, "DM", "Header")) version = header.readline() ndim = header.readline() nfields = header.readline() ntotalpart = int(header.readline()) dummy = header.readline() # nextid maxlevel = int(header.readline()) # max level # Skip over how many grids on each level; this is degenerate for i in range(maxlevel + 1): dummy = header.readline() grid_info = np.fromiter((int(i) for line in header.readlines() for i in line.split()), dtype='int64', count=3*self.num_grids).reshape((self.num_grids, 3)) # we need grid_info in `populate_grid_objects`, so save it to self for g, pg in izip(self.grids, grid_info): g.particle_filename = os.path.join(self.ds.output_dir, "DM", "Level_%s" % (g.Level), "DATA_%04i" % pg[0]) g.NumberOfParticles = pg[1] g._particle_offset = pg[2] self.grid_particle_count[:, 0] = grid_info[:, 1]
def _read_particle_header(self): if not self.ds.parameters["particles"]: self.pgrid_info = np.zeros((self.num_grids, 3), dtype='int64') return for fn in ['particle_position_%s' % ax for ax in 'xyz'] + \ ['particle_mass'] + \ ['particle_velocity_%s' % ax for ax in 'xyz']: self.field_list.append(("io", fn)) header = open(os.path.join(self.ds.output_dir, "DM", "Header")) version = header.readline() # NOQA ndim = header.readline() # NOQA nfields = header.readline() # NOQA ntotalpart = int(header.readline()) # NOQA nextid = header.readline() # NOQA maxlevel = int(header.readline()) # NOQA # Skip over how many grids on each level; this is degenerate for i in range(maxlevel + 1): header.readline() grid_info = np.fromiter( (int(i) for line in header.readlines() for i in line.split()), dtype='int64', count=3 * self.num_grids).reshape((self.num_grids, 3)) # we need grid_info in `populate_grid_objects`, so save it to self for g, pg in izip(self.grids, grid_info): g.particle_filename = os.path.join(self.ds.output_dir, "DM", "Level_%s" % (g.Level), "DATA_%04i" % pg[0]) g.NumberOfParticles = pg[1] g._particle_offset = pg[2] self.grid_particle_count[:, 0] = grid_info[:, 1]
def _populate_grid_objects(self): for g,f in izip(self.grids, self.filenames): g._prepare_grid() g._setup_dx() g.set_filename(f[0]) del self.filenames # No longer needed. self.max_level = self.grid_levels.max()
def _populate_grid_objects(self): reconstruct = ytcfg.getboolean("yt", "reconstruct_index") for g, f in izip(self.grids, self.filenames): g._prepare_grid() g._setup_dx() g.set_filename(f[0]) if reconstruct: if g.Parent is not None: g._guess_properties_from_parent() del self.filenames # No longer needed. self.max_level = self.grid_levels.max()
def _populate_grid_objects(self): reconstruct = ytcfg.getboolean("yt","reconstruct_index") for g,f in izip(self.grids, self.filenames): g._prepare_grid() g._setup_dx() g.set_filename(f[0]) if reconstruct: if g.Parent is not None: g._guess_properties_from_parent() del self.filenames # No longer needed. self.max_level = self.grid_levels.max()
def save(self, name=None, suffix=None, mpl_kwargs=None): r""" Saves a 1d profile plot. Parameters ---------- name : str The output file keyword. suffix : string Specify the image type by its suffix. If not specified, the output type will be inferred from the filename. Defaults to PNG. mpl_kwargs : dict A dict of keyword arguments to be passed to matplotlib. """ if not self._plot_valid: self._setup_plots() unique = set(self.plots.values()) if len(unique) < len(self.plots): iters = izip(range(len(unique)), sorted(unique)) else: iters = iteritems(self.plots) if not suffix: suffix = "png" suffix = ".%s" % suffix fullname = False if name is None: if len(self.profiles) == 1: prefix = self.profiles[0].ds else: prefix = "Multi-data" name = "%s%s" % (prefix, suffix) else: sfx = get_image_suffix(name) if sfx != '': suffix = sfx prefix = name[:name.rfind(suffix)] fullname = True else: prefix = name xfn = self.profiles[0].x_field if isinstance(xfn, tuple): xfn = xfn[1] fns = [] for uid, plot in iters: if isinstance(uid, tuple): uid = uid[1] if fullname: fns.append("%s%s" % (prefix, suffix)) else: fns.append("%s_1d-Profile_%s_%s%s" % (prefix, xfn, uid, suffix)) mylog.info("Saving %s", fns[-1]) with matplotlib_style_context(): plot.save(fns[-1], mpl_kwargs=mpl_kwargs) return fns
def save(self, name=None, suffix=None): r""" Saves a 1d profile plot. Parameters ---------- name : str The output file keyword. suffix : string Specify the image type by its suffix. If not specified, the output type will be inferred from the filename. Defaults to PNG. """ if not self._plot_valid: self._setup_plots() unique = set(self.figures.values()) if len(unique) < len(self.figures): iters = izip(range(len(unique)), sorted(unique)) else: iters = iteritems(self.figures) if not suffix: suffix = "png" suffix = ".%s" % suffix if name is None: if len(self.profiles) == 1: prefix = self.profiles[0].ds else: prefix = "Multi-data" name = "%s%s" % (prefix, suffix) else: sfx = get_image_suffix(name) if sfx != '': suffix = sfx prefix = name[:name.rfind(suffix)] else: prefix = name xfn = self.profiles[0].x_field if isinstance(xfn, tuple): xfn = xfn[1] canvas_cls = get_canvas(name) fns = [] for uid, fig in iters: if isinstance(uid, tuple): uid = uid[1] canvas = canvas_cls(fig) fns.append("%s_1d-Profile_%s_%s%s" % (prefix, xfn, uid, suffix)) mylog.info("Saving %s", fns[-1]) canvas.print_figure(fns[-1]) return fns
def _repr_html_(self): """Return an html representation of the plot object. Will display as a png for each WindowPlotMPL instance in self.plots""" ret = '' unique = set(self.plots.values()) if len(unique) < len(self.plots): iters = izip(range(len(unique)), sorted(unique)) else: iters = iteritems(self.plots) for uid, plot in iters: with matplotlib_style_context(): img = plot._repr_png_() img = base64.b64encode(img).decode() ret += r'<img style="max-width:100%%;max-height:100%%;" ' \ r'src="data:image/png;base64,{0}"><br>'.format(img) return ret
def _repr_html_(self): """Return an html representation of the plot object. Will display as a png for each WindowPlotMPL instance in self.plots""" ret = '' unique = set(self.figures.values()) if len(unique) < len(self.figures): iters = izip(range(len(unique)), sorted(unique)) else: iters = iteritems(self.figures) for uid, fig in iters: canvas = mpl.FigureCanvasAgg(fig) f = BytesIO() canvas.print_figure(f) f.seek(0) img = base64.b64encode(f.read()).decode() ret += r'<img style="max-width:100%%;max-height:100%%;" ' \ r'src="data:image/png;base64,{0}"><br>'.format(img) return ret
def compare_arbors(a1, a2, groups=None, fields=None): """ Compare all fields for all trees in two arbors. """ if groups is None: groups = ["tree", "prog"] if fields is None: fields = a1.field_list for field in fields: assert (a1[field] == a2[field]).all() i = 0 ntot = len(a1) pbar = get_pbar("Comparing trees", ntot) for t1, t2 in izip(a1, a2): compare_trees(t1, t2, groups=groups, fields=fields) i += 1 pbar.update(i) pbar.finish()
def calculate_spectrum(self, data_source=None, star_mass=None, star_creation_time=None, star_metallicity_fraction=None, star_metallicity_constant=None, min_age=YTQuantity(0.0, 'yr')): r"""For the set of stars, calculate the collective spectrum. Attached to the output are several useful objects: Attributes ---------- final_spec: array The collective spectrum in units of flux binned in wavelength. wavelength: array The wavelength for the spectrum bins, in Angstroms. total_mass: float Total mass of all the stars. avg_mass: float Average mass of all the stars. avg_metal: float Average metallicity of all the stars. Parameters ---------- data_source : AMRRegion object, optional The region from which stars are extracted for analysis. If this is not specified, the next three parameters must be supplied. star_mass : Array or list of floats An array of star masses in Msun units. star_creation_time : Array or list of floats An array of star creation times in code units. star_metallicity_fraction : Array or list of floats An array of star metallicity fractions, in code units (which is not Z/Zsun, rather just Z). star_metallicity_constant : Float If desired, override the star metallicity fraction of all the stars to the given value. min_age : Float Removes young stars younger than this number (in years) from the spectrum. Default: 0 (all stars). Examples -------- >>> import yt >>> from yt.analysis_modules.star_analysis.api import SpectrumBuilder >>> ds = yt.load("Enzo_64/RD0006/RedshiftOutput0006") >>> spec = SpectrumBuilder(ds, "bc", model="salpeter") >>> sp = ds.sphere([0.5, 0.5, 0.5], 0.1) >>> spec.calculate_spectrum(data_source=sp, min_age=1.e6) """ # Initialize values self.final_spec = np.zeros(self.wavelength.size, dtype='float64') self._data_source = data_source if isinstance(star_mass, YTArray): assert star_mass.units.same_dimensions_as(g.units) elif star_mass is not None: star_mass = YTArray(star_mass, 'Msun') self.star_mass = star_mass if isinstance(star_creation_time, YTArray): assert star_creation_time.units.same_dimensions_as(s.units) elif star_creation_time is not None: star_creation_time = self._ds.arr(star_creation_time, 'code_time') self.star_creation_time = star_creation_time if isinstance(star_metallicity_fraction, YTArray): assert \ star_metallicity_fraction.units.same_dimensions_as(Zsun.units) elif star_metallicity_fraction is not None: star_metallicity_fraction = self._ds.arr( star_metallicity_fraction, 'code_metallicity' ) self.star_metallicity_fraction = star_metallicity_fraction if isinstance(min_age, YTQuantity): assert min_age.units.same_dimensions_as(s.units) elif min_age is not None: min_age = YTQuantity(min_age, 'yr') self.min_age = min_age # Check to make sure we have the right set of data. if data_source is None: if self.star_mass is None or self.star_creation_time is None or \ (star_metallicity_fraction is None and star_metallicity_constant is None): mylog.error( """ If data_source is not provided, all of these paramters need to be set: star_mass (array, Msun), star_creation_time (array, code units), And one of: star_metallicity_fraction (array, code units). --OR-- star_metallicity_constant (float, code units). """) return None if star_metallicity_fraction is not None: self.star_metal = star_metallicity_fraction else: self.star_metal = \ self._ds.arr(np.ones_like(self.star_mass) * star_metallicity_constant, 'Zsun') else: # Get the data we need. if self.filter_provided: ct = self._filter['creation_time'] # mass_stars = self._data_source[self._filter, "particle_mass"] if star_metallicity_constant is None: self.star_metal = self._data_source[ self._filter, "metallicity_fraction"].in_units('Zsun') else: self.star_metal = \ self._ds.arr(np.ones_like( self._data_source[self._filter, "metallicity_fraction"]) * star_metallicity_constant, "Zsun") else: ct = self._data_source["creation_time"] if ct is None: errmsg = 'data source must have particle_age!' mylog.error(errmsg) raise RuntimeError(errmsg) mask = ct > 0 if not any(mask): errmsg = 'all particles have age < 0' mylog.error(errmsg) raise RuntimeError(errmsg) # type = self._data_source['particle_type'] self.star_creation_time = ct[mask] self.star_mass = self._data_source[ 'particle_mass'][mask].in_units('Msun') if star_metallicity_constant is not None: self.star_metal = self._ds.arr( np.ones_like(self.star_mass) * star_metallicity_constant, 'Zsun') else: self.star_metal = self._data_source[ "metallicity_fraction"][mask].in_units('Zsun') # Age of star in years. dt = (self.time_now - self.star_creation_time).in_units('yr') dt[dt < 0.0] = 0.0 # Remove young stars sub = dt >= self.min_age if len(sub) == 0: return self.star_metal = self.star_metal[sub] dt = dt[sub] self.star_creation_time = self.star_creation_time[sub] # Figure out which METALS bin the star goes into. Mindex = np.digitize(self.star_metal.in_units('Zsun'), METALS) # Replace the indices with strings. Mname = MtoD[Mindex] # Figure out which age bin this star goes into. Aindex = np.digitize(dt, self.age) # Ratios used for the interpolation. ratio1 = (dt - self.age[Aindex - 1]) / \ (self.age[Aindex] - self.age[Aindex - 1]) ratio2 = (self.age[Aindex] - dt) / \ (self.age[Aindex] - self.age[Aindex - 1]) # Sort the stars by metallicity and then by age, which should reduce # memory access time by a little bit in the loop. indexes = np.arange(self.star_metal.size) sort = np.asarray([indexes[i] for i in np.lexsort([indexes, Aindex, Mname])]) Mname = Mname[sort] Aindex = Aindex[sort] ratio1 = ratio1[sort] ratio2 = ratio2[sort] self.star_mass = self.star_mass[sort] self.star_creation_time = self.star_creation_time[sort] self.star_metal = self.star_metal[sort] # Interpolate the flux for each star, adding to the total by weight. pbar = get_pbar("Calculating fluxes", len(self.star_mass)) for i, star in enumerate(izip(Mname, Aindex, ratio1, ratio2, self.star_mass)): # Pick the right age bin for the right flux array. flux = self.flux[star[0]][star[1], :] # Get the one just before the one above. flux_1 = self.flux[star[0]][star[1] - 1, :] # interpolate in log(flux), linear in time. int_flux = star[3] * np.log10(flux_1) + star[2] * np.log10(flux) # Add this flux to the total, weighted by mass. self.final_spec += np.power(10., int_flux) * star[4] pbar.update(i) pbar.finish() # Normalize. self.total_mass = self.star_mass.sum() self.avg_mass = self.star_mass.mean() tot_metal = (self.star_metal * self.star_mass).sum() if tot_metal > 0: self.avg_metal = math.log10( (tot_metal / self.total_mass).in_units('Zsun')) else: self.avg_metal = -99
def calculate_spectrum(self, data_source=None, star_mass=None, star_creation_time=None, star_metallicity_fraction=None, star_metallicity_constant=None, min_age=YTQuantity(0.0, 'yr')): r"""For the set of stars, calculate the collective spectrum. Attached to the output are several useful objects: Attributes ---------- final_spec: array The collective spectrum in units of flux binned in wavelength. wavelength: array The wavelength for the spectrum bins, in Angstroms. total_mass: float Total mass of all the stars. avg_mass: float Average mass of all the stars. avg_metal: float Average metallicity of all the stars. Parameters ---------- data_source : AMRRegion object, optional The region from which stars are extracted for analysis. If this is not specified, the next three parameters must be supplied. star_mass : Array or list of floats An array of star masses in Msun units. star_creation_time : Array or list of floats An array of star creation times in code units. star_metallicity_fraction : Array or list of floats An array of star metallicity fractions, in code units (which is not Z/Zsun, rather just Z). star_metallicity_constant : Float If desired, override the star metallicity fraction of all the stars to the given value. min_age : Float Removes young stars younger than this number (in years) from the spectrum. Default: 0 (all stars). Examples -------- >>> import yt >>> from yt.analysis_modules.star_analysis.api import SpectrumBuilder >>> ds = yt.load("Enzo_64/RD0006/RedshiftOutput0006") >>> spec = SpectrumBuilder(ds, "bc", model="salpeter") >>> sp = ds.sphere([0.5, 0.5, 0.5], 0.1) >>> spec.calculate_spectrum(data_source=sp, min_age=1.e6) """ # Initialize values self.final_spec = np.zeros(self.wavelength.size, dtype='float64') self._data_source = data_source if isinstance(star_mass, YTArray): assert star_mass.units.same_dimensions_as(g.units) elif star_mass is not None: star_mass = YTArray(star_mass, 'Msun') self.star_mass = star_mass if isinstance(star_creation_time, YTArray): assert star_creation_time.units.same_dimensions_as(s.units) elif star_creation_time is not None: star_creation_time = self._ds.arr(star_creation_time, 'code_time') self.star_creation_time = star_creation_time if isinstance(star_metallicity_fraction, YTArray): assert \ star_metallicity_fraction.units.same_dimensions_as(Zsun.units) elif star_metallicity_fraction is not None: star_metallicity_fraction = self._ds.arr(star_metallicity_fraction, 'code_metallicity') self.star_metallicity_fraction = star_metallicity_fraction if isinstance(min_age, YTQuantity): assert min_age.units.same_dimensions_as(s.units) elif min_age is not None: min_age = YTQuantity(min_age, 'yr') self.min_age = min_age # Check to make sure we have the right set of data. if data_source is None: if self.star_mass is None or self.star_creation_time is None or \ (star_metallicity_fraction is None and star_metallicity_constant is None): mylog.error(""" If data_source is not provided, all of these paramters need to be set: star_mass (array, Msun), star_creation_time (array, code units), And one of: star_metallicity_fraction (array, code units). --OR-- star_metallicity_constant (float, code units). """) return None if star_metallicity_fraction is not None: self.star_metal = star_metallicity_fraction else: self.star_metal = \ self._ds.arr(np.ones_like(self.star_mass) * star_metallicity_constant, 'Zsun') else: # Get the data we need. if self.filter_provided: ct = self._filter['creation_time'] # mass_stars = self._data_source[self._filter, "particle_mass"] if star_metallicity_constant is None: self.star_metal = self._data_source[ self._filter, "metallicity_fraction"].in_units('Zsun') else: self.star_metal = \ self._ds.arr(np.ones_like( self._data_source[self._filter, "metallicity_fraction"]) * star_metallicity_constant, "Zsun") else: ct = self._data_source["creation_time"] if ct is None: errmsg = 'data source must have particle_age!' mylog.error(errmsg) raise RuntimeError(errmsg) mask = ct > 0 if not any(mask): errmsg = 'all particles have age < 0' mylog.error(errmsg) raise RuntimeError(errmsg) # type = self._data_source['particle_type'] self.star_creation_time = ct[mask] self.star_mass = self._data_source['particle_mass'][ mask].in_units('Msun') if star_metallicity_constant is not None: self.star_metal = self._ds.arr( np.ones_like(self.star_mass) * star_metallicity_constant, 'Zsun') else: self.star_metal = self._data_source[ "metallicity_fraction"][mask].in_units('Zsun') # Age of star in years. dt = (self.time_now - self.star_creation_time).in_units('yr') dt[dt < 0.0] = 0.0 # Remove young stars sub = dt >= self.min_age if len(sub) == 0: return self.star_metal = self.star_metal[sub] dt = dt[sub] self.star_creation_time = self.star_creation_time[sub] # Figure out which METALS bin the star goes into. Mindex = np.digitize(self.star_metal.in_units('Zsun'), METALS) # Replace the indices with strings. Mname = MtoD[Mindex] # Figure out which age bin this star goes into. Aindex = np.digitize(dt, self.age) # Ratios used for the interpolation. ratio1 = (dt - self.age[Aindex - 1]) / \ (self.age[Aindex] - self.age[Aindex - 1]) ratio2 = (self.age[Aindex] - dt) / \ (self.age[Aindex] - self.age[Aindex - 1]) # Sort the stars by metallicity and then by age, which should reduce # memory access time by a little bit in the loop. indexes = np.arange(self.star_metal.size) sort = np.asarray( [indexes[i] for i in np.lexsort([indexes, Aindex, Mname])]) Mname = Mname[sort] Aindex = Aindex[sort] ratio1 = ratio1[sort] ratio2 = ratio2[sort] self.star_mass = self.star_mass[sort] self.star_creation_time = self.star_creation_time[sort] self.star_metal = self.star_metal[sort] # Interpolate the flux for each star, adding to the total by weight. pbar = get_pbar("Calculating fluxes", len(self.star_mass)) for i, star in enumerate( izip(Mname, Aindex, ratio1, ratio2, self.star_mass)): # Pick the right age bin for the right flux array. flux = self.flux[star[0]][star[1], :] # Get the one just before the one above. flux_1 = self.flux[star[0]][star[1] - 1, :] # interpolate in log(flux), linear in time. int_flux = star[3] * np.log10(flux_1) + star[2] * np.log10(flux) # Add this flux to the total, weighted by mass. self.final_spec += np.power(10., int_flux) * star[4] pbar.update(i) pbar.finish() # Normalize. self.total_mass = self.star_mass.sum() self.avg_mass = self.star_mass.mean() tot_metal = (self.star_metal * self.star_mass).sum() if tot_metal > 0: self.avg_metal = math.log10( (tot_metal / self.total_mass).in_units('Zsun')) else: self.avg_metal = -99