Source code for exosim.recipes.createFocalPlane

import os.path
from collections import OrderedDict
from typing import Tuple, Union

import astropy.units as u

import exosim.log as log
import exosim.tasks.parse as parse
import exosim.utils as utils
from exosim.models.channel import Channel
from exosim.output import Output, SetOutput
from exosim.utils.ascii_arts import astronomer1
from exosim.utils.prepare_recipes import (
    clean_config_files,
    copy_input_files,
    load_options,
)
from exosim.utils.runConfig import RunConfig
from exosim.utils.timed_class import TimedClass
from exosim.utils.types import OutputType


[docs]class CreateFocalPlane(TimedClass, log.Logger): """ Pipeline to create the instrument focal planes. This pipeline loads the configuration file and produces an output, if indicated, where all the products are stored. It loads the source SED and the foregrounds and, after the optical chain production, it estimates the focal plane for the source and for the foregrounds. Attributes ------------ mainConfig: dict This is parsed from :class:`~exosim.tasks.load.loadOptions.LoadOptions` output: :class:`~exosim.output.output.Output` (optional) output file payloadConfig: dict payload configuration dictionary extracted from mainConfig` time: :class:`~astropy.units.Quantity` time grid. wl_grid: :class:`~numpy.ndarray` or :class:`~astropy.units.Quantity` wavelength grid. Examples -------- >>> import exosim.recipes as recipes >>> recipes.CreateFocalPlane(options_file= 'main _configuration.xml', >>> output_file = 'output_file.h5') """ def __init__( self, options_file: Union[str, dict], output_file: str, store_config: bool = False, ) -> None: """ Parameters ---------- options_file: str or dict input configuration file output_file: str output file store_config: bool store the input configuration into the output (default is False) """ super().__init__() self.graphics(astronomer1) RunConfig.stats() self.announce("started") clean_config_files() self.mainConfig, self.payloadConfig = load_options(options_file) if output_file is not None: copy_input_files(os.path.dirname(os.path.abspath(output_file))) self.output = SetOutput(output_file) # wavelength and time grid definition self.wl_grid = utils.grids.wl_grid( self.mainConfig["wl_grid"]["wl_min"], self.mainConfig["wl_grid"]["wl_max"], self.mainConfig["wl_grid"]["logbin_resolution"], ) if "time_grid" in self.mainConfig.keys(): self.time_grid = utils.grids.time_grid( self.mainConfig["time_grid"]["start_time"], self.mainConfig["time_grid"]["end_time"], self.mainConfig["time_grid"].get( "low_frequencies_resolution", None ), ) else: self.time_grid = [0] * u.hr if "pointing" in self.mainConfig.keys(): pointing = ( self.mainConfig["pointing"]["ra"], self.mainConfig["pointing"]["dec"], ) else: pointing = None # starting the pipeline self.info("Focal plane pipeline started") with self.output.use(append=True, cache=True) as out: # store configuration if store_config: out.store_dictionary(self.mainConfig, "configuration") # common path and source preparation sources, common_path = self.prepare_environment(out) self.log_runtime("preparation ended time", "info") # instrument focal plane production ch_out = out.create_group("channels") if isinstance(self.payloadConfig["channel"], OrderedDict): for ch in self.payloadConfig["channel"].keys(): self.announce("channel {} started".format(ch)) self.run_channel( self.payloadConfig["channel"][ch], common_path, sources, pointing, ch_out, ) self.log_runtime("{} ended in".format(ch), "info") # else, we load the only source available else: self.run_channel( self.payloadConfig["channel"], common_path, sources, pointing, ch_out, ) self.log_runtime( "channel {} ended time".format( self.payloadConfig["channel"]["value"] ), "info", ) self.log_runtime_complete("recipe ended", "info") self.info( "output {} size: {:.3f}".format(output_file, out.getsize()) ) self.announce("ended")
[docs] def prepare_environment( self, out: Output ) -> Tuple[OrderedDict, OrderedDict]: """ Il prepores the input data to build the instrument focal planes Parameters ---------- out: :class:`~exosim.output.output.OutputGroup` output group Returns ------- dict soureces dict `~collections.OrderedDict` common path dictionary """ out_sky = out.create_group("sky") sources, for_contrib = {}, {} parsePath = parse.ParsePath() if "sky" in self.mainConfig.keys(): sky = self.mainConfig["sky"] # source preparation if "source" in sky.keys(): parseSources = parse.ParseSources() sources = parseSources( parameters=sky["source"], wavelength=self.wl_grid, time=self.time_grid, output=out_sky, ) # foreground preparation if "foregrounds" in sky.keys(): for_contrib = parsePath( parameters=sky["foregrounds"], wavelength=self.wl_grid, time=self.time_grid, output=out_sky, group_name="foregrounds", ) # common optics preparation if "optical_path" in self.payloadConfig["Telescope"].keys(): common_path = parsePath( parameters=self.payloadConfig["Telescope"]["optical_path"], wavelength=self.wl_grid, time=self.time_grid, output=out, light_path=for_contrib, group_name="telescope", ) else: common_path = for_contrib return sources, common_path
[docs] def run_channel( self, description: dict, common_path: OrderedDict, sources: dict, pointing: Tuple[u.Quantity, u.Quantity] = None, out: OutputType = None, ) -> None: """ It instantiates and runs the :class:`~exosim.models.channel.Channel` for the indicated channel` Parameters ---------- description: dict channel description common_path: `~collections.OrderedDict` dictionary of contributes sources: dict dictionary containing :class:`~exosim.models.signal.Sed` pointing: (:class:`astropy.units.Quantity`, :class:`astropy.units.Quantity`) (optional) telescope pointing direction, expressed ad a tuple of RA and DEC in degrees. Default is ``None`` out: :class:`~exosim.output.output.OutputGroup (optional)` output group """ channel = Channel( parameters=description, wavelength=self.wl_grid, time=self.time_grid, output=out, ) channel.parse_path(light_path=common_path) channel.estimate_responsivity() channel.propagate_foreground() channel.propagate_sources( sources=sources, Atel=self.payloadConfig["Telescope"]["Atel"] ) channel.create_focal_planes() channel.rescale_contributions() channel.populate_focal_plane(pointing) # TODO test if no other stars are present channel.populate_bkg_focal_plane(pointing) if "irf_task" in description["detector"].keys(): channel.apply_irf() channel.populate_foreground_focal_plane() channel.focal_plane.write() channel.frg_focal_plane.write() if channel.bkg_focal_plane: channel.bkg_focal_plane.write() for key, value in channel.frg_sub_focal_planes.items(): value.write()