''' Module for SWIM mass analysis
'''
import logging
import datetime
import numpy as np
import irfpy.util.utc as utc
from irfpy.util.julday import JdObject
from irfpy.swim.swim_cache import SwimDataCache
class __swimcache:
instance = None
@classmethod
def cache(cls):
if cls.instance is None:
cls.instance = SwimDataCache()
return cls.instance
logger = logging.getLogger('swim_mass')
logger.setLevel(logging.DEBUG)
[docs]def getobstime(orbit=None, timerange=None):
''' Return the observation time of SWIM mass data.
:keyword orbit: Returns the obseration time for corresponding orbit number
:keyword timerange: Time range to be examined.
Either ``orbit`` or ``timerange`` should be specified.
>>> o939 = getobstime(orbit=939)
>>> print(len(o939))
885
>>> t0 = datetime.datetime(2009, 1, 25, 12, 0, 0)
>>> t1 = datetime.datetime(2009, 1, 25, 15, 0, 0)
>>> o2 = getobstime(timerange=[t0, t1])
>>> print(len(o2))
777
'''
return __swimcache.cache().getObstime(orbit=orbit, timerange=timerange)
[docs]def getdata(t, filter=[]):
''' Get the data.
:param t: Time.
:type t: Type supported by ``irfpy.util.utc.convert``.
:keyword filter: Filter to apply. Usually a function defined in
:class:`filter` class.
>>> t0 = datetime.datetime(2009, 1, 25, 14)
>>> data = getdata(t0)
>>> mspec = data.getData() # Mass spectra data
>>> print(mspec.shape)
(16, 16, 32)
>>> print(mspec.sum()) # Using v3.2 database.
1538.0
If you use filter to filter out one counts, the value should change.
>>> mspec_ocr = getdata(t0, filter=[filter.remove_one_count]).getData()
>>> print(mspec_ocr.shape)
(16, 16, 32)
>>> print(mspec_ocr.sum())
1409.0
You may remove one count event using :meth:`filter.remove_one_count_event_l1`.
>>> mspec_l1 = getdata(t0, filter=[filter.remove_one_count_event_l1]).getData()
>>> print(mspec_l1.shape)
(16, 16, 32)
>>> print(mspec_l1.sum())
1528.0
'''
t0 = utc.convert(t, datetime.datetime)
matx_jdo = __swimcache.cache().getMassMatrix(t0)
matx_jd = matx_jdo.getJd()
matx = matx_jdo.getData()
for f in filter:
matx = f(matx)
return JdObject(matx_jd, matx)
[docs]def statusCache():
return __swimcache.cache().statusCache()
[docs]def clearCache():
logging.debug('Clearing cache')
__swimcache.cache().clearCache()
[docs]class filter:
''' Collection of SWIM mass matrix fileters.
SWIM mass matrix filter is a function that get
raw E16xD16xM32 matrix (``np.array``) to return
the matrix that has the same shape.
'''
[docs] @classmethod
def remove_one_count(cls, raw):
''' As one count is not statistically siginificant, those counts are removed.
# Emulate the raw counts that consists fully with 1.
>>> raw = np.ones([16, 16, 32])
>>> print(raw.sum())
8192.0
# If the filter is applied, everything should be zero.
>>> proc = filter.remove_one_count(raw)
>>> print(proc.sum())
0.0
>>> print(raw.sum())
8192.0
'''
return np.where(raw <= 1, 0, raw)
[docs] @classmethod
def remove_one_count_event_l1(cls, raw):
''' Remove one count event with L1 (empirical) suppression.
One count event is not same as 1 count in the usual sense.
This is an instrumental origin, appears strange count
in a specific tof channel.
This can also be referred to swimmassspectrum.pro that
MW developed originally in IDL.
See https://butler.irf.se/sara-trac/file/SARA/swim_mass/swimmassspectrum.pro also.
The original procedure contains the comment like:
``define elements where one-count events can happen empiricaly
this is probably temperature independent, but takes less events away``
'''
# Copy and paste from MW's implementation. Note: order is M, E, D
maskpos= [[1,14,0],[10,9,0],[11,9,0],[11,10,0],[12,10,0],[18,6,0],[19,6,0],[20,6,0],[28,5,0],[24,9,0],[29,9,0],
[23,9,1],[24,9,1],[11,10,1],[12,10,1],
[10,9,2],[11,9,2],[11,10,2],[12,10,2],[23,9,2],[24,9,2], [27,11,2],[28,11,2],[29,11,2],[28,5,2],
[10,9,3],[11,9,3],[11,10,3],[12,10,3],[23,9,3],[30,12,3],[29,12,3],[24,9,3], [25,9,3],
[10,9,4],[11,9,4],[11,10,4],[12,10,4],[27,11,4],[28,11,4],[30,12,4],[29,6,4], [27,8,4],
[27,11,5], [28,11,5],[24,9,5], [25,9,5],
[1,15,6],[12,10,6],[23,9,6],[24,9,6],
[10,9,7],[11,9,7],[11,10,7],[12,10,7],[16,3,7],[17,4,7],[18,4,7],[18,6,7],[19,6,7],[20,6,7],
[30,6,9], [19,6,9],
[15,2,10],[16,2,10],[20,7,10],[21,7,10],[25,10,10],[26,10,10],[30,6,10],[29,12,10],[30,12,10],
[25,10,11],[26,10,11],[30,6,11],
[25,10,12],[26,10,12],
[15,2,13],[16,2,13],[26,4,13],[27,4,13],
[25,10,14],[26,10,14],[27,10,14],[11,10,14],[12,10,14],
[10,9,15],[11,9,15],[11,10,15],[12,10,15],[24,9,15],[1,14,15]]
maskpos = np.array(maskpos) # shape is 92, 3
proc = raw.copy()
for m, e, d in maskpos:
proc[e, d, m] = 0
return proc
[docs] @classmethod
def remove_one_count_event_l2(cls, raw):
''' Remove one count event with L2 (soft) suppression.
One count event is not same as 1 count in the usual sense.
This is an instrumental origin, appears strange count
in a specific tof channel.
This can also be referred to swimmassspectrum.pro that
MW developed originally in IDL.
See https://butler.irf.se/sara-trac/file/SARA/swim_mass/swimmassspectrum.pro also.
The original procedure contains the comment like:
``Define elements where one-count events can happen analyticaly:
this is temperature independent, but takes sometimes too many counts away``
'''
# SWIM DPU processing table
# ETOF for pacc 2 (was always used)
etof = np.array([514,527,543,563,586,614,648,687,733,787,850,923,1006,1101,1210,1333])
# Mask for pacc 2
mask = np.array([7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6])
# I do not yet understand what it means.
### MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
mask = np.where(mask < 7, 7, mask)
proc = raw.copy()
for iE in range(16):
for iM in range(32):
tof = (iM * 2. ** 19) / etof[iE] / (2 ** mask[iE])
if (tof >= 112 and tof <= 127 or tof >= 52 and tof <= 63 or tof >= 176 and tof <= 191):
for iD in range(16):
proc[iE, iD, iM] = 0
return proc
[docs] @classmethod
def remove_one_count_event_l3(cls, raw):
''' Remove one count event with L3 (strong) suppression.
One count event is not same as 1 count in the usual sense.
This is an instrumental origin, appears strange count
in a specific tof channel.
This can also be referred to swimmassspectrum.pro that
MW developed originally in IDL.
See https://butler.irf.se/sara-trac/file/SARA/swim_mass/swimmassspectrum.pro also.
The original procedure contains the comment like:
``Define elements where one-count events can happen analyticaly:
this is temperature independent, but takes sometimes too many counts away``
'''
# ; SWIM DPU processing tables
# ; ETOF for pacc 2 (was always used)
# ETOF = [514,527,543,563,586,614,648,687,733,787,850,923,1006,1101,1210,1333]
etof = np.array([514,527,543,563,586,614,648,687,733,787,850,923,1006,1101,1210,1333])
# ; MASK for pacc 2
# MASK = [7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6]
# MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
# Mask for pacc 2
mask = np.array([7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6])
# I do not yet understand what it means.
### MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
mask = np.where(mask < 7, 7, mask)
#for iD=0,maxe-1 do begin
# for iE=0,maxe-1 do begin
# for iM=0,maxm-1 do begin
# tof = (iM*2.^19)/ETOF[iE]/(2^MASK[iE])
# tofbg[iM,iE,iD] = (tof gt 52) && $
# ( ((floor((tof-3) / 16) mod 2) eq 1) || $
# ((floor((tof-1) / 16) mod 2) eq 1) )? 1 : 0
# endfor
# endfor
#endfor
proc = raw.copy()
for ie in range(16):
for im in range(32):
tof = (im * 2. ** 19) / etof[ie] / (2 ** mask[ie])
ifbg = (tof > 52) and ( ((np.floor((tof-3) / 16) % 2) == 1) or ((np.floor((tof-1) / 16) % 2) == 1) )
if ifbg:
for id in range(16):
proc[ie, id, im] = 0
return proc
[docs] @classmethod
def remove_one_count_event_l4(cls, raw):
''' Remove one count event with L4 (full) suppression.
One count event is not same as 1 count in the usual sense.
This is an instrumental origin, appears strange count
in a specific tof channel.
This can also be referred to swimmassspectrum.pro that
MW developed originally in IDL.
See https://butler.irf.se/sara-trac/file/SARA/swim_mass/swimmassspectrum.pro also.
The original procedure contains the comment like:
; Define elements where one-count events can happen analyticaly:
; this is temperature independent, but takes sometimes too many counts away
'''
# ; SWIM DPU processing tables
# ; ETOF for pacc 2 (was always used)
# ETOF = [514,527,543,563,586,614,648,687,733,787,850,923,1006,1101,1210,1333]
etof = np.array([514,527,543,563,586,614,648,687,733,787,850,923,1006,1101,1210,1333])
# ; MASK for pacc 2
# MASK = [7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6]
# MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
# Mask for pacc 2
mask = np.array([7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6])
# I do not yet understand what it means.
### MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
mask = np.where(mask < 7, 7, mask)
#MASK = MASK>7 ; cases where mask is 6 do not seem to generate one-ocunt-events.
#for iD=0,maxe-1 do begin
# for iE=0,maxe-1 do begin
# for iM=0,maxm-1 do begin
# tof = (iM*2.^19)/ETOF[iE]/(2^MASK[iE])
# tofbg[iM,iE,iD] = (tof gt 48) ? 1 : 0
# endfor
# endfor
#endfor
proc = raw.copy()
for ie in range(16):
for im in range(32):
tof = (im * 2. ** 19) / etof[ie] / (2 ** mask[ie])
ifbg = (tof > 48)
if ifbg:
for id in range(16):
proc[ie, id, im] = 0
return proc