# irfpy.vima.fov¶

Field of view of VEX/IMA

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

Warning

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

The users must upgrade to v4.5 or later.

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 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 irfpy.vexpvat.vexspice module.

irfpy.vima.fov.get_azimuth_angle(azim_nr, direction='look')[source]

Return the azimuthal angle corresponding to the index.

The derivation is simply:

$\Phi = 78.75 - 22.5 imes \mathrm{Index}$

for looking direction. It indicates that

• Index 3.5 is zero degrees.

• Index 7.5 is -90 degrees.

Parameters
• 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.

• direction – Either ‘look’ or ‘velocity’.

Returns

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

irfpy.vima.fov.get_elevation_geometric(elev_nr, direction='look')[source]

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.

Parameters
• elev_nr – Elevation index number. Floating values are allowed.

• direction – Either ‘look’ or ‘velocity’.

Returns

The elevation angle.

irfpy.vima.fov.get_elevation_table(elev_idx, energy_idx, elevation_table_version, direction='look')[source]

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 irfpy.vima.energy module.

In addition, “-1” will give you a geometric table (get_elevation_geometric())

Parameters
• elev_idx – Elevation index. -1, 2, or 3.

• energy_idx – Energy index.

• elevation_table_version – Energy table version, either 2 or 3.

• direction – Either ‘look’ or ‘velocity’.

Returns

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'))
--

irfpy.vima.fov.get_elevation_table_v2(elev_index, energy_index, direction='look')[source]

Elevation angle based on the table provided in IMA bible. Version 2, corr. to energy table v1.

See details in get_elevation_table() function, which calls this function with energy_table_version to be 2.

Parameters
• elev_index – Elevation index.

• energy_index – Energy index.

• direction – Either ‘look’ or ‘velocity’.

Returns

The corresponding angle. If “invalid” (non-measurable case), masked value is returned.

>>> print(get_elevation_table_v2(2, 40, direction='look'))
-30.8

irfpy.vima.fov.get_elevation_table_v3(elev_index, energy_index, direction='look')[source]

Elevation angle based on the table provided in IMA bible. Version 3 Fov table corresponds to energy table v3.

See details in get_elevation_table() function, which calls this function with energy_table_version to be 3.

Parameters
• elev_index – Elevation index.

• energy_index – Energy index.

• direction – Either ‘look’ or ‘velocity’.

Returns

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))
--


Returns

(A16, P16) table with boolean.

Return type

np.array with each element as boolean. True bins are blocked.

You can get a boolean array as follows:

>>> shadow_mask = get_shadow_mask()
(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 =   // 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};


Returns

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
>>> plt.plot(alist, plist)

class irfpy.vima.fov.TableFOV[source]

Bases: object

The class represents the FoV based on the setting tables.

>>> tfov = TableFOV()
>>> sfov = SimpleFOV()


For higher energies, the TableFOV and 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:.3f} {vv:.3f} {vv:.3f}'.format(vv=tv))
-0.168 0.842 -0.512
>>> print('{vv:.3f} {vv:.3f} {vv:.3f}'.format(vv=tv3))
-0.168 0.843 -0.511
>>> print('{vv:.3f} {vv:.3f} {vv:.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:.3f} {vv:.3f} {vv:.3f}'.format(vv=tv))
-0.168 0.846 -0.506
>>> print('{vv:.3f} {vv:.3f} {vv:.3f}'.format(vv=tv3))
-0.195 0.979 -0.052
>>> print('{vv:.3f} {vv:.3f} {vv:.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)
[-- -- --]

viewvector_imasframe(table_id, azim_nr, elev_nr, ene_nr, only_in_fov=True)[source]
velocityvector_imasframe(table_id, azim_nr, elev_nr, ene_nr, only_in_fov=True)[source]
elevation_angle(table_id, elev_nr, ene_nr, direction='look')[source]
azimuth_angle(azim_nr, direction='look', normalize=True)[source]

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 (get_azimuth_angle()).

Parameters
• azim_nr – Azimuthal index.

• direction – “look” or “velocity”.

• 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.

Returns

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

class irfpy.vima.fov.SimpleFOV[source]

Bases: object

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:.2f} {vv:.2f} {vv:.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:.2f} {vv:.2f} {vv:.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:.2f} {vv:.2f} {vv:.2f}'.format(vv=vv))
1.00 -0.00 -0.00

>>> vv = fov.velocityvector_imasframe(7.5, 15.5)
>>> print('{vv:.2f} {vv:.2f} {vv:.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

viewvector_imasframe(azim_nr, elev_nr)[source]

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.

Parameters
• azim_nr – Azimuthal index.

• elev_nr – Elevation index.

Returns

A vector (viewing vector in the IMAS frame).

>>> fov = SimpleFOV()
>>> print(fov.viewvector_imasframe(3.5, 7.5))
[1. 0. 0.]
>>> print('{f:.1f} {f:.1f} {f:.1f}'.format(f=fov.viewvector_imasframe(7.5, 7.5)))
0.0 1.0 0.0

velocityvector_imasframe(azim_nr, elev_nr)[source]

Return the velocity vectors in the IMAS frame.

Parameters
• azim_nr – Azim index

• elev_nr – Elev index

Returns

Velocity vector, i.e., minus viewvector_imasframe()

elevation_angle(elev_nr, direction='look')[source]

Return the elevation angle, with respective to x-y plane of IMAS frame.

Parameters
• elev_nr – Elevation index.

• direction – “look” for looking direction, “velocity” for the velocity direction.

Returns

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

azimuth_angle(azim_nr, direction='look', normalize=True)[source]

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 (get_azimuth_angle()).

Parameters
• azim_nr – Azimuthal index.

• direction – “look” or “velocity”.

• 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.

Returns

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
`
numbering_imasframe(viewvector)[source]

Converting viewing vector to the index of (Az, Pol).

Parameters

viewvector

Returns