How to handle IMA science data¶
Due to highly complex data structure of the IMA data (too many modes, time series of 4-dimensional, many processing levels, different operations, similar sensors on MEX & VEX but not fully compatible operations and processing, …) the access to the IMA science data is highly complicated.
The irfpy.aspera
library give a quick access to such dataset.
It is noted that the “final form of the matrix” depends highly on the users. Thus, the interface of the data access should be as simple and flexible as possible.
Getting the matrix at the specific time¶
To get the full matrix (192s data), you may just use the following syntax.
>>> import datetime
>>> from irfpy.vima import scidata_util # Use from irfpy.mima import scidata_util for MEX.
>>> tstart, data = scidata_util.get3d(datetime.datetime(2008, 1, 9, 14, 30))
The returned tstart
is the time of the start of the data.
The data
includes the VEX/IMA data.
The data.matrix
is the matrix that you want.
>>> print(data.matrix)
This is (32, 16, 96, 8) shaped array.
Getting the time series matrix¶
To get the time series of the matrix, you may use the following syntax.
>>> import datetime
>>> from irfpy.vima import scidata_util
>>> timeser = scidata_util.getarray2d(datetime.datetime(2008, 1, 9, 14, 30), (datetime.datetime(2008, 1, 9, 15, 30)))
>>> print(timeser)
<TimeSeriesCntMatrix2D:len=105 from 2008-01-09 14:29:40.863880 to 2008-01-09 15:11:16.908056>
A bit more in details¶
ASPERA/IMA data structure¶
The ASPERA/IMA sensor can measure ions with mass, energy and direction discrimilated.
At a certain time, IMA measures ions at a specific energy and polar angle. Simultaneously, the mass and azimuth angle can be discrimimated. It means that the data in IMA at a certain time has (M=32, A=16) shaped array. The accumulation time is 125 ms.
Then, the energy is swept. Usually, energy has 96 steps with 12 sec. Considering this, the 12-sec resolution data with (M=32, A=16, E=96) can be obtained.
The energy sweep is repeated with different polar angle scan. 16 steps (=192 s) are sweeped. The resulting dataset is the 192-sec resolution data with (M=32, A=16, E=96, P=16).
This 192-sec resolution data is transferred as is if the mode is 24. In this mode, the data is 192-sec resolution data with (M=32, A=16, E=96, P=16). For MEX, mode=24 is used near the pericenter.
If the mode is 25, the neighboring polar angle is added up on board, and sent to the ground. In this mode, the data is 192-sec resolution data with (M=32, A=16, E=96, P=8). For VEX, mode=25 has been used for the beginning of the mission. Later the mode=24 is used, but with 1 count reduction, for VEX.
In summary, the data at a certain time can be considered as (depending on the way of data analysis)
3D (azimuth, energy, polar + mass) data with time resolution of 192s
2D (azimuth, energy + mass) data with time resolution of 12s (mode 24)
2D (azimuth, energy + mass) data with time resolution of 24s (mode 25)
1D (azimuth) data with resolution of 125 ms at specific energy and (mode 24)
1D (azimuth) data with resolution of 250 ms at specific energy and (mode 25)
Each of them is indeed a time series.
More advanced dataset¶
For IMA, there are other “operation”, such as 32 second mode, and fast-sweep mode (24-s resolution). 32 second mode has not used so that IRFPY will not support this. Fast sweep mode was prepared for Phobos flyby for MEX. This is intended to be implemented into IRPFY.
Object oriented dataset¶
For irfpy.aspera
, each of these data is represented by a specific class in an object oriented way.
Below we review the class used for each dataset.
Data |
At specific time |
Time series |
---|---|---|
3D (Az, En, Po; Ma) |
||
2D (Az, En; Ma) |
||
1D (Az; Ma) |
N/A (To be developed) |
N/A (To be developed) |
3D (azimuth, energy, polar + mass)¶
To represent the 3D distribution data at a certain time,
irfpy.imacommon.imascipac.CntMatrix
class is used.
The object contains the count rate matrix, mode, and observation time.
Count rate matrix is a masked array with the shape corresponding to
the mode (for Mode 24, the shape is (32, 16, 96, 16)).
2D (azimuth, energy + mass) data¶
To represent the 2D distribution at a ceratin time,
irfpy.imacommon.imascipac.CntMatrix2D
class is used.
The object contains the count rate matrix, mode, polar index, and observation time.
Count rate matrix is a masked array with the shape corresponding to
the mode (but both mode 24 and 25, the shape is (32, 16, 96)).
The polar index is a pair of (start, stop), both inclusive.
Time series of the data¶
Time series of 3D data is irfpy.imacommon.imascipac.TimeSeriesCntMatrix
.
Use irfpy.vima.scidata_util.getarray3d
to get the time series data.
Time series of 2D data is irfpy.imacommon.imascipac.TimeSeriesCntMatrix2D
.
Use irfpy.vima.scidata_util.getarray2d
to get the time series data.
To read (VEX/IMA)¶
The first step to read the VEX/IMA is getting time series of 2D data.
Reading time series of 2D data¶
Use irfpy.vima.scidata_util.getarray2d()
function. With time intervals as argument,
the function will return the time series of 2D data (irfpy.imacommon.imascipac.TimeSeriesCntMatrix2D
.
>>> import datetime
>>> from irfpy.vima import scidata_util
>>> t0 = datetime.datetime(2012, 10, 5, 0, 1, 23)
>>> t1 = datetime.datetime(2012, 10, 6, 4, 59, 43)
>>> dataset = scidata_util.getarray2d(t0, t1)
The dataset represent the time series of VEX/IMA 2D data. Let’s look at the dataset.
>>> print(dataset)
<TimeSeriesCntMatrix2D:len=3362 from 2012-10-05 00:01:11.198276 to 2012-10-06 03:44:03.177666>
You may find that there are 3362 2-D data.
You can use the getobstime()
method to get the
list of observation time.
>>> obstime = dataset.getobstime()
>>> print(obstime)
[datetime.datetime(2012, 10, 5, 0, 1, 11, 198276),
datetime.datetime(2012, 10, 5, 0, 1, 23, 198281),
datetime.datetime(2012, 10, 5, 0, 1, 36, 167030),
datetime.datetime(2012, 10, 5, 0, 1, 48, 167035),
datetime.datetime(2012, 10, 5, 0, 2, 0, 167040),
...]
You can get the array expression of the dataset by getarray()
method.
>>> dataarray = dataset.getarray()
>>> print(dataarray.shape)
(32, 16, 96, 3362)
Note on the start time¶
It could be slightly minor issue, but the first data in the example above is
slightly earlier than the given time.
Given time is t0=2012-10-05T00:01:23
, but the
first data is observed by obstime[0]=2012-10-05T00:01:11
.
This is because the data at t0
might be included in the data at index 0.
This could produce a problem if t0
falls at a large data gap.
For example,
>>> tg0 = datetime.datetime(2006, 12, 5, 0, 0, 0)
>>> tg1 = datetime.datetime(2006, 12, 6, 0, 0, 0)
>>> dataset2 = scidata_util.getarray2d(tg0, tg1)
>>> obstime2 = dataset2.getobstime()
>>> print(obstime2)
[datetime.datetime(2006, 12, 4, 9, 41, 0, 48676),
datetime.datetime(2006, 12, 5, 5, 21, 31, 41914),
datetime.datetime(2006, 12, 5, 5, 21, 55, 41914),
datetime.datetime(2006, 12, 5, 5, 22, 19, 41925),
datetime.datetime(2006, 12, 5, 5, 22, 43, 41926),
...]
As you see, the first data is observed 14 hour before the given time. Thus, this is users’ responsibility to check if the first data (index=0) is valid for the data analysis or not.
One idea is to use the following syntax.
>>> if t0 - obstime2[0] > datetime.timedelta(seconds=12):
... dataset2 = dataset2.clipped(obstime2[1], obstime2[-1])
>>> obstime2 = dataset2.getobstime()
>>> print(obstime2)
[datetime.datetime(2006, 12, 5, 5, 21, 31, 41914),
datetime.datetime(2006, 12, 5, 5, 21, 55, 41914),
datetime.datetime(2006, 12, 5, 5, 22, 19, 41925),
datetime.datetime(2006, 12, 5, 5, 22, 43, 41926),
...]
Reading 2D data at a certain time¶
You can get the single 2-D data using the index of the time series data,
iteration, and
get()
method.
In any cases, the obtained value is a tuple of (datetime, irfpy.imacommon.imascipac.CntMatrix2D
).
Using index
>>> data0 = dataset[0] # Return the first data.
>>> print(data0)
(datetime.datetime(2012, 10, 5, 0, 1, 11, 198276), <irfpy.imacommon.imascipac.CntMatrix2D object at 0x10f8b16d0>)
Using iteration
>>> for obstime, data in dataset:
... print(obstime, data)
2012-10-05 00:01:11.198276 <<class 'irfpy.imacommon.imascipac.CntMatrix2D'>@2012-10-05T00:01:11.198276:MOD=24 >>24<<:POL=14/14:CNTmax=13>
2012-10-05 00:01:23.198281 <<class 'irfpy.imacommon.imascipac.CntMatrix2D'>@2012-10-05T00:01:23.198281:MOD=24 >>24<<:POL=15/15:CNTmax=5>
2012-10-05 00:01:36.167030 <<class 'irfpy.imacommon.imascipac.CntMatrix2D'>@2012-10-05T00:01:36.167030:MOD=24 >>24<<:POL=00/00:CNTmax=2>
2012-10-05 00:01:48.167035 <<class 'irfpy.imacommon.imascipac.CntMatrix2D'>@2012-10-05T00:01:48.167035:MOD=24 >>24<<:POL=01/01:CNTmax=4>
...
Using
get
method.
>>> data_at_0100 = dataset.get(datetime.datetime(2012, 10, 5, 1)) # Data at 1 oclock.
>>> print(data_at_0100)
(datetime.datetime(2012, 10, 5, 0, 59, 48, 230124), <irfpy.imacommon.imascipac.CntMatrix2D object at 0x10fad8190>)
Now let’s look at the irfpy.imacommon.imascipac.CntMatrix2D
object more carefully.
>>> dat2d = data0[1]
>>> print(dat2d)
<<class 'irfpy.imacommon.imascipac.CntMatrix2D'>@2012-10-05T00:01:11.198276:MOD=24:POL=14/14:CNTmax=13>
You may see that the CntMatrix2D
contains the information on the counts and some other misc data.
The attributes below includes them.
- t
Time in datetime object
- matrix
Matrix of count rate. Shape depends on the mode, but for nominal modes it is (M32,A16,E96).
- polar
Tuple providing the start polar index and the stop polar index (inclusive)
- mode
Mode object (
irfpy.imacommon.imamode.Mode
)
See example below.
>>> print(dat.t)
2012-10-05 00:01:11.198276
>>> print(dat.polar)
[14, 14]
>>> print(dat.mode)
<IMA:Mode-24 (Exm-0) M32/A16/E96/P16>
>>> print(dat.matrix)
[[[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
...,
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]]
...
>>> print(dat.matrix.shape)
(32, 16, 96)
Time series of 3D data¶
Time series of 3-D data can be obtained by using irfpy.vima.scidata_util.getarray3d()
function.
>>> import datetime
>>> from irfpy.vima import scidata_util
>>> t0 = datetime.datetime(2012, 10, 5, 0, 1, 23)
>>> t1 = datetime.datetime(2012, 10, 6, 4, 59, 43)
>>> dataset3d = scidata_util.getarray3d(t0, t1)
The dataset3d
is an object of irfpy.imacommon.imascipac.TimeSeriesCntMatrix
, as seen below.
>>> print(dataset3d)
<TimeSeriesCntMatrix:len=211 from 2012-10-05 00:01:11.198276 to 2012-10-06 03:41:04.177631>
For the given time range, you can realize 211 3-D data is available.
Of course the functionality works for the mode 25 data.
>>> t0 = datetime.datetime(2008, 10, 5, 2, 1, 23)
>>> t1 = datetime.datetime(2008, 10, 5, 8, 59, 43)
.. >>> dataset = scidata_util.getarray2d(t0, t1)
.. >>> dataset3d = imascipac.convert2to3(dataset)
>>> dataset3d = scidata_util.getarray3d(t0, t1)
>>> print(dataset3d)
<TimeSeriesCntMatrix:len=54 from 2008-10-05 00:38:38.833861 to 2008-10-05 08:56:40.876417>
You can look at the observation time as below; the time resolution is 24 s for this case.
>>> print(dataset3d.getobstime())
[datetime.datetime(2008, 10, 5, 0, 38, 38, 833861),
datetime.datetime(2008, 10, 5, 6, 7, 3, 868441),
datetime.datetime(2008, 10, 5, 6, 10, 15, 868476),
datetime.datetime(2008, 10, 5, 6, 13, 27, 837259),
datetime.datetime(2008, 10, 5, 6, 16, 39, 831038),
datetime.datetime(2008, 10, 5, 6, 19, 51, 799822),
datetime.datetime(2008, 10, 5, 6, 23, 3, 793610),
...
You can get the array expression of the dataset by getarray()
method.
>>> dataarray = dataset3d.getarray()
>>> print(dataarray.shape)
(32, 16, 96, 8, 54)
Specific 3D data¶
To get the 3D data of the specific time, you can use the index, or get()
method.
>>> print(dataset3d[15])
(datetime.datetime(2008, 10, 5, 6, 51, 51, 881401), <irfpy.imacommon.imascipac.CntMatrix object at ...>)
>>> dat3d15 = dataset3d[15][1] # Index 0 is time, and index 1 is the data (CntMatrix object)
>>> print(dat3d15.mode)
<IMA:Mode-25 (Exm-1) M32/A16/E96/P 8>
The matrix
contains the count rate data.
>>> print(dat3d15.matrix)
[[[[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
...,
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 1. 0. ..., 0. 0. 0.]]
[[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
...,
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
...
>>> print(dat3d15.matrix.shape)
(32, 16, 96, 8)
Processing data¶
There are some functions that can convert the object-oriented dataset to a simple numpy array.
irfpy.imacommon.imascipac.timeseries2d_to_energytime_simple()
will convert the
irfpy.imacommon.imascipac.TimeSeriesCntMatrix2D
to (96, N) numpy array.
This is useful to make the E-t diagram.
>>> import datetime
>>> from irfpy.vima import scidata_util
>>> t0 = datetime.datetime(2012, 10, 5, 0, 1, 23)
>>> t1 = datetime.datetime(2012, 10, 6, 4, 59, 43)
>>> dataset = scidata_util.getarray2d(t0, t1)
>>> print(dataset)
<TimeSeriesCntMatrix2D:len=3362 from 2012-10-05 00:01:11.198276 to 2012-10-06 03:44:03.177666>
>>> from irfpy.imacommon import imascipac
>>> etmatrix = imascipac.timeseries2d_to_energytime_simple(dataset) # etmatrix is numpy array.
>>> print(etmatrix)
[[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
...,
[ 0. 1. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]]
>>> print(etmatrix.shape)
(96, 3362)