def _make_energy_binning(**kwargs): """Build the energy binning for the MDP calculation. While there's surely some overlap with the code in ximpol.evt.binning module, none of the binning methods implemented there is exactly what we need here---the closest being that for the modulation cube, which is also supporting the extra EQP binning mode that really does not make a lot of sense here (we don't have an event file with the column energy). I guess we'll just go along with some code duplication. Too bad. """ ebinalg = kwargs['ebinalg'] emin = kwargs['emin'] emax = kwargs['emax'] ebins = kwargs['ebins'] ebinning = kwargs['ebinning'] if ebinalg == 'LIN': ebinning = numpy.linspace(emin, emax, ebins + 1) elif ebinalg == 'LOG': ebinning = numpy.linspace(numpy.log10(emin), numpy.log10(emax), ebins + 1) elif ebinalg == 'FILE': ebinfile = self.get('ebinfile') assert ebinfile is not None ebinning = numpy.loadtxt(ebinfile) elif ebinalg == 'LIST': assert isinstance(ebinning, list) ebinning = numpy.array(ebinning, 'd') else: abort('ebinalg %s not implemented yet' % ebinalg) return ebinning
def make_binning(self): """Build the modulation cube binning. """ ebinalg = self.get('ebinalg') emin = self.get('emin') emax = self.get('emax') ebins = self.get('ebins') if ebinalg == 'LIN': ebinning = numpy.linspace(emin, emax, ebins + 1) elif ebinalg == 'LOG': ebinning = numpy.linspace(numpy.log10(emin), numpy.log10(emax), ebins + 1) elif ebinalg == 'EQP': if self.get('mc'): energy = self.event_data['MC_ENERGY'] else: energy = self.event_data['ENERGY'] ebinning = self.equipopulated_binning(ebins, energy, emin, emax) elif ebinalg == 'FILE': ebinfile = self.get('ebinfile') assert ebinfile is not None ebinning = self.read_binning(ebinfile) elif ebinalg == 'LIST': ebinning = self.get('ebinning') assert isinstance(ebinning, list) ebinning = numpy.array(ebinning, 'd') else: abort('ebinalg %s not implemented yet' % ebinalg) phibinning = numpy.linspace(0, 2*numpy.pi, self.get('phibins') + 1) return (ebinning, phibinning)
def rvs_phi(self, energy, polarization_degree, polarization_angle): """Return random variates for a given array of values of energy, polarization degree and polarization angle. Arguments --------- energy : array An array of energy values. (The function returns an equal-length array of phi values.) polarization_degree : array or float The polarization degree, in [0--1]. (This can either be a vector or an array of the same length as `energy`.) polarization_angle : array or float The polarization angle, in radians. (This can either be a vector or an array of the same length as `energy`.) """ try: min_degree = polarization_degree.min() max_degree = polarization_degree.max() except AttributeError: # This is catching the case where the polarization degree is # constant and is passed through as a float. min_degree = max_degree = polarization_degree if max_degree > 1: abort('The polarization degree must be <= 1') if min_degree < 0: abort('The polarization degree must be >= 0') visibility = self(energy)*polarization_degree return self.generator.rvs_phi(visibility, polarization_angle)
def make_binning(self): """Build the modulation cube binning. """ ebinalg = self.get('ebinalg') emin = self.get('emin') emax = self.get('emax') ebins = self.get('ebins') if ebinalg == 'LIN': ebinning = numpy.linspace(emin, emax, ebins + 1) elif ebinalg == 'LOG': ebinning = numpy.linspace(numpy.log10(emin), numpy.log10(emax), ebins + 1) elif ebinalg == 'EQP': if self.get('mc'): energy = self.event_data['MC_ENERGY'] else: energy = self.event_data['ENERGY'] ebinning = self.equipopulated_binning(ebins, energy, emin, emax) elif ebinalg == 'FILE': ebinfile = self.get('ebinfile') assert ebinfile is not None ebinning = self.read_binning(ebinfile) elif ebinalg == 'LIST': ebinning = self.get('ebinning') assert isinstance(ebinning, list) ebinning = numpy.array(ebinning, 'd') else: abort('ebinalg %s not implemented yet' % ebinalg) phibinning = numpy.linspace(0, 2 * numpy.pi, self.get('phibins') + 1) return (ebinning, phibinning)
def xpmdp(**kwargs): """Calculate the MDP. """ logger.info('Loading the instrument response functions...') aeff = load_arf(kwargs['irfname']) modf = load_mrf(kwargs['irfname']) module_name = os.path.basename(kwargs['configfile']).replace('.py', '') ROI_MODEL = imp.load_source(module_name, kwargs['configfile']).ROI_MODEL logger.info(ROI_MODEL) # This is copied from xpobbsim and should probably be factored out. # Actually, this should be a method of the ROI class. TBD if kwargs['tstart'] < ROI_MODEL.min_validity_time(): kwargs['tstart'] = ROI_MODEL.min_validity_time() logger.info('Simulation start time set to %s...' % kwargs['tstart']) tstop = kwargs['tstart'] + kwargs['duration'] if tstop > ROI_MODEL.max_validity_time(): tstop = ROI_MODEL.max_validity_time() logger.info('Simulation stop time set to %s...' % tstop) kwargs['tstop'] = tstop observation_time = kwargs['tstop'] - kwargs['tstart'] # This is copied from roi.py and should probably be factored out. # Again, the ROI class should be able to sum the count spectra of all the # component and expose the result. sources = ROI_MODEL.values() if len(sources) > 1: abort('Multiple sources not implemented, yet.') source = sources[0] if isinstance(source, xPeriodicPointSource): psamples = numpy.linspace(kwargs['phasemin'], kwargs['phasemax'], 100) logger.info('Sampling phases: %s' % psamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, psamples, scale=observation_time) time_integrated_spectrum = count_spectrum.build_time_integral() else: tsamples = source.sampling_time(kwargs['tstart'], kwargs['tstop']) logger.info('Sampling times: %s' % tsamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, tsamples) time_integrated_spectrum = count_spectrum.build_time_integral() # Thuis should be a callable method in the binning module. ebinning = _make_binning(kwargs['ebinalg'], kwargs['emin'], kwargs['emax'], kwargs['ebins'], kwargs['ebinning']) # And this might be implemented in the irf.mrf module. _x = time_integrated_spectrum.x _y = time_integrated_spectrum.y * modf(_x) mu_spectrum = xInterpolatedUnivariateSplineLinear(_x, _y) for _emin, _emax in zip(ebinning[:-1], ebinning[1:]) +\ [(ebinning[0], ebinning[-1])]: num_counts = count_spectrum.num_expected_counts(emin=_emin, emax=_emax) mu_average = mu_spectrum.integral(_emin, _emax) / num_counts mdp = 4.29 / mu_average / numpy.sqrt(num_counts) logger.info('%.2f--%.2f keV: %d counts in %d s, mu %.3f, MDP %.2f%%' %\ (_emin, _emax, num_counts, observation_time, mu_average, 100*mdp))
def mapped_column_density_HI(ra, dec, map_name='LAB'): """Return the mapped H_I column density at a given position in the sky. The value is read from one of the available input maps. Note that the data in the maps are stored in Galactic coordinates, while we're giving Celestial coordinates in input, here---the transformation is handled internally. Arguments --------- ra : float Right ascension of the source (in decimal degrees). dec: float Declination of the source (in decimal degrees). map: str The HI column density map to use. Can be either 'LAB' (LAB survey) or 'DL' (Dickey & Lockman). """ # Make sure the map name makes sense. assert map_name in ['LAB', 'DL'] # Transform from Celestial to Galactic coordinates. gal_coords = SkyCoord(ra, dec, unit='deg').galactic l, b = gal_coords.l.degree, gal_coords.b.degree # Open the selected input FITS map and grab the values. file_path = os.path.join(XIMPOL_SRCMODEL,'fits','h1_nh_%s.fits' % map_name) if not os.path.exists(file_path): abort('Could not find %s' % file_path) hdu_list = fits.open(file_path) _wcs = WCS(hdu_list[0].header) _data = hdu_list[0].data row, col = [int(item) for item in _wcs.wcs_world2pix(l, b, 1)] return _data[col, row]
def xpviewbin(file_path): """Quick FITS image viewer. """ try: binalg = fits.open(file_path)[0].header['BINALG'] except Exception as e: abort('Could not determine file type (%s)' % e) VIEW_DICT[binalg](file_path).plot(show=True)
def xpirfview(file_path): """Quick FITS image viewer. """ file_ext = file_path.split('.').pop() if not file_ext in CLASS_DICT.keys(): abort('Unrecognized file extension (.%s)' % file_ext) irf = CLASS_DICT[file_ext](file_path) irf.plot()
def xpmdp(**kwargs): """Calculate the MDP. """ logger.info('Loading the instrument response functions...') aeff = load_arf(kwargs['irfname']) modf = load_mrf(kwargs['irfname']) module_name = os.path.basename(kwargs['configfile']).replace('.py', '') ROI_MODEL = imp.load_source(module_name, kwargs['configfile']).ROI_MODEL logger.info(ROI_MODEL) # This is copied from xpobbsim and should probably be factored out. # Actually, this should be a method of the ROI class. TBD if kwargs['tstart'] < ROI_MODEL.min_validity_time(): kwargs['tstart'] = ROI_MODEL.min_validity_time() logger.info('Simulation start time set to %s...' % kwargs['tstart']) tstop = kwargs['tstart'] + kwargs['duration'] if tstop > ROI_MODEL.max_validity_time(): tstop = ROI_MODEL.max_validity_time() logger.info('Simulation stop time set to %s...' % tstop) kwargs['tstop'] = tstop observation_time = kwargs['tstop'] - kwargs['tstart'] # This is copied from roi.py and should probably be factored out. # Again, the ROI class should be able to sum the count spectra of all the # component and expose the result. sources = ROI_MODEL.values() if len(sources) > 1: abort('Multiple sources not implemented, yet.') source = sources[0] if isinstance(source, xPeriodicPointSource): psamples = numpy.linspace(kwargs['phasemin'], kwargs['phasemax'], 100) logger.info('Sampling phases: %s' % psamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, psamples, scale=observation_time) time_integrated_spectrum = count_spectrum.build_time_integral() else: tsamples = source.sampling_time(kwargs['tstart'], kwargs['tstop']) logger.info('Sampling times: %s' % tsamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, tsamples) time_integrated_spectrum = count_spectrum.build_time_integral() # Thuis should be a callable method in the binning module. ebinning =_make_binning(kwargs['ebinalg'], kwargs['emin'], kwargs['emax'], kwargs['ebins'], kwargs['ebinning']) # And this might be implemented in the irf.mrf module. _x = time_integrated_spectrum.x _y = time_integrated_spectrum.y*modf(_x) mu_spectrum = xInterpolatedUnivariateSplineLinear(_x, _y) for _emin, _emax in zip(ebinning[:-1], ebinning[1:]) +\ [(ebinning[0], ebinning[-1])]: num_counts = count_spectrum.num_expected_counts(emin=_emin, emax=_emax) mu_average = mu_spectrum.integral(_emin, _emax)/num_counts mdp = 4.29/mu_average/numpy.sqrt(num_counts) logger.info('%.2f--%.2f keV: %d counts in %d s, mu %.3f, MDP %.2f%%' %\ (_emin, _emax, num_counts, observation_time, mu_average, 100*mdp))
def xpmdp(**kwargs): """Calculate the MDP. """ logger.info('Loading the instrument response functions...') aeff = load_arf(kwargs['irfname']) modf = load_mrf(kwargs['irfname']) module_name = os.path.basename(kwargs['configfile']).replace('.py', '') ROI_MODEL = imp.load_source(module_name, kwargs['configfile']).ROI_MODEL logger.info(ROI_MODEL) # This is copied from xpobbsim and should probably be factored out. # Actually, this should be a method of the ROI class. TBD if kwargs['tstart'] < ROI_MODEL.min_validity_time(): kwargs['tstart'] = ROI_MODEL.min_validity_time() logger.info('Simulation start time set to %s...' % kwargs['tstart']) tstop = kwargs['tstart'] + kwargs['duration'] if tstop > ROI_MODEL.max_validity_time(): tstop = ROI_MODEL.max_validity_time() logger.info('Simulation stop time set to %s...' % tstop) kwargs['tstop'] = tstop # This is copied from roi.py and should probably be factored out. # Again, the ROI class should be able to sum the count spectra of all the # component and expose the result. sources = ROI_MODEL.values() if len(sources) > 1: abort('Multiple sources not implemented, yet.') source = sources[0] if isinstance(source, xPeriodicPointSource): observation_time = kwargs['tstop'] - kwargs['tstart'] psamples = numpy.linspace(kwargs['phasemin'], kwargs['phasemax'], 100) logger.info('Sampling phases: %s' % psamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, psamples, source.column_density, source.redshift, scale_factor=observation_time) else: tsamples = source.sampling_time(kwargs['tstart'], kwargs['tstop']) logger.info('Sampling times: %s' % tsamples) count_spectrum = xCountSpectrum(source.energy_spectrum, aeff, tsamples, source.column_density, source.redshift) # Do the actual work. ebinning =_make_energy_binning(**kwargs) mdp_table = count_spectrum.build_mdp_table(ebinning, modf) logger.info(mdp_table) file_path = kwargs['outfile'] if file_path is not None: logger.info('Writing output file path %s...' % file_path) open(file_path, 'w').write('%s\n\n%s' % (kwargs, mdp_table)) logger.info('Done.') return mdp_table
def make_binning(self): """Build the light-curve binning. """ tbinalg = self.get('tbinalg') tstart = self.get('tstart') tstop = self.get('tstop') tbins = self.get('tbins') if tbinalg == 'LIN': return numpy.linspace(tstart, tstop, tbins + 1) elif tbinalg == 'LOG': return numpy.logspace(numpy.log10(tstart), numpy.log10(tstop), tbins + 1) elif tbinalg == 'FILE': tbinfile = self.get('tbinfile') assert tbinfile is not None return self.read_binning(tbinfile) abort('tbinalg %s not implemented yet' % tbinalg)
def _make_binning(ebinalg, emin=1., emax=10., ebins=5, ebinning=None): """Build the modulation cube binning. Warning ------- This is copied from evt/binning.py and should be factored out. """ if ebinalg == 'LIN': ebinning = numpy.linspace(emin, emax, ebins + 1) elif ebinalg == 'LOG': ebinning = numpy.linspace(numpy.log10(emin), numpy.log10(emax), ebins + 1) #elif ebinalg == 'FILE': # ebinfile = self.get('ebinfile') # assert ebinfile is not None # ebinning = self.read_binning(ebinfile) elif ebinalg == 'LIST': assert isinstance(ebinning, list) ebinning = numpy.array(ebinning, 'd') else: abort('ebinalg %s not implemented yet' % ebinalg) return ebinning
def __init__(self, num_samples=1000): """Constructor. Arguments --------- num_samples : int The number of data points used to sample (logarithmically) the photon energies when tabulating the absorption cross section internally. """ file_path = os.path.join(XIMPOL_SRCMODEL, 'ascii', 'XsecFitParam.txt') if not os.path.exists(file_path): abort('Could not find %s' % file_path) # Read the data from file and calculate the minimum and maximum # energies. e_lo, e_hi, c0, c1, c2 = numpy.loadtxt(file_path, delimiter=',', unpack=True) emin = e_lo[0] emax = e_hi[-1] # Sample the energy logarithmically between emin and emax. _x = numpy.logspace(numpy.log10(emin), numpy.log10(emax), num_samples) # Here comes the interesting part---the cross section is tabulated # by means of a set of piecewise quadratic functions, and the # three coefficients are provided in each energy bin. We do some # magic with the numpy.digitize() function, returning for each value # in _x its bin index in the original table. Note that we need to # clip the array removing negative numbers, as the double log/exp # operations done in defining the binning where driving the first # index to -1. _bin = (numpy.digitize(_x, e_lo) - 1).clip(min=0) # Calculate the cross section values---compact, isn't it? _y = 1.0e-24*(c0[_bin] + c1[_bin]*_x + c2[_bin]*(_x**2.))/(_x**3.) # And, finally, build the basic spline underlying the model. _fmt = dict(xname='Energy', xunits='keV', yname='$\\sigma_{abs}$', yunits='cm$^2$') self.xsection = xInterpolatedUnivariateSplineLinear(_x, _y, **_fmt)
def check_input_file(file_path, extension=None): """Make sure that an input file exists (and, optionally, has the right extension). Note that we abort the execution with no mercy if anything fails. """ if not os.path.exists(file_path): abort('Input file %s does not exists' % file_path) if not os.path.isfile(file_path): abort('Input file %s is not a file' % file_path) if extension is not None and not file_path.endswith('.%s' % extension): abort('Input file %s is not a .%s file' % (file_path, extension))