Source code for irfpy.mima.energy

""" Energy table for MEX/IMA

Energy table for VEX/IMA can be obtained by a function

- :func:`get_default_table_for` : When you have raw data
  (:class:`CntMatrix2D <irfpy.imacommon.imascipac.CntMatrix2D>`
  or :class:`CntMatrix <irfpy.imacommon.imascipac.CntMatrix>`)

See the description in :func:`get_default_table_for` to read the data and the energy table.

- :func:`get_default_table` : When you know EEPROM/PROM of the data.

**Energy table, patch, and version.**

- Italic is for the EEPROM section where patch was applied.
- Plus (+) is for the EEPROM section that is used for nominal operation.
- T0 is version 4: :func:`get_default_table_v4`
- T1 is version 5: :func:`get_default_table_v5`
- T2 is also version 5 but different from T1. ``irfpy`` calls as ``v5_late``: :func:`get_default_table_v5_late`
- T3 is version 6: :func:`get_default_table_v6` or :func:`get_default_table_v6_squashed`

========== == == ====== ====== ====== ====== ====== ==============================
Patch ver            p0     p1     p2     p3     p4
Patch date       020412 060520 090625 130220 130909
---------- -- -- ------ ------ ------ ------ ------ ------------------------------
Section    HK HK
---------- -- -- ------ ------ ------ ------ ------ ------------------------------
PROM        0  0    +T0     T0     T0     T0     T0
EEPROM0     1  1     T0  +*T1*     T1     T1     T1
EEPROM1     2  2     T0   *T1*     T1     T1     T1
EEPROM2     3  3     T0   *T1*     T1     T1     T1
EEPROM3     4  4     T0   *T1*     T1     T1     T1
EEPROM4     5  5     T0   *T1*     T1     T1     T1
EEPROM5     6  6     T0   *T1*     T1     T1     T1
EEPROM6     7  7     T0   *T1*     T1     T1     T1
EEPROM7     8  8     T0   *T1*     T1     T1     T1
EEPROM8     9  9     T0   *T1*     T1     T1     T1
EEPROM9    10  a     T0   *T1*     T1     T1     T1
EEPROM10   11  b     T0   *T1*     T1     T1     T1
EEPROM11   12  c     T0   *T1*     T1     T1     T1
EEPROM12   13  d     T0   *T1*     T1     T1     T1
EEPROM13   14  e     T0   *T1*     T1     T1   *T3* For fast-mode
EEPROM14   15  f     T0   *T1*     T1   *T2*     T2 For auto-reduction
EEPROM15   16 10     T0   *T1*  +*T2*    +T2    +T2
========== == == ====== ====== ====== ====== ====== ==============================

For IMAextra, ``ETableN`` entry of ``data`` dictionary gives the information of energy table.
Users can use the function :func:`get_default_table_extra` to choose the energy table.

======== =========== ===========================================
IMAEXTRA PROM/EEPROM Version
-------- ----------- -------------------------------------------
0        0           :func:`v4 <get_default_table_v4>`
1        1           :func:`v5 <get_default_table_v5>`
2        15, 16      :func:`v5late <get_default_table_v5_late>`
3? (TBC) 14          :func:`v6 <get_default_table_v6>`
======== =========== ===========================================

See https://sspt-wiki.irf.se/doku.php?id=sspt:imaenergytable for details.

**Negative energy**

Some of the default table contains negative energy, which should be invalid.
For normal data analysis, those values shall be disregarded.
In this case, you can use, for example,

>>> tbl = get_default_table_v5_late()
>>> print(tbl[95])
-20.0
>>> tbl[tbl < 0] = np.nan
>>> print(tbl[95])
nan

For some specific purposes, ``irfpy`` support to change this feature,
namely, the negative values are converted to arbitrary positive values.

>>> tbl = get_default_table_v5_late(keep_negative=False)
>>> tbl[95]    # This is an arbitrary positive value.
1e-10
"""
import numpy as np


[docs]def get_default_table_for(imadata, keep_negative=True): """ Get the energy table for MEX/IMA :param imadata: Data of MEX/IMA. :class:`irfpy.imacommon.imascipac.CntMatrix` object is expected. :param keep_negative: If *True* (default), negative energy is kept as is. Thus, the returned table will contain negative energy. If *False*, the negative values are proxied by a very small positive energy, in order to confirm the returned array always positive. :return: The energy table in eV/q. (96) shape. Example of getting the energy table: First, to get the IMA data, a peraparation is eneded. >>> import datetime >>> from irfpy.mima.rawdata import DataCenterCount3d >>> dc = DataCenterCount3d() Then, you get the data. >>> t0 = datetime.datetime(2005, 10, 5, 7, 30) >>> t, ima3d = dc.nextof(t0) # ima3d is an object of irfpy.imacommon.imascipac.CntMatrix >>> print(t) 2005-10-05 07:31:47.529660 >>> print(ima3d) <<class 'irfpy.imacommon.imascipac.CntMatrix'>(MEX/IMA)@2005-10-05T07:31:47.529660:MOD=24 >>24<<:CNTmax=108> Now, you can get the IMA energy table. >>> etbl = get_default_table_for(ima3d) # Getting the energy table >>> print(etbl[0]) 32288.7 Different time uses different energy table. >>> t0 = datetime.datetime(2008, 10, 5, 4, 0, 0) >>> t, ima3d = dc.nextof(t0) >>> etbl = get_default_table_for(ima3d) >>> print(etbl[0]) 25001.5 >>> t0 = datetime.datetime(2012, 10, 5, 4, 0, 0) >>> t, ima3d = dc.nextof(t0) >>> etbl = get_default_table_for(ima3d) >>> print(etbl[0]) 15005.6 """ promsection = imadata.hk.promsection return get_default_table(promsection, keep_negative=keep_negative)
[docs]def get_default_table_extra(etablen, keep_negative=True): """Get the default energy table for MEX/IMA used for IMAEXTRA :param etablen: ETableN :param keep_negative: If *True* (default), negative energy is kept as is. Thus, the returned table will contain negative energy. If *False*, the negative values are proxied by a very small positive energy, in order to confirm the returned array always positive. :return: The energy table in eV/q. (96) shape. Limitation is that we only support 0, 1, and 2. """ if etablen == 0: return get_default_table_v4(keep_negative=keep_negative) elif etablen == 1: return get_default_table_v5(keep_negative=keep_negative) elif etablen == 2: return get_default_table_v5_late(keep_negative=keep_negative) else: raise ValueError('ETableN {} not supported. It must be either of (0, 1, 2)'.format(etablen))
[docs]def get_default_table(promsection, keep_negative=True): """ Get the default energy table for MEX/IMA. :param promsection: PROM/EEPROM section. This defines the energy / elevation table. :param keep_negative: If *True* (default), negative energy is kept as is. Thus, the returned table will contain negative energy. If *False*, the negative values are proxied by a very small positive energy, in order to confirm the returned array always positive. :return: The energy table in eV/q. (96) shape. >>> etbl0 = get_default_table(0) >>> print(etbl0[0]) 32288.7 >>> etbl1 = get_default_table(1) >>> print(etbl1[0]) 25001.5 >>> etbl14 = get_default_table(14) >>> print(etbl14[0]) 4000.0 >>> etbl15 = get_default_table(15) >>> print(etbl15[0]) 15005.6 >>> etbl16 = get_default_table(16) >>> print(etbl16[0]) 15005.6 """ if promsection == 0: # In practice, 0 (EEPROM) was used for the initial phase, etable = get_default_table_v4(negative=keep_negative) elif promsection == 1: etable = get_default_table_v5(negative=keep_negative) elif promsection == 14: etable = get_default_table_v6(negative=keep_negative) elif promsection in (15, 16): # and 15(RAW) and 16(RAW) was used for the later phase. etable = get_default_table_v5_late(negative=keep_negative) else: raise ValueError('No EEPROM {} used. It must be either of (0, 1, 14, 15, 16)'.format(promsection)) return etable
def __handle_negative(negative, keep_negative): """ A helper function to handle the negative energy :param negative: negative keyword, bool or None :param keep_negative: keep_negative keyword, bool or None :return: bool value if or not we use negative energy >>> __handle_negative(None, None) # +doctest: +IGNORE_EXCEPTION_DETAILS Traceback (most recent call last): ValueError: Either negative (=None) or keep_negative (=None) should be bool. >>> __handle_negative(True, False) True >>> __handle_negative(True, True) True >>> __handle_negative(None, True) True >>> __handle_negative(None, False) False >>> __handle_negative(False, True) False >>> __handle_negative(False, False) False """ # If negative is None, use keep_negative value if negative is None: if keep_negative is None: raise ValueError('Either negative (={}) or keep_negative (={}) should be bool.'.format(negative, keep_negative)) else: return keep_negative else: # Otherwise, use negative return negative
[docs]def get_default_table_v4(negative=None, keep_negative=True): ''' Return the default table (v4). :keyword negative: (OBSOLETE) Alias to ``keep_negative``. By historical reason, ``negative`` is prioritized than ``keep_negative`` but should use ``keep_negative`` for future. :keyword keep_negative: If *True*, negative energy is considered as valid (default). If *False*, negative energy is proxied by a very small positive energy, in order to confirm the returned array always positive. :returns: Energy table in eV/q. 96 elements. ''' etbl = np.array([32288.7, 29659.4, 27234.1, 25001.5, 22950.2, 21068.8, 19334.8, 17748.2, 16286.2, 14948.9, 13713.6, 12568.9, 11526.2, 10574.3, 9690.3, 8874.3, 8137.6, 7446.3, 6823.0, 6245.0, 5712.3, 5225.0, 4771.6, 4352.3, 3978.3, 3627.0, 3309.7, 3015.0, 2743.0, 2493.7, 2267.0, 2051.7, 1859.0, 1677.7, 1519.0, 1371.7, 1235.7, 1099.7, 986.3, 884.3, 782.3, 691.7, 612.3, 533.0, 465.0, 397.0, 340.3, 283.7, 227.0, 181.7, 147.7, 102.3, 68.3, 34.3, 0.3, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, ]) negative = __handle_negative(negative, keep_negative) if not negative: etbl_negative = np.linspace(100e-10, 1e-10, 96) etbl = np.where(etbl > 0, etbl, etbl_negative) return etbl
[docs]def get_default_table_v5(negative=None, keep_negative=True): ''' Return the default table (v5). :keyword negative: (OBSOLETE) Alias to ``keep_negative``. By historical reason, ``negative`` is prioritized than ``keep_negative`` but should use ``keep_negative`` for future. :keyword keep_negative: If *True*, negative energy is considered as valid (default). If *False*, negative energy is proxied by a very small positive energy, in order to confirm the returned array always positive. :returns: Energy table in eV/q. 96 elements. ''' etbl = np.array([25001.5,23018.1,21204.8,19527.5,17986.2, 16558.2,15254.9,14042.2,12931.6,11911.6,10970.9, 10109.6,9304.9,8568.3,7888.3,7265.0,6698.3,6165.6, 5678.3,5225.0,4817.0,4431.6,4080.3,3763.0,3468.3, 3185.0,2935.7,2709.0,2493.7,2289.7,2108.3,1949.7, 1791.0,1655.0,1519.0,1394.3,1292.3,1190.3,1088.3, 1009.0,929.7,850.3,782.3,725.7,669.0,612.3,567.0, 521.7,476.3,442.3,408.3,374.3,340.3,317.7,295.0, 272.3,249.7,227.0,215.7,193.0,181.7,159.0,147.7, 136.3,125.0,113.7,113.7,102.3,92.4,85.1,78.4,72.2, 66.5,61.2,56.4,51.9,47.8,44.0,40.6,37.4,34.4,31.7, 29.2,26.9,24.7,22.8,21.0,19.3,17.8,16.4,15.1,13.9, 12.8,11.8,10.9,10.0]) return etbl
[docs]def get_default_table_v5_late(negative=None, keep_negative=True): ''' Return the default table (yet another v5). :keyword negative: (OBSOLETE) Alias to ``keep_negative``. By historical reason, ``negative`` is prioritized than ``keep_negative`` but should use ``keep_negative`` for future. :keyword keep_negative: If *True*, negative energy is considered as valid (default). If *False*, negative energy is proxied by a very small positive energy, in order to confirm the returned array always positive. :returns: Energy table in eV/q. 96 elements. >>> tbl = get_default_table_v5_late() >>> print(tbl.shape) (96,) >>> print(tbl[-1]) -20.0 >>> tbl2 = get_default_table_v5_late(negative=False) >>> print(tbl2.shape) (96,) >>> print(tbl2[-1]) 1e-10 ''' etbl = np.array([15005.6, 13747.6, 12602.9, 11548.9, 10585.6, 9701.6, 8896.9, 8148.9, 7469, 6845.6, 6279, 5757.6, 5270.3, 4839.6, 4431.6, 4057.6, 3717.6, 3411.7, 3128.3, 2867.7, 2629.7, 2403, 2210.3, 2017.7, 1859, 1700.3, 1553, 1428.3, 1303.7, 1201.7, 1099.7, 1009, 918.3, 850.3, 771, 714.3, 646.3, 601, 544.3, 499, 465, 419.7, 385.7, 351.7, 329, 295, 272.3, 249.7, 227, 215.7, 193, 181.7, 159, 147.7, 136.3, 125, 113.7, 102.3, 95.9, 87.9, 80.6, 73.9, 67.7, 62.1, 56.9, 52.1, 47.8, 43.8, 40.1, 36.8, 33.7, 30.9, 28.3, 26, 23.8, 21.8, 20, 17.9, 15.8, 13.7, 11.6, 9.5, 7.4, 5.3, 3.2, 1, -1, -3.2, -5.3, -7.4, -9.5, -11.6, -13.7, -15.8, -17.9, -20,]) negative = __handle_negative(negative, keep_negative) if not negative: etbl_negative = np.linspace(100e-10, 1e-10, 96) etbl = np.where(etbl > 0, etbl, etbl_negative) return etbl
[docs]def get_default_table_v6(negative=None, keep_negative=True): ''' Return the default table for the v6, the 24s fast scan. :keyword negative: (OBSOLETE) Alias to ``keep_negative``. By historical reason, ``negative`` is prioritized than ``keep_negative`` but should use ``keep_negative`` for future. :keyword keep_negative: If *True*, negative energy is considered as valid (default). If *False*, negative energy is proxied by a very small positive energy, in order to confirm the returned array always positive. :returns: Energy table in eV/q. 96 elements. >>> etbl = get_default_table_v6() >>> print(etbl.shape) (96,) >>> print(etbl[0]) 4000.0 ''' e32 = get_default_table_v6_squashed() return np.hstack([e32, e32, e32])
[docs]def get_default_table_v6_squashed(negative=None, keep_negative=True): ''' Get the default table for v6, the 24s fast scan, with 32 energy steps. :keyword negative: (OBSOLETE) Alias to ``keep_negative``. By historical reason, ``negative`` is prioritized than ``keep_negative`` but should use ``keep_negative`` for future. :keyword keep_negative: If *True*, negative energy is considered as valid (default). If *False*, negative energy is proxied by a very small positive energy, in order to confirm the returned array always positive. :keyword invalidstep: Either ``keep``, ``replace``, or ``nan``. :returns: Energy table in eV/q. 32 elements. ''' e32 = np.array([4000, 3407.3, 2902.4, 2472.3, 2105.9, 1793.9, 1528.0, 1301.6, 1108.7, 944.4, 804.5, 685.3, 583.7, 497.2, 423.5, 360.8, 307.3, 261.8, 223.0, 189.9, 161.8, 137.8, 117.4, 100.0, 88.8, 77.5, 66.2, 55.0, 43.8, 32.5, 21.2, 10.0]) return e32