Source code for pyspex.data

#!/usr/bin/env python

from . import pyspex_f2py
import os
import numpy


[docs]class Data: """Main data class used to set and get observed data. :ivar ninst: Number of instruments loaded. :vartype ninst: int :ivar inst: Python list of instrument objects. :vartype inst: list of objects """ def __init__(self): self.ninst = 0 # Number of instruments loaded. self.inst = [] # Python list of instrument objects.
[docs] def update(self): """Update the number of instruments.""" self.ninst = int(pyspex_f2py.api_instrument.api_instrument_n()) for i in numpy.arange(self.ninst): ins = Instrument() ins.update(i+1) self.inst.append(ins)
[docs] def load(self, resfile, spofile): """Add a new set of spectrum and response file to the dataset. Provide the full filename including extension! :param resfile: SPEX response file name (including .res extension). :type resfile: str :param spofile: SPEX spectrum file name (including .spo extension). :type spofile: str :rtype: int """ res = os.path.splitext(resfile)[0] rext = os.path.splitext(resfile)[1] if rext != '.res': print("Error: Response file does not have the proper .res extension.") return -1 spo = os.path.splitext(spofile)[0] sext = os.path.splitext(spofile)[1] if sext != '.spo': print("Error: Spectrum file does not have the proper .spo extension.") return -1 cmd = 'data {:s} {:s}'.format(res, spo) ier = pyspex_f2py.api_command(cmd) if ier == 0: self.update() return ier
[docs] def delete(self, ins): """Delete instrument with number `ins`. :param ins: Instrument number to delete. :type ins: int """ ier = pyspex_f2py.api_command("data delete inst {:d}".format(ins)) if ier == 0: self.update() return ier
[docs] def save(self, ins, spofile, overwrite=False): """Save a spectrum to a .spo file. :param ins: Instrument number to save. :type ins: int :param spofile: Output filename for SPEX output file (including .spo extension). :type spofile: str :param overwrite: (Optional) Overwrite an existing .spo file with the same name. :type overwrite: bool """ spo = os.path.splitext(spofile)[0] sext = os.path.splitext(spofile)[1] if sext != '.spo': print("Error: Spectrum file does not have the proper .spo extension.") return -1 if overwrite: ier = pyspex_f2py.api_command("data save {:d} {:s} overwrite".format(ins, spo)) else: ier = pyspex_f2py.api_command("data save {:d} {:s}".format(ins, spo)) return ier
[docs]class Instrument: """Properties of an instrument. :ivar nsector: Number of sectors in instrument. :vartype nsector: int :ivar nregion: Number of data regions in response. :vartype nsector: int :ivar nreg: Number of regions in data. :vartype nreg: int :ivar ncomp: Number of response components. :vartype ncomp: int :ivar index: Index number of this instrument. :vartype index: int :ivar sponame: Filename of .spo file. :vartype sponame: str :ivar resname: Filename of .res file :vartype resname: str :ivar reg: List of regions for this instrument. :vartype reg: list of objects """ def __init__(self): self.index = 0 # Index number of this instrument. self.nsector = 0 # Number of sectors in instrument self.nregion = 0 # Number of data regions in response self.nreg = 0 # Number of regions in data self.ncomp = 0 # Number of response components self.sponame = '' # Filename of .spo file self.resname = '' # Filename of .res file self.reg = [] # List of regions for this instrument
[docs] def update(self, iins): """Update the instrument information. :param iins: Instrument number to update. :type iins: int """ self.index = iins pyspex_f2py.api_instrument.api_instrument_update(float(iins)) self.nsector = int(pyspex_f2py.api_instrument.inst_nsector) self.nregion = int(pyspex_f2py.api_instrument.inst_nregion) self.nreg = int(pyspex_f2py.api_instrument.inst_nreg) self.ncomp = int(pyspex_f2py.api_instrument.inst_ncomp) self.sponame = pyspex_f2py.api_instrument.inst_sponame.view('S252').tobytes().decode('utf-8') self.resname = pyspex_f2py.api_instrument.inst_resname.view('S252').tobytes().decode('utf-8') for i in numpy.arange(self.nreg): r = Region() r.update(iins, i+1) self.reg.append(r)
[docs]class Region: """Properties of one region. :ivar index: Region number. :vartype index: int :ivar emin: Min data energy range (keV). :vartype emin: float :ivar emax: Max data energy range (keV). :vartype emax: float :ivar srccount: Net source counts. :vartype srccount: float :ivar srccerr: Net source count error. :vartype srccerr: float :ivar bkgcount: Subtracted background counts. :vartype bkgcount: float :ivar bkgcerr: Error subtracted background counts. :vartype bkgcerr: float :ivar srcrate: Net source count rate (counts/s). :vartype srcrate: float :ivar srcrerr: Net source count rate error (counts/s). :vartype srcrerr: float :ivar bkgrate: Background count rate subtracted. :vartype bkgrate: float :ivar bkgrerr: Error background count rate subtracted. :vartype bkgrerr: float :ivar mbkgrate: Model background count rate. :vartype mbkgrate: float :ivar tintmin: Minimum integration time per channel. :vartype tintmin: float :ivar tintmax: Maximum integration time per channel. :vartype tintmax: float :ivar tintaver: Average integration time per channel. :vartype tintaver: float """ def __init__(self): self.index = 0 # Region number self.emin = 0. # Min data energy range (keV) self.emax = 0. # Max data energy range (keV) self.srccount = 0. # Net source counts self.srccerr = 0. # Net source count error self.bkgcount = 0. # Subtracted background counts self.bkgcerr = 0. # Error subtracted background counts self.srcrate = 0. # Net source count rate (counts/s) self.srcrerr = 0. # Net source count rate error (counts/s) self.bkgrate = 0. # Background count rate subtracted self.bkgrerr = 0. # Error background count rate subtracted self.mbkgrate = 0. # Model background count rate self.tintmin = 0. # Minimum integration time per channel self.tintmax = 0. # Maximum integration time per channel self.tintaver = 0. # Average integration time per channel
[docs] def update(self, iins, ireg): """Update the region properties. :param iins: Instrument number. :type iins: int :param ireg: Region number to update. :type ireg: int """ self.index = int(ireg) pyspex_f2py.api_region.api_reg_update(float(iins), float(ireg)) self.emin = float(pyspex_f2py.api_region.reg_edmin) self.emax = float(pyspex_f2py.api_region.reg_edmax) self.srccount = float(pyspex_f2py.api_region.reg_sc) self.srccerr = float(pyspex_f2py.api_region.reg_sce) self.bkgcount = float(pyspex_f2py.api_region.reg_bc) self.bkgcerr = float(pyspex_f2py.api_region.reg_dbc) self.srcrate = float(pyspex_f2py.api_region.reg_scs) self.srcrerr = float(pyspex_f2py.api_region.reg_scse) self.bkgrate = float(pyspex_f2py.api_region.reg_bce) self.bkgrerr = float(pyspex_f2py.api_region.reg_dbce) self.mbkgrate = float(pyspex_f2py.api_region.reg_bmce) self.tintmin = float(pyspex_f2py.api_region.reg_tintmin) self.tintmax = float(pyspex_f2py.api_region.reg_tintmax) self.tintaver = float(pyspex_f2py.api_region.reg_tintaver)
[docs]class Simulate: """Class to simulate spectra.""" def __init__(self): pass
[docs] def simulate(self, extime, inst=None, reg=None, ssys=None, bsys=None, noise=None, bnoise=None, seed=None): """Simulate a spectrum for exposure time extime and optionally with a number of options. :param extime: Exposure time to simulate. :type extime: float :param inst: (Optional) Instrument range to simulate (default all) :type inst: str :param reg: (Optional) Region range to simulate (default all) :type reg: str :param ssys: (Optional) Add a systematic error to the source spectrum (Default 0). :type ssys: float :param bsys: (Optional) Add a systematic error to the background spectrum (Default 0). :type bsys: float :param noise: (Optional) Add Poisson noise to the simulated source spectrum (Default True). :type noise: bool :param bnoise: (Optional) Add Poisson noise to the simulated background spectrum (Default False). :type bnoise: bool :param seed: (Optional) Set the random seed for the simulation (Default: system clock). :type seed: int """ # Instrument range if inst is not None: ier = self.set_instrument(inst) # Region range if reg is not None: ier = self.set_region(reg) # Default values for systematic errors api_ssys = 0. api_bsys = 0 if ssys is not None: api_ssys = ssys if bsys is not None: api_bsys = bsys if ssys is not None or bsys is not None: ier = self.set_syserr(api_ssys, api_bsys) # Noise settings if noise is not None: ier = self.set_noise(noise) if bnoise is not None: ier = self.set_bnoise(bnoise) if seed is not None: ier = self.set_random_seed(seed) else: ier = self.set_random() ier = self.simulate_exposure(extime) return ier
[docs] def set_instrument(self, irange): """Define the range of instruments to simulate. :param irange: Instrument range to simulate (default all) :type irange: str """ ier = pyspex_f2py.api_data_simulate.api_simulate_instrument(irange) return ier
[docs] def set_region(self, rrange): """Define the range of regions to simulate. :param rrange: Region range to simulate (default all) :type rrange: str """ ier = pyspex_f2py.api_data_simulate.api_simulate_region(rrange) return ier
[docs] def set_syserr(self, src, bkg): """Add a systematic error to the source spectrum (src) and to the background spectrum (bkg). :param src: Add a systematic error to the source spectrum. :type src: float :param bkg: Add a systematic error to the background spectrum. :type bkg: float """ ier = pyspex_f2py.api_data_simulate.api_simulate_syserr(src, bkg) return ier
[docs] def set_noise(self, status): """Add Poisson noise to the source spectrum (status is True or False). :param status: Add Poisson noise to the simulated source spectrum. :type status: bool """ ier = pyspex_f2py.api_data_simulate.api_simulate_noise(status) return ier
[docs] def set_bnoise(self, status): """Add Poisson noise to the background spectrum (status is True or False). :param status: Add Poisson noise to the simulated background spectrum. :type status: bool """ ier = pyspex_f2py.api_data_simulate.api_simulate_bnoise(status) return ier
[docs] def set_random(self): """Set the random seed to a random number (default).""" ier = pyspex_f2py.api_data_simulate.api_simulate_random() return ier
[docs] def set_random_seed(self, seed): """Set the random seed to an integer value. :param seed: Set the random seed for the simulation. :type seed: int """ ier = pyspex_f2py.api_data_simulate.api_simulate_random_seed(float(seed)) return ier
[docs] def simulate_exposure(self, extime): """Simulate the spectrum for the provided exposure time. :param extime: Exposure time to simulate. :type extime: float """ ier = pyspex_f2py.api_data_simulate.api_simulate_exposure(extime) return ier
[docs]class Bins: """Class containing the binning methods.""" def __init__(self): pass
[docs] def bin(self, inst, reg, elow, ehigh, factor, unit=None): """Bin the spectrum using a fixed factor. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param factor: Binning factor :type factor: int :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_bin(float(inst), float(reg), elow, ehigh, float(factor), unit) return ier
[docs] def obin(self, inst, reg, elow, ehigh, unit=None): """Bin the spectrum optimally given the instrument resolution and statistics. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_obin(float(inst), float(reg), elow, ehigh, unit) return ier
[docs] def rbin(self, inst, reg, elow, ehigh, unit=None): """Bin the spectrum and the response optimally given the instrument resolution and statistics. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_rbin(float(inst), float(reg), elow, ehigh, unit) return ier
[docs] def vbin(self, inst, reg, elow, ehigh, factor, snr, unit=None): """Bin the spectrum using a variable bin size, given a minimum bin factor and a minimum signal to noise ratio. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param factor: Minimal binning factor :type factor: int :param snr: Minimal signal to noise for a data point after binning. :type snr: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_vbin(float(inst), float(reg), elow, ehigh, float(factor), snr, unit) return ier
[docs] def syserr(self, inst, reg, elow, ehigh, src, bkg, unit=None): """Add an additional error to the source and background spectrum. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param src: Error value to be quadratically added to the current error bar of the source spectrum. :type src: float :param bkg: Error value to be quadratically added to the current error bar of the background spectrum. :type bkg: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_syserr(float(inst), float(reg), elow, ehigh, src, bkg, unit) return ier
[docs] def use(self, inst, reg, elow, ehigh, unit=None): """Use the bins given by the energy/channel range. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_use(float(inst), float(reg), elow, ehigh, unit) return ier
[docs] def ignore(self, inst, reg, elow, ehigh, unit=None): """Ignore the bins given by the energy/channel range. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int :param elow: Start point of energy/channel interval. :type elow: float :param ehigh: End point of energy/channel interval. :type ehigh: float :param unit: Unit of the energy/channel range, for example: 'kev', 'ev', 'ryd', 'j', 'hz', 'ang', 'nm' :type unit: str """ ier = pyspex_f2py.api_data_bin.api_bin_ignore(float(inst), float(reg), elow, ehigh, unit) return ier
[docs] def reset(self, inst, reg): """Reset the binning and use status to use all with the original binning. :param inst: Instrument number. :type inst: int :param reg: Region number. :type reg: int """ ier = pyspex_f2py.api_data_bin.api_bin_use(float(inst), float(reg), 1, 10000000, unit=None) ier = pyspex_f2py.api_data_bin.api_bin_bin(float(inst), float(reg), 1, 10000000, 1, unit=None) return ier