Skip to content

Commit

Permalink
Merge pull request #512 from mperrin/jwst_ote_opd_updates
Browse files Browse the repository at this point in the history
JWST OTE OPD updates for Release 1.0.0
  • Loading branch information
mperrin authored Dec 10, 2021
2 parents 44a8e03 + a31e922 commit be0a5df
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 67 deletions.
21 changes: 17 additions & 4 deletions dev_utils/make-minimal-datafiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@
try:
inputfile = sys.argv[1]
except IndexError:
print("""ERROR - no input data file provided.\n\nUsage: make-minimal-datafiles.py <path_to_full_data.tar.gz>\n""")
print("""ERROR - no input data file provided.\n\nUsage: make-minimal-datafiles.py <path_to_full_data.tar.gz> <version\n""")
sys.exit(1)

try:
version = sys.argv[2]
except IndexError:
print("""ERROR - no version number provided.\n\nUsage: make-minimal-datafiles.py <path_to_full_data.tar.gz> <version>\n""")
sys.exit(1)

insts = ['FGS', 'NIRCam', 'NIRSpec','NIRISS','MIRI']

WORKING_DIR = os.path.expanduser("~/tmp/minimal-webbpsf-data")
WORKING_DIR = os.path.expanduser(f"~/tmp/minimal-webbpsf-data-{version}")
subprocess.call("mkdir -p "+WORKING_DIR, shell=True)


Expand All @@ -42,6 +47,14 @@
f0.writeto(files[0], overwrite=True)
f0.close()

# Do the same for the Rev AA OTE OPD
ote_fn = os.path.join(WORKING_DIR, 'webbpsf-data','JWST_OTE_OPD_RevAA_prelaunch_predicted.fits.gz')
f0 = fits.open(ote_fn)
f0[0].data = f0[0].data[0]
f0.writeto(ote_fn, overwrite=True)
f0.close()


print("#### Removing extra optional pupil files ####")
# keep just the 1024 and 2048 ones for tests; don't need the rest
os.remove(os.path.join(WORKING_DIR, 'webbpsf-data','jwst_pupil_RevW_npix4096.fits.gz'))
Expand All @@ -51,7 +64,7 @@

print("#### Creating tar file ####")
os.chdir(WORKING_DIR)
subprocess.call('tar cvzf minimal-webbpsf-data.tar.gz webbpsf-data', shell=True)
print("===> {0}/minimal-webbpsf-data.tar.gz ".format(WORKING_DIR))
subprocess.call(f'tar cvzf minimal-webbpsf-data-{version}.tar.gz webbpsf-data', shell=True)
print(f"===> {WORKING_DIR}/minimal-webbpsf-data-{version}.tar.gz ")


4 changes: 2 additions & 2 deletions dev_utils/master_data_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ TMPDIR="/tmp/webbpsf-data"

./make-data-sdist.sh $VER

./make-minimal-datafiles.py ${PWD}/webbpsf-data-${VER}.tar.gz
./make-minimal-datafiles.py ${PWD}/webbpsf-data-${VER}.tar.gz $VER


echo
echo "================================================="
echo "OUTPUT FILES:"
echo
echo ${PWD}/webbpsf-data-${VER}.tar.gz
echo ~/tmp/minimal-webbpsf-data/minimal-webbpsf-data.tar.gz
echo ~/tmp/minimal-webbpsf-data-${VER}/minimal-webbpsf-data-${VER}.tar.gz
echo
echo You probably want to test if those look as expected, and if so then copy into the Box folder 'webbpsf_data_public'
echo "================================================="
Expand Down
4 changes: 2 additions & 2 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ Installing the Required Data Files

Files containing such information as the JWST pupil shape, instrument throughputs, and aperture positions are distributed separately from WebbPSF. To run WebbPSF, you must download these files and tell WebbPSF where to find them using the ``WEBBPSF_PATH`` environment variable.

1. Download the following file: `webbpsf-data-0.9.0.tar.gz <https://stsci.box.com/shared/static/qcptcokkbx7fgi3c00w2732yezkxzb99.gz>`_ [approx. 240 MB]
2. Untar ``webbpsf-data-0.9.0.tar.gz`` into a directory of your choosing.
1. Download the following file: `webbpsf-data-1.0.0.tar.gz <https://stsci.box.com/shared/static/34o0keicz2iujyilg4uz617va46ks6u9.gz>`_ [approx. 280 MB]
2. Untar ``webbpsf-data-1.0.0.tar.gz`` into a directory of your choosing.
3. Set the environment variable ``WEBBPSF_PATH`` to point to that directory. e.g. ::

export WEBBPSF_PATH=$HOME/data/webbpsf-data
Expand Down
29 changes: 18 additions & 11 deletions docs/jwst.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,31 +75,35 @@ JWST's optical system has been extremely precisely engineered and assembled. Ind

Further information on JWST's predicted optical performance is available in `"Status of the optical performance for the James Webb Space Telescope" <http://dx.doi.org/10.1117/12.2055502>`_, Lightsey *et al.*, (2014) and `"Predicted JWST imaging performance" <http://dx.doi.org/10.1117/12.926817>`_, Knight *et al.* (2012).

For each science instrument, if you examine ``inst.opd_list`` (where ``inst`` is an instance of an instrument model), you will see the filenames for a "predicted" OPD map and a "requirements" OPD map. For example::
For each science instrument, if you examine ``inst.opd_list`` (where ``inst`` is an instance of an instrument model), you will see the filenames for two "predicted" OPDs and a "requirements" OPD map. For example::

>>> nc = webbpsf.NIRCam()
>>> nc.opd_list
['OPD_RevW_ote_for_NIRCam_predicted.fits.gz',
['JWST_OTE_OPD_RevAA_prelaunch_predicted.fits.gz',
'OPD_RevW_ote_for_NIRCam_predicted.fits.gz',
'OPD_RevW_ote_for_NIRCam_requirements.fits.gz']

By default, WebbPSF selects the (slightly more conservative) ``requirements`` OPD map::
As of WebbPSF 1.0, WebbPSF selects the 'JWST_OTE_OPD_RevAA_prelaunch_predicted.fits.gz' OPD as the default OPD map for all instruments. This is a *significant change* from prior versions::

>>> nc.pupilopd
'OPD_RevW_ote_for_NIRCam_requirements.fits.gz'
'JWST_OTE_OPD_RevAA_prelaunch_predicted.fits.gz'

Performance predictions for a large active deployable space telescope are inherently probabilistic, and Monte Carlo methods have been used to derive overall probability distributions based on the individual error budget terms. The "predicted" OPD maps provided with WebbPSF correspond to the median values from such simulations, and provide a reasonable approximation of current performance expectations. However, performance at such levels is not guaranteed. The "requirements" OPD maps are more conservative, set to the slightly higher levels of residual wavefront error that we can be confident will be achieved in practice. Both the predicted and required values contain maximal budgeted contributions from OTE temporal drifts and dynamics (roughly 55 nm of low and mid frequency error); i.e. they correspond to times well after a wavefront control and shortly before a next set of control moves might be issued.
Performance predictions for a large active deployable space telescope are inherently probabilistic, and Monte Carlo methods have been used to derive overall probability distributions based on the individual error budget terms. The "prelaunch_predicted" OPD maps provided with WebbPSF are based on a recent integrated modeling cycle, the so-called PSR2020 ("Predicted Stability Requirements 2020") modeling effort, and provide a reasonable approximation of current performance expectations. However, performance at such levels is not guaranteed. See :doc:`jwst_optical_budgets` for more details on the contents of this OPD model.

To select the ``predicted`` map, simply assign it to the ``pupilopd`` attribute before calculating the PSF::
The older "predicted" and "requirements" OPD maps are more conservative, dating to 2016. The Requirements map is set to the slightly higher levels of residual wavefront error that we can be confident will be achieved in practice. Both the predicted and required values contain maximal budgeted contributions from OTE temporal drifts and dynamics (roughly 55 nm of low and mid frequency error); i.e. they correspond to times well after a wavefront control and shortly before a next set of control moves might be issued. Further, they also include very conservative levels of instrument WFE, which is both higher than the as-built instruments *and* is double-booked relative to the SI WFE models elsewhere in webbpsf. These files are kept for consistency with past versions of WebbPSF, but we now know hopefully we may do better in flight.

To select a different OPD map, simply assign it to the ``pupilopd`` attribute before calculating the PSF::

>>> nc.pupilopd = 'OPD_RevW_ote_for_NIRCam_predicted.fits.gz'

For both the required and predicted cases, the OPD files contain 10 Monte Carlo realizations of the telescope. You can select one of these by specifying the plane number in a tuple::
For all provided WFE cases, the OPD files contain *10 Monte Carlo realizations of the telescope*, representing slight variations or uncertainties in the alignment process. You can select one of these by specifying the plane number in a tuple::

>>> nc.pupilopd = ('OPD_RevW_ote_for_NIRCam_predicted.fits.gz', 7)

Note that these represent 10 distinct, totally independent realizations of JWST and its optical error budget. They do not represent any sort of time series or wavefront drift.
The average levels of WFE from the telescope itself used in the OPD files are as follows.
Note that these represent 10 distinct, totally independent realizations of JWST and its optical error budget. They do *not* represent any sort of time series or wavefront drift.


The "prelaunch_predicted" OPD file is for the telescope only, and has ~60-65 nm rms WFE (consistent with budget predictions). This is for the global WFE of the telescope on-axis. Additional terms for off-axis telescope WFE and SI WFE are modeled separately and added on top of this. Again, see :doc:`jwst_optical_budgets`. For the older OPD files, the average levels of WFE from the telescope itself used in those "predicted" and "requirements" OPD files are as follows.

========== ============ ============
Instrument Predicted Requirements
Expand All @@ -111,10 +115,13 @@ MIRI 204 nm rms 258 nm rms
========== ============ ============


While different OPD maps are used for each SI, these OPD maps do not include wavefront
error contributions from optics internal to the science instrument. Additional details
As noted above, these older files accidentally do also include conservative models for
wavefront error contributions from optics internal to the science instrument. This is why the models for NIRSpec and MIRI have such higher WFE.
We recommend the use of the newer "prelaunch_predicted" OPDs instead. Additional details
on the SI-specific wavefront error models are given under each instrument model section below.

How well will any of these models represent the true in-flight performance that will be achieved by the observatory? We'll all learn together in 2022. Stay tuned for WebbPSF 1.1 and beyond.

Field Dependent Aberrations
---------------------------
While the OTE is designed to have low aberrations across all of the science instruments, it has small intrinsic aberrations
Expand Down
161 changes: 148 additions & 13 deletions docs/jwst_optical_budgets.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion webbpsf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class UnsupportedPythonError(Exception):
# required. If changes to the code and data mean WebbPSF won't work
# properly with an old data package, increment this version number.
# (It's checked against $WEBBPSF_DATA/version.txt)
DATA_VERSION_MIN = (0, 9, 0)
DATA_VERSION_MIN = (1, 0, 0)


class Conf(_config.ConfigNamespace):
Expand Down
29 changes: 15 additions & 14 deletions webbpsf/opds.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def __init__(self, name='unnamed OPD', opd=None, opd_index=0, transmission=None,
if None, will infer based on npix.
ext : int, optional
FITS extension to load OPD from
slice : int, optional
opd_index : int, optional
slice of a datacube to load OPD from, if the selected extension contains a datacube.
"""
Expand Down Expand Up @@ -621,7 +621,7 @@ def __init__(self, opd=None, opd_index=0, transmission=None, rm_ptt=False, rm_pi
FITS file to load an OPD from. The OPD must be specified in microns.
ext : int, optional
FITS extension to load OPD from
slice : int, optional
opd_index : int, optional
slice of a datacube to load OPD from, if the selected extension contains a datacube.
pupilfile : str
FITS file for pupil mask, with throughput from 0-1. If not explicitly provided, will be inferred from
Expand Down Expand Up @@ -1117,7 +1117,7 @@ class OTE_Linear_Model_WSS(OPD):
def __init__(self, name='Unnamed OPD', opd=None, opd_index=0, transmission=None,
segment_mask_file=None, zero=False, rm_ptt=False,
rm_piston=False, v2v3=None, control_point_fieldpoint='nrca3_full',
npix=1024):
npix=1024, include_nominal_field_dependence=True):
"""
Parameters
----------
Expand All @@ -1127,7 +1127,7 @@ def __init__(self, name='Unnamed OPD', opd=None, opd_index=0, transmission=None,
FITS extension to load OPD from
transmission: str or fits.HDUList
FITS file to load aperture transmission from.
slice : int, optional
opd_index : int, optional
slice of a datacube to load OPD from, if the selected extension contains a datacube.
segment_mask_file : str
FITS file for pupil mask, with throughput from 0-1. If not explicitly provided, will
Expand All @@ -1140,8 +1140,12 @@ def __init__(self, name='Unnamed OPD', opd=None, opd_index=0, transmission=None,
v2v3 : tuple of 2 astropy.Quantities
Tuple giving V2,v3 coordinates as quantities, typically in arcminutes, or None to default to
the master chief ray location between the two NIRCam modules.
include_nominal_field_dependence : bool
Include the Zernike polynomial model for OTE field dependence for the nominal OTE.
Note, if OPD is None, then this will be ignored and the nominal field dependence will be disabled.
control_point_fieldpoint: str
Name of the field point where the OTE control point is located, on instrument defined by "control_point_instr".
A parameter used in the field dependence model for a misaligned secondary mirror.
Name of the field point where the OTE MIMF control point is located, on instrument defined by "control_point_instr".
Default: 'nrca3_full'.
The OTE control point is the field point to which the OTE has been aligned and defines the field angles
for the field-dependent SM pose aberrations.
Expand All @@ -1150,7 +1154,8 @@ def __init__(self, name='Unnamed OPD', opd=None, opd_index=0, transmission=None,
"""

OPD.__init__(self, name=name, opd=opd, opd_index=opd_index, transmission=transmission, segment_mask_file=segment_mask_file, npix=npix)
OPD.__init__(self, name=name, opd=opd, opd_index=opd_index, transmission=transmission,
segment_mask_file=segment_mask_file, npix=npix)
self.v2v3 = v2v3

# load influence function table:
Expand Down Expand Up @@ -1188,7 +1193,9 @@ def __init__(self, name='Unnamed OPD', opd=None, opd_index=0, transmission=None,
self._global_hexike_coeffs = np.zeros(self._number_global_zernikes)

# Field dependence model data
self._include_nominal_field_dep = True
# Note, if the OTE is set to None, we disable this automatically. This is to enable modeling the ideal case with
# truly NO WFE for opd=None.
self._include_nominal_field_dep = include_nominal_field_dependence if opd else False
self._field_dep_file = None
self._field_dep_hdr = None
self._field_dep_data = None
Expand Down Expand Up @@ -2692,13 +2699,7 @@ def enable_adjustable_ote(instr):
elif isinstance(instr.pupilopd, fits.HDUList):
opdpath = instr.pupilopd
else:
# assume it is a string and try to use as filename
# either an absolute or relative directory path if that works,
# or else infer that it's a filename in the WebbPSF data directory.
if not os.path.exists(instr.pupilopd):
opdpath = os.path.join(instr._datapath, 'OPD', instr.pupilopd)
else:
opdpath = instr.pupilopd
opdpath = instr.get_opd_file_full_path(instr.pupilopd)

pupilpath = instr.pupil

Expand Down
5 changes: 4 additions & 1 deletion webbpsf/optical_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ def visualize_wfe_budget(inst, slew_delta_time=14 * u.day, slew_case='EOL', ptt_
wfe_ote = ote.get_opd(wave).copy()

# Figure out the field dependent part and factor that out
wfe_ote_field_dep_nominal = ote._get_field_dependence_nominal_ote(ote.v2v3)
if ote._include_nominal_field_dep:
wfe_ote_field_dep_nominal = ote._get_field_dependence_nominal_ote(ote.v2v3)
else: # pragma: no cover
wfe_ote_field_dep_nominal = np.zeros_like(wfe_ote)
wfe_ote_field_dep_mimf = ote._get_field_dependence_secondary_mirror(ote.v2v3)
wfe_ote_field_dep = wfe_ote_field_dep_nominal + wfe_ote_field_dep_mimf

Expand Down
20 changes: 10 additions & 10 deletions webbpsf/otelm/jwst_wfe_summary_from_optical_budget.csv
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Values derived from JWST Optical Budget Rev Y.v2,
# Values derived from JWST Optical Budget Rev AA
Value,NIRCam_req,NIRCam_pred,NIRSpec_req,NIRSpec_pred,MIRI_req,MIRI_pred,NIRISS_req,NIRISS_pred,FGS_req,FGS_pred,Optical Budget Source
System Total including uncertainty reserve,150,124,238,166,421,172,180,137,186,147,"Syst Brief, top summary table"
System Performance,135,93,233,121,386,132,161,100,155,99,"Syst Brief, system performance"
OTE Total,122,77,128,79,133,77,131,84,115,76,"Syst, OTE totals"
System Total including uncertainty reserve,150,127,238,169,421,176,180,140,186,147,"Syst Brief, top summary table"
System Performance,135,96,233,123,386,134,161,103,155,103,"Syst Brief, system performance"
OTE Total,122,81,128,82,133,82,131,87,115,77,"Syst, OTE totals"
OTE total static,81,60,87,61,85,60,92,69,91,66,"Syst, OTE WFC Residual (=static)"
OTE residual low freq (field dep),33,21,44,24,41,22,53,41,50,35,"Syst, Comp. OTE Resid, Lo freq"
OTE residual controllable modes (mid freq),39,17,40,14,40,14,41,14,43,17,"RSS (Comp OTE Resid Mid, WFSC sensing and control resid, less OTE pm figure mid)"
OTE uncontrollable high freq,64,54,64,53,64,53,64,54,64,54,"RSS(Syst Comp OTE Resid High, OTE PM Figure mid)"
OTE total dynamic,90,49,94,50,102,49,93,48,70,38,computed from the below 3
OTE vibe,13,4,13,4,13,4,13,4,13,4,"Syst, OTE Steady State Vibe"
OTE stability,57,33,57,33,57,33,57,33,57,33,"Syst, OTE stability"
Image motion (as equiv. WFE),69,36,73,37,84,36,72,34,39,19,"Syst, Image Motion Equ"
OTE residual controllable modes (mid freq),56,38,57,36,56,36,57,36,58,38,"RSS (Comp OTE Resid Mid, WFSC sensing and control resid, less OTE pm figure mid)"
OTE uncontrollable high freq,49,42,49,41,49,41,49,42,49,42,"RSS(Syst Comp OTE Resid High, OTE PM Figure mid)"
OTE total dynamic,91,53,94,55,103,56,93,53,71,40,computed from the below 3
OTE vibe,13,3,13,3,13,3,13,3,13,3,"Syst, OTE Steady State Vibe"
OTE stability,58,34,58,34,58,34,58,34,58,34,"Syst, OTE stability"
Image motion (as equiv. WFE),69,41,73,43,84,44,72,40,39,20,"Syst, Image Motion Equ"
ISIM+SI total,58,52,195,92,363,107,93,55,103,68,"Syst, ISIM total"
SI internal WFE,56,52,194,92,362,107,91,55,101,68,"Syst, [SI name] WFC Resid"
ISIM structural,13,0,14,0,13,0,13,0,18,0,"Syst, ISIM Struct WFC Resid"
Expand Down
Loading

0 comments on commit be0a5df

Please sign in to comment.