Exemple #1
0
def reference_keys_to_dataset_keys(rmapping, header):
    """Given a header dictionary for a reference file,  map the header back to
    keys relevant to datasets.
    """
    result = dict(header)

    #  XXXXX TODO   Add/consolidate logic to handle P_ pattern keywords

    # If USEAFTER is defined,  or we're configured to fake it...
    #   don't invent one if its missing and we're not faking it.
    if "USEAFTER" in header or config.ALLOW_BAD_USEAFTER:

        # Identify reference involved as best as possible
        filename = header.get("FILENAME", None) or rmapping.filename

        reformatted = timestamp.reformat_useafter(filename, header).split()
        result["DATE-OBS"] = reformatted[0]
        result["DATE_OBS"] = reformatted[0]
        result["TIME-OBS"] = reformatted[1]
        result["TIME_OBS"] = reformatted[1]

    return result
Exemple #2
0
def reference_keys_to_dataset_keys(rmapping, header):
    """Given a header dictionary for a reference file,  map the header back to
    keys relevant to datasets.
    """
    result = dict(header)
    
    #  XXXXX TODO   Add/consolidate logic to handle P_ pattern keywords

    # If USEAFTER is defined,  or we're configured to fake it...
    #   don't invent one if its missing and we're not faking it.
    if "USEAFTER" in header or config.ALLOW_BAD_USEAFTER:

        # Identify reference involved as best as possible
        filename = header.get("FILENAME", None) or rmapping.filename

        reformatted = timestamp.reformat_useafter(filename, header).split()
        result["DATE-OBS"] = reformatted[0]
        result["DATE_OBS"] = reformatted[0]
        result["TIME-OBS"] = reformatted[1]
        result["TIME_OBS"] = reformatted[1]
    
    return result
Exemple #3
0
def reference_keys_to_dataset_keys(rmapping, header):
    """Given a header dictionary for a reference file, map the header back to keys
    relevant to datasets.  So for ACS biasfile the reference says BINAXIS1 but
    the dataset says NUMCOLS.  This would convert { "BINAXIS1": 1024 } to {
    "NUMCOLS" : 1024 }.

    In general,  rmap parkeys are matched against datset values and are defined
    as dataset header keywords.   For refactoring though,  what's initially
    available are reference file keywords...  which need to be mapped into the
    terms rmaps know:  dataset keywords.
    """
    header = dict(header)

    # Basic common pattern translations
    translations = {
            "META.EXPOSURE.P_EXPTYPE" : "META.EXPOSURE.TYPE",
            "P_EXP_TY" : "META.EXPOSURE.TYPE",

            "META.INSTRUMENT.P_BAND" : "META.INSTRUMENT.BAND",
            "P_BAND" : "META.INSTRUMENT.BAND",

            "META.INSTRUMENT.P_DETECTOR"  : "META.INSTRUMENT.DETECTOR",
            "P_DETECT"  : "META.INSTRUMENT.DETECTOR",

            "META.INSTRUMENT.P_CHANNEL" : "META.INSTRUMENT.CHANNEL",
            "P_CHANNE" : "META.INSTRUMENT.CHANNEL",

            "META.INSTRUMENT.P_FILTER" : "META.INSTRUMENT.FILTER",
            "P_FILTER"  : "META.INSTRUMENT.FILTER",

            "META.INSTRUMENT.P_PUPIL"  : "META.INSTRUMENT.PUPIL",
            "P_PUPIL" : "META.INSTRUMENT.PUPIL",

            "META.INSTRUMENT.P_MODULE"  : "META.INSTRUMENT.MODULE",
            "P_MODULE" : "META.INSTRUMENT.MODULE",

            "META.SUBARRAY.P_SUBARRAY" : "META.SUBARRAY.NAME",
            "P_SUBARR" : "META.SUBARRAY.NAME",

            "META.INSTRUMENT.P_GRATING" : "META.INSTRUMENT.GRATING",
            "P_GRATIN" : "META.INSTRUMENT.GRATING",

            "META.EXPOSURE.PREADPATT" : "META.EXPOSURE.READPATT",
            "META.EXPOSURE.P_READPATT" : "META.EXPOSURE.READPATT",
            "P_READPA" : "META.EXPOSURE.READPATT",

            # vvvv Speculative,  not currently defined or required by CAL vvvvv
            "META.INSTRUMENT.PCORONAGRAPH" : "META.INSTRUMENT.CORONAGRAPH",
            "P_CORONM" : "META.INSTRUMENT.CORONAGRAPH",
        }

    # Rmap header reference_to_dataset field tranlations,  can override basic!
    try:
        translations.update(rmapping.reference_to_dataset)
    except AttributeError:
        pass

    log.verbose("reference_to_dataset translations:\n", log.PP(translations), verbosity=60)
    log.verbose("reference_to_dataset input header:\n", log.PP(header), verbosity=80)

    for key in header:
        # Match META.X.P_SOMETHING or P_SOMETH
        if (key.split(".")[-1].startswith("P_")) and key not in translations:
            log.warning("CRDS-pattern-like keyword", repr(key),
                        "w/o CRDS translation to corresponding dataset keyword.")
            log.info("Pattern-like keyword", repr(key),
                     "may be misspelled or missing its translation in CRDS.  Pattern will not be used.")
            log.info("The translation for", repr(key),
                     "can be defined in crds.jwst.locate or rmap header reference_to_dataset field.")
            log.info("If this is not a pattern keyword, adding a translation to 'not-a-pattern'",
                     "will suppress this warning.")

    # Add replacements for translations *if* the existing untranslated value
    # is poor and the translated value is better defined.   This is to do
    # translations w/o replacing valid/concrete DM values with something
    # like guessed values of "UNDEFINED" or "N/A".
    for rkey in sorted(translations):
        if rkey in header:
            dkey = translations[rkey]
            dval = header.get(translations[rkey], None)
            rval = header[rkey]
            if rval not in [None, "UNDEFINED"] and rval != dval:
                log.info("Setting", repr(dkey), "=", repr(dval),
                         "to value of", repr(rkey), "=", repr(rval))
                header[dkey] = rval

    header = abstract.cross_strap_header(header)

    # NOTE:  the hacks below happen after cross-strapping and pattern handling
    # so if the keywords are still undefined they're undefined.  They have to
    # be explicitly defined as UNDEFINED somehow since they're nearly universally
    # used in constraints as condition variables even if they're not used in rmaps.
    # Unlike the targets of constraints,  CRDS is nominally unaware of condition
    # variables so they need to be incidentally defined.  This currently doesn't
    # work out if the rmap doesn't use them.  Condition variables are eval'ed in
    # expressions.

    if "SUBARRAY" not in header:
        header["SUBARRAY"] = header["META.SUBARRAY.NAME"] = "UNDEFINED"

    if "EXP_TYPE" not in header:
        header["EXP_TYPE"] = header["META.EXPOSURE.TYPE"] = "UNDEFINED"

    if "USEAFTER" not in header and "META.USEAFTER" in header:
        header["USEAFTER"] = header["META.USEAFTER"]
    if "USEAFTER" not in header and "META.USEAFTER" in header:
        header["USEAFTER"] = header["META.USEAFTER"]

    # If USEAFTER is defined,  or we're configured to fake it...
    #   don't invent one if its missing and we're not faking it.
    if "USEAFTER" in header or config.ALLOW_BAD_USEAFTER:

        # Identify this as best as possible,
        filename = header.get("FILENAME", None) or rmapping.filename

        reformatted = timestamp.reformat_useafter(filename, header).split()
        header["DATE-OBS"] = header["META.OBSERVATION.DATE"] = reformatted[0]
        header["TIME-OBS"] = header["META.OBSERVATION.TIME"] = reformatted[1]

    log.verbose("reference_to_dataset output header:\n", log.PP(header), verbosity=80)

    return header
Exemple #4
0
def reference_keys_to_dataset_keys(rmapping, header):
    """Given a header dictionary for a reference file, map the header back to keys
    relevant to datasets.  So for ACS biasfile the reference says BINAXIS1 but
    the dataset says NUMCOLS.  This would convert { "BINAXIS1": 1024 } to {
    "NUMCOLS" : 1024 }.

    In general,  rmap parkeys are matched against datset values and are defined
    as dataset header keywords.   For refactoring though,  what's initially
    available are reference file keywords...  which need to be mapped into the
    terms rmaps know:  dataset keywords.

    Another aspect of this translation is handling reference file "pattern"
    keywords which typically define or-barred sets of values rather than
    discrete values, any of which the reference is defined to support:
    e.g. 'DETECTOR1|DETECTOR2' vs. 'DETECTOR1'.  In this case, the reference
    file will define a pattern keyword used to define the match pattern in the
    rmap, while a dataset will define a discrete valued keyword which is
    matched on.  e.g. reference file keyword "META.EXPOSURE.P_EXPTYPE" is
    translated back to dataset keyword "META.EXPOSURE.TYPE".  Reference files
    can specify parameters in either form and the P_ pattern variant is given
    preference if both values are defined.  For CRDS purposes, only the P_
    version is checked and used since it will be used to replace the discrete
    valued keyword in the header which is certified and used to define the rmap
    updates.

    Note, can't test unrecognized "P_" keywords because the logging appeares to go to stderr which doctests don't check.

    ==================================================
    Test adding a translation.

    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({'MOUSE' : 'RAT'}, ''), \
    {"MOUSE" : "MICKEY", "RAT" : "MORTIMER"})
    {'MOUSE': 'MICKEY', 'RAT': 'MICKEY', 'ROMAN.META.SUBARRAY.NAME': 'UNDEFINED', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED'}

    ==================================================
    Test replacing translated values with untranslated values.

    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({'MOUSE' : 'RAT'}, ''), \
    {"ROMAN.META.EXPOSURE.P_EXPTYPE" : None, \
    "ROMAN.META.INSTRUMENT.P_BAND" : "UNDEFINED", \
    "ROMAN.META.INSTRUMENT.P_DETECTOR"  : "RADAR", \
    "ROMAN.META.INSTRUMENT.P_CHANNEL" : None, \
    "ROMAN.META.INSTRUMENT.CHANNEL" : None, \
    "ROMAN.META.INSTRUMENT.P_FILTER" : "UNDEFINED", \
    "ROMAN.META.INSTRUMENT.FILTER" : None, \
    "ROMAN.META.INSTRUMENT.P_MODULE" : "LUNAR", \
    "ROMAN.META.INSTRUMENT.MODULE" : None, \
    "ROMAN.META.SUBARRAY.P_SUBARRAY" : None, \
    "ROMAN.META.SUBARRAY.NAME" : "YELLOW", \
    "ROMAN.META.INSTRUMENT.P_GRATING" : "UNDEFINED", \
    "ROMAN.META.INSTRUMENT.GRATING" : "MOZZARELLA", \
    "ROMAN.META.EXPOSURE.PREADPATT" : "CHECKERBOARD", \
    "ROMAN.META.EXPOSURE.READPATT" : "CHESSBOARD"})
    {'ROMAN.META.EXPOSURE.P_EXPTYPE': None, 'ROMAN.META.INSTRUMENT.P_BAND': 'UNDEFINED', 'ROMAN.META.INSTRUMENT.P_DETECTOR': 'RADAR', 'ROMAN.META.INSTRUMENT.P_CHANNEL': None, 'ROMAN.META.INSTRUMENT.CHANNEL': None, 'ROMAN.META.INSTRUMENT.P_FILTER': 'UNDEFINED', 'ROMAN.META.INSTRUMENT.FILTER': None, 'ROMAN.META.INSTRUMENT.P_MODULE': 'LUNAR', 'ROMAN.META.INSTRUMENT.MODULE': 'LUNAR', 'ROMAN.META.SUBARRAY.P_SUBARRAY': None, 'ROMAN.META.SUBARRAY.NAME': 'YELLOW', 'ROMAN.META.INSTRUMENT.P_GRATING': 'UNDEFINED', 'ROMAN.META.INSTRUMENT.GRATING': 'MOZZARELLA', 'ROMAN.META.EXPOSURE.PREADPATT': 'CHECKERBOARD', 'ROMAN.META.EXPOSURE.READPATT': 'CHECKERBOARD', 'ROMAN.META.INSTRUMENT.DETECTOR': 'RADAR', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED'}

    ==================================================
    Test setting missing subarray and exposure type values.

    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({}, ''), \
    {})
    {'ROMAN.META.SUBARRAY.NAME': 'UNDEFINED', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED'}

    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({}, ''), \
    {'ROMAN.META.SUBARRAY.NAME' : 'REDOCTOBER', \
    'ROMAN.META.EXPOSURE.TYPE' : 'NORTHFACE'})
    {'ROMAN.META.SUBARRAY.NAME': 'REDOCTOBER', 'ROMAN.META.EXPOSURE.TYPE': 'NORTHFACE'}

    ==================================================
    Test preserving existing subarry adn exposure type values.

    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({}, ''), \
    {'ROMAN.META.SUBARRAY.NAME' : 'REDOCTOBER', \
    'ROMAN.META.EXPOSURE.TYPE' : 'NORTHFACE'})
    {'ROMAN.META.SUBARRAY.NAME': 'REDOCTOBER', 'ROMAN.META.EXPOSURE.TYPE': 'NORTHFACE'}

    ==================================================
    Test preseverving existing DATE/TIME if no USEAFTER value.

    >>> config.ALLOW_BAD_USEAFTER.reset()
    >>> reference_keys_to_dataset_keys( \
    namedtuple('x', ['reference_to_dataset', 'filename'])({}, 'secret_code_file.txt'), \
    {'ROMAN.META.OBSERVATION.DATE' : '1879-03-14', \
     'ROMAN.META.OBSERVATION.TIME' : '12:34:56'})
    {'ROMAN.META.OBSERVATION.DATE': '1879-03-14', 'ROMAN.META.OBSERVATION.TIME': '12:34:56', 'ROMAN.META.SUBARRAY.NAME': 'UNDEFINED', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED'}

    ==================================================
    Test setting DATE/TIME with no USEAFTER, but allowed "bad use after".

    >>> config.ALLOW_BAD_USEAFTER.reset()
    >>> config.ALLOW_BAD_USEAFTER.set("1")
    False
    >>> reference_keys_to_dataset_keys(namedtuple('x', ['reference_to_dataset', 'filename'])({}, 'secret_code_file.txt'), {})
    {'ROMAN.META.SUBARRAY.NAME': 'UNDEFINED', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED', 'ROMAN.META.OBSERVATION.DATE': '1900-01-01', 'ROMAN.META.OBSERVATION.TIME': '00:00:00'}

    ==================================================
    Test setting DATE/TIME from USEAFTER.

    >>> config.ALLOW_BAD_USEAFTER.reset()
    >>> config.ALLOW_BAD_USEAFTER.set("1")
    False
    >>> reference_keys_to_dataset_keys(namedtuple('x', ['reference_to_dataset', 'filename'])({}, 'secret_code_file.txt'), \
    {'ROMAN.META.USEAFTER' : '1770-12-01T01:23:45', \
     'ROMAN.META.OBSERVATION.DATE' : '1879-03-14', \
     'ROMAN.META.OBSERVATION.TIME' : '12:34:56'})
    {'ROMAN.META.USEAFTER': '1770-12-01T01:23:45', 'ROMAN.META.OBSERVATION.DATE': '1770-12-01', 'ROMAN.META.OBSERVATION.TIME': '01:23:45', 'ROMAN.META.SUBARRAY.NAME': 'UNDEFINED', 'ROMAN.META.EXPOSURE.TYPE': 'UNDEFINED'}

    ==================================================
    Test bad formatted USEAFTER.

    >>> config.ALLOW_BAD_USEAFTER.reset()
    >>> reference_keys_to_dataset_keys(namedtuple('x', ['reference_to_dataset', 'filename'])({}, 'secret_code_file.txt'), \
    {'ROMAN.META.USEAFTER' : 'bad user after', \
     'ROMAN.META.OBSERVATION.DATE' : '1879-03-14', \
     'ROMAN.META.OBSERVATION.TIME' : '12:34:56'})
    Traceback (most recent call last):
    ...
    crds.core.exceptions.InvalidUseAfterFormat: Bad USEAFTER time format = 'bad user after'
    """
    header = dict(header)

    # Basic common pattern translations
    translations = {
        "ROMAN.META.EXPOSURE.P_EXPTYPE": "ROMAN.META.EXPOSURE.TYPE",
        "ROMAN.META.INSTRUMENT.P_BAND": "ROMAN.META.INSTRUMENT.BAND",
        "ROMAN.META.INSTRUMENT.P_DETECTOR": "ROMAN.META.INSTRUMENT.DETECTOR",
        "ROMAN.META.INSTRUMENT.P_CHANNEL": "ROMAN.META.INSTRUMENT.CHANNEL",
        "ROMAN.META.INSTRUMENT.P_FILTER": "ROMAN.META.INSTRUMENT.FILTER",
        "ROMAN.META.INSTRUMENT.P_MODULE": "ROMAN.META.INSTRUMENT.MODULE",
        "ROMAN.META.SUBARRAY.P_SUBARRAY": "ROMAN.META.SUBARRAY.NAME",
        "ROMAN.META.INSTRUMENT.P_GRATING": "ROMAN.META.INSTRUMENT.GRATING",
        "ROMAN.META.EXPOSURE.PREADPATT": "ROMAN.META.EXPOSURE.READPATT",
        "ROMAN.META.EXPOSURE.P_READPATT": "ROMAN.META.EXPOSURE.READPATT",

        # vvvv Speculative,  not currently defined or required by CAL vvvvv
        "ROMAN.META.INSTRUMENT.PCORONAGRAPH":
        "ROMAN.META.INSTRUMENT.CORONAGRAPH",
    }

    # Rmap header reference_to_dataset field tranlations,  can override basic!
    try:
        translations.update(rmapping.reference_to_dataset)
    except AttributeError:
        pass

    log.verbose("reference_to_dataset translations:\n",
                log.PP(translations),
                verbosity=60)
    log.verbose("reference_to_dataset input header:\n",
                log.PP(header),
                verbosity=80)

    for key in header:
        # Match META.X.P_SOMETHING or P_SOMETH
        if (key.split(".")[-1].startswith("P_")) and key not in translations:
            log.warning(
                "CRDS-pattern-like keyword", repr(key),
                "w/o CRDS translation to corresponding dataset keyword.")
            log.info(
                "Pattern-like keyword", repr(key),
                "may be misspelled or missing its translation in CRDS.  Pattern will not be used."
            )
            log.info(
                "The translation for", repr(key),
                "can be defined in crds.roman.locate or rmap header reference_to_dataset field."
            )
            log.info(
                "If this is not a pattern keyword, adding a translation to 'not-a-pattern'",
                "will suppress this warning.")

    # Add replacements for translations *if* the existing untranslated value
    # is poor and the translated value is better defined.   This is to do
    # translations w/o replacing valid/concrete DM values with something
    # like guessed values of "UNDEFINED" or "N/A".
    for rkey in sorted(translations):
        if rkey in header:
            dkey = translations[rkey]
            dval = header.get(translations[rkey], None)
            rval = header[rkey]
            if rval not in [None, "UNDEFINED"] and rval != dval:
                log.info("Setting", repr(dkey), "=", repr(dval), "to value of",
                         repr(rkey), "=", repr(rval))
                header[dkey] = rval

    if "ROMAN.META.SUBARRAY.NAME" not in header:
        header["ROMAN.META.SUBARRAY.NAME"] = "UNDEFINED"

    if "ROMAN.META.EXPOSURE.TYPE" not in header:
        header["ROMAN.META.EXPOSURE.TYPE"] = "UNDEFINED"

    # If USEAFTER is defined,  or we're configured to fake it...
    #   don't invent one if its missing and we're not faking it.
    if "ROMAN.META.USEAFTER" in header or config.ALLOW_BAD_USEAFTER:

        # Identify this as best as possible,
        filename = header.get("ROMAN.META.FILENAME", None) or rmapping.filename

        reformatted = timestamp.reformat_useafter(filename, header).split()
        header["ROMAN.META.OBSERVATION.DATE"] = reformatted[0]
        header["ROMAN.META.OBSERVATION.TIME"] = reformatted[1]

    log.verbose("reference_to_dataset output header:\n",
                log.PP(header),
                verbosity=80)

    return header
Exemple #5
0
def reference_keys_to_dataset_keys(rmapping, header):
    """Given a header dictionary for a reference file, map the header back to keys
    relevant to datasets.  So for ACS biasfile the reference says BINAXIS1 but
    the dataset says NUMCOLS.  This would convert { "BINAXIS1": 1024 } to {
    "NUMCOLS" : 1024 }.

    In general,  rmap parkeys are matched against datset values and are defined
    as dataset header keywords.   For refactoring though,  what's initially
    available are reference file keywords...  which need to be mapped into the
    terms rmaps know:  dataset keywords.

    Another aspect of this translation is handling reference file "pattern"
    keywords which typically define or-barred sets of values rather than
    discrete values, any of which the reference is defined to support:
    e.g. 'DETECTOR1|DETECTOR2' vs. 'DETECTOR1'.  In this case, the reference
    file will define a pattern keyword used to define the match pattern in the
    rmap, while a dataset will define a discrete valued keyword which is
    matched on.  e.g. reference file keyword "META.EXPOSURE.P_EXPTYPE" is
    translated back to dataset keyword "META.EXPOSURE.TYPE".  Reference files
    can specify parameters in either form and the P_ pattern variant is given
    preference if both values are defined.  For CRDS purposes, only the P_
    version is checked and used since it will be used to replace the discrete
    valued keyword in the header which is certified and used to define the rmap
    updates.
    """
    header = dict(header)

    # Basic common pattern translations
    translations = {
            "META.EXPOSURE.P_EXPTYPE" : "META.EXPOSURE.TYPE",

            "META.INSTRUMENT.P_BAND" : "META.INSTRUMENT.BAND",

            "META.INSTRUMENT.P_DETECTOR"  : "META.INSTRUMENT.DETECTOR",

            "META.INSTRUMENT.P_CHANNEL" : "META.INSTRUMENT.CHANNEL",

            "META.INSTRUMENT.P_FILTER" : "META.INSTRUMENT.FILTER",

            "META.INSTRUMENT.P_MODULE"  : "META.INSTRUMENT.MODULE",

            "META.SUBARRAY.P_SUBARRAY" : "META.SUBARRAY.NAME",

            "META.INSTRUMENT.P_GRATING" : "META.INSTRUMENT.GRATING",

            "META.EXPOSURE.PREADPATT" : "META.EXPOSURE.READPATT",
            "META.EXPOSURE.P_READPATT" : "META.EXPOSURE.READPATT",

            # vvvv Speculative,  not currently defined or required by CAL vvvvv
            "META.INSTRUMENT.PCORONAGRAPH" : "META.INSTRUMENT.CORONAGRAPH",
        }

    # Rmap header reference_to_dataset field tranlations,  can override basic!
    try:
        translations.update(rmapping.reference_to_dataset)
    except AttributeError:
        pass

    log.verbose("reference_to_dataset translations:\n", log.PP(translations), verbosity=60)
    log.verbose("reference_to_dataset input header:\n", log.PP(header), verbosity=80)

    for key in header:
        # Match META.X.P_SOMETHING or P_SOMETH
        if (key.split(".")[-1].startswith("P_")) and key not in translations:
            log.warning("CRDS-pattern-like keyword", repr(key),
                        "w/o CRDS translation to corresponding dataset keyword.")
            log.info("Pattern-like keyword", repr(key),
                     "may be misspelled or missing its translation in CRDS.  Pattern will not be used.")
            log.info("The translation for", repr(key),
                     "can be defined in crds.roman.locate or rmap header reference_to_dataset field.")
            log.info("If this is not a pattern keyword, adding a translation to 'not-a-pattern'",
                     "will suppress this warning.")

    # Add replacements for translations *if* the existing untranslated value
    # is poor and the translated value is better defined.   This is to do
    # translations w/o replacing valid/concrete DM values with something
    # like guessed values of "UNDEFINED" or "N/A".
    for rkey in sorted(translations):
        if rkey in header:
            dkey = translations[rkey]
            dval = header.get(translations[rkey], None)
            rval = header[rkey]
            if rval not in [None, "UNDEFINED"] and rval != dval:
                log.info("Setting", repr(dkey), "=", repr(dval),
                         "to value of", repr(rkey), "=", repr(rval))
                header[dkey] = rval

    if "META.SUBARRAY.NAME" not in header:
        header["META.SUBARRAY.NAME"] = "UNDEFINED"

    if "META.EXPOSURE.TYPE" not in header:
        header["META.EXPOSURE.TYPE"] = "UNDEFINED"

    # If USEAFTER is defined,  or we're configured to fake it...
    #   don't invent one if its missing and we're not faking it.
    if "META.USEAFTER" in header or config.ALLOW_BAD_USEAFTER:

        # Identify this as best as possible,
        filename = header.get("META.FILENAME", None) or rmapping.filename

        reformatted = timestamp.reformat_useafter(filename, header).split()
        header["META.OBSERVATION.DATE"] = reformatted[0]
        header["META.OBSERVATION.TIME"] = reformatted[1]

    log.verbose("reference_to_dataset output header:\n", log.PP(header), verbosity=80)

    return header