Source code for parse_cm.characteristics

# Licensed under a 3-clause BSD style license - see LICENSE.rst
import re

import numpy as np

from .common import _get_content_as_lines

__all__ = ['read_characteristics']


def transform_ODB_SI_ALIGN(values):
    """
    Transform the raw tuple of ODB_SI_ALIGN values into a structure suitable
    for Python manipulation.

    :param values: tuple
    :returns: dictionary of matrices, one per detector in C/Python order
    """
    values = np.array(values).reshape(4, 3, 3)

    si_align = {'ACIS-I': values[0].transpose(),
                'ACIS-S': values[1].transpose(),
                'HRC-I': values[2].transpose(),
                'HRC-S': values[3].transpose()}

    return si_align


[docs] def read_characteristics(content='CHARACTERIS_12OCT15', item=None, raw=False): """ Read OFLS ODB CHARACTERISTICS file. If ``item`` is supplied then only that item is returns. By default any available transformation routines will be applied. Transform routines are any function named ``transform_<item>``. This can be disabled by setting ``raw=True`` to get raw values. :param content: OFLS ODB characteristics file name or lines :param item: return only the ``item`` characteristic :param raw: return raw values instead of transforming where possible :returns: dictionary of characteristic values """ lines = _get_content_as_lines(content) # Remove comments and whitespace lines = (line for line in lines if not (line.startswith('C') or re.match(r'\s*[$]', line))) lines = (re.sub(r'!.*', '', line).strip() for line in lines) lines = [line for line in lines if line] # Drop zeros initialization for ODB_OBC_SCP_MEM, otherwise code fails because it ends # up trying to set a tuple. lines = [line for line in lines if not line.startswith('ODB_OBC_SCP_MEM = 1024*0')] # If getting just an item then keep only relevant lines if item is not None: new_lines = [] for line in lines: if new_lines and line.startswith('ODB'): lines = new_lines break if new_lines or line.startswith(item): new_lines.append(line) last_line = len(lines) - 1 dict_vars = set() re_mult = re.compile(r'(\d+) \* ([^,]+,)', re.VERBOSE) # NOTE: a much better way to do this would be to collect up the lines into a single # string for each key and then use eval(). This requires a little change in logic as # well as parsing the indices. Next time! for i, line in enumerate(lines): if i == last_line: continue # Fix a couple of errors in baseline characteristics if line == '1,2,4, 1,2,5, 1,2,6, 1,3,4 1,4,6,': line = '1,2,4, 1,2,5, 1,2,6, 1,3,4, 1,4,6,' if line.endswith('9,17,3, 10,19,4, 9,19,3, 10,20,4, 9,16,3, 9,17,3'): line = line + ',' # Change Fortran D-style exponents to E line = re.sub(r'([\d.])D([-+\d])', r'\1E\2', line) # Replace multiplier syntax with expanded version. E.g. 3*0.0, = > 0.0, 0.0, 0.0, while True: match = re_mult.search(line) if match: mult, val = match.groups() line = re_mult.sub(val * int(mult), line) else: break # If the next line is not an ODB specifier then append a Python continuation char if not lines[i + 1].startswith('ODB'): line = line + '\\' # Turn ODB declaration into a Python declaration setting a key value # in the global `ODB` dict. if line.startswith('ODB'): match = re.match(r'(ODB_ \w+) ' r'( \( [\d,\s]+ \) )?' r' \s* = (.*)', line, re.VERBOSE) if not match: raise ValueError('Could not parse line\n{}'.format(line)) name, indices, value = match.groups() if indices: dict_vars.add(name) line = 'ODB["{}"][{}] ={}'.format(name, indices[1:-1], value) else: line = 'ODB["{}"] ={}'.format(name, value) lines[i] = line declare_dicts = ['ODB["{}"] = dict()'.format(var) for var in dict_vars] lines = ['ODB = dict()'] + declare_dicts + lines # This sets `ODB` locally. Note: cannot define ODB (e.g. ODB=None) to fix flymake # highlighting. For some reason this prevents exec statement from working. namespace = {} exec('\n'.join(lines), namespace) ODB = namespace['ODB'] for key, val in ODB.items(): if isinstance(val, tuple) and len(val) == 1: ODB[key] = val[0] if not raw: transform_func = 'transform_{}'.format(key) if transform_func in globals(): ODB[key] = globals()[transform_func](val) return ODB[item] if item else ODB