Source code for irfpy.vima.fov

""" Field of view of VEX/IMA

VEX/IMA field of view is handled in this module.

.. warning::

    The function :func:`get_elevation_table` (and :func:`get_elevation_table_v2`) contains
    a critical bug for the version before v4.4.1a3.

    The users must upgrade to v4.5 or later.

    .. code-block:: bash

        pip install --find-links=https://irfpy.irf.se/sdist irfpy.aspera -U

There are two types of approach.

1. Geometric FOV (a.k.a Simple FOV)
2. Table FOV

The geometric FOV is calculated under the assumption that the elevaion and azimuth angles
are equally separated in the angular space.  It is also the approach that is used for SPICE.
Benefits are an intuitive calculation of the angles as well as an easy inverse calculation
(from a vector to the bin).

The table FOV approach is using tables produced for setting of the instrument.
It is not separated in a regular grid, but provides more accurate way of careful analyses.

Both approches are provided by this module.

The geometric FOV can be started from

>>> gfov = SimpleFOV()

and the table FOV from

>>> tfov = TableFOV()

For any methods in the table FOV, the table id should be provided as an argument.
There are two elevation tables, ``2`` and ``3``.
They are corresponding to the energy tables version ``1`` and ``3``, respectively.

To get the viewing direction, you can do as follows.

>>> print(gfov.viewvector_imasframe(5, 7))    # Azim=5, Elev=7
[ 0.83046807  0.55490102 -0.04906767]

>>> print(tfov.viewvector_imasframe(2, 5, 7, 30))    # Table v2, Azim=5, Elev=7, EneStep=30
[ 0.83047695  0.55490696 -0.04884977]

>>> print(tfov.viewvector_imasframe(3, 5, 7, 30))    # Table v3, Azim=5, Elev=7, Enestep=30
[ 0.83079978  0.55512266 -0.04013179]

These vectors are in the so-called IMAS frame. The name comes from SPICE.

*General notice*

.. warning::

    It is known that the fov table has been swapped for the version before 4.1.1a3.
    At the release of v4.2.0, the energy table has been fixed.

The FOV is sometimes confusing.  Users should be careful about

1. What coordinate system is used.
2. Whether the *looking* or *velocity* direction is needed.
3. Definition of zero-angle, and which direction it increases.

The coordinate system is (sometimes) defined arbitrarily.
In particular,

- What is the definition of zero angle?
- What is the plus, and minus?
- The unit is in degrees or in radians?

Original documents may sometimes not include enough information
or even sometimes **wrongly** described.  Be careful!!

The *looking* or *velocity* directions make the results completely anti-parallel.
The original documents sometimes lack the definition.

Below, be careful about all the issues above,
and if you find any problems or difficulties,
please ask to the developers for clarification and debugging.

*Relation to SPICE*

This :mod:`irfpy.vima.fov` module has no dependency on SPICE. However,
SPICE is a good tool to investigate the sensor looking/coming directions.
But note that the SPICE kernel only support the "geometric" polar direction, i.e. energy-independent.
See :mod:`irfpy.vexpvat.vexspice` module.
"""
import numpy as np
import numpy as _np
from irfpy.util import exception as ex

def _get_azimuth_angle_bible(azim_nr):
    r'''Return the azimuthal angle written in the bible.

    The derivation is simply:

    .. math::

        \Phi = 78.75 - 22.5 \times \mathrm{Index}

    :param azim_nr: Azimuthal index number. The index number is generalized to the real number, and to below zero or above 15.
        For example, index 0 means the center direction of the bin 0.  Index 3.5 gives the direction
        between 3 and 4.
    :return: The azimuthal angle. Zero degree is +z in the SC frame. The definition follows the IMA bible.
    '''
    return 78.75 - 22.5 * np.array(azim_nr)


[docs]def get_azimuth_angle(azim_nr, direction='look'): ''' Return the azimuthal angle corresponding to the index. The derivation is simply: .. math:: \Phi = 78.75 - 22.5 \times \mathrm{Index} for looking direction. It indicates that - Index 3.5 is zero degrees. - Index 7.5 is -90 degrees. :param azim_nr: Azimuthal index number. The index number is generalized to the real number, and to below zero or above 15. For example, index 0 means the center direction of the bin 0. Index 3.5 gives the direction between 3 and 4. :keyword direction: Either 'look' or 'velocity'. :return: The azimuthal angle. definition follows the IMA bible. >>> get_azimuth_angle(0) 78.75 >>> get_azimuth_angle(3.5) 0.0 >>> get_azimuth_angle(3.5, direction='velocity') 180.0 ''' if direction == 'look': return _get_azimuth_angle_bible(azim_nr) elif direction == 'velocity': return 180 - _get_azimuth_angle_bible(azim_nr) else: raise ex.IrfpyException('``direction`` must be ``look`` r ``velocity``')
[docs]def get_elevation_geometric(elev_nr, direction='look'): ''' Return the "geometric" elevation angle corresponding to the index. zero angle is defined as the middle plane of the scanning electrode. Positive toward higher elevation index for looking angle. :param elev_nr: Elevation index number. Floating values are allowed. :param direction: Either 'look' or 'velocity'. :return: The elevation angle. ''' if direction == 'look': theta = -42.1875 + 5.625 * np.array(elev_nr) elif direction == 'velocity': theta = -(-42.1875 + 5.625 * np.array(elev_nr)) else: raise ValueError('``direction`` must be ``look`` r ``velocity``') return theta
[docs]def get_elevation_table(elev_idx, energy_idx, elevation_table_version, direction='look'): """ Elevation angle based on the table provided in IMA bible. The elevation table depends not only the elevation index, but also the energy step. This function returns the elevation angle as a function of the elevation index and energy index. The elevation table depends on the energy table. Two elevation tables are prepared, namely versions 2 and 3. The elevation table version 2 corresponds to energy table version 1. The elevation table version 3 corresponds to energy table version 3. For energy table version, see also :mod:`irfpy.vima.energy` module. In addition, "-1" will give you a geometric table (:func:`get_elevation_geometric`) :param elev_idx: Elevation index. -1, 2, or 3. :param energy_idx: Energy index. :param elevation_table_version: Energy table version, either ``2`` or ``3``. :param direction: Either 'look' or 'velocity'. :return: The elevation angle. If "invalid" (non-measurable case), masked value is returned. >>> print(get_elevation_table(2, 40, '2', direction='look')) -30.8 >>> print(get_elevation_table(2, 40, 2, direction='velocity')) 30.8 >>> print(get_elevation_table(2, 55, '3', direction='look')) -26.3 >>> print(get_elevation_table(2, 55, 3, direction='velocity')) 26.3 >>> print(get_elevation_table(0, 0, '3')) -- """ if elevation_table_version in (2, '2', 'v2'): return get_elevation_table_v2(elev_idx, energy_idx, direction=direction) elif elevation_table_version in (3, '3', 'v3'): return get_elevation_table_v3(elev_idx, energy_idx, direction=direction) elif elevation_table_version in (-1, '-1', 'default', 'geometric'): return get_elevation_geometric(elev_idx, direction=direction) else: raise ValueError('energy_table_version should be 1 or 3')
[docs]def get_elevation_table_v2(elev_index, energy_index, direction='look'): """ Elevation angle based on the table provided in IMA bible. Version 2, corr. to energy table v1. See details in :func:`get_elevation_table` function, which calls this function with ``energy_table_version`` to be ``2``. :param elev_index: Elevation index. :param energy_index: Energy index. :param direction: Either 'look' or 'velocity'. :return: The corresponding angle. If "invalid" (non-measurable case), masked value is returned. >>> print(get_elevation_table_v2(2, 40, direction='look')) -30.8 """ lookangle = __tblv2[energy_index, elev_index] if direction == 'look': return lookangle elif direction == 'velocity': return -lookangle else: raise ValueError('``direction`` must be ``look`` or ``velocity``')
[docs]def get_elevation_table_v3(elev_index, energy_index, direction='look'): """ Elevation angle based on the table provided in IMA bible. Version 3 Fov table corresponds to energy table v3. See details in :func:`get_elevation_table` function, which calls this function with ``energy_table_version`` to be ``3``. :param elev_index: Elevation index. :param energy_index: Energy index. :param direction: Either 'look' or 'velocity'. :return: The corresponding angle. If "invalid" (non-measurable case), masked value is returned. >>> print(get_elevation_table_v3(3, 45)) -23.2 >>> print(get_elevation_table_v3(3, 45, direction='velocity')) 23.2 >>> print(get_elevation_table_v3(0, 0)) -- """ lookangle = __tblv3[energy_index, elev_index] if direction == 'look': return lookangle elif direction == 'velocity': return -lookangle else: raise ValueError('``direction`` must be ``look`` or ``velocity``')
__tblv2 = np.ma.masked_less(np.array([ [-100.0, -100.0, -100.0, -100.0, -100.0, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, -100.0, -100.0, -100.0, -100.0, -100.0], [-100.0, -100.0, -100.0, -100.0, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, -100.0, -100.0, -100.0, -100.0], [-100.0, -100.0, -100.0, -100.0, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, -100.0, -100.0, -100.0, -100.0], [-100.0, -100.0, -100.0, -100.0, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, -100.0, -100.0, -100.0, -100.0], [-100.0, -100.0, -100.0, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, -100.0, -100.0, -100.0], [-100.0, -100.0, -100.0, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, -100.0, -100.0, -100.0], [-100.0, -100.0, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, -100.0, -100.0], [-100.0, -100.0, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, -100.0, -100.0], [-100.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, -100.0], [-100.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, -100.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.3, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.3, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.3, -30.7, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.1, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.3, -30.7, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.1, -19.5, -13.9, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.5, 25.2, 30.7, 36.4, 41.9], [-42.0, -36.3, -30.8, -25.2, -19.6, -14.0, -8.3, -2.8, 2.8, 8.4, 13.9, 19.6, 25.2, 30.8, 36.4, 41.9], [-42.0, -36.3, -30.8, -25.1, -19.6, -14.0, -8.4, -2.8, 2.8, 8.3, 14.0, 19.5, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 41.9], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 41.9], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.5, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.7, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.9, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.3, -30.8, -25.1, -19.6, -13.9, -8.4, -2.7, 2.8, 8.3, 14.0, 19.6, 25.2, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.1, -19.6, -14.0, -8.4, -2.9, 2.8, 8.4, 13.9, 19.6, 25.2, 30.8, 36.3, 42.0], [-42.0, -36.3, -30.8, -25.2, -19.6, -13.9, -8.4, -2.8, 2.7, 8.4, 14.0, 19.6, 25.1, 30.8, 36.4, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.7, -13.9, -8.3, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, 41.9], [-42.0, -36.4, -30.9, -25.1, -19.5, -14.0, -8.4, -2.8, 2.7, 8.3, 14.1, 19.6, 25.2, 30.8, 36.4, 41.9], [-42.0, -36.4, -30.8, -25.1, -19.6, -13.9, -8.4, -2.7, 2.8, 8.3, 14.0, 19.5, 25.2, 30.8, 36.5, 42.0], [-42.0, -36.4, -30.8, -25.2, -19.6, -14.0, -8.4, -2.8, 2.8, 8.5, 14.1, 19.7, 25.3, 30.7, 36.3, 41.9], [-42.0, -36.4, -30.7, -25.2, -19.6, -13.9, -8.4, -2.8, 2.9, 8.3, 14.0, 19.7, 25.1, 30.8, 36.5, 41.9], [-42.0, -36.3, -30.8, -25.1, -19.7, -14.0, -8.5, -2.8, 2.9, 8.4, 14.1, 19.5, 25.2, 30.7, 36.4, 41.9], [-41.9, -36.4, -30.7, -25.3, -19.6, -13.9, -8.5, -3.0, 2.9, 8.4, 14.0, 19.5, 25.2, 30.9, 36.3, 42.0], [-42.0, -36.3, -30.7, -25.1, -19.7, -14.0, -8.4, -2.8, 2.9, 8.3, 13.9, 19.6, 25.2, 30.8, 36.5, 41.9], [-42.1, -36.2, -30.7, -25.2, -19.6, -14.1, -8.5, -2.7, 2.8, 8.4, 13.9, 19.5, 25.3, 30.9, 36.4, 42.0], [-41.9, -36.5, -30.8, -25.1, -19.7, -14.0, -8.3, -2.9, 2.8, 8.5, 13.9, 19.6, 25.3, 30.7, 36.4, 42.1], [-42.1, -36.5, -30.7, -25.2, -19.7, -13.8, -8.3, -2.8, 2.7, 8.5, 14.0, 19.5, 25.0, 30.9, 36.4, 41.9], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.2, -30.9, -25.2, -19.6, -13.9, -8.2, -2.9, 2.7, 8.4, 14.1, 19.8, 25.0, 30.7, 36.4, 42.1], [-41.9, -36.2, -30.9, -25.2, -19.5, -14.2, -8.5, -2.8, 3.0, 8.3, 14.0, 19.7, 25.0, 30.7, 36.5, 42.2], [-42.2, -36.5, -30.7, -25.0, -19.7, -14.0, -8.3, -3.0, 2.7, 8.5, 14.2, 19.5, 25.2, 31.0, 36.2, 42.0], [-42.2, -36.5, -30.8, -25.1, -19.3, -14.2, -8.4, -2.7, 3.0, 8.2, 13.9, 19.6, 25.3, 31.0, 36.2, 41.9], [-41.9, -36.2, -30.6, -25.0, -19.3, -14.2, -8.6, -3.0, 2.7, 8.3, 14.0, 19.6, 25.2, 30.9, 36.5, 42.2], [-41.8, -36.3, -30.8, -25.3, -19.8, -14.2, -8.1, -2.6, 2.9, 8.4, 13.9, 19.4, 25.0, 31.1, 36.6, 42.1], [-42.1, -36.1, -30.8, -25.4, -19.5, -14.1, -8.2, -2.8, 2.5, 8.5, 13.8, 19.8, 25.1, 31.1, 36.4, 41.7], [-42.1, -36.3, -30.5, -25.5, -19.7, -13.9, -8.9, -3.1, 2.7, 8.5, 14.3, 19.3, 25.1, 30.9, 36.6, 41.7], [-41.7, -36.3, -30.8, -25.3, -19.8, -14.3, -8.0, -2.6, 2.9, 8.4, 13.9, 19.4, 24.9, 31.2, 36.6, 42.1], [-41.9, -36.0, -30.9, -24.9, -19.8, -13.8, -8.7, -2.8, 3.2, 8.3, 14.3, 19.4, 25.3, 30.4, 36.4, 42.3], [-41.8, -36.3, -30.7, -25.2, -19.7, -14.1, -8.6, -3.0, 2.5, 8.1, 13.6, 19.2, 25.6, 31.2, 36.7, 42.3], [-42.4, -36.4, -30.4, -25.4, -19.3, -14.3, -8.3, -3.3, 2.7, 8.8, 13.8, 19.8, 24.8, 30.9, 35.9, 41.9], [-41.7, -36.2, -30.8, -25.3, -19.9, -14.5, -7.9, -2.5, 3.0, 8.4, 13.9, 19.3, 24.8, 30.2, 36.8, 42.2], [-41.7, -35.8, -31.1, -25.2, -19.2, -14.5, -8.6, -2.7, 3.2, 8.0, 13.9, 19.8, 25.7, 30.5, 36.4, 42.3], [-41.4, -36.3, -31.2, -24.8, -19.6, -15.8, -8.0, -2.9, 2.2, 8.7, 13.8, 20.2, 25.4, 30.5, 36.9, 42.1], [-42.2, -36.6, -31.1, -25.5, -19.9, -14.3, -8.7, -3.2, 2.4, 8.0, 13.6, 19.2, 24.8, 30.3, 35.9, 41.5], [-41.3, -36.8, -30.7, -24.6, -20.1, -14.0, -8.0, -3.4, 2.6, 8.7, 13.2, 19.3, 25.4, 31.4, 36.0, 42.0], [-41.6, -36.6, -30.0, -25.1, -20.2, -13.6, -8.7, -2.1, 2.9, 7.8, 14.4, 19.3, 25.9, 30.8, 35.8, 42.4], [-41.6, -36.2, -30.8, -25.5, -21.9, -14.8, -7.6, -2.3, 3.1, 8.5, 13.8, 19.2, 24.5, 29.9, 37.1, 42.4], [-41.2, -35.4, -31.5, -25.7, -19.9, -14.1, -8.3, -2.4, 3.4, 9.2, 13.1, 18.9, 24.7, 30.5, 36.4, 42.2], [-42.7, -36.4, -30.0, -25.8, -19.5, -13.2, -9.0, -2.7, 3.7, 7.9, 14.2, 20.5, 24.7, 31.1, 37.4, 41.6], [-41.8, -37.2, -30.3, -28.0, -18.9, -14.3, -7.5, -2.9, 1.7, 8.6, 13.1, 20.0, 24.6, 31.4, 36.0, 42.9], [-42.9, -35.4, -30.5, -25.5, -20.5, -13.1, -8.1, -3.1, 1.8, 9.3, 14.3, 19.2, 24.2, 31.6, 36.6, 41.6], [-41.2, -35.8, -33.1, -25.0, -19.6, -14.2, -8.8, -3.4, 2.0, 7.4, 12.8, 20.9, 26.3, 31.7, 37.1, 42.5], [-41.8, -35.9, -30.1, -24.2, -18.3, -15.4, -9.6, -3.7, 2.2, 8.0, 13.9, 19.7, 25.6, 31.5, 37.3, 43.2], [-42.2, -39.0, -29.5, -26.3, -19.9, -13.6, -7.2, -4.0, 2.4, 8.7, 15.1, 18.3, 24.6, 31.0, 37.3, 40.5], [-42.3, -35.4, -32.0, -25.1, -18.2, -14.7, -7.8, -4.4, 2.6, 9.5, 12.9, 19.8, 26.7, 30.2, 37.1, 40.5], [-46.0, -34.7, -31.0, -23.5, -19.7, -12.2, -8.5, -1.0, 2.8, 6.5, 14.0, 17.8, 25.3, 29.0, 36.5, 40.3], [-41.8, -37.7, -29.6, -25.5, -21.4, -13.3, -9.2, -1.1, 3.0, 7.1, 15.2, 19.3, 23.4, 31.5, 35.6, 43.7], [-40.9, -36.5, -32.1, -23.3, -18.8, -14.4, -10.0, -1.2, 3.3, 7.7, 12.1, 21.0, 25.4, 29.8, 34.2, 43.1], [-39.7, -34.9, -30.1, -25.3, -20.5, -15.7, -6.1, -1.3, 3.5, 8.3, 13.1, 17.9, 27.5, 32.3, 37.2, 42.0], [-43.1, -37.8, -32.6, -27.4, -17.0, -11.8, -6.6, -1.4, 3.9, 9.1, 14.3, 19.5, 24.7, 29.9, 35.1, 40.3]]), -100) __tblv3 = np.ma.masked_less(np.array([[-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0, -1000.0], [19.5, 24.7, 29.9, 35.1, 40.3, 45.6, 50.8, 56.0, 61.2, 71.6, 76.8, 82.0, 87.3, 92.5, 97.7, 102.9], [13.1, 17.8, 22.6, 32.2, 36.9, 41.7, 46.5, 51.2, 60.8, 65.6, 70.3, 75.1, 79.9, 84.6, 94.2, 99.0], [7.6, 16.3, 20.7, 25.1, 29.4, 38.2, 42.5, 46.9, 55.7, 60.0, 64.4, 68.8, 77.5, 81.9, 86.2, 95.0], [3.0, 11.0, 15.0, 23.0, 27.0, 31.0, 38.9, 42.9, 50.9, 54.9, 58.9, 66.9, 70.9, 78.9, 82.9, 86.9], [-1.0, 6.4, 13.7, 17.4, 24.7, 28.3, 35.7, 39.3, 46.6, 50.3, 57.6, 61.3, 68.6, 72.3, 79.6, 83.3], [-4.2, 2.5, 9.2, 12.5, 19.2, 25.9, 29.3, 36.0, 42.7, 46.0, 52.8, 59.5, 62.8, 69.5, 76.2, 79.6], [-6.9, -0.8, 5.3, 11.5, 17.6, 20.7, 26.8, 33.0, 39.1, 45.2, 48.3, 54.4, 60.6, 66.7, 72.8, 79.0], [-9.2, -3.5, 2.1, 7.7, 13.3, 18.9, 24.5, 30.2, 35.8, 41.4, 47.0, 52.6, 58.3, 63.9, 69.5, 75.1], [-11.0, -5.8, -0.7, 4.5, 9.6, 14.8, 22.5, 27.6, 32.8, 37.9, 43.0, 50.8, 55.9, 61.0, 66.2, 71.3], [-14.7, -10.0, -3.0, 1.7, 8.8, 13.5, 18.2, 25.3, 30.0, 37.1, 41.8, 46.5, 53.5, 58.2, 62.9, 70.0], [-17.8, -11.3, -4.9, -0.6, 5.9, 10.2, 16.7, 23.1, 27.5, 33.9, 38.2, 44.7, 51.2, 55.5, 61.9, 66.2], [-18.3, -12.4, -8.4, -2.5, 3.4, 9.4, 15.3, 21.2, 25.1, 31.1, 37.0, 42.9, 48.8, 54.7, 58.7, 64.6], [-22.1, -14.9, -9.5, -4.1, 1.3, 6.8, 12.2, 17.6, 23.0, 30.2, 35.7, 41.1, 46.5, 51.9, 57.3, 62.7], [-21.9, -17.0, -12.0, -5.4, -0.4, 4.5, 11.1, 16.1, 22.7, 27.7, 32.6, 39.3, 44.2, 50.8, 55.8, 60.8], [-24.6, -18.6, -12.5, -8.0, -1.9, 4.1, 8.7, 14.7, 20.8, 25.3, 31.4, 37.4, 43.5, 48.0, 54.1, 60.2], [-25.3, -19.8, -14.2, -8.7, -3.1, 2.4, 8.0, 13.5, 19.0, 24.6, 30.1, 35.7, 41.2, 46.8, 52.3, 57.8], [-27.0, -21.9, -15.6, -10.5, -5.4, 0.9, 6.0, 12.4, 17.4, 23.8, 28.8, 33.9, 40.3, 45.3, 51.7, 56.8], [-28.2, -22.4, -17.7, -11.9, -6.1, -0.3, 5.5, 11.3, 16.0, 21.8, 27.6, 33.4, 39.2, 43.8, 49.6, 55.4], [-30.0, -23.7, -18.4, -13.0, -6.7, -1.3, 4.0, 9.3, 15.7, 21.0, 26.3, 31.6, 38.0, 43.3, 48.6, 53.9], [-30.4, -24.6, -19.7, -13.9, -8.0, -2.2, 2.7, 8.5, 14.3, 20.2, 25.1, 30.9, 36.7, 42.6, 47.4, 53.3], [-31.4, -26.1, -20.7, -14.5, -9.1, -3.8, 2.4, 7.8, 13.1, 18.5, 24.7, 30.1, 35.4, 40.8, 47.0, 52.3], [-32.8, -27.1, -21.4, -15.7, -10.0, -4.3, 1.4, 7.1, 12.0, 17.7, 23.4, 29.2, 34.9, 40.6, 46.3, 51.2], [-33.0, -27.8, -21.8, -16.6, -10.6, -5.4, 0.6, 5.8, 11.8, 17.0, 23.0, 28.2, 34.2, 39.4, 45.4, 50.6], [-33.7, -28.2, -22.7, -17.3, -11.8, -6.3, -0.2, 5.3, 10.8, 16.2, 21.7, 27.9, 33.3, 38.8, 44.3, 49.7], [-34.6, -28.9, -23.3, -17.7, -12.1, -6.4, -0.8, 4.2, 9.9, 15.5, 21.1, 26.8, 32.4, 38.0, 43.7, 49.3], [-35.1, -29.9, -24.2, -18.5, -12.8, -7.0, -1.9, 3.9, 9.6, 15.3, 20.5, 26.2, 31.9, 37.7, 42.8, 48.6], [-35.8, -30.0, -24.8, -19.0, -13.2, -8.0, -2.2, 3.5, 8.8, 14.6, 20.3, 25.6, 31.3, 37.1, 42.4, 48.1], [-36.6, -30.8, -25.1, -19.8, -14.0, -8.3, -3.0, 2.8, 8.5, 13.8, 19.6, 25.3, 30.6, 36.4, 42.1, 47.4], [-37.0, -31.3, -25.6, -19.9, -14.6, -8.9, -3.2, 2.5, 7.8, 13.5, 19.2, 24.5, 30.2, 35.9, 41.7, 46.9], [-37.1, -31.5, -26.3, -20.6, -15.0, -9.4, -3.7, 1.9, 7.5, 13.2, 18.8, 24.4, 30.1, 35.3, 40.9, 46.6], [-37.7, -32.1, -26.6, -20.7, -15.2, -9.7, -4.5, 1.4, 7.3, 12.8, 18.3, 23.9, 29.4, 34.9, 40.8, 46.3], [-38.2, -32.5, -26.7, -21.3, -15.6, -10.2, -4.5, 1.3, 6.7, 12.4, 17.8, 23.5, 29.3, 34.7, 40.4, 45.8], [-38.4, -32.8, -27.2, -21.7, -16.1, -10.3, -4.7, 0.8, 6.4, 12.0, 17.5, 23.1, 28.6, 34.5, 40.1, 45.6], [-38.8, -33.1, -27.5, -21.8, -16.2, -10.8, -5.2, 0.5, 6.1, 11.8, 17.2, 22.8, 28.5, 34.1, 39.8, 45.2], [-38.9, -33.4, -27.7, -22.1, -16.6, -10.9, -5.5, 0.2, 5.9, 11.3, 17.0, 22.7, 28.1, 33.8, 39.3, 45.0], [-39.1, -33.7, -28.0, -22.3, -16.9, -11.2, -5.7, -0.1, 5.6, 11.1, 16.8, 22.4, 27.9, 33.6, 39.0, 44.7], [-39.5, -33.9, -28.2, -22.6, -17.0, -11.5, -5.9, -0.3, 5.4, 11.0, 16.4, 22.1, 27.7, 33.3, 39.0, 44.4], [-39.7, -34.0, -28.4, -22.9, -17.3, -11.8, -6.0, -0.4, 5.1, 10.7, 16.2, 22.0, 27.5, 33.1, 38.7, 44.2], [-39.8, -34.2, -28.6, -23.1, -17.5, -11.9, -6.2, -0.6, 4.9, 10.5, 16.1, 21.8, 27.2, 32.9, 38.5, 44.1], [-40.0, -34.5, -28.8, -23.2, -17.7, -12.0, -6.5, -0.9, 4.8, 10.3, 15.9, 21.6, 27.1, 32.7, 38.4, 43.9], [-40.2, -34.6, -29.0, -23.3, -17.9, -12.2, -6.6, -1.0, 4.5, 10.2, 15.8, 21.4, 26.9, 32.6, 38.2, 43.7], [-40.3, -34.7, -29.2, -23.6, -18.0, -12.3, -6.7, -1.2, 4.4, 10.0, 15.6, 21.2, 26.9, 32.5, 38.0, 43.6], [-40.5, -34.9, -29.3, -23.6, -18.2, -12.5, -6.9, -1.3, 4.3, 9.9, 15.5, 21.0, 26.7, 32.3, 37.9, 43.5], [-40.6, -35.0, -29.5, -23.9, -18.3, -12.6, -7.0, -1.4, 4.2, 9.8, 15.4, 21.0, 26.5, 32.1, 37.7, 43.3], [-40.8, -35.1, -29.5, -24.0, -18.3, -12.8, -7.2, -1.5, 4.0, 9.6, 15.3, 20.8, 26.4, 32.1, 37.6, 43.2], [-40.9, -35.3, -29.6, -24.0, -18.4, -12.9, -7.3, -1.7, 4.0, 9.6, 15.2, 20.7, 26.3, 31.9, 37.5, 43.1], [-40.9, -35.3, -29.7, -24.1, -18.6, -12.9, -7.4, -1.7, 3.8, 9.5, 15.0, 20.6, 26.3, 31.8, 37.5, 43.0], [-41.0, -35.4, -29.8, -24.2, -18.6, -13.1, -7.4, -1.8, 3.8, 9.3, 14.9, 20.6, 26.2, 31.8, 37.3, 42.9], [-41.1, -35.5, -29.9, -24.3, -18.7, -13.1, -7.5, -1.9, 3.7, 9.3, 14.9, 20.5, 26.1, 31.6, 37.3, 42.8], [-41.1, -35.6, -30.0, -24.4, -18.8, -13.2, -7.6, -2.0, 3.6, 9.2, 14.8, 20.4, 26.0, 31.6, 37.2, 42.8], [-41.3, -35.6, -30.0, -24.4, -18.8, -13.2, -7.6, -2.0, 3.5, 9.1, 14.7, 20.3, 25.9, 31.5, 37.1, 42.7], [-41.3, -35.7, -30.1, -24.5, -18.9, -13.3, -7.7, -2.1, 3.4, 9.1, 14.7, 20.3, 25.9, 31.5, 37.1, 42.7], [-41.4, -35.8, -30.1, -24.5, -19.0, -13.4, -7.8, -2.2, 3.4, 9.0, 14.6, 20.2, 25.8, 31.4, 37.0, 42.6], [-41.4, -35.8, -30.2, -24.6, -19.0, -13.4, -7.8, -2.2, 3.4, 9.0, 14.5, 20.1, 25.7, 31.4, 37.0, 42.5], [-41.4, -35.9, -30.3, -24.7, -19.1, -13.5, -7.9, -2.3, 3.3, 8.9, 14.5, 20.1, 25.7, 31.3, 36.9, 42.5], [-41.5, -35.9, -30.3, -24.7, -19.1, -13.5, -7.9, -2.3, 3.3, 8.9, 14.4, 20.1, 25.7, 31.3, 36.8, 42.4], [-41.6, -36.0, -30.4, -24.8, -19.2, -13.6, -8.0, -2.4, 3.2, 8.8, 14.4, 20.0, 25.6, 31.2, 36.8, 42.4], [-41.6, -36.0, -30.4, -24.8, -19.2, -13.6, -8.0, -2.4, 3.2, 8.8, 14.4, 20.0, 25.6, 31.2, 36.8, 42.4], [-41.6, -36.0, -30.4, -24.8, -19.2, -13.6, -8.0, -2.4, 3.2, 8.8, 14.3, 19.9, 25.5, 31.1, 36.7, 42.3], [-41.6, -36.0, -30.5, -24.9, -19.3, -13.7, -8.1, -2.5, 3.1, 8.7, 14.3, 19.9, 25.5, 31.1, 36.7, 42.3], [-41.7, -36.1, -30.5, -24.9, -19.3, -13.7, -8.1, -2.5, 3.1, 8.7, 14.3, 19.9, 25.5, 31.1, 36.7, 42.3], [-41.7, -36.1, -30.5, -24.9, -19.3, -13.7, -8.1, -2.5, 3.1, 8.7, 14.3, 19.9, 25.5, 31.1, 36.7, 42.2], [-41.7, -36.1, -30.5, -24.9, -19.3, -13.7, -8.1, -2.5, 3.1, 8.7, 14.2, 19.8, 25.4, 31.0, 36.6, 42.2], [-1000.0, -36.1, -30.5, -24.9, -19.4, -13.8, -8.2, -2.6, 3.0, 8.6, 14.2, 19.8, 25.4, 31.0, 36.6, -39.6], [-1000.0, -36.2, -30.6, -25.0, -19.4, -13.8, -8.2, -2.6, 3.0, 8.6, 14.2, 19.8, 25.4, 31.0, 36.6, -32.7], [-1000.0, -1000.0, -30.6, -25.0, -19.4, -13.8, -8.2, -2.6, 3.0, 8.6, 14.2, 19.8, 25.4, 31.0, -32.0, -26.4], [-1000.0, -1000.0, -30.6, -25.0, -19.4, -13.8, -8.2, -2.6, 3.0, 8.6, 14.2, 19.8, 25.4, 31.0, -26.2, -20.6], [-41.8, -36.2, -30.6, -25.0, -19.5, -13.8, -8.2, -2.7, 3.0, 8.5, 14.2, 19.8, 25.3, 30.9, 36.6, 42.1], [-41.8, -36.2, -30.6, -25.0, -19.4, -13.8, -8.3, -2.6, 3.0, 8.5, 14.2, 19.7, 25.4, 30.9, 36.6, 42.1], [-41.8, -36.3, -30.6, -25.1, -19.5, -13.8, -8.3, -2.6, 3.0, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.3, 30.9, 36.5, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.6, 25.3, 30.9, 36.4, 42.1], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.6, 25.3, 30.8, 36.4, 42.0], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.5, 14.1, 19.7, 25.2, 30.8, 36.4, 42.0], [-41.9, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.8, 2.9, 8.5, 14.1, 19.6, 25.2, 30.8, 36.4, 42.0], [-1000.0, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, -1000.0], [-1000.0, -36.3, -30.7, -25.1, -19.5, -13.9, -8.3, -2.7, 2.9, 8.4, 14.0, 19.6, 25.2, 30.8, 36.4, -1000.0], [-1000.0, -1000.0, -30.7, -25.1, -19.5, -14.0, -8.3, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, -1000.0, -1000.0], [-1000.0, -1000.0, -30.7, -25.1, -19.5, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, 30.8, -1000.0, -1000.0], [-1000.0, -1000.0, -1000.0, -25.2, -19.5, -14.0, -8.4, -2.8, 2.8, 8.4, 14.0, 19.6, 25.2, -1000.0, -1000.0, -1000.0]])[::-1, :], -100)
[docs]def get_shadow_mask(): """ Return the shadow mask index. Shadow mask is implemented in the on-board computer. :returns: (A16, P16) table with boolean. :rtype: np.array with each element as boolean. *True* bins are blocked. You can get a boolean array as follows: >>> shadow_mask = get_shadow_mask() >>> print(shadow_mask.shape) (16, 16) For example, (A=12, P=1) is masked. >>> print(shadow_mask[12, 1]) True On the other hand, (A=1, P=12) is unmasked. >>> print(shadow_mask[1, 12]) False The original code in the IMA software is as follows. :: int shadow[16] = // Entrance index. {0x02CF, // 0 0x04CF, // 1 0x04CF, // 2 0x04CF, // 3 0x04CF, // 4 0x04CF, // 5 0x03CF, // 6 0x12CF, // 7 0x22FF, // 8 0xFF00, // 9 0xFF00, // 10 0x00EF, // 11 0x00EF, // 12 0x00EF, // 13 0x00EF, // 14 0x00EF // 15}; """ shadow = [[[0, 2], [0xc, 0xf]], # 0 [[0, 4], [0xC, 0xF]], # 1 [[0, 4], [0xC, 0xF]], # 2 [[0, 4], [0xC, 0xF]], # 3 [[0, 4], [0xC, 0xF]], # 4 [[0, 4], [0xC, 0xF]], # 5 [[0, 3], [0xC, 0xF]], # 6 [[1, 2], [0xC, 0xF]], # 7 [[2, 2], [0xF, 0xF]], # 8 [[0xf, 0xF]], # 9 [[0xf, 0xF]], # 10 [[0, 0], [0xE, 0xF]], # 11 [[0, 0], [0xE, 0xF]], # 12 [[0, 0], [0xE, 0xF]], # 13 [[0, 0], [0xE, 0xF]], # 14 [[0, 0], [0xE, 0xF]], # 15 ] matrix = _np.zeros([16, 16], dtype=bool) # (A, P) for iel, sha in enumerate(shadow): for asrng in sha: for iaz in range(asrng[0], asrng[1] + 1): matrix[iaz, iel] = True return matrix
[docs]def edge_shadow_mask(): """ Return a list of index of edge of the shadow mask. :return: A tuple with two element. ``((a0, a1, a2, ...), (p0, p1, p2, ...))`` ``a0`` and ``p0`` is the azimuth/polar index of the first point, and follows... >>> alist, plist = edge_shadow_mask() >>> import matplotlib.pyplot as plt # doctest: +SKIP >>> plt.plot(alist, plist) # doctest: +SKIP """ coords = np.array([[0, 7], [1, 7], [1, 8], [2, 8], [2, 9], [3, 9], [3, 7], [4, 7], [4, 6], [5, 6], [5, 1], [3, 1], [3, 0], [12, 0], [12, 8], [15, 8], [15, 11], [14, 11], [14, 16], [1, 16], [1, 11], [0, 11], [0, 7]]) - 0.5 a = coords[:, 0] p = coords[:, 1] return (tuple(a), tuple(p))
[docs]class TableFOV: """ The class represents the FoV based on the setting tables. - table id=2, Default table, called v2. (:func:`get_elevation_table_v2`). - table id=3, Updated table, called v3. (:func:`get_elevation_table_v3`). >>> tfov = TableFOV() >>> sfov = SimpleFOV() For higher energies, the :class:`TableFOV` and :class:`SimpleFOV` returns very similar values. For Azimuth=8, Elev=2, for Estep=10. >>> tv = tfov.viewvector_imasframe(2, 8, 2, 10) # For v2, estep=10 >>> tv3 = tfov.viewvector_imasframe(3, 8, 2, 10) # For v3 >>> sv = sfov.viewvector_imasframe(8, 2) >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=tv)) -0.168 0.842 -0.512 >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=tv3)) -0.168 0.843 -0.511 >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=sv)) -0.167 0.841 -0.514 However, for lower energies, the value deviate, in particular for v3. >>> tv = tfov.viewvector_imasframe(2, 8, 2, 75) # For v2, estep=75 >>> tv3 = tfov.viewvector_imasframe(3, 8, 2, 75) # For v3 >>> sv = sfov.viewvector_imasframe(8, 2) >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=tv)) -0.168 0.846 -0.506 >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=tv3)) -0.195 0.979 -0.052 >>> print('{vv[0]:.3f} {vv[1]:.3f} {vv[2]:.3f}'.format(vv=sv)) -0.167 0.841 -0.514 For outside the aperutre (elev>45 or elev<45 degrees), corresponding vector values are returned if ``only_in_fov`` keyword is set to True. >>> tv3 = tfov.viewvector_imasframe(3, 2, 15, 80) # For elevation 15, energy 80. It is masked. >>> print(tv3) [-- -- --] >>> tv3 = tfov.viewvector_imasframe(3, 2, 15, 80, only_in_fov=False) # For elevation 15, energy 80. It is masked. >>> print(tv3) [ 0.09700817 -0.06481879 0.99317065] For low energies (negative energy steps), the masked value will be returned. >>> tv3 = tfov.viewvector_imasframe(3, 8, 2, 95) >>> print(tv3) [-- -- --] """ def __init__(self): pass
[docs] def viewvector_imasframe(self, table_id, azim_nr, elev_nr, ene_nr, only_in_fov=True): elev = self.elevation_angle(table_id, elev_nr, ene_nr, direction='look') # Angle in terms of z axis. (0 is x-y plane) if np.ma.is_masked(elev): return np.ma.masked_array([np.inf, np.inf, np.inf], mask=[True, True, True]) if only_in_fov: elev = np.ma.masked_outside(elev, -45, 45) else: elev = np.ma.masked_outside(elev, -180, 180) theta = np.deg2rad(elev) azim = self.azimuth_angle(azim_nr, direction='look') # Angle in x-y plane. (0 is x axis) phi = np.deg2rad(azim) cp = np.cos(phi) sp = np.sin(phi) ct = np.cos(theta) st = np.sin(theta) x = ct * cp y = ct * sp z = st return np.ma.masked_array([x, y, z])
[docs] def velocityvector_imasframe(self, table_id, azim_nr, elev_nr, ene_nr, only_in_fov=True): return -self.viewvector_imasframe(table_id, azim_nr, elev_nr, ene_nr, only_in_fov=only_in_fov)
[docs] def elevation_angle(self, table_id, elev_nr, ene_nr, direction='look'): return get_elevation_table(elev_nr, ene_nr, table_id, direction=direction)
[docs] def azimuth_angle(self, azim_nr, direction='look', normalize=True): """ Return the azimuthal angle. The definition is - 0 degrees is along the x-axis of IMAS, the azimuth index 3.5 (looking) - 90 degrees is along the y-axis of IMAS, the azimuth index 7.5 (looking) The definition is different from the IMA bible (:func:`get_azimuth_angle`). :param azim_nr: Azimuthal index. :param direction: "look" or "velocity". :param normalize: If *True*, the angle is always in the range of (0, 360). If *False*, the angles are not necesarrily in this range, but proportional to *azim_nr*. :return: Angle in degrees. >>> fov = TableFOV() >>> print(fov.azimuth_angle(3.5)) 0.0 >>> print(fov.azimuth_angle(7.5)) 90.0 >>> print(fov.azimuth_angle(7.5, direction='velocity')) 270.0 """ if direction == 'look': theta = 22.5 * (np.array(azim_nr) - 3.5) elif direction == 'velocity': theta = 180 + self.azimuth_angle(azim_nr, direction='look') else: raise ValueError('``direction`` must be ``look`` or ``velocity``.') if normalize: while theta.min() < 0: theta = np.where(theta < 0, theta + 360, theta) while theta.max() >= 360: theta = np.where(theta >= 360, theta - 360, theta) return theta
[docs] def shadow_mask(self): raise NotImplementedError('')
[docs]class SimpleFOV(): """ This class represents the Simple Field-of-View, i.e., the geometric FoV. >>> fov = SimpleFOV() The definition follows the SPICE. Usually, IMA refers to the system "IMAS". For example, looking (viewing) vector for azimuthal channel 11.5 and elevation channel 7.5 is along the along -Ximas. >>> vv = fov.viewvector_imasframe(11.5, 7.5) >>> print('{vv[0]:.2f} {vv[1]:.2f} {vv[2]:.2f}'.format(vv=vv)) -1.00 0.00 0.00 The looking vector for azumuth channle 7.5 and elevation channel 15.5 is X_imas = 0, Y_imas = +sqrt(2) / 2, and Z_imas = +sqrt(2) / 2 >>> vv = fov.viewvector_imasframe(7.5, 15.5) >>> print('{vv[0]:.2f} {vv[1]:.2f} {vv[2]:.2f}'.format(vv=vv)) 0.00 0.71 0.71 Of course the velocity vectors are opposite in sign. >>> vv = fov.velocityvector_imasframe(11.5, 7.5) >>> print('{vv[0]:.2f} {vv[1]:.2f} {vv[2]:.2f}'.format(vv=vv)) 1.00 -0.00 -0.00 >>> vv = fov.velocityvector_imasframe(7.5, 15.5) >>> print('{vv[0]:.2f} {vv[1]:.2f} {vv[2]:.2f}'.format(vv=vv)) -0.00 -0.71 -0.71 :: +Yimas ^ +Zima | A# indicate the azimuthal V8 | V7 sector "#" position in V9 ....|.... V6 the sensor assembly. .' A0 | A15 `. V10.' A1 | A14`. V5 V# indicate the "#" sector . A2 | A13. view direction. V11. | . V4 .A3 | A12. +Ximas For example, for . o--------------> +Yima Sector "14" the view .A4 / +Zimas A11. direction is the vector V12. / +Xima . V3 emanating from the .A5 / A10. aperture center through V13 . / A9 . V2 the point designated `. / A7 A8 .' by "V14". V14 ......... ' V1 / V15 V0 V Azimuthal sector "14" view direction :: +Yimas +Zima Polar Sector "3" ^ ^ view dir. A# indicate the polar V8 | V7 / sector "#" position in .----|----. V3 the sensor assembly. V15 ,-' P8|P7 `/. V0 .' | P3 `. `.P15 | / P0.' V# indicate the "#" sector `. | / .' view direction. `. | / .' `. | / .' For example, for polar `. |/+Ximas Sector "3" the view <-------------`o'+Yima direction is the vector +Zimas .' `. emanating from the +Xima .' `. aperture center through .' `. the point designated .' `. by "V2". .'P15 P0`. `. .' V15 `-. P8 P7 ,-' V0 `---------' V8 V7 """ def __init__(self): pass
[docs] def viewvector_imasframe(self, azim_nr, elev_nr): """ Return the viewing vector of the given indexes in the IMAS frame According to the definition, the x-axis is for the azimuth index 3.5 and elevation index 7.5. The y-axis is for the azimuth index 7.5 and elevation index 7.5. The z-axis is for the elevation index 23.5. :param azim_nr: Azimuthal index. :param elev_nr: Elevation index. :return: A vector (viewing vector in the IMAS frame). >>> fov = SimpleFOV() >>> print(fov.viewvector_imasframe(3.5, 7.5)) # doctest: +NORMALIZE_WHITESPACE [1. 0. 0.] >>> print('{f[0]:.1f} {f[1]:.1f} {f[2]:.1f}'.format(f=fov.viewvector_imasframe(7.5, 7.5))) 0.0 1.0 0.0 """ anr = np.array(azim_nr) elr = np.array(elev_nr) if anr.shape != elr.shape: raise ValueError('Azimuth / Elevation array should have the same shape') elev = self.elevation_angle(elr, direction='look') # Angle in terms of z axis. (0 is x-y plane) elev = np.ma.masked_outside(elev, -90, 90) theta = np.deg2rad(elev) azim = self.azimuth_angle(anr, direction='look') # Angle in x-y plane. (0 is x axis) phi = np.deg2rad(azim) cp = np.cos(phi) sp = np.sin(phi) ct = np.cos(theta) st = np.sin(theta) x = ct * cp y = ct * sp z = st return np.ma.masked_array([x, y, z])
[docs] def velocityvector_imasframe(self, azim_nr, elev_nr): """ Return the velocity vectors in the IMAS frame. :param azim_nr: Azim index :param elev_nr: Elev index :return: Velocity vector, i.e., minus :meth:`viewvector_imasframe` """ return -self.viewvector_imasframe(azim_nr, elev_nr)
[docs] def elevation_angle(self, elev_nr, direction='look'): """ Return the elevation angle, with respective to x-y plane of IMAS frame. :param elev_nr: Elevation index. :param direction: "look" for looking direction, "velocity" for the velocity direction. :return: The angle in degrees. The looking direction of elevation index 0 is -42.1875 degrees. >>> fov = SimpleFOV() >>> print(fov.elevation_angle(0)) -42.1875 The velocity of particle in the elevation index 0 is 42.1875 degrees. >>> print(fov.elevation_angle(0, direction='velocity')) 42.1875 The looking direction of elevation index 7.5 is 0 degrees. >>> print(fov.elevation_angle(7.5)) 0.0 """ if direction == 'look': theta = -42.1875 + 5.625 * np.array(elev_nr) elif direction == 'velocity': # theta = -(-42.1875 + 5.625 * np.array(elev_nr)) theta = -self.elevation_angle(elev_nr, direction='look') else: raise ValueError('``direction`` must be ``look`` or ``velocity``.') return theta
[docs] def azimuth_angle(self, azim_nr, direction='look', normalize=True): """ Return the azimuthal angle. The definition is - 0 degrees is along the x-axis of IMAS, the azimuth index 3.5 (looking) - 90 degrees is along the y-axis of IMAS, the azimuth index 7.5 (looking) The definition is different from the IMA bible (:func:`get_azimuth_angle`). :param azim_nr: Azimuthal index. :param direction: "look" or "velocity". :param normalize: If *True*, the angle is always in the range of (0, 360). If *False*, the angles are not necesarrily in this range, but proportional to *azim_nr*. :return: Angle in degrees. >>> fov = SimpleFOV() >>> print(fov.azimuth_angle(3.5)) 0.0 >>> print(fov.azimuth_angle(7.5)) 90.0 >>> print(fov.azimuth_angle(7.5, direction='velocity')) 270.0 """ if direction == 'look': theta = 22.5 * (np.array(azim_nr) - 3.5) elif direction == 'velocity': theta = 180 + self.azimuth_angle(azim_nr, direction='look') else: raise ValueError('``direction`` must be ``look`` or ``velocity``.') if normalize: while theta.min() < 0: theta = np.where(theta < 0, theta + 360, theta) while theta.max() >= 360: theta = np.where(theta >= 360, theta - 360, theta) return theta
[docs] def numbering_imasframe(self, viewvector): """ Converting viewing vector to the index of (Az, Pol). :param viewvector: :return: """ raise NotImplementedError('Implementation to be done. Refer to MEX version at irfpy.mima.fov.')
[docs] def shadow_mask(self): return get_shadow_mask()