opticam ======= .. py:module:: opticam Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/opticam/analyzer/index /autoapi/opticam/background/index /autoapi/opticam/correctors/index /autoapi/opticam/differential_photometer/index /autoapi/opticam/finders/index /autoapi/opticam/fitting/index /autoapi/opticam/instruments/index /autoapi/opticam/mef_slice/index /autoapi/opticam/noise/index /autoapi/opticam/photometers/index /autoapi/opticam/plotting/index /autoapi/opticam/reducer/index /autoapi/opticam/timing/index /autoapi/opticam/utils/index Classes ------- .. autoapisummary:: opticam.Analyzer opticam.DifferentialPhotometer opticam.BaseBackground opticam.DefaultBackground opticam.BaseLocalBackground opticam.DefaultLocalBackground opticam.BiasCorrector opticam.DarkNoiseCorrector opticam.FlatFieldCorrector opticam.DefaultFinder opticam.Instrument opticam.OPTICAM_MX opticam.MEFSlice opticam.AperturePhotometer opticam.OptimalPhotometer opticam.Reducer Functions --------- .. autoapisummary:: opticam.generate_instrument_json_template opticam.generate_flats opticam.generate_observations opticam.generate_gappy_observations opticam.scan_data Package Contents ---------------- .. py:class:: Analyzer(out_directory, light_curves = None, norm = 'mean', prefix = None, phot_label = None, show_plots = True) Helper class for analyzing OPTICAM light curves. .. py:attribute:: norm :value: 'mean' .. py:attribute:: out_directory .. py:attribute:: prefix :value: None .. py:attribute:: phot_label :value: None .. py:attribute:: show_plots :value: True .. py:method:: join(analyzer) Combine another `Analyzer` instance with the current one. If the new `Analyzer` has light curves with filters that are not present in the current `Analyzer`, those filters will be added. If the new `Analyzer` has light curves with filters that are already present in the current `Analyzer`, those light curves will be merged. Parameters ---------- analyzer : Analyzer The analyzer instance being combined with the current one. Returns ------- Analyzer A new `Analyzer` instance with the combined light curves. .. py:method:: rebin(time_bin_size, method = 'mean') Rebin the light curves, propagating errors accordingly. Returns a new `Analyzer` instance containing the binned light curves. Rebinning uses a common reference time to ensure simultaneity between multiple light curves. Parameters ---------- time_bin_size : Quantity The time bin size. method : Literal['mean', 'sum'], optional The type of binning, by default `'mean'`. Returns ------- Analyzer A new `Analyzer` instance containing the binned light curves. .. py:method:: get_lc(key) Return the light curve for a single key. Parameters ---------- key : str The camera:filter key (e.g., "1:g" for camera 1 with a g filter). Returns ------- TimeSeries The light curve for the key. .. py:method:: plot(save = True, return_fig = False) Plot the light curves. Parameters ---------- save : bool, optional Whether to save the plot, by default `True`. return_fig : bool, optional Whether to return the resulting `Figure` instance, by default `False`. This can be used to make edits to the plot. Returns ------- Figure | None The figure containing the light curves. .. py:method:: fold(period, epoch_time = None, nbins = None, sharey = False, save = True, return_fig = False) Fold the light curves on the given period. Parameters ---------- period : Quantity The period used to fold the light curves. Must have units of time. epoch_time : Time | None, optional The reference time that defines zero phase, by default `None`. If `None`, the first time light curve time value is used. nbins : int | None, optional Bin the folded light curve into this many bins, by default `None`. If `None`, no binning is performed. sharey : bool, optional Whether to share y axes, by default `False`. save : bool, optional Whether to save the figure, by default `True`. return_fig : bool, optional Whether to return the figure, by default `False`. Useful if you want to edit the figure before saving. Returns ------- Table | tuple[Table, Figure] If `return_fig=True`, the folded light curve and resulting figure are returned. Otherwise, just the folded time series is returned. The folded light curve is converted from a `TimeSeries` to a `Table` since the `fold()` method of `TimeSeries` replaces the time column with phase values, causing time formatting errors. .. py:method:: lomb_scargle(frequency = None, scale = 'linear', save = True, return_fig = False) Compute the Lomb-Scargle periodogram for each light curve. Parameters ---------- frequency : Quantity | None, optional The frequency grid, by default `None`. If `None`, the `autofrequency()` method of `astropy`'s `LombScargle` class is used to generate a frequency grid. scale : Literal['linear', 'semilogx', 'semilogy', 'loglog'], optional The scale for the resulting plot, by default `'linear'`. save : bool, optional Whether to save the resulting plot, by default `True`. return_fig : bool, optional Whether to return the figure, by default `False`. Useful if you want to edit the figure before saving. Returns ------- dict[str, LombScargle] | tuple[dict[str, LombScargle], Figure] If `return_fig=True`, the Lomb-Scargle periodograms and figure are returned. Otherwise, only the Lomb-Scargle periodograms are returned. .. py:method:: multiband_lomb_scargle(frequency = None, scale = 'linear', save = True, return_fig = False) Compute the multiband Lomb-Scargle periodogram from all light curves. Parameters ---------- frequency : Quantity | None, optional The frequency grid, by default `None`. If `None`, the `autofrequency()` method of `astropy`'s `LombScargleMultiband` class is used to generate a frequency grid. scale : Literal['linear', 'semilogx', 'semilogy', 'loglog'], optional The scale for the resulting plot, by default `'linear'`. save : bool, optional Whether to save the resulting plot, by default `True`. return_fig : bool, optional Whether to return the figure, by default `False`. Useful if you want to edit the figure before saving. Returns ------- LombScargleMultiband | tuple[LombScargleMultiband, Figure] If `return_fig=True`, the multiband Lomb-Scargle periodogram and figure are returned. Otherwise, only the multiband Lomb-Scargle periodogram is returned. .. py:method:: export_light_curves_to_stingray() Export the light curves from an `astropy.timeseries.TimeSeries` table to a dictionary of `stingray.Lightcurve` instances. Returns ------- dict[str, Lightcurve] The light curves {filter: Lightcurve}. .. py:class:: DifferentialPhotometer(out_directory, show_plots = True) Helper class for creating relative light curves. .. py:attribute:: out_directory .. py:attribute:: show_plots :value: True .. py:attribute:: keys .. py:attribute:: time_key :value: 'BMJD' .. py:attribute:: time_scale :value: 'tdb' .. py:attribute:: t_ref .. py:attribute:: catalogs .. py:method:: get_relative_light_curve(key, target, comparisons, phot_label, prefix = None, match_other_cameras = False, show_diagnostics = True) Compute the relative light curve for a target source with respect to one or more comparison sources. By default, the relative light curve is computed for a single filter. The relative light curve is saved to out_directory/relative_light_curves. To automatically match the target and comparison sources across the other two filters, set match_other_cameras to True. Note that this can incorrectly match sources, so it is recommended to manually check the results. Parameters ---------- key : str The camera:filter key for which the relative light curve will be computed. target : int The catalog ID of the target source. comparisons : int | List[int] The catalog ID(s) of the comparison source(s). phot_label : str The photometry label, used for file reading and labelling. prefix : str, optional The prefix to use when saving the relative light curve (e.g., the target star's name), by default None. match_other_cameras : bool, optional Whether to match the target and comparison(s) IDs to the remaining catalog filters, by default `False`. If `True`, astroalign must be installed. show_diagnostics : bool, optional Whether to show diagnostic plots, by default True. Returns ------- Analyzer An Analyzer object containing the relative light curve(s). .. py:method:: _compute_relative_light_curve(key, target, comparisons, prefix, phot_label, show_diagnostics) Compute the relative light curve for a target source with respect to one or more comparison sources for a given filter. Parameters ---------- key : str The camera:filter key. target : int The catalog ID of the target source. comparisons : List[int] The catalog ID(s) of the comparison source(s). prefix : str | None The prefix to use when saving the relative light curve (e.g., the target star's name), by default None. phot_label : str The photometry label, used for file reading and labelling. show_diagnostics : bool Whether to show diagnostic plots, by default True. Returns ------- TimeSeries | None The relative light curve for the target source with respect to the comparison sources, or None if the light curve could not be computed. .. py:method:: _match_other_cameras(input_key, input_target, input_comparisons, prefix, phot_label, show_diagnostics) Compute the relative light curves for all available filters. Parameters ---------- input_key : str The input filter. input_target : int The target ID in the input filter's catalog. input_comparisons : List[int] The comparison ID(s) in the input filter's catalog. prefix : str | None The prefix to use when saving the relative light curve (e.g., the target source's name). phot_label : str The photometry label. show_diagnostics : bool Whether to show the diagnostic plots. Returns ------- Tuple[TimeSeries, List[str]] The light curves for all available filters and the list of filters that were successfully matched. .. py:method:: _plot_diags(key, target, comparisons, target_df, comp_dfs, phot_label, show) Plot a combination of diagnostic plots for the specified target and comparison sources. Parameters ---------- key : str The image filter. target : int The target ID. comparisons : List[int] The comparison ID(s). target_df : DataFrame The target light curve. comp_dfs : List[DataFrame] The comparison light curve(s). phot_label : str The photometry label. show : bool Whether to show the plots. .. py:method:: _plot_diag(key, comparison1, comparison2, comparison1_df, comparison2_df, phot_label, show) Plot the relative diagnostic light curve for two comparison sources for a given filter. Parameters ---------- key : str The filter to compute the relative light curve. comparison1 : int The catalog ID of the first comparison source. comparison2 : int The catalog ID of the second comparison source. comparison1_df : DataFrame The data frame of the first comparison source. comparison2_df : DataFrame The data frame of the second comparison source. phot_label : str The photometry label. show : bool Whether to show the diagnostic plot. .. py:class:: BaseBackground(box_size) Bases: :py:obj:`abc.ABC` Base class for OPTICAM background estimators. .. py:attribute:: box_size .. py:method:: __call__(image) :abstractmethod: Compute the 2D background for an image. Parameters ---------- image : NDArray The image. Returns ------- Background2D The two-dimensional background. .. py:class:: DefaultBackground(box_size) Bases: :py:obj:`BaseBackground` Default background estimator. .. py:method:: __call__(image) Compute the 2D background for an image. Parameters ---------- image : NDArray The image. Returns ------- Background2D The two-dimensional background. .. py:class:: BaseLocalBackground(r_in_scale = 5, r_out_scale = 7.5, sigma_clip = SigmaClip(sigma=3, maxiters=10)) Bases: :py:obj:`abc.ABC` Base class for local background estimators. .. py:attribute:: r_in_scale :value: 5 .. py:attribute:: r_out_scale :value: 7.5 .. py:attribute:: sigma_clip .. py:method:: __call__(data, position, semimajor_axis, semiminor_axis, theta) :abstractmethod: Compute the local background and its error at a given position (**per pixel**). Parameters ---------- data : NDArray The image data. semimajor_axis : float The (unscaled) semi-major axis of the aperture. semiminor_axis : float The (unscaled) semi-minor axis of the aperture. theta : float The rotation angle of the PSF. position : Tuple[float, float] The x, y position at which to compute the local background. Returns ------- Tuple[float, float] The local background and its error per pixel. .. py:method:: get_annulus(position, semimajor_axis, semiminor_axis, theta) :abstractmethod: Define an annulus at the given position. Parameters ---------- position : NDArray The centre of the annulus. semimajor_axis : float The semimajor standard deviation of the PSF. semiminor_axis : float The semiminor standard deviation of the PSF. theta : float The orientation of the source **in radians**. Returns ------- Aperture The annulus. .. py:method:: get_stats(data, position, semimajor_axis, semiminor_axis, theta) Get the stats of the annulus. Parameters ---------- data : NDArray The image data. position : NDArray The centre of the annulus. semimajor_axis : float The semimajor standard deviation of the PSF. semiminor_axis : float The semiminor standard deviation of the PSF. theta : float The orientation of the source **in radians**. Returns ------- ApertureStats The stats of the annulus. .. py:class:: DefaultLocalBackground(r_in_scale = 5, r_out_scale = 7.5, sigma_clip = SigmaClip(sigma=3, maxiters=10)) Bases: :py:obj:`BaseLocalBackground` Default local background estimator using an elliptical annulus. .. py:method:: get_annulus(position, semimajor_axis, semiminor_axis, theta) Define an annulus at the given position. Parameters ---------- position : NDArray The centre of the annulus. semimajor_axis : float The semimajor standard deviation of the PSF. semiminor_axis : float The semiminor standard deviation of the PSF. theta : float The orientation of the source **in radians**. Returns ------- Aperture The annulus. .. py:method:: __call__(data, position, semimajor_axis, semiminor_axis = None, theta = 0.0) Compute the sigma-clipped local background (mean) and its error (standard deviation) at a given position. Parameters ---------- data : NDArray The image data. error : NDArray The error in the image data. position : NDArray The x, y position at which to compute the local background. semimajor_axis : float The (unscaled) semimajor axis of the aperture. semiminor_axis : float | None, optional The (unscaled) semiminor axis of the aperture, by default `None`. If `None`, it is assumed to be equal to the semimajor axis (i.e., the annulus is circular). theta : float, optional The rotation angle of the PSF, by default 0 (i.e., no rotation). Returns ------- Tuple[float, float] The local background (mean) and its error (standard deviation). .. py:class:: BiasCorrector(out_directory = None, data_directory = None, instrument = OPTICAM_MX(), rebin_factor = 1, *args, **kwargs) Bases: :py:obj:`Corrector` Helper clsas for performing bias corrections. .. py:property:: master_image_path :type: pathlib.Path | None The path to the master calibration image. Returns ------- Path The path to the master calibration image. .. py:method:: correct(image, camera) Subtract the bias from an image. Parameters ---------- image : NDArray[np.float64] The image. camera : str The camera that took the image. Returns ------- tuple[NDArray[np.float64], NDArray[np.float64]] The corrected image and the variance of the master bias image. Raises ------ ValueError If no bias images were found with the given filter. .. py:method:: create_master_images(overwrite = False) Create master bias images for each filter. Parameters ---------- overwrite : bool, optional Whether to overwrite the existing master bias image, by default `False`. .. py:method:: run_checks(data_files_by_key, return_errors = False) Run a series of checks on the corrector to ensure that it is compatible with the data. In this case, check the binning of the science images matches those of the bias images (ignoring self.rebin_factor) and that there are no missing filters. Parameters ---------- data_files_by_key : dict[str, list[MEFSlice] The science image files grouped by camera:filter keys. return_errors : bool, optional Whether to return the number of errors raised, by default `False`. Returns ------- None | int If `return_errors=True`, the number of errors raised is returned. Otherwise, nothing is returned. .. py:method:: _validate_data(files) Ensure that the bias images in the specified directory are valid (i.e., all use the same binning and have exposure times of 0 s). Parameters ---------- files : list[MEFSlice] The bias image files. Returns ------- dict[str, list[MEFSlice]] A dictionary containing the bias image files for each camera. .. py:class:: DarkNoiseCorrector(out_directory = None, data_directory = None, instrument = OPTICAM_MX(), rebin_factor = 1, bias_corrector = None) Bases: :py:obj:`Corrector` Helper class for performing dark noise corrections. .. py:attribute:: bias_corrector :value: None .. py:property:: master_image_path :type: pathlib.Path | None The path to the master calibration image. Returns ------- Path The path to the master calibration image. .. py:method:: correct(image, camera = None, fltr = None, key = None, dark_flux = None) Subtract the dark noise from an image. Parameters ---------- image : NDArray[np.float64] The image. camera : str The camera that took the image. fltr : str The image filter. dark_flux : float | None, optional The exposure-integrated dark current, by default `None`. If the instrument provides a measure of the dark current in the image header, this obviates the need for master darks. Returns ------- NDArray[np.float64] | tuple[NDArray[np.float64], float] The corrected image and the variance of the master dark image. Raises ------ ValueError If no dark images were found with the given filter. .. py:method:: create_master_images(overwrite = False) Create master dark images for each available filter. Parameters ---------- overwrite : bool, optional Whether to overwrite any existing master dark image, by default `False`. .. py:method:: run_checks(data_files_by_key, return_errors = False) Run a series of checks on the corrector to ensure that it is compatible with the data. In this case, check the binning of the science images matches to those of the darks (neglecting self.rebin_factor), there are no missing filters, and the exposure times of the science images matches those of the darks. Parameters ---------- data_files_by_key : dict[str, list[MEFSlice] The science image files grouped by camera:filter keys. return_errors : bool, optional Whether to return the number of errors raised, by default `False`. Returns ------- None | int If `return_errors=True`, the number of errors raised is returned. Otherwise, nothing is returned. .. py:method:: _validate_data(files) Ensure that the dark images in the specified directory are valid (i.e., all use the same binning). Parameters ---------- file_paths : list[MEFSlice] The dark image files Returns ------- dict[str, list[Path]] A dictionary containing the dark image files for each filter. .. py:class:: FlatFieldCorrector(out_directory = None, data_directory = None, instrument = OPTICAM_MX(), rebin_factor = 1, bias_corrector = None, dark_corrector = None) Bases: :py:obj:`Corrector` Helper class for performing flat-field corrections. .. py:attribute:: bias_corrector :value: None .. py:attribute:: dark_corrector :value: None .. py:property:: master_image_path :type: pathlib.Path | None The path to the master flat. Returns ------- Path The path to the master flat. .. py:method:: correct(image, camera = None, fltr = None, key = None) Correct an image for flat-fielding. Parameters ---------- image : NDArray[np.float64] The image. camera : str The camera that took the image. fltr : str The image filter. Returns ------- tuple[NDArray[np.float64], NDArray[np.float64]] The corrected image and the variance of the master flat-field image scaled by the square of the calibrated image. .. py:method:: create_master_images(overwrite = False) Create master flat-field images for each filter. Parameters ---------- bias_corrector : BiasCorrector | None, optional The bias corrector. overwrite : bool, optional Whether to overwrite the existing master flat-field image, by default `False`. .. py:method:: run_checks(data_files_by_key, return_errors = False) Run a series of checks on the corrector to ensure that it is compatible with the data. In this case, check the binning of the science images can be matched to those of the flats (accounting for self.rebin_factor), and that the there are no missing filters. Parameters ---------- data_files_by_key : dict[str, list[MEFSlice]] The science images grouped by camera:filter keys. return_errors : bool, optional Whether to return the number of errors raised, by default `False`. Returns ------- None | int If `return_errors=True`, the number of errors raised is returned. Otherwise, nothing is returned. .. py:method:: _validate_data(files) Ensure that the flat-field images in the specified directory are valid (i.e., all use the same binning). Parameters ---------- file_paths : list[MEFSlice] The flat-field image files. Returns ------- dict[str, list[MEFSlice]] A dictionary containing the paths to the flat-field image files grouped by each filter. .. py:method:: _dark_corrector_is_valid() Check that the dark images have the same exposure time as the flat-field images. Returns ------- tuple[bool, float, float] If the exposure times are equal, returns `True, 0., 0.,`. Otherwise, returns `False, flat_exposure_time, dark_exposure_time`. .. py:class:: DefaultFinder(npixels, border_width = 0) Default source finder. Combines image segmentation with source deblending. .. py:attribute:: border_width :value: 0 .. py:attribute:: finder .. py:method:: __call__(data, threshold) .. py:function:: generate_instrument_json_template(out_directory) Generate a template JSON file that can be used to define an `Instrument`. Parameters ---------- out_directory : Path | str The path to the directory to which the template is saved. .. py:class:: Instrument Bases: :py:obj:`abc.ABC` Base class for instruments. Parameters ---------- location : EarthLocation The location of the observatory as an `astropy.coordinates.EarthLocation` object. pixel_scales : dict[str, float] The pixel scales for each camera in arcsec/pixel {camera: pixel scale}. binning_kw : str, optional The binning keyword, by default "BINNING". camera_kw : str, optional The keyword that uniquely identifies the camera that took the image, by default "INSTRUME". For single-camera instruments, this keyword doesn't matter. For multi-camera instruments, however, it is used to apply calibrations like flats correctly. dark_curr_kw : str, optional The dark current keyword, by default "DARKCURR". Dark current values are assumed to be in electrons/pixel. dateobs_kw : str, optional The observation date keyword, by default "DATE-OBS". By default, observation dates are assumed to be in ISO 8601/FITS format (YYYY-MM-DDTHH:MM:SS[.sss]). dec_kw : str, optional The DEC keyword, by default "DEC". DEC values are assumed to be in units of degrees. exptime_kw : str, optional The exposure time keyword, by default "EXPTIME". Exposure times are assumed to be in units of seconds. filter_kw : str, optional The filter keyword, by default "FILTER". gain_kw : str, optional The gain keyword, by default "GAIN". Gain values are assumed to be in units of electrons/ADU. ra_kw : str, optional The RA keyword, by default "RA". RA values are assumed to be in units of hour angle. read_noise_kw : str, optional The read noise keyword, by default "RDNOISE". .. py:attribute:: location :type: astropy.coordinates.EarthLocation .. py:attribute:: pixel_scales :type: dict[str, float] .. py:attribute:: binning_kw :type: str :value: 'BINNING' .. py:attribute:: camera_kw :type: str :value: 'INSTRUME' .. py:attribute:: dark_curr_kw :type: str :value: 'DARKCURR' .. py:attribute:: dateobs_kw :type: str :value: 'DATE-OBS' .. py:attribute:: dec_kw :type: str :value: 'DEC' .. py:attribute:: exptime_kw :type: str :value: 'EXPTIME' .. py:attribute:: filter_kw :type: str :value: 'FILTER' .. py:attribute:: gain_kw :type: str :value: 'GAIN' .. py:attribute:: ra_kw :type: str :value: 'RA' .. py:attribute:: read_noise_kw :type: str :value: 'RDNOISE' .. py:method:: run_checks(file, return_errors = False) Check that the instrument can be used to parse an image's header. Parameters ---------- file : MEFSlice | Path The file to use for checking the instrument. If a `Path` or `str` instance is specified, the first HDU of the corresponding FITS file is used. return_errors : bool, optional Whether to return the number of errors raised, by default `False`. Returns ------- None | int If `return_errors=True`, returns the number of errors raised. Otherwise, nothing is returned. Raises ------ ValueError If the header of the file could not be read. .. py:method:: get_mjd(file = None, header = None) Given the path to a FITS file, or its header, parse its observation date into *local* Modified Julian Date (MJD). Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- float The local MJD of the image. .. py:method:: get_camera(file = None, header = None) Given the path to a FITS file, get the corresponding camera. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- str A unique identifier for the camera. .. py:method:: get_sky_coord(file = None, header = None) Given the path to a FITS file, get the corresponding sky coordinates. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- SkyCoord The sky coordinates of the image. .. py:method:: get_dark_flux(file = None, header = None) Given the path to a FITS file, get the corresponding dark flux (i.e., the exposure-integrated dark current). If the instrument does not list a dark current in the image headers, the returned dark flux can be `None`. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- float | None The dark flux in the image. .. py:method:: get_binning(file = None, header = None) Get the binning of an image using the instrument's `binning_kw` attribute. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- str The binning of the image. .. py:method:: get_filter(file = None, header = None) Get the filter of an image using the instrument's `filter_kw` attribute. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- str The filter of the image. .. py:method:: get_read_noise(file = None, header = None) Get the read noise in an image, in electrons per pixel, using the instrument's `read_noise_kw` attribute. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- float The read noise in the image. .. py:method:: from_json(file_path = None, config = None) :classmethod: Create an instrument from a configuration file/dictionary. Parameters ---------- file_path : Path | str | None, optional The path to the configuration file, by default `None`. If `None`, a dictionary must be passed to `config`. If a value is passed to `file_path`, `config` is ignored. config : dict[str, Any] | None, optional The configuration dictionary, by default `None`. If `None`, a path must be passed to `file_path`. If a value is passed to `file_path`, `config` is ignored. Returns ------- Instrument The configured instrument. Raises ------ AssertionError If required keys are missing from the configuration file/dictionary. .. py:method:: to_json(file_path) Export the instrument configuration to a JSON file. Parameters ---------- file_path : Path | str The location to which the file is written. If `save_path` does not include the file name, the file will be saved as `instrument_config.json`. .. py:class:: OPTICAM_MX(location=EarthLocation.from_geodetic(lon=-115.463611 * u.deg, lat=31.044167 * u.deg, height=2790 * u.m), pixel_scales={'1': 0.1397, '2': 0.1406, '3': 0.1661}, dateobs_kw='UT', exptime_kw='EXPOSURE') Bases: :py:obj:`Instrument` OAN-SPM OPTICAM-MX instrument. .. py:method:: get_mjd(file = None, header = None) Get the timestamp of the image in MJD. OPTICAM uses a "UT" keyword to represent an image's timestamp in ISO format. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- float The timestamp of the image in MJD format. .. py:method:: get_camera(file = None, header = None) Given the path to a FITS file, get the corresponding camera. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- str A unique identifier for the camera. .. py:method:: get_read_noise(file = None, header = None) Get the read noise in an image, in electrons per pixel, using the instrument's `read_noise_kw` attribute. Parameters ---------- file : MEFSlice | None, optional The `MEFSlice` instance corresponding to the file, by default `None`. If `None`, a `Header` must be passed to `header` instead. header : Header, optional The header of the FITS file, by default `None`. If `None`, a `MEFSlice` must be passed to `file` instead. Returns ------- float The read noise in the image. .. py:class:: MEFSlice Helper class to represent a slice of a Multi-extension FITS (MEF) file. Parameters ---------- path : Path The file path. ext : int The slice's extension number. .. py:attribute:: path :type: pathlib.Path .. py:attribute:: ext :type: int .. py:property:: key :type: str The file path and extension number combined to create a uniquely identifiable string. Returns ------- str The uniquely identifiable string. .. py:method:: get_header() Get the slice's header. Returns ------- Header The slice's header. .. py:method:: get_data() Get the slice's data. Returns ------- NDArray[np.float64] The slice's data. .. py:method:: get_data_and_header() Get the slice's data and header. Returns ------- tuple[NDArray[np.float64], Header] The slice's data and header. .. py:class:: AperturePhotometer(semimajor_axis = None, semiminor_axis = None, orientation = None, forced = False, source_matching_tolerance = 5.0, local_background_estimator = None) Bases: :py:obj:`BasePhotometer` A photometer for performing aperture photometry. .. py:attribute:: semimajor_axis :value: None .. py:attribute:: semiminor_axis :value: None .. py:attribute:: orientation :value: None .. py:method:: compute(image, bias_var, dark_var, flat_var, background_rms, cat_coords, image_coords, psf_params, read_noise) Compute the fluxes of the catalogued sources from the given image. Parameters ---------- image : NDArray The image. If `self.local_background_estimator` is undefined, this image will be background subtracted. bias_var : float | NDArray The bias correction variance term. dark_var : float | NDArray The dark noise correction variance term. flat_var : float | NDArray The flat-field correction variance term scaled by the square of the calibrated image. background_rms : NDArray | None The background RMS. May be `None` if `self.local_background_estimator` is defined. cat_coords : NDArray The source coordinates in the catalogue. image_coords : NDArray | None The source coordinates in the image. If `match_sources` is True, this will be used to match sources in the image to sources in the catalogue. psf_params : Dict[str, float] The PSF parameters for the camera used to take the image. This parameter is defined in the catalogue and has the following keys: 'semimajor_sigma' (in pixels), 'semiminor_sigma' (in pixels), and 'orientation' (in *degrees*). read_noise : float The detector's read noise. Returns ------- Dict[str, List] The photometry results. .. py:method:: compute_aperture_flux(image, bias_var, dark_var, flat_var, background_rms, position, psf_params, read_noise) Compute the aperture flux of a source in the image. Parameters ---------- image : NDArray The image. bias_var : float | NDArray The bias correction variance term. dark_var : float | NDArray The dark noise correction variance term. flat_var : float | NDArray The flat-field correction variance term scaled by the square of the calibrated image. background_rms : NDArray | None The background RMS. May be `None` if `self.local_background_estimator` is defined. position : NDArray The position of the source. psf_params : Dict[str, float] The PSF parameters for the camera used to take the image. This parameter is defined in the catalogue and has the following keys: 'semimajor_sigma' (in pixels), 'semiminor_sigma' (in pixels), and 'orientation' (in *degrees*). read_noise : float The instrument's read noise. Returns ------- Tuple[float, float] | Tuple[float, float, float, float, float] The flux and its error. If `local_background_estimator` is defined, the local background and its error are also returned. .. py:method:: get_aperture(position, psf_params) .. py:method:: get_aperture_area(psf_params) Get the area of the aperture. Parameters ---------- psf_params : Dict[str, float], The PSF parameters. Returns ------- float The area of the aperture. .. py:class:: OptimalPhotometer(forced = False, source_matching_tolerance = 5.0, local_background_estimator = None) Bases: :py:obj:`BasePhotometer` A photometer that implements the optimal photometry method described in Naylor 1998, MNRAS, 296, 339-346. .. py:method:: compute(image, bias_var, dark_var, flat_var, background_rms, cat_coords, image_coords, psf_params, read_noise) Compute the fluxes of the catalogued sources from the given image. Parameters ---------- image : NDArray The image. If `self.local_background_estimator` is undefined, this image will be background subtracted. bias_var : float | NDArray The bias correction variance term. dark_var : float | NDArray The dark noise correction variance term. flat_var : float | NDArray The flat-field correction variance term scaled by the square of the calibrated image. background_rms : NDArray | None The background RMS. May be `None` if `self.local_background_estimator` is defined. cat_coords : NDArray The source coordinates in the catalogue. image_coords : NDArray | None The source coordinates in the image. If `match_sources` is True, this will be used to match sources in the image to sources in the catalogue. psf_params : Dict[str, float] The PSF parameters for the camera used to take the image. This parameter is defined in the catalogue and has the following keys: 'semimajor_sigma' (in pixels), 'semiminor_sigma' (in pixels), and 'orientation' (in *degrees*). read_noise : float The detector's read noise. Returns ------- Dict[str, List] The photometry results. .. py:method:: compute_optimal_flux(image, bias_var, dark_var, flat_var, background_rms, position, psf_params, read_noise) Compute the optimal flux of a source in the image as described in Naylor 1998, MNRAS, 296, 339-346. Parameters ---------- image : NDArray The image. bias_var : float | NDArray The bias correction variance term. dark_var : float | NDArray The dark noise correction variance term. flat_var : float | NDArray The flat-field correction variance term scaled by the square of the calibrated image. background_rms : NDArray | None The background RMS. May be `None` if `self.local_background_estimator` is defined. position : NDArray The position of the source in the image, given as (y, x) coordinates. psf_params : Dict[str, float] The PSF parameters for the camera used to take the image. This parameter is defined in the catalogue and has the following keys: 'semimajor_sigma' (in pixels), 'semiminor_sigma' (in pixels), and 'orientation' (in *degrees*). read_noise : float The instrument's read noise. Returns ------- Tuple[float, float] | Tuple[float, float, float, float] The flux and flux error. If `local_background_estimator` is defined, the background and its error are also returned. .. py:class:: Reducer(out_directory, data_directory, aperture_selector = np.median, background = None, barycenter = True, bias_corrector = None, dark_corrector = None, finder = None, flat_corrector = None, instrument = OPTICAM_MX(), number_of_processors = cpu_count() // 2, rebin_factor = 1, remove_cosmic_rays = False, show_plots = True, threshold = 5, verbose = True) Class for reducing astronomical images. .. py:attribute:: verbose :value: True .. py:attribute:: out_directory .. py:attribute:: logger .. py:attribute:: data_directory .. py:attribute:: rebin_factor :value: 1 .. py:attribute:: instrument .. py:attribute:: aperture_selector .. py:attribute:: threshold :value: 5 .. py:attribute:: remove_cosmic_rays :value: False .. py:attribute:: barycenter :value: True .. py:attribute:: number_of_processors .. py:attribute:: show_plots :value: True .. py:attribute:: bias_corrector :value: None .. py:attribute:: dark_corrector :value: None .. py:attribute:: flat_corrector :value: None .. py:attribute:: reference_files .. py:attribute:: transforms .. py:attribute:: unaligned_files :value: [] .. py:attribute:: catalogs :type: dict[str, astropy.table.QTable] .. py:attribute:: psf_params .. py:method:: _log_params() Log the input parameters of a `Reducer` instance to file. Parameters ---------- reducer : Reducer The `Reducer` instance. .. py:method:: create_catalogs(max_catalog_sources = 15, n_alignment_sources = 15, transform_type = 'affine', rotation_limit = None, translation_limit = None, scale_limit = None, overwrite = False) Initialise the source catalogs for each camera. Some aspects of this method are parallelised for speed. Parameters ---------- max_catalog_sources : int, optional The maximum number of sources to include in the catalog, by default 30. Since source IDs are ordered by brightness, the brightest `max_catalog_sources` sources are included in the catalog. n_alignment_sources : int, optional The (maximum) number of sources to use for image alignment, by default 30. If `transform_type='translation'`, `n_alignment_sources` must be >= 1, and the brightest `n_alignment_sources` sources are used for image alignment. If `transform_type='affine'`, `n_alignment_sources` must be >= 3 and represents that *maximum* number of sources that *may* be used for image alignment. transform_type : Literal['affine', 'translation'], optional The type of transform to use for image alignment, by default 'affine'. 'translation' performs simple x, y translations, while 'affine' uses `astroalign.find_transform()`. 'affine' is generally more robust (and is therefore the default) while 'translation' can work with fewer sources. rotation_limit : float, optional The maximum rotation limit (in degrees) for affine transformations, by default `None` (no limit). scale_limit : float, optional The maximum scale limit for affine transformations, by default `None` (no limit). translation_limit : float | int | list[float | int] | None, optional The maximum translation limit for both types of transformations, by default `None` (no limit). Can be a scalar value that applies to both x- and y-translations, or an iterable where the first value defines the x-translation limit and the second value defines the y-translation limit. overwrite : bool, optional Whether to overwrite existing catalogs, by default False. .. py:method:: _align_batch(batch, reference_image_shape, reference_coords, transform_type, rotation_limit, scale_limit, translation_limit, n_alignment_sources) Align a batch of images with respect to some reference coordinates. Parameters ---------- batch: list[MEFSlice] The files. reference_image_shape : tuple[int] The reference image's shape. reference_coords : NDArray The source coordinates in the reference image. transform_type : Literal['affine', 'translation'] The type of transform to use for image alignment. rotation_limit : float | None The maximum rotation limit (in degrees) for image alignment. scale_limit : float | None The maximum scaling limit for image alignment. translation_limit : list[float] | None The maximum translation limit for image alignment. n_alignment_sources : int The (maximum) number of sources to use for image alignment. Returns ------- tuple[NDArray[np.float64], dict[str, list[float]], dict[str, dict[str, float]], list[tuple[str, str]]] The stacked image, transforms, background results, and log messages. .. py:method:: _valid_transform(file, transform, rotation_limit, scale_limit, translation_limit) Find whether a transform is valid given some transform limits. Parameters ---------- file : MEFSlice The path to the file being transformed. transform : SimilarityTransform The transform. rotation_limit : float | None The rotation limit. scale_limit : float | None The scale limit. translation_limit : list[float] | None The translation limit. Returns ------- tuple[bool, None | tuple[str, str]] Whether the transform is valid. If not, a log message is also returned as a tuple: (log level, log string). .. py:method:: plot_background_meshes(save = False) Plot the background mesh over an image from each filter to verify it's appropriately sized. If stacked catalog images exist, those will be used. Otherwise, a random image will be chosen for each filter. Parameters ---------- save : bool, optional Whether to save the plot, by default `False`. .. py:method:: plot_growth_curves(targets = None, save = False) Plot the growth curves for the sources identified in the catalog images. The resulting plots are saved to out_directory/diag/growth_curves as PDF files. Parameters ---------- targets : dict[str, int | list[int]] | None, optional The targets for which growth curves will be created, by default `None` (growth curves are created for all catalog sources). To create growth curves for specific targets, pass a dictionary with keys listing the desired filters and values listing each filter's correpsonding target(s). For example: ``` # plot growth curves for the three brightest sources in each catalog plot_growth_curves( targets = { 'g': [1, 2, 3], 'r': [1, 2, 3], 'i': [1, 2, 3], }, ) ``` save : bool, optional Whether to save the plots, by default `False`. .. py:method:: plot_psfs() Plot the PSFs for the catalog sources. .. py:method:: plot_snrs(save = False) Plot the signal-to-noise ratios for each catalogued source in the reference images. Parameters ---------- save : bool, optional Whether to save the plot, by default `False`. .. py:method:: plot_noise(save = False) Plot the noise characterisation for each reference image. Parameters ---------- save : bool, optional Whether to save the plot, by default 'False'. .. py:method:: create_gifs(keep_frames = True, overwrite = False) Create alignment gifs for each camera. Some aspects of this method are parallelised for speed. The frames are saved in out_directory/diag/*_gif_frames and the GIFs are saved in out_directory/cat. Parameters ---------- keep_frames : bool, optional Whether to save the GIF frames in out_directory/diag, by default True. If False, the frames will be deleted after the GIF is saved. overwrite : bool, optional Whether to overwrite existing GIFs, by default False. .. py:method:: plot_apertures(photometer, targets = None, save = False) Plot the apertures over each source. Parameters ---------- photometer : AperturePhotometer The `AperturePhotometer` instance. If a local background estimator has been defined, this will also be plotted. targets : dict[str, int] | dict[str, list[int]] | dict[str, list[int] | int] | None The targets for which apertures will be plotted, by default `None` (apertures are plotted for all sources). To plot apertures for specific targets, pass a dictionary with keys listing the desired filters and values listing each filter's correpsonding target(s). For example: ``` # plot apertures for the three brightest sources in each filter photometer = opticam.AperturePhotometer() plot_apertures( photometer=photometer, targets = { 'g': [1, 2, 3], 'r': [1, 2, 3], 'i': [1, 2, 3], }, ) ``` save : bool, optional Whether to save the plots, by default `False`. .. py:method:: photometry(photometer, overwrite = False) Perform photometry on the catalogs using the provided photometer. Parameters ---------- photometer : BasePhotometer The photometer. Should be a subclass of `BasePhotometer`, or implement a `compute` method that follows the `BasePhotometer` interface. overwrite : bool, optional Whether to overwrite any existing light curves files computed using the same photometer, by default `False`. .. py:method:: _perform_photometry(file, photometer, cat_coords, key) Perform photometry on a file. Parameters ---------- file : MEFSlice The file. photometer : BasePhotometer The photometer to use. cat_coords : NDArray The coordinates of the sources in the catalog. key : str The camera:filter key. Returns ------- dict[str, list] The photometry results. .. py:method:: update_unaligned_files(files) Add one or more files to the list of unaligned files. Unaligned files are skipped when performing photometry. Parameters ---------- files : MEFSlice | list[MEFSlice] The file or files. .. py:function:: generate_flats(out_directory, n_flats = 5, binning_scale = 4, overwrite = False) Create synthetic flat-field images. Parameters ---------- out_directory : Path | str The directory to save the data. n_flats : int, optional The number of flats per camera, by default 5. binning_scale : int, optional The binning scale of the flat-field images, by default 4 (512x512). overwrite : bool, optional Whether to overwrite data if they currently exist, by default False. .. py:function:: generate_observations(out_directory, n_images = 100, circular_aperture = True, binning_scale = 4, overwrite = False) Create synthetic observation data for testing and following the tutorials. Parameters ---------- out_directory : Path | str The directory to save the data. n_images : int, optional The number of images to create, by default 100. circular_aperture : bool, optional Whether to apply a circular aperture shadow to the images, by default True. binning_scale : int, optional The binning scale of the images, by default 4 (512x512). overwrite : bool, optional Whether to overwrite data if they currently exist, by default False. .. py:function:: generate_gappy_observations(out_directory, n_images = 1000, circular_aperture = True, binning_scale = 4, overwrite = False) Create synthetic observation data for testing and following the tutorials. Parameters ---------- out_directory : Path | str The directory to save the data. n_images : int, optional The number of images to create, by default 100. circular_aperture : bool, optional Whether to apply a circular aperture shadow to the images, by default True. binning_scale : int, optional The binning scale of the images, by default 4 (512x512). overwrite : bool, optional Whether to overwrite data if they currently exist, by default False. .. py:function:: scan_data(out_directory, data_directory, instrument, barycenter = True, verbose = True, return_output = False, logger = None, number_of_processors=cpu_count() // 2) Check that the data are self-consistent. Parameters ---------- out_directory : Path | str The path to the directory in which output files will be saved. data_directory : Path | str The path to the directory containing the data. instrument : Instrument The instrument that produced the data. barycenter : bool, optional Whether to apply a Barycentric correction to the image time stamps, by default `True`. Only relevant if `return_output=True`. verbose : bool, optional Whether to print any output info, by default `True`. return_output : bool, optional Whether to return any output, by default `False`. logger : Logger | None, optional The logger, by default `None`. number_of_processors : _type_, optional The number of processors to use, by default `cpu_count() // 2`. Returns ------- None | tuple[dict[str, list[MEFSlice]], int, dict[str, float], list[MEFSlice], float]: If `return_output=True`, the files grouped by camera, binning scale, Barycentric MJD dates, ignored files, and the reference date are returned. Otherwise, nothing is returned.