Making WFI Mosaics with RomanCal#
Server Information#
IMPORTANT: To run this tutorial, please make sure you are logged in the RRN with a medium server.
Kernel Information and Read-Only Status#
To run this notebook, please select “Roman Research Nexus {VERSION}” kernel at the top right of your window. For example “Roman Research Nexus 2026.1”.
This notebook is read-only. You can run cells and make edits, but you must save changes to a different location. We recommend saving the notebook within your home directory, or to a new folder within your home (e.g. file > save notebook as > my-nbs/nb.ipynb). Note that a directory must exist before you attempt to add a notebook to it.
Imports#
Libraries used
romancal for creating association files and running the pipeline
astropy.visualization for creating image normalizations
roman_datamodels for opening Roman WFI ASDF files
glob for creating lists of files
os for checking if files exist
json for creating association files
s3fs for streaming files from an S3 bucket
import roman_datamodels as rdm
from romancal.pipeline import MosaicPipeline
from romancal.associations import asn_from_list
from astropy.visualization import simple_norm
import s3fs
import glob
import os
import json
import matplotlib.pyplot as plt
Introduction#
The purpose of this notebook is to combine multiple Level 2 (L2; calibrated rate image) data products into a Level 3 (L3; distortion-corrected, co-added image) product. Details about the Roman data levels can be found here. The pipeline for combining images is called the Mosaic Pipeline. Please review the RDox pages for details. It consists of the following steps:
Flux step: Transform instrumental units of data numbers per second (DN/s) into physical surface brightness units of megaJanskys per steradian (MJy/sr).
Skymatch step: Determine scaling factors necessary to match the flux levels in the overlapping sections of the input images. The images will be scaled by these factors later during the combination process.
Outlier detection step: Examine the input images to detect and flag outliers in the pixel values for a given sky position.
Resample step: Use the drizzle algorithm to combine the input data products. Reject outliers and other undesirable pixels based on data quality flags and oversample the pixels if indicated.
Note: L3 data products in the Roman Archive will be tessellated on the sky such that individual L3 files (“sky cells”) will be small with some overlap between adjacent cells. More information is available on the RDox pages on sky tessellation. In this tutorial, we will not utilize tessellation. The tutorial will be updated in the future to demonstrate the creation of both tessellated and non-tessellated products.
Tutorial Data#
In this tutorial, we use L2 WFI data files produced by RomanCal processing of L1 simulated files created with Roman I-Sim. If you have already worked through the tutorials Simulating WFI Imaging Data with Roman I-Sim and Calibrating WFI Exposures with RomanCal, you may already have these files saved locally. If not, these files are also available in the Nexus S3 bucket. For more information on how to access these data, see the Data Discovery and Access tutorial.
The L2 products used in this tutorial represent data from one WFI detector (WFI11) across four different pointings, each with small dithers. These dithers are optimized for gap-filling between detectors rather than for oversampling. Therefore, in this tutorial we will generate a mosaicked L3 product using the native pixel scale.
Making WFI Mosaics#
Generating the Association File#
Association table files (often abbreviated “association files” or “ASN files”) are JavaScript Object Notation (JSON) formatted files containing a list of the input products to be processed together, and the output products to be created. In the Mosaic Pipeline, association files specifically enumerate the input L2 products that are used to create a single L3 product. For more information, please visit the RDox pages on association files.
The association generator function asn_from_list() can be used to create a properly formatted JavaScript Object Notation (JSON) file for use with the Mosaic Pipeline. The code takes as input a list of L2 products and the name of the L3 output product. You can include either one or many L2 products as input. For use cases that do use a single input file, you can skip several pipeline steps (skymatch and outlier_detection).
If you have not completed the previous Exposure Pipeline tutorial, then you can download the data products from the Nexus S3 bucket. The code cell below will check if you have the files saved on disk and, if not, it will retrieve them from the S3 bucket.
# Copy the files from the S3 bucket if they are not in local storage
input_files = ['r0003201001001001004_0001_wfi11_f106_cal.asdf',
'r0003201001001001004_0002_wfi11_f106_cal.asdf',
'r0003201001001001004_0003_wfi11_f106_cal.asdf',
'r0003201001001001004_0004_wfi11_f106_cal.asdf']
for f in input_files:
if not os.path.exists(f):
fs = s3fs.S3FileSystem(anon=True)
asdf_dir_uri = "s3://stpubdata/roman/nexus/soc_simulations/tutorial_data/roman-2026.1/"
asdf_file_uri = asdf_dir_uri + f
fs.get(asdf_file_uri, f'./{f}')
Next we can create the association JSON file using the asn_from_list() function:
# Collect our input files and make the L3 output filename
input_files = glob.glob('r0003*_????_wfi11_f106_cal.asdf')
product_name = 'my_roman_mosaic'
# Create the ASN JSON object
asn = asn_from_list.asn_from_list([(i, 'science') for i in input_files],
product_name=product_name,
with_exptype=True, target='')
Now let’s take a look at the JSON object we just created. It should contain a listing of each of our input files as well as the output product name:
asn
{
"asn_type": "None",
"asn_rule": "DMS_ELPP_Base",
"version_id": null,
"code_version": "0.22.0",
"target": "",
"degraded_status": "No known degraded exposures in association.",
"program": "noprogram",
"data_release_id": "p",
"constraints": "No constraints",
"asn_id": "a3001",
"asn_pool": "none",
"skycell_wcs_info": "none",
"products": [
{
"name": "my_roman_mosaic",
"members": [
{
"expname": "r0003201001001001004_0001_wfi11_f106_cal.asdf",
"exptype": "science"
},
{
"expname": "r0003201001001001004_0002_wfi11_f106_cal.asdf",
"exptype": "science"
},
{
"expname": "r0003201001001001004_0003_wfi11_f106_cal.asdf",
"exptype": "science"
},
{
"expname": "r0003201001001001004_0004_wfi11_f106_cal.asdf",
"exptype": "science"
}
]
}
]
}
We can also save the ASN file to disk:
# Write the ASN file to disk
_, serialized = asn.dump(format='json')
with open('my_roman_mosaic_asn.json', 'w') as f:
f.write(serialized)
Running the Mosaic Pipeline#
Next we run the Mosaic Pipeline using the MosaicPipeline class. As with the L1 to L2 Exposure Pipeline, there are many optional arguments to customize the behavior of the pipeline. At this time, we will not delve into these optional parameters. The simulated input files are based on a simple gap-filling dither pattern rather than sub-pixel dithering optimized for the point spread function(PSF). As a result, we use the default native sampling of the WFI detectors. In the future, additional details may be provided to explore optimizing the Mosaic Pipeline output.
If we had only a single input image, this is where we would skip the skymatch and outlier detection steps by passing the optional argument steps={'skymatch': {'skip': True}, 'outlier_detection': {'skip': True}}. For now, we will skip the source catalog step that would normally make the single-band source catalog and segmentation map, which are Level 4 (L4; high-level extracted information) files.
Note: The following cell will take several minutes to complete.
result = MosaicPipeline.call('my_roman_mosaic_asn.json', save_results=True, resample_on_skycell=False,
steps={'source_catalog': {'skip': True}})
2026-06-01 19:35:13,211 - CRDS - ERROR - Error determining best reference for 'pars-fluxstep' = No match found.
2026-06-01 19:35:13,212 - CRDS - ERROR - Error determining best reference for 'pars-skymatchstep' = No match found.
2026-06-01 19:35:13,214 - CRDS - ERROR - Error determining best reference for 'pars-outlierdetectionstep' = No match found.
2026-06-01 19:35:13,215 - CRDS - ERROR - Error determining best reference for 'pars-resamplestep' = No match found.
2026-06-01 19:35:13,217 - CRDS - ERROR - Error determining best reference for 'pars-sourcecatalogstep' = Unknown reference type 'pars-sourcecatalogstep'
2026-06-01 19:35:13,218 - CRDS - ERROR - Error determining best reference for 'pars-mosaicpipeline' = Unknown reference type 'pars-mosaicpipeline'
2026-06-01 19:35:13,223 - stpipe.step - INFO - MosaicPipeline instance created.
2026-06-01 19:35:13,223 - stpipe.step - INFO - FluxStep instance created.
2026-06-01 19:35:13,225 - stpipe.step - INFO - SkyMatchStep instance created.
2026-06-01 19:35:13,226 - stpipe.step - INFO - OutlierDetectionStep instance created.
2026-06-01 19:35:13,228 - stpipe.step - INFO - ResampleStep instance created.
2026-06-01 19:35:13,229 - stpipe.step - INFO - SourceCatalogStep instance created.
2026-06-01 19:35:13,398 - stpipe.step - INFO - Step MosaicPipeline running with args ('my_roman_mosaic_asn.json',).
2026-06-01 19:35:13,407 - stpipe.step - INFO - Step MosaicPipeline parameters are:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: True
skip: False
suffix: None
search_output_file: True
input_dir: ''
update_version: False
on_disk: False
resample_on_skycell: False
steps:
flux:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: False
skip: False
suffix: None
search_output_file: True
input_dir: ''
update_version: False
skymatch:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: False
skip: False
suffix: None
search_output_file: True
input_dir: ''
update_version: False
skymethod: match
match_down: True
subtract: False
stepsize: None
skystat: mode
dqbits: ~DO_NOT_USE+NON_SCIENCE
lower: None
upper: None
nclip: 5
lsigma: 4.0
usigma: 4.0
binwidth: 0.1
outlier_detection:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: False
skip: False
suffix: None
search_output_file: True
input_dir: ''
update_version: False
weight_type: ivm
pixfrac: 1.0
kernel: square
fillval: NaN
maskpt: 0.7
snr: 5.0 4.0
scale: 1.2 0.7
backg: 0.0
save_intermediate_results: False
resample_data: True
resample_on_skycell: True
good_bits: ~DO_NOT_USE+NON_SCIENCE
in_memory: True
pixmap_stepsize: 10.0
pixmap_order: 3
resample:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: False
skip: False
suffix: None
search_output_file: True
input_dir: ''
update_version: False
pixfrac: 1.0
kernel: square
fillval: NAN
weight_type: ivm
output_shape: None
crpix: None
crval: None
rotation: None
pixel_scale_ratio: 1.0
pixel_scale: None
output_wcs: ''
resample_on_skycell: True
in_memory: True
good_bits: ~DO_NOT_USE+NON_SCIENCE
include_var_flat: False
propagate_dq: False
pixmap_stepsize: 10.0
pixmap_order: 3
source_catalog:
pre_hooks: []
post_hooks: []
output_file: None
output_dir: None
output_ext: .asdf
output_use_model: False
output_use_index: True
save_results: False
skip: True
suffix: cat
search_output_file: True
input_dir: ''
update_version: False
bkg_boxsize: 1000
kernel_fwhm: 2.0
snr_threshold: 3.0
npixels: 25
deblend: False
fit_psf: True
forced_segmentation: ''
2026-06-01 19:35:13,407 - romancal.pipeline.mosaic_pipeline - INFO - Starting Roman mosaic level calibration pipeline ...
2026-06-01 19:35:13,606 - stpipe.step - INFO - Step flux running with args (<romancal.datamodels.library.ModelLibrary object at 0x7ffb7da0bed0>,).
2026-06-01 19:35:15,422 - stpipe.step - INFO - Step flux done
2026-06-01 19:35:15,593 - stpipe.step - INFO - Step skymatch running with args (<romancal.datamodels.library.ModelLibrary object at 0x7ffb7da0bed0>,).
2026-06-01 19:35:15,885 - stcal.skymatch.skymatch - INFO -
2026-06-01 19:35:15,886 - stcal.skymatch.skymatch - INFO - ***** stcal.skymatch.skymatch.skymatch() started on 2026-06-01 19:35:15.885733
2026-06-01 19:35:15,887 - stcal.skymatch.skymatch - INFO -
2026-06-01 19:35:15,887 - stcal.skymatch.skymatch - INFO - Sky computation method: 'match'
2026-06-01 19:35:15,887 - stcal.skymatch.skymatch - INFO - Sky matching direction: DOWN
2026-06-01 19:35:15,888 - stcal.skymatch.skymatch - INFO - Sky subtraction from image data: OFF
2026-06-01 19:35:15,888 - stcal.skymatch.skymatch - INFO -
2026-06-01 19:35:15,890 - stcal.skymatch.skymatch - INFO - ---- Computing differences in sky values in overlapping regions.
2026-06-01 19:35:18,575 - stcal.skymatch.skymatch - INFO - * Image ID=r0003201001001001004_0001_wfi11_f106_cal.asdf. Sky background: 0.00340952
2026-06-01 19:35:18,575 - stcal.skymatch.skymatch - INFO - * Image ID=r0003201001001001004_0002_wfi11_f106_cal.asdf. Sky background: 0
2026-06-01 19:35:18,576 - stcal.skymatch.skymatch - INFO - * Image ID=r0003201001001001004_0003_wfi11_f106_cal.asdf. Sky background: 0.00231594
2026-06-01 19:35:18,576 - stcal.skymatch.skymatch - INFO - * Image ID=r0003201001001001004_0004_wfi11_f106_cal.asdf. Sky background: 0.00439232
2026-06-01 19:35:18,577 - stcal.skymatch.skymatch - INFO -
2026-06-01 19:35:18,577 - stcal.skymatch.skymatch - INFO - ***** stcal.skymatch.skymatch.skymatch() ended on 2026-06-01 19:35:18.577092
2026-06-01 19:35:18,578 - stcal.skymatch.skymatch - INFO - ***** stcal.skymatch.skymatch.skymatch() TOTAL RUN TIME: 0:00:02.691359
2026-06-01 19:35:18,578 - stcal.skymatch.skymatch - INFO -
2026-06-01 19:35:18,582 - stpipe.step - INFO - Step skymatch done
2026-06-01 19:35:18,759 - stpipe.step - INFO - Step outlier_detection running with args (<romancal.datamodels.library.ModelLibrary object at 0x7ffb7da0bed0>,).
2026-06-01 19:35:18,796 - stcal.resample.resample - INFO - Output pixel scale: 0.10772630117450682 arcsec.
2026-06-01 19:35:18,796 - stcal.resample.resample - INFO - Driz parameter kernel: square
2026-06-01 19:35:18,797 - stcal.resample.resample - INFO - Driz parameter pixfrac: 1.0
2026-06-01 19:35:18,797 - stcal.resample.resample - INFO - Driz parameter fillval: NaN
2026-06-01 19:35:18,798 - stcal.resample.resample - INFO - Driz parameter weight_type: ivm
2026-06-01 19:35:18,798 - stcal.resample.resample - INFO - Evaluating the full pixel map every 10.0 pixels
2026-06-01 19:35:18,798 - stcal.resample.resample - INFO - Interpolating the rest with order 3 bivariate splines
2026-06-01 19:35:19,463 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:35:22,313 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:35:25,171 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:35:27,997 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:35:30,173 - stcal.alignment.util - INFO - Update S_REGION to POLYGON ICRS 271.070347920 -0.419189523 271.070346866 -0.222320204 270.869256760 -0.222319306 270.869253946 -0.419188624
2026-06-01 19:35:57,378 - stcal.outlier_detection.utils - INFO - Blotting (4088, 4088) <-- (6579, 6720)
2026-06-01 19:35:58,487 - romancal.outlier_detection.utils - INFO - 3598 pixels marked as outliers
2026-06-01 19:35:59,073 - stcal.outlier_detection.utils - INFO - Blotting (4088, 4088) <-- (6579, 6720)
2026-06-01 19:36:00,205 - romancal.outlier_detection.utils - INFO - 3799 pixels marked as outliers
2026-06-01 19:36:00,784 - stcal.outlier_detection.utils - INFO - Blotting (4088, 4088) <-- (6579, 6720)
2026-06-01 19:36:01,910 - romancal.outlier_detection.utils - INFO - 3629 pixels marked as outliers
2026-06-01 19:36:02,489 - stcal.outlier_detection.utils - INFO - Blotting (4088, 4088) <-- (6579, 6720)
2026-06-01 19:36:03,609 - romancal.outlier_detection.utils - INFO - 3237 pixels marked as outliers
2026-06-01 19:36:03,616 - stpipe.step - INFO - Step outlier_detection done
2026-06-01 19:36:03,800 - stpipe.step - INFO - Step resample running with args (<romancal.datamodels.library.ModelLibrary object at 0x7ffb7da0bed0>,).
2026-06-01 19:36:03,837 - stcal.resample.resample - INFO - Output pixel scale: 0.10772630117450682 arcsec.
2026-06-01 19:36:03,837 - stcal.resample.resample - INFO - Driz parameter kernel: square
2026-06-01 19:36:03,838 - stcal.resample.resample - INFO - Driz parameter pixfrac: 1.0
2026-06-01 19:36:03,838 - stcal.resample.resample - INFO - Driz parameter fillval: NAN
2026-06-01 19:36:03,838 - stcal.resample.resample - INFO - Driz parameter weight_type: ivm
2026-06-01 19:36:03,839 - stcal.resample.resample - INFO - Evaluating the full pixel map every 10.0 pixels
2026-06-01 19:36:03,839 - stcal.resample.resample - INFO - Interpolating the rest with order 3 bivariate splines
2026-06-01 19:36:04,547 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:36:09,071 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:09,084 - py.warnings - WARNING - /home/runner/micromamba/envs/ci-env/lib/python3.13/site-packages/stcal/resample/resample.py:1259: RuntimeWarning: invalid value encountered in sqrt
data=np.sqrt(variance),
2026-06-01 19:36:11,287 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:15,102 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:36:19,576 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:19,589 - py.warnings - WARNING - /home/runner/micromamba/envs/ci-env/lib/python3.13/site-packages/stcal/resample/resample.py:1259: RuntimeWarning: invalid value encountered in sqrt
data=np.sqrt(variance),
2026-06-01 19:36:21,882 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:25,751 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:36:30,203 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:30,216 - py.warnings - WARNING - /home/runner/micromamba/envs/ci-env/lib/python3.13/site-packages/stcal/resample/resample.py:1259: RuntimeWarning: invalid value encountered in sqrt
data=np.sqrt(variance),
2026-06-01 19:36:32,429 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:36,346 - stcal.resample.resample - INFO - Resampling science and variance data
2026-06-01 19:36:40,787 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:40,800 - py.warnings - WARNING - /home/runner/micromamba/envs/ci-env/lib/python3.13/site-packages/stcal/resample/resample.py:1259: RuntimeWarning: invalid value encountered in sqrt
data=np.sqrt(variance),
2026-06-01 19:36:43,001 - stcal.resample.resample - INFO - Drizzling (4088, 4088) --> (6579, 6720)
2026-06-01 19:36:46,673 - romancal.resample.resample - INFO - Mean, max exposure times: 116.8, 265.6
2026-06-01 19:36:46,701 - stcal.alignment.util - INFO - Update S_REGION to POLYGON ICRS 271.070347920 -0.419189523 271.070346866 -0.222320204 270.869256760 -0.222319306 270.869253946 -0.419188624
2026-06-01 19:36:46,713 - stpipe.step - INFO - Step resample done
2026-06-01 19:36:46,899 - stpipe.step - INFO - Step source_catalog running with args (<roman_datamodels.datamodels._datamodels.MosaicModel object at 0x7ffb7d58ed90>,).
2026-06-01 19:36:46,900 - stpipe.step - INFO - Step skipped.
2026-06-01 19:36:49,759 - stpipe.step - INFO - Saved model in my_roman_mosaic_coadd.asdf
2026-06-01 19:36:49,760 - stpipe.step - INFO - Step MosaicPipeline done
Now let’s open the mosaic file we’ve created and take a look at what’s inside:
mos_file = rdm.open('my_roman_mosaic_coadd.asdf')
mos_file.info()
root (AsdfObject)
├─asdf_library (Software)
│ ├─author (str): The ASDF Developers
│ ├─homepage (str): http://github.com/asdf-format/asdf
│ ├─name (str): asdf
│ └─version (str): 5.3.0
├─history (AsdfDictNode)
│ └─extensions (AsdfListNode)
│ ├─0 (ExtensionMetadata) ...
│ ├─1 (ExtensionMetadata) ...
│ ├─2 (ExtensionMetadata) ...
│ ├─3 (ExtensionMetadata) ...
│ ├─4 (ExtensionMetadata) ...
│ └─3 not shown
└─roman (WfiMosaic) # The schema for WFI Level 3 mosaics.
├─meta (AsdfDictNode) # Common Level 3 Metadata ...
├─data (NDArrayType) # Science Data (MJy / steradian) ...
├─context (NDArrayType) # Context Data ...
├─err (NDArrayType) # Error Data (MJy / steradian) ...
├─weight (NDArrayType) # Weight Data ...
├─var_poisson (NDArrayType) # Poisson Variability (MJy^2 / steradian^2) ...
├─var_rnoise (NDArrayType) # Read Noise Variance (MJy^2 / steradian^2 ...
└─individual_image_cal_logs (AsdfListNode) ...
Some nodes not shown.
norm = simple_norm(mos_file.data, 'asinh', vmin=0.01, vmax=3.5)
fig, ax = plt.subplots(figsize=(20, 15))
ax.imshow(mos_file.data, origin='lower', norm=norm)
<matplotlib.image.AxesImage at 0x7ffb7c116900>
An L3 file contains several extensions that may be of interest:
data: The mosiac image in units of MegaJanskys per steradian
context: An image showing the input images that contributed to each output pixel
err: The error image
weight: A weight map showing the relative coverage on the sky from the input images and how they contributed to the final mosaic
For more information on the how arrays are computed by the drizzle algorithm, we suggest consulting the DrizzlePac Handbook. While the DrizzlePac Handbook is written for HST, many of the same terms and principles apply to Roman as the underlying algorithm is the same.
Additional Resources#
About this Notebook#
Author: Tyler Desjardins
Updated On: 2026-04-17
| Top of page |
|
|