Pandeia Tutorials
How to Use this Article
In this article, several examples on how to use Pandeia for Roman are given. Prior to reading these examples, users should consult the article Overview of Pandeia for information on how to install Pandeia and the necessary supporting data files, as well as for configuration information for Pandeia simulations. All calculations in this article were performed using Pandeia and reference data This documentation is written for Pandeia version 2024.12 (released on December 11, 2024).
Example 1: Computing the Signal-to-Noise Ratio
Running the code below will generate output in the form of a dictionary that contains all of the information from the Pandeia Engine Report. This is largely the standard way of running Pandeia where the properties of the instrumental set up and astronomical scene are specified.
Description of Code Snippet
The configuration below uses the default point source normalized to an AB magnitude of 25, the WFI multi-accumulation (MA) table "c2a_img_hlwas
" (a MA table optimized for an early design of the High Latitude Wide Area Survey) with no truncation (139.15 seconds of total exposure time), and the F129 imaging filter. The Appendix: WFI MultiAccum Tables article in the Roman APT User's Guide provides and overview of MA tables in Roman at this time. See the article Overview of Pandeia for more information.
Python Implementation
from pandeia.engine.perform_calculation import perform_calculation from pandeia.engine.calc_utils import build_default_calc # Get Default Parameters calc = build_default_calc('roman', 'wfi', 'imaging') # Set the global variable for the filter name (change to any valid filter) FILTER = 'f129' # Modify defaults to simulate a 25th AB magnitude source mag = 25 calc['scene'][0]['spectrum']['normalization']['norm_flux'] = mag calc['scene'][0]['spectrum']['normalization']['norm_fluxunit'] = 'abmag' # Set number of exposures and filter nexp = 3 calc['configuration']['detector']['nexp'] = nexp calc['configuration']['instrument']['filter'] = FILTER # Run calculation and return signal-to-noise ratio report = perform_calculation(calc) SNR = report['scalar']['sn'] print(f'Estimated S/N: {SNR:.2f}')
Warnings from Running the Code Block
This step may generate a WARNING from synphot that the spectrum is extrapolated, which can be ignored.
Running
Pandeia
for Roman will likely return a warning such as: if np.log(abs(val)) < -1*precision and val != 0.0
. This is related to a JWST-specific test for float precision, and can be ignored in this case.
Result from the Example
This calculation should output an estimated signal-to-noise of 11.89 .
Example 2: Calculating the Corresponding Magnitude for a Given Setup
In this example, it is assumed that the user has an exposure configuration and is interested in understanding the corresponding magnitude for a given signal-to-noise ratio and for a specific observing setup. This application may be common for Roman when users are exploring the Roman science data archive.
The default observational setup for Roman will be used. As in the previous example, the MA table is set to the "High Latitude Wide Area Survey – Imaging" table with 5 resultants. The Table of Code Inputs for Limiting Magnitude Calculation summarizes the parameters that can be adjusted in the Python implementation of this example and their presets. Starting with this example, users can change these parameters to better match their scientific use case.
Description of Code Snippet
The output from the code is the the
limiting magnitude
of a source with
SN
= 5
from
NEXP
= 10
FILTER
='f129'
; the code will assume a flat SED. The calculation is determined by setting up a helper function to optimize the signal-to-noise at the input magnitude and a method that computes the magnitude at a given signal-to-noise given the number of exposures. The latter function sets up the build_default_calc
for Roman and performs the
Pandeia
simulations over a range of magnitudes iteratively to find the best match magnitude for the specified signal-to-noise. The parameters summarized in the Table of Code Inputs for Corresponding Magnitude Calculation are input near the end of the code-block and can be easily modified for the use case of interest. The result of this code is given at the end of the code block for a user to confirm their execution of the code.
Table of Code Inputs for Corresponding Magnitude Calculation
Specified Input | Description | Parameter in Code Example | Value in Code Example |
---|---|---|---|
signal-to-noise | the value that is useful for the science case being investigated | SN | 5 |
number of exposures | the number of individual exposures of a given Multi-Accumulation sequence | NEXP | 10 |
filter | the filter used in the observation | FILTER | 'f129' |
Python Implementation
from pandeia.engine.calc_utils import build_default_calc from pandeia.engine.perform_calculation import perform_calculation from scipy import interpolate import numpy as np def compute_mag(filt, nexp, bracket=(18, 30)): """ Method to compute the magnitude from S/N and number of exposures Parameters ---------- filt : str Name of Roman WFI filter nexp : int Number of exposures bracket : tuple Range of magnitudes to test. default: (18, 30) Returns ------- mag_range : float An array of magnitudes used to compute the SNRs computed_snrs: float An array of computed SNRs from Pandeia calculations """ # Set up default Roman observation calc = build_default_calc('roman', 'wfi', 'imaging') # Modify defaults to place a source with an AB magnitude calc['scene'][0]['spectrum']['normalization']['norm_fluxunit'] = 'abmag' calc['scene'][0]['spectrum']['normalization']['norm_waveunit'] = 'um' # Set number of exposures and filter calc['configuration']['detector']['nexp'] = nexp calc['configuration']['instrument']['filter'] = filt # Create an array of magnitudes range of interest mag_range = np.arange(bracket[0], bracket[1]+1, 1) # Create empty lists to save the computations computed_snrs = [] # Compute the SNRs for a given magnitude for m in range(len(mag_range)): mag = mag_range[m] calc['scene'][0]['spectrum']['normalization']['norm_flux'] = mag report = perform_calculation(calc) computed_snrs.append(report['scalar']['sn']) return mag_range, computed_snrs def _mag2sn_(mag_range, computed_snrs, sntarget): """ Calculate a magnitude given a desired SNR by interpolating (computed_snrs, mag_range) from compute_mag Parameters ---------- mag_range: float An array of magnitudes used in calculating a range of SNRs in compute_mag computed_snrs: float An array of computed SNR given the mag_range using Pandeia calculation object sntarget: float Required S/N """ interpolator = interpolate.interp1d(computed_snrs, mag_range) mag = interpolator(sntarget) return mag # Required S/N and number of exposures sn = 5. nexp = 10 FILTER = 'f129' # Run minimizer function to estimate the magnitude given sn and nexp mag_range, computed_snrs = compute_mag(FILTER, nexp) mag = _mag2sn_(mag_range, computed_snrs, sn) print(f'Estimated magnitude: {mag:.2f}')
Result from the Example
This calculation should output an estimated limiting magnitude of 26.77 mag at a signal-to-noise of 5 based on the inputs from the Table of Code Inputs for Corresponding Magnitude Calculation.
Example 3: Determining the Optimal Number of Exposures
In this example, we assume the user has a required signal-to-noise at a desired magnitude limit, and wishes to know the number of exposures, for the default MA table, required to achieve these observational results.
Description of Code Snippet
In this case, the inputs to the code are
SN
,
MAG
, and
FILTER
, which are described in the Table of Code Inputs for Determining Number of Exposures. The output will be
NEXP
. The code will assume a flat spectral energy distribution (SED). The calculation is determined by setting up a helper function to optimize the signal-to-noise at the input magnitude and a method that computes the number of exposures at a given signal-to-noise given the source magnitude. The latter function sets up the build_default_calc
for Roman and iteratively performs the
Pandeia
simulations over a range of exposures to find the best match. The parameters summarized in the Table of Code Inputs for Determining Number of Exposures are input near the end of the code-block and can be easily modified for the use case of interest. The result of this code is given at the end of the code block.
Table of Code Inputs for Determining Number of Exposures
Specified Input | Description | Parameter in Code Example | Value in Code Example |
---|---|---|---|
signal-to-noise | value that is useful for the science case being investigated | SN | 20 |
source magnitude | magnitude in ABMag for the source of interest | MAG | 26 |
filter | filter used in the observation | FILTER | 'f129' |
Python Implementation
from scipy.optimize import minimize_scalar from pandeia.engine.calc_utils import build_default_calc from pandeia.engine.perform_calculation import perform_calculation def _nexp2sn_(nexp, calc, sntarget): """ Helper function to optimize the S/N given a number of exposures. """ calc['configuration']['detector']['nexp'] = int(nexp) etc = perform_calculation(calc)['scalar'] return (sntarget - etc['sn'])**2 def compute_nexp(filt, sn, mag, bracket=(1, 1000), xtol=0.1): """ Method to compute the number of exposures from S/N and magnitude Parameters ---------- filt : str Name of Roman WFI filter sn : float Required S/N mag : float AB Magnitude of source bracket : tuple, default (1, 1000) Range of magnitudes to test xtold: float, default 0.1 Target tolerance for minimizer Returns ------- nexp : float Optimal number of exposures for specified S/N and magnitude report: dict Pandeia dictionary with optimal parameters exptime: float Exposure time for optimal observation """ # Setup default Roman observation calc = build_default_calc('roman', 'wfi', 'imaging') # Modify defaults to place a source with an AB magnitude calc['scene'][0]['spectrum']['normalization']['norm_flux'] = mag calc['scene'][0]['spectrum']['normalization']['norm_fluxunit'] = 'abmag' calc['scene'][0]['spectrum']['normalization']['norm_waveunit'] = 'um' # Set filter calc['configuration']['instrument']['filter'] = filt # Check that the minimum of 1 exposure has a S/N lower than requested, # otherwise there is no sense in attempting to minimize nexp. calc['configuration']['detector']['nexp'] = 1 report = perform_calculation(calc) if report['scalar']['sn'] > sn: nexp = 1 else: res = minimize_scalar(_nexp2sn_, bracket=bracket, bounds=bracket, args=(calc, sn), method='bounded', options={'xatol':xtol}) # Take the optimization result and set it to nexp # 'x' is the solution array in the optimization result object # For more details on the minimize_scalar function, refer to https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize_scalar.html nexp = int(res['x']) calc['configuration']['detector']['nexp'] = nexp report = perform_calculation(calc) # This generally returns a S/N less than the required amount. # Let's ensure that we get *AT LEAST* the required S/N for two reasons: # 1) Better to err on the side of caution # 2) Make code consistent with the above if-clause if report['scalar']['sn'] < sn: nexp += 1 exptime = report['scalar']['total_exposure_time'] return nexp, report, exptime # Desired magnitude and S/N mag = 26. sn = 20. FILTER = 'f129' # Run minimizer function nexp, etc, exptime = compute_nexp(FILTER, sn, mag) # Print reported numbers print(f'Number of exposures: {nexp}') print(f'Actual S/N reached: {etc["scalar"]["sn"]:.2f}') print(f'Exposure time: {exptime:.2f}')
Warnings Issued by Running this Code
This step may generate a WARNING from synphot that the spectrum is extrapolated, which may be ignored. There may be an additional WARNING that the signal-to-noise for a single exposure is larger than what was requested, which may also be ignored.
Result from the Example
This calculation should output
48
exposures, a signal-to-noise reached of
20.12
, and an exposure time of
6679.14
seconds.
Since nexp must be an integer, the signal-to-noise returned will be at least the required value, but could be a higher value. The value of the returned signal-to-noise can be significantly higher than the requested value when the inferred nexp is small.
Example 4: Modifying the Spectral Energy Distribution (SED)
A scientific goal may require specifying something more complex than a flat SED (as assumed in other examples). In this instance, we assume that the SED is determined by a star selected from a grid of Phoenix models (the only supported stellar models at this time).
Description of Code Snippet
The code will simulate a
mag
= 25 AB magnitude source in
FILTER
= 'f129'
with
nexp
= 3
(using the default MA table). A step is added, however, to modify the SED shape from the default flat spectrum; the user sets the
sed_type
to 'phoenix'
and then specifies the
key
as 'a0v'
, which is a star of type A0V (i.e., an A0 main-sequence star). A summary of these options is given in Pre-Configured Spectral Energy Distributions section of the article Overview of Pandeia.
Python Implementation
from pandeia.engine.perform_calculation import perform_calculation from pandeia.engine.calc_utils import build_default_calc # Get Default Parameters calc = build_default_calc('roman', 'wfi', 'imaging') # Set the global variable for the filter name (change to any valid filter) FILTER = 'f129' # Modify defaults to simulate a 25th AB magnitude source mag = 25 calc['scene'][0]['spectrum']['normalization']['norm_flux'] = mag calc['scene'][0]['spectrum']['normalization']['norm_fluxunit'] = 'abmag' # Set number of exposures and filter nexp = 3 calc['configuration']['detector']['nexp'] = nexp calc['configuration']['instrument']['filter'] = FILTER # Modify SED shape calc['scene'][0]['spectrum']['sed']['sed_type'] = 'phoenix' calc['scene'][0]['spectrum']['sed']['key'] = 'a0v' # Run calculation and return signal-to-noise ratio report = perform_calculation(calc) SNR = report['scalar']['sn'] print(f'Estimated S/N: {SNR:.2f}')
Result from the Example
This calculation should output an estimated signal-to-noise ratio of
15.87
.
More Information and Options to Explore
Further information about Pandeia is available on the Pandeia for JWST Documentation on JDox, including detailed breakdowns of all of the allowable keywords and pre-configured options.
For additional questions not answered in this article, please contact the Roman Help Desk at STScI.