Repository: spacetelescope/jwst

Issue:
No spec2 associations created for NIRSPEC IFU data
_Issue [JP-3629](https://jira.stsci.edu/browse/JP-3629) was created on JIRA by [Robert Jedrzejewski](https://jira.stsci.edu/secure/ViewProfile.jspa?name=rij):_

Recent fixes for JP-3151 and JP-3518 appear to have interacted in such a way as to no longer create spec2 associations for NIRSpec IFU data.

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/spacetelescope/jwst/pull/8508?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spacetelescope) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 57.97%. Comparing base [(`4179c09`)](https://app.codecov.io/gh/spacetelescope/jwst/commit/4179c09d7d802f4267b965bfc22a51beca962ab7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spacetelescope) to head [(`29dacec`)](https://app.codecov.io/gh/spacetelescope/jwst/commit/29dacec9d2ade0e5555090548ac534c81d63cd06?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spacetelescope).
> Report is 1 commits behind head on master.


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master    #8508   +/-   ##
=======================================
  Coverage   57.97%   57.97%           
=======================================
  Files         387      387           
  Lines       38830    38831    +1     
=======================================
+ Hits        22513    22514    +1     
  Misses      16317    16317           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/spacetelescope/jwst/pull/8508?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spacetelescope).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spacetelescope).

emolter: I don't see any button to dismiss my review, which was supposed to be related to a different PR entirely, sorry about that

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 4465bfd5d..50b2f6ecc 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -22,7 +22,7 @@ assign_wcs
 
 - Updated the routines that load NIRSpec MOS slit and source data from the MSA meta
   data file to properly handle background and virtual slits, and assign appropriate
-  meta data to them for use downstream. [#8442]
+  meta data to them for use downstream. [#8442, #8533]
 
 associations
 ------------
@@ -36,6 +36,9 @@ associations
 - Updated Level3 rules for new handling of NIRSpec MOS source_id formatting when
   constructing output file names. [#8442]
 
+- Added default values for new non-header keywords (``MOSTILNO`` and ``DITHPTIN``)
+  to the default values in the ``asn_make_pool`` script. [#8508]
+
 - Create WFSS Pure-Parallel associations [#8528]
 
 dark_current
@@ -103,6 +106,13 @@ general
 
 - Increase minimum required scipy. [#8441]
 
+master_background_mos
+---------------------
+
+- Updated check for NIRSpec MOS background slits to use new naming convention:
+  ``slit.source_name`` now contains the string "BKG" instead of
+  "background". [#8533]
+
 outlier_detection
 -----------------
 
diff --git a/jwst/assign_wcs/nirspec.py b/jwst/assign_wcs/nirspec.py
index e08834e82..3577a84d5 100644
--- a/jwst/assign_wcs/nirspec.py
+++ b/jwst/assign_wcs/nirspec.py
@@ -674,7 +674,13 @@ def get_open_msa_slits(prog_id, msa_file, msa_metadata_id, dither_position,
                     (s['source_name'], s['alias'], s['stellarity'], s['ra'], s['dec'])
                     for s in msa_source if s['source_id'] == source_id][0]
             except IndexError:
-                log.warning("Could not retrieve source info from MSA file")
+                source_name = f"{prog_id}_VRT{slitlet_id}"
+                source_alias = "VRT{}".format(slitlet_id)
+                stellarity = 0.0
+                source_ra = 0.0
+                source_dec = 0.0
+                log.warning(f"Could not retrieve source info from MSA file; "
+                            f"assigning virtual source_name={source_name}")
 
             if source_id < 0:
                 log.info(f'Slitlet {slitlet_id} contains virtual source, with source_id={source_id}')
diff --git a/jwst/associations/mkpool.py b/jwst/associations/mkpool.py
index 8cc7a6039..4ab467666 100644
--- a/jwst/associations/mkpool.py
+++ b/jwst/associations/mkpool.py
@@ -25,12 +25,16 @@ NON_HEADER_COLS = {
     'is_imprt': 'f',
     'pntgtype': 'science',
     'targetid': '1',
+    'mostilno': '1',
+    'dithptin': '1'
 }
 
 
 def mkpool(data,
-           asn_candidate=NON_HEADER_COLS['asn_candidate'], dms_note=NON_HEADER_COLS['dms_note'],
-           is_imprt=NON_HEADER_COLS['is_imprt'], pntgtype=NON_HEADER_COLS['pntgtype'],
+           asn_candidate=NON_HEADER_COLS['asn_candidate'],
+           dms_note=NON_HEADER_COLS['dms_note'],
+           is_imprt=NON_HEADER_COLS['is_imprt'],
+           pntgtype=NON_HEADER_COLS['pntgtype'],
            **kwargs):
     """Create an association pool from a list of FITS files.
 
@@ -112,8 +116,14 @@ def mkpool(data,
     defaults = {param: 'null' for param in params}
     pool = AssociationPool(names=params, dtype=[object] * len(params))
 
-    # Set default values for user-settable non-header parameters
-    non_header_params = {'dms_note': dms_note, 'is_imprt': is_imprt, 'pntgtype': pntgtype}
+    # Set non-header values from hard-coded defaults
+    non_header_params = NON_HEADER_COLS.copy()
+
+    # Update default values for user-settable non-header parameters
+    non_header_params.update(
+        {'dms_note': dms_note,
+         'is_imprt': is_imprt,
+         'pntgtype': pntgtype})
 
     # Setup for target id calculation
     targetid = 0  # Start off with no target id.
diff --git a/jwst/master_background/master_background_mos_step.py b/jwst/master_background/master_background_mos_step.py
index 3c51c93a6..252155a3c 100644
--- a/jwst/master_background/master_background_mos_step.py
+++ b/jwst/master_background/master_background_mos_step.py
@@ -191,7 +191,7 @@ class MasterBackgroundMosStep(Pipeline):
         # count how many are background vs source.
         num_bkg = num_src = 0
         for slit in data.slits:
-            if "background" in slit.source_name:
+            if nirspec_utils.is_background_msa_slit(slit):
                 num_bkg += 1
             else:
                 num_src += 1
diff --git a/jwst/master_background/nirspec_utils.py b/jwst/master_background/nirspec_utils.py
index 66ccbcab2..77bfa3285 100644
--- a/jwst/master_background/nirspec_utils.py
+++ b/jwst/master_background/nirspec_utils.py
@@ -101,7 +101,7 @@ def create_background_from_multislit(input_model):
     bkg_model.update(input_model)
     slits = []
     for slit in input_model.slits:
-        if "background" in slit.source_name:
+        if is_background_msa_slit(slit):
             log.info(f'Using background slitlet {slit.source_name}')
             slits.append(slit)
 
@@ -242,3 +242,23 @@ def correct_nrs_fs_bkg(input_model, primary_slit):
         input_model.data *= (pl_uniform / pl_point)
 
     return input_model
+
+
+def is_background_msa_slit(slit):
+    """
+    Check if an MSA slitlet is a background source.
+
+    Parameters
+    ----------
+    slit : `~jwst.datamodels.SlitModel`
+        The slit model to check.
+
+    Returns
+    -------
+    bool
+        True if the slit is background; False if it is not.
+    """
+    if "BKG" in str(slit.source_name).upper():
+        return True
+    else:
+        return False


Test patch:
diff --git a/jwst/assign_wcs/tests/test_nirspec.py b/jwst/assign_wcs/tests/test_nirspec.py
index b89ccdcc4..24a78bfab 100644
--- a/jwst/assign_wcs/tests/test_nirspec.py
+++ b/jwst/assign_wcs/tests/test_nirspec.py
@@ -4,6 +4,7 @@ Test functions for NIRSPEC WCS - all modes.
 import functools
 from math import cos, sin
 import os.path
+import shutil
 
 import pytest
 import numpy as np
@@ -355,6 +356,35 @@ def test_msa_configuration_multiple_returns():
     _compare_slits(slitlet_info[1], ref_slit2)
 
 
+def test_msa_missing_source(tmp_path):
+    """
+    Test the get_open_msa_slits function with missing source information.
+    """
+    # modify an existing MSA file to remove source info
+    msaconfl = get_file_path('msa_configuration.fits')
+    bad_confl = str(tmp_path / 'bad_msa_configuration.fits')
+    shutil.copy(msaconfl, bad_confl)
+
+    with fits.open(bad_confl) as msa_hdu_list:
+        source_table = table.Table(msa_hdu_list['SOURCE_INFO'].data)
+        source_table.remove_rows(slice(0, -1))
+        msa_hdu_list['SOURCE_INFO'] = fits.table_to_hdu(source_table)
+        msa_hdu_list[3].name = 'SOURCE_INFO'
+        msa_hdu_list.writeto(bad_confl, overwrite=True)
+
+    prog_id = '1234'
+    msa_meta_id = 12
+    dither_position = 1
+
+    slitlet_info = nirspec.get_open_msa_slits(
+        prog_id, bad_confl, msa_meta_id, dither_position, slit_y_range=[-.5, .5])
+
+    # MSA slit: virtual source name assigned
+    ref_slit = trmodels.Slit(55, 9376, 1, 251, 26, -5.6, 1.0, 4, 1, '1111x',
+                             '1234_VRT55', 'VRT55', 0.0,
+                             -0.31716078999999997, -0.18092266, 0.0, 0.0)
+    _compare_slits(slitlet_info[0], ref_slit)
+
 open_shutters = [[24], [23, 24], [22, 23, 25, 27], [22, 23, 25, 27, 28]]
 main_shutter = [24, 23, 25, 28]
 result = ["x", "x1", "110x01", "110101x"]
diff --git a/jwst/associations/tests/test_mkpool.py b/jwst/associations/tests/test_mkpool.py
index 563c08258..1dda46f2e 100644
--- a/jwst/associations/tests/test_mkpool.py
+++ b/jwst/associations/tests/test_mkpool.py
@@ -9,7 +9,7 @@ from astropy.io import fits
 
 from jwst.associations.tests import helpers
 from jwst.associations import AssociationPool
-from jwst.associations.mkpool import from_cmdline, mkpool
+from jwst.associations.mkpool import from_cmdline, mkpool, NON_HEADER_COLS
 
 # Optional column settings
 OPT_COLS = [('asn_candidate', [('a3001', 'coron')]),
@@ -19,6 +19,7 @@ OPT_COLS = [('asn_candidate', [('a3001', 'coron')]),
 
 # Required column names
 REQUIRED_PARAMS = set(('program', 'filename'))
+NON_HEADER_PARAMS = set(NON_HEADER_COLS.keys())
 
 
 def test_hdu(exposures):
@@ -29,6 +30,7 @@ def test_hdu(exposures):
     pool = mkpool(hdus)
     assert isinstance(pool, AssociationPool)
     assert REQUIRED_PARAMS.issubset(pool.colnames)
+    assert NON_HEADER_PARAMS.issubset(pool.colnames)
     assert len(pool) == len(exposures)
 
 
@@ -40,6 +42,7 @@ def test_hdulist(exposures):
     pool = mkpool(hduls)
     assert isinstance(pool, AssociationPool)
     assert REQUIRED_PARAMS.issubset(pool.colnames)
+    assert NON_HEADER_PARAMS.issubset(pool.colnames)
     assert len(pool) == len(exposures)
     [h.close() for h in hduls]
 
@@ -48,6 +51,7 @@ def test_mkpool(exposures):
     pool = mkpool(exposures)
     assert isinstance(pool, AssociationPool)
     assert REQUIRED_PARAMS.issubset(pool.colnames)
+    assert NON_HEADER_PARAMS.issubset(pool.colnames)
     assert len(pool) == len(exposures)
     filenames = [
         filename
@@ -68,6 +72,16 @@ def test_opt_cols_cmdline(mkpool_cmdline, opt_cols):
     _test_opt_cols(mkpool_cmdline, opt_cols)
 
 
+def test_nonheader_cols(mkpool_with_args):
+    """Ensure that non-header defaults are properly set."""
+    _test_nonheader_cols(mkpool_with_args)
+
+
+def test_nonheader_cols_cmdline(mkpool_cmdline):
+    """Ensure that non-header defaults are properly set with the command line."""
+    _test_nonheader_cols(mkpool_cmdline)
+
+
 # ####################
 # Fixtures & Utilities
 # ####################
@@ -111,3 +125,14 @@ def _test_opt_cols(mkpool_with_args, opt_cols):
     if column == 'asn_candidate':
         expected = '[' + str(('o001', 'observation')) + ', ' + str(expected)[1:]
     assert mkpool_with_args[0][column] == expected
+
+
+def _test_nonheader_cols(mkpool_with_args):
+    """Ensure that non-header defaults are properly set"""
+    opt_dict = dict(OPT_COLS)
+    for column, expected in NON_HEADER_COLS.items():
+        if column in opt_dict:
+            expected = opt_dict[column]
+        if column == 'asn_candidate':
+            expected = '[' + str(('o001', 'observation')) + ', ' + str(expected)[1:]
+        assert mkpool_with_args[0][column] == expected
diff --git a/jwst/master_background/tests/test_nirspec_corrections.py b/jwst/master_background/tests/test_nirspec_corrections.py
index af44f2f0c..6e5a4f427 100644
--- a/jwst/master_background/tests/test_nirspec_corrections.py
+++ b/jwst/master_background/tests/test_nirspec_corrections.py
@@ -2,11 +2,12 @@
 Unit tests for master background NIRSpec corrections
 """
 import numpy as np
+import pytest
 
 from stdatamodels.jwst import datamodels
 
 from jwst.master_background.nirspec_utils import (
-    correct_nrs_ifu_bkg, correct_nrs_fs_bkg
+    correct_nrs_ifu_bkg, correct_nrs_fs_bkg, is_background_msa_slit
 )
 
 
@@ -54,3 +55,15 @@ def test_fs_correction():
     result = correct_nrs_fs_bkg(input, primary_slit=True)
 
     assert np.allclose(corrected, result.data, rtol=1.e-7)
+
+
+@pytest.mark.parametrize('name,status',
+                         [('BKG101', True), ('bkg101', True),
+                          ('background_101', False), ('101', False),
+                          (None, False)])
+def test_is_background(name, status):
+    """Test check for background slit."""
+    slit = datamodels.SlitModel()
+    if name is not None:
+        slit.source_name = name
+    assert is_background_msa_slit(slit) == status