Source code for pyEDITH.observation

import numpy as np
from .units import *
from . import utils
import logging

logger = logging.getLogger("pyEDITH")


[docs] class Observation: """ A class representing an astronomical observation. This class encapsulates various parameters and methods related to astronomical observations, including target star properties, planet characteristics, observational settings, telescope specifications, instrument details, and detector parameters. Parameters ----------- wavelength : np.ndarray Wavelength array (in microns). nlambd : int Number of wavelength points. SNR : np.ndarray Signal-to-noise ratio array. tp : ndarray Exposure time of every planet (nmeananom x norbits x ntargs array). exptime : ndarray Exposure time for each target and wavelength. fullsnr : ndarray Signal-to-noise ratio for each target and wavelength. td_limit : float Limit placed on exposure times. """ def __init__(self) -> None: """ Initialize the default parameters of the Observation class. Sets the default exposure time limit (td_limit) to a large value. """ # Misc parameters that probably don't need to be changed self.td_limit = 1e20 * TIME # limit placed on exposure times # scalar
[docs] def load_configuration(self, parameters: dict) -> None: """ Load configuration parameters for the observation from a dictionary. This method initializes various observation parameters from the provided dictionary, including wavelength arrays, signal-to-noise ratios, and aperture settings. For IFS mode, it can calculate or regrid the wavelength grid based on specified parameters. Parameters ---------- parameters : dict A dictionary containing observation parameters including wavelengths, SNR values, aperture settings, and observation mode settings. Must include 'observing_mode', 'wavelength', 'snr'. Raises ------ KeyError If required parameters are missing or if regridding is requested without necessary parameters """ self.observing_mode = parameters["observing_mode"] if self.observing_mode not in ["IMAGER", "IFS"]: raise KeyError("Invalid observing mode. Must be 'IMAGER' or 'IFS'.") # -------- INPUTS --------- # Observational parameters if parameters["observing_mode"] == "IMAGER": self.wavelength = ( parameters["wavelength"] * WAVELENGTH ) # wavelength # nlambd array #unit: micron elif ( parameters["observing_mode"] == "IFS" and bool(parameters["regrid_wavelength"]) is False ): self.wavelength = ( parameters["wavelength"] * WAVELENGTH ) # wavelength # nlambd array #unit: micron IFS_resolution = self.wavelength / np.gradient( self.wavelength ) # calculate the resolution from the wavelength grid dlam_um = np.gradient(self.wavelength) if ~np.isfinite(IFS_resolution).any(): logger.warning( "Wavelength grid is not valid. Using default spectral resolution of 140." ) IFS_resolution = 140 * np.ones_like( self.wavelength ) # default resolution dlam_um = self.wavelength / IFS_resolution self.delta_wavelength = dlam_um elif ( parameters["observing_mode"] == "IFS" and bool(parameters["regrid_wavelength"]) is True ): logger.info("Calculating a new wavelength grid and re-gridding spectra...") if "spectral_resolution" not in parameters.keys(): raise KeyError( "regrid_wavelength is True; you must specify new resolution for each spectral channel: parameters['spectral_resolution']." ) if "lam_low" not in parameters.keys(): raise KeyError( "regrid_wavelength is True; you must specify the wavelength boundaries between spectral channels: parameters['lam_low']." ) if "lam_high" not in parameters.keys(): raise KeyError( "regrid_wavelength is True; you must specify the wavelength boundaries between spectral channels: parameters['lam_high']." ) new_lam, new_dlam = utils.regrid_wavelengths( parameters["wavelength"], parameters["spectral_resolution"], parameters["lam_low"], parameters["lam_high"], ) self.wavelength = ( new_lam * WAVELENGTH ) # wavelength # nlambd array #unit: micron self.delta_wavelength = new_dlam * WAVELENGTH self.SNR = parameters["snr"] * DIMENSIONLESS # signal to noise # nlambd array self.CRb_multiplier = float(parameters["CRb_multiplier"]) self.nlambd = len(self.wavelength)
[docs] def set_output_arrays(self): """ Initialize arrays for storing observation results. This method creates and initializes the arrays that will store the calculated exposure times and signal-to-noise ratios for each wavelength point in the observation. """ # Initialize some arrays needed for outputs... self.tp = 0.0 * TIME # exposure time of every planet # (nmeananom x norbits x ntargs array), used in c function # [NOTE: nmeananom = nphases in C code] # NOTE: ntargs fixed to 1. self.exptime = np.full((self.nlambd), 0.0) * TIME # only used for snr calculation self.fullsnr = np.full((self.nlambd), 0.0) * DIMENSIONLESS
[docs] def validate_configuration(self): """ Validate that all required observation parameters are present and correctly formatted. This method checks that all mandatory attributes exist on the observation object and that they have the expected types and units. Raises ------ TypeError If an attribute has an incorrect type ValueError If a Quantity attribute has incorrect units """ expected_args = { "wavelength": WAVELENGTH, "nlambd": int, "SNR": DIMENSIONLESS, "CRb_multiplier": float, } utils.validate_attributes(self, expected_args)