def __parse_config(self, config): """Parse the configuration options Arguments --------- config: configparser.SectionProxy Parsed options to initialize class Raises ------ ExpectedFluxError if iter out prefix is not valid """ self.eta_value = config.get("eta value") if self.eta_value is None: raise ExpectedFluxError("Missing argument 'eta value' required " "by Dr16FixEtaExpectedFlux") if not (self.eta_value.endswith(".fits") or self.eta_value.endswith(".fits.gz")): try: _ = float(self.eta_value) except ValueError as error: raise ExpectedFluxError( "Wrong argument 'eta value' passed to " "Dr16FixEtaExpectedFlux. Expected a fits file or " f"a float. Found {self.eta_value}") from error
def __init__(self, config): """Initialize class instance""" self.los_ids = {} self.iter_out_prefix = None self.out_dir = None self.num_bins_variance = None self.num_processors = None self.__parse_config(config) # check that Forest class variables are set # these are required in order to initialize the arrays try: Forest.class_variable_check() except AstronomicalObjectError as error: raise ExpectedFluxError( "Forest class variables need to be set " "before initializing variables here.") from error # initialize wavelength array for variance functions self.log_lambda_var_func_grid = None self._initialize_variance_wavelength_array() # variance functions are initialized by the child classes # initialize mean continuum self.get_mean_cont = None self.get_mean_cont_weight = None self._initialize_mean_continuum_arrays() # to store the stack of deltas self.get_stack_delta = None self.get_stack_delta_weights = None
def __parse_config(self, config): """Parse the configuration options Arguments --------- config: configparser.SectionProxy Parsed options to initialize class Raises ------ ExpectedFluxError if variables are not valid """ self.iter_out_prefix = config.get("iter out prefix") if self.iter_out_prefix is None: raise ExpectedFluxError( "Missing argument 'iter out prefix' required " "by ExpectedFlux") if "/" in self.iter_out_prefix: raise ExpectedFluxError( "Error constructing ExpectedFlux. " "'iter out prefix' should not incude folders. " f"Found: {self.iter_out_prefix}") self.num_bins_variance = config.getint("num bins variance") if self.num_bins_variance is None: raise ExpectedFluxError( "Missing argument 'num bins variance' required by ExpectedFlux" ) self.num_processors = config.getint("num processors") if self.num_processors is None: raise ExpectedFluxError( "Missing argument 'num processors' required by ExpectedFlux") if self.num_processors == 0: self.num_processors = (multiprocessing.cpu_count() // 2) self.out_dir = config.get("out dir") if self.out_dir is None: raise ExpectedFluxError( "Missing argument 'out dir' required by ExpectedFlux") self.out_dir += "Log/"
def read_true_continuum_one_healpix(self, forests, healpix=None): """Read the forest continuum from one healpix and insert it into Arguments --------- forests: List of Forest A list of forest instances where the continuum will be computed healpix: int (Optional) Healpix number that forests belong to Return ------ forests: List of Forest The modified forest instances Raise ----- ExpectedFluxError if Forest.wave_solution is not 'lin' or 'log' """ if healpix is None: healpix = healpy.ang2pix(IN_NSIDE, np.pi / 2 - forests[0].dec, forests[0].ra, nest=True) filename_truth = ( f"{self.input_directory}/{healpix//100}/{healpix}/truth-{IN_NSIDE}-" f"{healpix}.fits") hdul = fitsio.FITS(filename_truth) header = hdul["TRUE_CONT"].read_header() lambda_min = header["WMIN"] lambda_max = header["WMAX"] delta_lambda = header["DWAVE"] lambda_ = np.arange(lambda_min, lambda_max + delta_lambda, delta_lambda) true_cont = hdul["TRUE_CONT"].read() for forest in forests: indx = np.nonzero(true_cont["TARGETID"] == forest.targetid)[0] if indx.size == 0: raise ExpectedFluxError("Forest target id was not found in " "the truth file.") indx = indx[0] # Should we also check for healpix consistency here? true_continuum = interp1d(lambda_, true_cont["TRUE_CONT"][indx]) forest.continuum = true_continuum(10**forest.log_lambda) forest.continuum *= self.get_mean_flux(forest.log_lambda) hdul.close() return forests
def compute_forest_variance(self, forest, continuum): # pylint: disable=no-self-use """Compute the forest variance Arguments --------- forest: Forest A forest instance where the variance will be computed continuum: array of float Quasar continuum associated with the forest Raise ----- MeanExpectedFluxError if function was not overloaded by child class """ raise ExpectedFluxError("Function 'compute_forest_variance' was not " "overloaded by child class")
def compute_expected_flux(self, forests): # pylint: disable=no-self-use """Compute the mean expected flux of the forests. This includes the quasar continua and the mean transimission. It is computed iteratively following as explained in du Mas des Bourboux et al. (2020) Arguments --------- forests: List of Forest A list of Forest from which to compute the deltas. Raise ----- MeanExpectedFluxError if function was not overloaded by child class """ raise ExpectedFluxError("Function 'compute_expected_flux' was not " "overloaded by child class")
def __parse_config(self, config): """Parse the configuration options Arguments --------- config: configparser.SectionProxy Parsed options to initialize class Raises ------ ExpectedFluxError if variables are not valid """ self.input_directory = config.get("input directory") if self.input_directory is None: raise ExpectedFluxError( "Missing argument 'input directory' required " "by TrueContinuum") self.use_constant_weight = config.getboolean("use constant weight") self.raw_statistics_filename = config.get("raw statistics file")
def __parse_config(self, config): """Parse the configuration options Arguments --------- config: configparser.SectionProxy Parsed options to initialize class Raises ------ ExpectedFluxError if variables are not valid """ self.force_stack_delta_to_zero = config.getboolean( "force stack delta to zero") if self.force_stack_delta_to_zero is None: raise ExpectedFluxError( "Missing argument 'force stack delta to zero' required by Dr16ExpectedFlux" ) limit_eta_string = config.get("limit eta") if limit_eta_string is None: raise ExpectedFluxError( "Missing argument 'limit eta' required by Dr16ExpectedFlux") limit_eta = limit_eta_string.split(",") if limit_eta[0].startswith("(") or limit_eta[0].startswith("["): eta_min = float(limit_eta[0][1:]) else: eta_min = float(limit_eta[0]) if limit_eta[1].endswith(")") or limit_eta[1].endswith("]"): eta_max = float(limit_eta[1][:-1]) else: eta_max = float(limit_eta[1]) self.limit_eta = (eta_min, eta_max) limit_var_lss_string = config.get("limit var lss") if limit_var_lss_string is None: raise ExpectedFluxError( "Missing argument 'limit var lss' required by Dr16ExpectedFlux" ) limit_var_lss = limit_var_lss_string.split(",") if limit_var_lss[0].startswith("(") or limit_var_lss[0].startswith( "["): var_lss_min = float(limit_var_lss[0][1:]) else: var_lss_min = float(limit_var_lss[0]) if limit_var_lss[1].endswith(")") or limit_var_lss[1].endswith("]"): var_lss_max = float(limit_var_lss[1][:-1]) else: var_lss_max = float(limit_var_lss[1]) self.limit_var_lss = (var_lss_min, var_lss_max) self.min_num_qso_in_fit = config.getint("min num qso in fit") if self.min_num_qso_in_fit is None: raise ExpectedFluxError( "Missing argument 'min qso in fit' required by Dr16ExpectedFlux" ) self.num_iterations = config.getint("num iterations") if self.num_iterations is None: raise ExpectedFluxError( "Missing argument 'num iterations' required by Dr16ExpectedFlux" ) self.order = config.getint("order") if self.order is None: raise ExpectedFluxError( "Missing argument 'order' required by Dr16ExpectedFlux") self.use_constant_weight = config.getboolean("use constant weight") if self.use_constant_weight is None: raise ExpectedFluxError( "Missing argument 'use constant weight' required by Dr16ExpectedFlux" ) if self.use_constant_weight: self.logger.warning( "Deprecation Warning: option 'use constant weight' is now deprecated " "and will be removed in future versions. Consider using class " "Dr16FixedEtaVarlssFudgeExpectedFlux with options 'eta = 0', " "'var lss = 1' and 'fudge = 0'") # if use_ivar_as_weight is set, we fix eta=1, var_lss=0 and fudge=0 # if use_constant_weight is set, we fix eta=0, var_lss=1, and fudge=0 self.use_ivar_as_weight = config.getboolean("use ivar as weight") if self.use_ivar_as_weight is None: raise ExpectedFluxError( "Missing argument 'use ivar as weight' required by Dr16ExpectedFlux" ) if self.use_ivar_as_weight: self.logger.warning( "Deprecation Warning: option 'use ivar as weight' is now deprecated " "and will be removed in future versions. Consider using class " "Dr16FixedEtaVarlssFudgeExpectedFlux with options 'eta = 1', " "'var lss = 0' and 'fudge = 0'")
def read_raw_statistics(self): """Read the LSS delta variance and mean transmitted flux from files written by the raw analysis """ # files are only for lya so far, this will need to be updated so that # regions other than Lya are available if self.raw_statistics_filename != "": filename = self.raw_statistics_filename else: filename = resource_filename( 'picca', 'delta_extraction') + '/expected_fluxes/raw_stats/' if Forest.wave_solution == "log": filename += 'colore_v9_lya_log.fits.gz' elif Forest.wave_solution == "lin" and np.isclose( 10**Forest.log_lambda_grid[1] - 10**Forest.log_lambda_grid[0], 2.4, rtol=0.1): filename += 'colore_v9_lya_lin_2.4.fits.gz' elif Forest.wave_solution == "lin" and np.isclose( 10**Forest.log_lambda_grid[1] - 10**Forest.log_lambda_grid[0], 3.2, rtol=0.1): filename += 'colore_v9_lya_lin_3.2.fits.gz' else: raise ExpectedFluxError( "Couldn't find compatible raw satistics file. Provide a " "custom one using 'raw statistics file' field.") self.logger.info( f'Reading raw statistics var_lss and mean_flux from file: {filename}' ) try: hdul = fitsio.FITS(filename) except IOError as error: raise ExpectedFluxError( f"raw statistics file {filename} couldn't be loaded") from error header = hdul[1].read_header() if Forest.wave_solution == "log": pixel_step = Forest.log_lambda_grid[1] - Forest.log_lambda_grid[0] log_lambda_min = Forest.log_lambda_grid[0] log_lambda_max = Forest.log_lambda_grid[-1] - pixel_step / 2 log_lambda_rest_min = Forest.log_lambda_rest_frame_grid[ 0] - pixel_step / 2 log_lambda_rest_max = Forest.log_lambda_rest_frame_grid[-1] if (header['LINEAR'] or not np.isclose( header['L_MIN'], 10**log_lambda_min, rtol=1e-3) or not np.isclose( header['L_MAX'], 10**log_lambda_max, rtol=1e-3) or not np.isclose( header['LR_MIN'], 10**log_lambda_rest_min, rtol=1e-3) or not np.isclose( header['LR_MAX'], 10**log_lambda_rest_max, rtol=1e-3) or not np.isclose(header['DEL_LL'], pixel_step, rtol=1e-3)): raise ExpectedFluxError( "raw statistics file pixelization scheme does not match " "input pixelization scheme. " "\t\tL_MIN\tL_MAX\tLR_MIN\tLR_MAX\tDEL_LL" f"raw\t{header['L_MIN']}\t{header['L_MAX']}\t" f"{header['LR_MIN']}\t{header['LR_MAX']}\t{header['DEL_LL']}" f"input\t{log_lambda_min}\t{log_lambda_max}\t" f"{log_lambda_rest_min}\t{log_lambda_rest_max}" "provide a custom file in 'raw statistics file' field " "matching input pixelization scheme") log_lambda = hdul[1]['LAMBDA'][:] elif Forest.wave_solution == "lin": pixel_step = 10**Forest.log_lambda_grid[ 1] - 10**Forest.log_lambda_grid[0] lambda_min = 10**Forest.log_lambda_grid[0] lambda_max = 10**Forest.log_lambda_grid[-1] - pixel_step / 2 lambda_rest_min = 10**Forest.log_lambda_rest_frame_grid[ 0] - pixel_step / 2 lambda_rest_max = 10**Forest.log_lambda_rest_frame_grid[-1] if (not header['LINEAR'] or not np.isclose(header['L_MIN'], lambda_min, rtol=1e-3) or not np.isclose(header['L_MAX'], lambda_max, rtol=1e-3) or not np.isclose(header['LR_MIN'], lambda_rest_min, rtol=1e-3) or not np.isclose(header['LR_MAX'], lambda_rest_max, rtol=1e-3) or not np.isclose(header['DEL_L'], 10**Forest.log_lambda_grid[1] - 10**Forest.log_lambda_grid[0], rtol=1e-3)): raise ExpectedFluxError( "raw statistics file pixelization scheme does not match " "input pixelization scheme. " "\t\tL_MIN\tL_MAX\tLR_MIN\tLR_MAX\tDEL_L" f"raw\t{header['L_MIN']}\t{header['L_MAX']}\t" f"{header['LR_MIN']}\t{header['LR_MAX']}\t{header['DEL_L']}" f"input\t{lambda_min}\t{lambda_max}\t{lambda_rest_min}\t" f"{lambda_rest_max} provide a custom file in 'raw " "statistics file' field matching input pixelization scheme") log_lambda = np.log10(hdul[1]['LAMBDA'][:]) flux_variance = hdul[1]['VAR'][:] mean_flux = hdul[1]['MEANFLUX'][:] hdul.close() var_lss = flux_variance / mean_flux**2 self.get_var_lss = interp1d(log_lambda, var_lss, fill_value='extrapolate', kind='nearest') self.get_mean_flux = interp1d(log_lambda, mean_flux, fill_value='extrapolate', kind='nearest')