def detect(self, channel, i_time, header, bins, bin_range): """ For a given timestep, map the intensity along the loop to the 3D field and return the Hi-C data product. Parameters ---------- channel : `dict` i_time : `int` header : `~sunpy.util.metadata.MetaDict` bins : `~synthesizAR.util.SpatialPair` bin_range : `~synthesizAR.util.SpatialPair` Returns ------- AIA data product : `~sunpy.map.Map` """ with h5py.File(self.counts_file, 'r') as hf: weights = np.array(hf[channel['name']][i_time, :]) units = u.Unit(get_keys(hf[channel['name']].attrs, ('unit','units'))) hpc_coordinates = self.total_coordinates dz = np.diff(bin_range.z)[0].cgs / bins.z * (1. * u.pixel) visible = is_visible(hpc_coordinates, self.observer_coordinate) hist, _, _ = np.histogram2d(hpc_coordinates.Tx.value, hpc_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=visible * weights * dz.value) header['bunit'] = (units * dz.unit).to_string() counts = gaussian_filter(hist.T, (channel['gaussian_width']['y'].value, channel['gaussian_width']['x'].value)) return Map(counts.astype(np.float32), header)
def make_los_velocity_map(time: u.s, field, instr, **kwargs): """ Return map of LOS velocity at a given time for a given instrument resolution. """ plot_settings = { 'cmap': cm.get_cmap('bwr'), 'norm': colors.SymLogNorm(10, vmin=-1e8, vmax=1e8) } plot_settings.update(kwargs.get('plot_settings', {})) bins, bin_range = instr.make_detector_array(field) visible = is_visible(instr.total_coordinates, instr.observer_coordinate) hist_coordinates, _, _ = np.histogram2d(instr.total_coordinates.Tx.value, instr.total_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=visible) with h5py.File(instr.counts_file, 'r') as hf: try: i_time = np.where( np.array(hf['time']) * u.Unit(hf['time'].attrs['units']) == time)[0][0] except IndexError: raise IndexError( f'{time} is not a valid time in observing time for {instr.name}' ) v_x = u.Quantity(hf['velocity_x'][i_time, :], hf['velocity_x'].attrs['units']) v_y = u.Quantity(hf['velocity_y'][i_time, :], hf['velocity_y'].attrs['units']) v_z = u.Quantity(hf['velocity_z'][i_time, :], hf['velocity_z'].attrs['units']) v_los = instr.los_velocity(v_x, v_y, v_z) hist, _, _ = np.histogram2d(instr.total_coordinates.Tx.value, instr.total_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=v_los.value * visible) hist /= np.where(hist_coordinates == 0, 1, hist_coordinates) meta = instr.make_fits_header(field, instr.channels[0]) del meta['wavelnth'] del meta['waveunit'] meta['bunit'] = v_los.unit.to_string() meta['detector'] = 'LOS Velocity' meta['comment'] = 'LOS velocity calculated by synthesizAR' return GenericMap(hist.T, meta, plot_settings=plot_settings)
def peek_fieldlines(magnetogram, fieldlines, **kwargs): """ Quick plot of streamlines overplotted on magnetogram Parameters ---------- magnetogram : `~sunpy.map.Map` fieldlines : `list` """ fig = plt.figure(figsize=kwargs.get('figsize', (8, 8))) ax = fig.gca(projection=magnetogram) # Plot map norm = kwargs.get('norm', Normalize(vmin=-1.5e3, vmax=1.5e3)) magnetogram.plot(axes=ax, title=False, cmap=kwargs.get('cmap', 'hmimag'), norm=norm) # Grid ax.grid(alpha=0.) magnetogram.draw_grid(axes=ax, grid_spacing=10 * u.deg, alpha=0.75, color='k') # Lines line_frequency = kwargs.get('line_frequency', 5) for line in fieldlines[::line_frequency]: try: coord = line.transform_to(magnetogram.coordinate_frame) except AttributeError: # This try-catch is due to a bug where to convert out of an HEEQ frame # one must first transform to a polar HGS frame # FIXME: once this is fixed upstream in SunPy, this can be removed coord = line.transform_to(HeliographicStonyhurst).transform_to( magnetogram.coordinate_frame) # Mask lines behind the solar disk i_visible = np.where(is_visible(coord, magnetogram.observer_coordinate)) coord_visible = SkyCoord(Tx=coord.Tx[i_visible], Ty=coord.Ty[i_visible], distance=coord.distance[i_visible], frame=magnetogram.coordinate_frame) ax.plot_coord(coord_visible, '-', color=kwargs.get('color', 'k'), lw=kwargs.get('lw', 1), alpha=kwargs.get('alpha', 0.5)) plt.show()
def make_temperature_map(time: u.s, field, instr, **kwargs): """ Return map of column-averaged electron temperature at a given time for a given instrument resolution. """ plot_settings = {'cmap': cm.get_cmap('inferno')} plot_settings.update(kwargs.get('plot_settings', {})) bins, bin_range = instr.make_detector_array(field) visible = is_visible(instr.total_coordinates, instr.observer_coordinate) hist_coordinates, _, _ = np.histogram2d(instr.total_coordinates.Tx.value, instr.total_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=visible) with h5py.File(instr.counts_file, 'r') as hf: try: i_time = np.where( u.Quantity(hf['time'], get_keys(hf['time'].attrs), ( 'unit', 'units')) == time)[0][0] except IndexError: raise IndexError( f'{time} is not a valid time in observing time for {instr.name}' ) weights = np.array(hf['electron_temperature'][i_time, :]) units = u.Unit( get_keys(hf['electron_temperature'].attrs, ('unit', 'units'))) hist, _, _ = np.histogram2d(instr.total_coordinates.Tx.value, instr.total_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=weights * visible) hist /= np.where(hist_coordinates == 0, 1, hist_coordinates) meta = instr.make_fits_header(field, instr.channels[0]) del meta['wavelnth'] del meta['waveunit'] meta['bunit'] = units.to_string() meta['detector'] = 'Electron Temperature' meta[ 'comment'] = 'Column-averaged electron temperature calculated by synthesizAR' return GenericMap(hist.T, meta, plot_settings=plot_settings)
def integrate_los(self, time, channel, skeleton, coordinates, coordinates_centers): client = distributed.get_client() # Get Coordinates coords = coordinates_centers.transform_to(self.projected_frame) # Compute weights i_time = np.where(time == self.observing_time)[0][0] widths = np.concatenate( [l.field_aligned_coordinate_width for l in skeleton.loops]) loop_area = np.concatenate( [l.cross_sectional_area for l in skeleton.loops]) root = skeleton.loops[0].zarr_root # NOTE: do this outside of the client.map call to make Dask happy path = f'{{}}/{self.name}/{channel.name}' kernels = np.concatenate( client.gather( client.map( lambda l: root[path.format(l.name)][i_time, :], skeleton.loops, ))) unit_kernel = u.Unit( root[f'{skeleton.loops[0].name}/{self.name}/{channel.name}']. attrs['unit']) area_ratio = (loop_area / self.pixel_area).decompose() weights = area_ratio * widths * (kernels * unit_kernel) visible = is_visible(coords, self.observer) # Bin bins, (blc, trc) = self.get_detector_array(coordinates) hist, _, _ = np.histogram2d( coords.Tx.value, coords.Ty.value, bins=bins, range=((blc.Tx.value, trc.Tx.value), (blc.Ty.value, trc.Ty.value)), weights=weights.value * visible, ) header = self.get_header(channel, coordinates) header['bunit'] = weights.unit.decompose().to_string() header['date-obs'] = (self.observer.obstime + time).isot return Map(hist.T, header)
def _detect(self, channel, i_time, header, bins, bin_range): """ For a given channel and timestep, map the intensity along the loop to the 3D field and return the XRT data product. Parameters ---------- channel : `dict` i_time : `int` header : `~sunpy.util.metadata.MetaDict` bins : `SpatialPair` bin_range : `SpatialPair` Returns ------- XRT data product : `~sunpy.Map` """ with h5py.File(self.counts_file, 'r') as hf: weights = np.array(hf[channel['name']][i_time, :]) units = u.Unit( get_keys(hf[channel['name']].attrs, ('unit', 'units'))) hpc_coordinates = self.total_coordinates dz = np.diff(bin_range.z).cgs[0] / bins.z * (1. * u.pixel) visible = is_visible(hpc_coordinates, self.observer_coordinate) hist, _, _ = np.histogram2d(hpc_coordinates.Tx.value, hpc_coordinates.Ty.value, bins=(bins.x.value, bins.y.value), range=(bin_range.x.value, bin_range.y.value), weights=visible * weights * dz.value) header['bunit'] = (units * dz.unit).to_string() if self.apply_psf: counts = self.psf_smooth(hist.T, header) return Map(counts, header)
def make_emission_measure_map(time: u.s, field, instr, temperature_bin_edges=None, **kwargs): """ Compute true emission meausure in each pixel as a function of electron temperature. Parameters ---------- time : `~astropy.units.Quantity` field : `~synthesizAR.Field` instr : `~synthesizAR.instruments.InstrumentBase` temperature_bin_edges : `~astropy.units.Quantity` Other Parameters ---------------- plot_settings : `dict` Returns ------- `~synthesizAR.maps.EMCube` """ plot_settings = { 'cmap': cm.get_cmap('magma'), 'norm': colors.SymLogNorm(1, vmin=1e25, vmax=1e29) } plot_settings.update(kwargs.get('plot_settings', {})) # read unbinned temperature and density with h5py.File(instr.counts_file, 'r') as hf: try: i_time = np.where( np.array(hf['time']) * u.Unit(hf['time'].attrs['units']) == time)[0][0] except IndexError: raise IndexError( f'{time} is not a valid time in observing time for {instr.name}' ) unbinned_temperature = np.array(hf['electron_temperature'][i_time, :]) temperature_unit = u.Unit(hf['electron_temperature'].attrs['units']) unbinned_density = np.array(hf['density'][i_time, :]) density_unit = u.Unit(hf['density'].attrs['units']) # setup bin edges and weights if temperature_bin_edges is None: temperature_bin_edges = 10.**(np.arange(5.5, 7.5, 0.1)) * u.K bins, bin_range = instr.make_detector_array(field) x_bin_edges = ( np.diff(bin_range.x) / bins.x.value * np.arange(bins.x.value + 1) + bin_range.x[0]) y_bin_edges = ( np.diff(bin_range.y) / bins.y.value * np.arange(bins.y.value + 1) + bin_range.y[0]) dh = np.diff(bin_range.z).cgs[0] / bins.z * (1. * u.pixel) visible = is_visible(instr.total_coordinates, instr.observer_coordinate) emission_measure_weights = (unbinned_density**2) * dh * visible # bin in x,y,T space with emission measure weights xyT_coordinates = np.append(np.stack( [instr.total_coordinates.Tx, instr.total_coordinates.Ty], axis=1), unbinned_temperature[:, np.newaxis], axis=1) hist, _ = np.histogramdd( xyT_coordinates, bins=[x_bin_edges, y_bin_edges, temperature_bin_edges.value], weights=emission_measure_weights) meta_base = instr.make_fits_header(field, instr.channels[0]) del meta_base['wavelnth'] del meta_base['waveunit'] meta_base['detector'] = r'Emission measure' meta_base['comment'] = 'LOS Emission Measure distribution' em_unit = density_unit * density_unit * dh.unit data = np.transpose(hist, (1, 0, 2)) * em_unit return EMCube(data, meta_base, temperature_bin_edges, plot_settings=plot_settings)