Working with Instrumental Descriptions

the instrumental description is loaded by the event source, and consists of a hierarchy of classes in the ctapipe.instrument module, the base of which is the SubarrayDescription

[1]:
from ctapipe.utils.datasets import get_dataset_path
from ctapipe.io import EventSource
import numpy as np

#filename = get_dataset_path("gamma_test_large.simtel.gz") # try this one as well
filename = get_dataset_path("gamma_test_large.simtel.gz")

with EventSource(filename, max_events=1) as source:
    subarray = source.subarray

the SubarrayDescription:

[2]:
subarray.info()
Subarray : MonteCarloArray
Num Tels : 98
Footprint: 4.92 km2

       Type        Count Tel IDs
------------------ ----- -------
SST_ASTRI_ASTRICam    69 30-98
    LST_LST_LSTCam     4 1-4
  MST_MST_FlashCam    25 5-29
[3]:
subarray.to_table()
[3]:
Table length=98
tel_idpos_xpos_ypos_znametypecamera_typecamera_indexoptics_indextel_description
mmm
int16float64float64float64str5str3str8int64int64str18
1-20.065.016.0LSTLSTLSTCam21LST_LST_LSTCam
2-20.0-65.016.0LSTLSTLSTCam21LST_LST_LSTCam
380.00.016.0LSTLSTLSTCam21LST_LST_LSTCam
4-120.00.016.0LSTLSTLSTCam21LST_LST_LSTCam
50.00.010.0MSTMSTFlashCam02MST_MST_FlashCam
60.0151.199996948242210.0MSTMSTFlashCam02MST_MST_FlashCam
70.0-151.199996948242210.0MSTMSTFlashCam02MST_MST_FlashCam
8146.6559906005859475.599998474121110.0MSTMSTFlashCam02MST_MST_FlashCam
9146.65599060058594-75.599998474121110.0MSTMSTFlashCam02MST_MST_FlashCam
..............................
89956.7870483398438739.8229980468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
90956.7870483398438-739.8229980468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
91-239.196990966796881109.73498535156255.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
92-239.19699096679688-1109.73498535156255.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
93-956.7870483398438739.8229980468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
94-956.7870483398438-739.8229980468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
951195.9840087890625369.91198730468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
961195.9840087890625-369.91198730468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
97-1195.9840087890625369.91198730468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
98-1195.9840087890625-369.91198730468755.0ASTRISSTASTRICam10SST_ASTRI_ASTRICam
[ ]:

You can also get a table of just the OpticsDescriptions (CameraGeometry is more complex and can’t be stored on a single table row, so each one can be converted to a table separately)

[4]:
subarray.to_table(kind='optics')
[4]:
Table length=3
descriptionnametypemirror_areanum_mirrorsnum_mirror_tilesequivalent_focal_length
m2m
str18str5str3float64int64int64float64
SST_ASTRI_ASTRICamASTRISST14.562566757202148222.1500000953674316
LST_LST_LSTCamLSTLST386.7332458496094119828.0
MST_MST_FlashCamMSTMST103.8305587768554718416.0

Make a sub-array with only SC-type telescopes:

[5]:
sc_tels =[tel_id for tel_id, tel in subarray.tel.items() if tel.optics.num_mirrors ==  2]
newsub = subarray.select_subarray(sc_tels, name="SCTels")
newsub.info()
Subarray : SCTels
Num Tels : 69
Footprint: 4.92 km2

       Type        Count Tel IDs
------------------ ----- -------
SST_ASTRI_ASTRICam    69 30-98

can also do this by using Table.group_by

Explore some of the details of the telescopes

[6]:
tel = subarray.tel[1]
tel
[6]:
TelescopeDescription(type=LST, name=LST, optics=LST, camera=LSTCam)
[7]:
tel.optics.mirror_area
[7]:
$386.73325 \; \mathrm{m^{2}}$
[8]:
tel.optics.num_mirror_tiles
[8]:
198
[9]:
tel.optics.equivalent_focal_length
[9]:
$28 \; \mathrm{m}$
[10]:
tel.camera
[10]:
CameraDescription(camera_name=LSTCam, geometry=LSTCam, readout=LSTCam)
[11]:
tel.camera.geometry.pix_x
[11]:
$[0,~-0.0094487737,~-0.047244198,~\dots,~-0.6519913,~-0.6141959,~-0.62364468] \; \mathrm{m}$
[12]:
%matplotlib inline
from ctapipe.visualization import CameraDisplay
CameraDisplay(tel.camera.geometry)
[12]:
<ctapipe.visualization.mpl_camera.CameraDisplay at 0x7f6531f765b0>
../_images/examples_InstrumentDescription_18_1.png
[13]:
CameraDisplay(subarray.tel[98].camera.geometry)
[13]:
<ctapipe.visualization.mpl_camera.CameraDisplay at 0x7f6527350b20>
../_images/examples_InstrumentDescription_19_1.png

Plot the subarray

We’ll make a subarray by telescope type and plot each separately, so they appear in different colors. We also calculate the radius using the mirror area (and exagerate it a bit).

This is just for debugging and info, for any “real” use, a visualization.ArrayDisplay should be used

[14]:
subarray.peek()
../_images/examples_InstrumentDescription_21_0.png
[15]:
subarray.footprint
[15]:
$4.9235437 \; \mathrm{km^{2}}$

Get info about the subarray in general

[16]:
subarray.telescope_types
[16]:
[TelescopeDescription(type=SST, name=ASTRI, optics=ASTRI, camera=ASTRICam),
 TelescopeDescription(type=LST, name=LST, optics=LST, camera=LSTCam),
 TelescopeDescription(type=MST, name=MST, optics=MST, camera=FlashCam)]
[17]:
subarray.camera_types
[17]:
[CameraDescription(camera_name=FlashCam, geometry=FlashCam, readout=FlashCam),
 CameraDescription(camera_name=ASTRICam, geometry=ASTRICam, readout=ASTRICam),
 CameraDescription(camera_name=LSTCam, geometry=LSTCam, readout=LSTCam)]
[18]:
subarray.optics_types
[18]:
[OpticsDescription(name=LST, equivalent_focal_length=28.00 m, num_mirrors=1, mirror_area=386.73 m2),
 OpticsDescription(name=MST, equivalent_focal_length=16.00 m, num_mirrors=1, mirror_area=103.83 m2),
 OpticsDescription(name=ASTRI, equivalent_focal_length=2.15 m, num_mirrors=2, mirror_area=14.56 m2)]
[19]:
from astropy.coordinates import SkyCoord
from ctapipe.coordinates import GroundFrame
center = SkyCoord("10.0 m", "2.0 m", "0.0 m", frame='groundframe')
coords = subarray.tel_coords  # a flat list of coordinates by tel_index
coords.separation(center)
[19]:
[$95^\circ38{}^\prime18.00148086{}^{\prime\prime}$ $117^\circ35{}^\prime31.27302433{}^{\prime\prime}$ $15^\circ56{}^\prime32.52698026{}^{\prime\prime}$ $166^\circ24{}^\prime15.7253012{}^{\prime\prime}$ $90^\circ00{}^\prime00{}^{\prime\prime}$ $78^\circ42{}^\prime54.16815351{}^{\prime\prime}$ $101^\circ17{}^\prime05.83184649{}^{\prime\prime}$ $16^\circ19{}^\prime25.41596944{}^{\prime\prime}$ $38^\circ42{}^\prime43.34925204{}^{\prime\prime}$ $138^\circ18{}^\prime26.2816408{}^{\prime\prime}$ $160^\circ45{}^\prime08.60655268{}^{\prime\prime}$ $45^\circ50{}^\prime11.58180769{}^{\prime\prime}$ $68^\circ26{}^\prime09.42492861{}^{\prime\prime}$ $11^\circ27{}^\prime33.95564116{}^{\prime\prime}$ $111^\circ33{}^\prime50.57507139{}^{\prime\prime}$ $134^\circ09{}^\prime48.41819231{}^{\prime\prime}$ $168^\circ32{}^\prime26.04435884{}^{\prime\prime}$ $78^\circ41{}^\prime43.72807471{}^{\prime\prime}$ $101^\circ18{}^\prime16.27192529{}^{\prime\prime}$ $16^\circ02{}^\prime24.20158042{}^{\prime\prime}$ $38^\circ36{}^\prime32.84913188{}^{\prime\prime}$ $141^\circ23{}^\prime27.15086812{}^{\prime\prime}$ $163^\circ57{}^\prime35.79841958{}^{\prime\prime}$ $45^\circ48{}^\prime42.20493911{}^{\prime\prime}$ $68^\circ25{}^\prime33.02273995{}^{\prime\prime}$ $11^\circ21{}^\prime07.59158637{}^{\prime\prime}$ $111^\circ34{}^\prime26.97726005{}^{\prime\prime}$ $134^\circ11{}^\prime17.79506089{}^{\prime\prime}$ $168^\circ38{}^\prime52.40841363{}^{\prime\prime}$ $49^\circ01{}^\prime53.88209151{}^{\prime\prime}$ $130^\circ58{}^\prime06.11790849{}^{\prime\prime}$ $153^\circ34{}^\prime33.89607713{}^{\prime\prime}$ $57^\circ29{}^\prime13.31292386{}^{\prime\prime}$ $80^\circ06{}^\prime19.07824957{}^{\prime\prime}$ $99^\circ53{}^\prime40.92175043{}^{\prime\prime}$ $122^\circ30{}^\prime46.68707614{}^{\prime\prime}$ $1^\circ21{}^\prime19.767395{}^{\prime\prime}$ $23^\circ51{}^\prime29.09114511{}^{\prime\prime}$ $156^\circ08{}^\prime30.90885489{}^{\prime\prime}$ $178^\circ38{}^\prime40.232605{}^{\prime\prime}$ $78^\circ41{}^\prime26.15149805{}^{\prime\prime}$ $101^\circ18{}^\prime33.84850195{}^{\prime\prime}$ $34^\circ34{}^\prime02.39137677{}^{\prime\prime}$ $57^\circ11{}^\prime07.33168189{}^{\prime\prime}$ $122^\circ48{}^\prime52.66831811{}^{\prime\prime}$ $145^\circ25{}^\prime57.60862323{}^{\prime\prime}$ $15^\circ57{}^\prime57.37624672{}^{\prime\prime}$ $38^\circ34{}^\prime56.93351141{}^{\prime\prime}$ $141^\circ25{}^\prime03.06648859{}^{\prime\prime}$ $164^\circ02{}^\prime02.62375328{}^{\prime\prime}$ $78^\circ41{}^\prime25.22810173{}^{\prime\prime}$ $101^\circ18{}^\prime34.77189827{}^{\prime\prime}$ $11^\circ18{}^\prime54.92436156{}^{\prime\prime}$ $168^\circ41{}^\prime05.07563844{}^{\prime\prime}$ $45^\circ48{}^\prime11.26179707{}^{\prime\prime}$ $68^\circ25{}^\prime20.46124877{}^{\prime\prime}$ $111^\circ34{}^\prime39.53875123{}^{\prime\prime}$ $134^\circ11{}^\prime48.73820293{}^{\prime\prime}$ $63^\circ12{}^\prime03.82140047{}^{\prime\prime}$ $85^\circ49{}^\prime13.70626482{}^{\prime\prime}$ $29^\circ21{}^\prime33.48064028{}^{\prime\prime}$ $51^\circ58{}^\prime41.62927485{}^{\prime\prime}$ $3^\circ09{}^\prime32.00022804{}^{\prime\prime}$ $25^\circ45{}^\prime53.65643251{}^{\prime\prime}$ $94^\circ10{}^\prime46.29373518{}^{\prime\prime}$ $116^\circ47{}^\prime56.17859953{}^{\prime\prime}$ $128^\circ01{}^\prime18.37072515{}^{\prime\prime}$ $150^\circ38{}^\prime26.51935972{}^{\prime\prime}$ $154^\circ14{}^\prime06.34356749{}^{\prime\prime}$ $176^\circ50{}^\prime27.99977196{}^{\prime\prime}$ $78^\circ41{}^\prime24.82136926{}^{\prime\prime}$ $101^\circ18{}^\prime35.17863074{}^{\prime\prime}$ $15^\circ57{}^\prime47.41407165{}^{\prime\prime}$ $38^\circ34{}^\prime53.48248332{}^{\prime\prime}$ $141^\circ25{}^\prime06.51751668{}^{\prime\prime}$ $164^\circ02{}^\prime12.58592835{}^{\prime\prime}$ $11^\circ18{}^\prime46.40953986{}^{\prime\prime}$ $168^\circ41{}^\prime13.59046014{}^{\prime\prime}$ $52^\circ49{}^\prime06.0104884{}^{\prime\prime}$ $75^\circ26{}^\prime16.42056571{}^{\prime\prime}$ $38^\circ57{}^\prime04.26530019{}^{\prime\prime}$ $61^\circ34{}^\prime14.31046822{}^{\prime\prime}$ $104^\circ33{}^\prime43.57943429{}^{\prime\prime}$ $127^\circ10{}^\prime53.9895116{}^{\prime\prime}$ $118^\circ25{}^\prime45.68953178{}^{\prime\prime}$ $141^\circ02{}^\prime55.73469981{}^{\prime\prime}$ $66^\circ31{}^\prime35.8563378{}^{\prime\prime}$ $89^\circ08{}^\prime46.531159{}^{\prime\prime}$ $26^\circ24{}^\prime12.85346442{}^{\prime\prime}$ $49^\circ01{}^\prime22.34800835{}^{\prime\prime}$ $90^\circ51{}^\prime13.468841{}^{\prime\prime}$ $113^\circ28{}^\prime24.1436622{}^{\prime\prime}$ $130^\circ58{}^\prime37.65199165{}^{\prime\prime}$ $153^\circ35{}^\prime47.14653558{}^{\prime\prime}$ $5^\circ52{}^\prime51.91477485{}^{\prime\prime}$ $28^\circ29{}^\prime50.48159858{}^{\prime\prime}$ $151^\circ30{}^\prime09.51840142{}^{\prime\prime}$ $174^\circ07{}^\prime08.08522515{}^{\prime\prime}$]

Telescope IDs vs Indices

Note that subarray.tel is a dict mapped by tel_id (the indentifying number of a telescope). It is possible to have telescope IDs that do not start at 0, are not contiguouous (e.g. if a subarray is selected). Some functions and properties like tel_coords are numpy arrays (not dicts) so they are not mapped to the telescope ID, but rather the index within this SubarrayDescription. To convert between the two concepts you can do:

[20]:
subarray.tel_ids_to_indices([1,5,23])
[20]:
array([ 0,  4, 22])

or you can get the indexing array directly in numpy or dict form:

[21]:
subarray.tel_index_array
[21]:
array([-1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
       16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
       50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
       67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
       84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97])
[22]:
subarray.tel_index_array[[1,5,23]]
[22]:
array([ 0,  4, 22])
[23]:
subarray.tel_indices[1]  # this is a dict of tel_id -> tel_index, so we can only do one at once
[23]:
0
[24]:
ids = subarray.get_tel_ids_for_type(subarray.telescope_types[0])
ids
[24]:
[30,
 31,
 32,
 33,
 34,
 35,
 36,
 37,
 38,
 39,
 40,
 41,
 42,
 43,
 44,
 45,
 46,
 47,
 48,
 49,
 50,
 51,
 52,
 53,
 54,
 55,
 56,
 57,
 58,
 59,
 60,
 61,
 62,
 63,
 64,
 65,
 66,
 67,
 68,
 69,
 70,
 71,
 72,
 73,
 74,
 75,
 76,
 77,
 78,
 79,
 80,
 81,
 82,
 83,
 84,
 85,
 86,
 87,
 88,
 89,
 90,
 91,
 92,
 93,
 94,
 95,
 96,
 97,
 98]
[25]:
idx = subarray.tel_ids_to_indices(ids)
idx
[25]:
array([29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
       46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
       63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
       80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
       97])
[26]:
subarray.tel_coords[idx]
[26]:
<SkyCoord (GroundFrame): (x, y, z) in m
    [(  205.5       ,  -158.8999939 , 5.),
     ( -205.5       ,   158.8999939 , 5.),
     ( -205.5       ,  -158.8999939 , 5.),
     (  164.82301331,   424.82397461, 5.),
     (  164.82301331,  -424.82397461, 5.),
     ( -164.82301331,   424.82397461, 5.),
     ( -164.82301331,  -424.82397461, 5.),
     (  494.46899414,   110.        , 5.),
     (  494.46899414,  -110.        , 5.),
     ( -494.46899414,   110.        , 5.),
     ( -494.46899414,  -110.        , 5.),
     (    0.        ,   519.79498291, 5.),
     (    0.        ,  -519.79498291, 5.),
     (  391.60601807,   403.73898315, 5.),
     (  391.60601807,  -403.73898315, 5.),
     ( -391.60601807,   403.73898315, 5.),
     ( -391.60601807,  -403.73898315, 5.),
     (  618.07299805,   318.61099243, 5.),
     (  618.07299805,  -318.61099243, 5.),
     ( -618.07299805,   318.61099243, 5.),
     ( -618.07299805,  -318.61099243, 5.),
     (    0.        ,   723.52703857, 5.),
     (    0.        ,  -723.52703857, 5.),
     (  820.        ,     0.        , 5.),
     ( -820.        ,     0.        , 5.),
     (  435.3039856 ,   673.18603516, 5.),
     (  435.3039856 ,  -673.18603516, 5.),
     ( -435.3039856 ,   673.18603516, 5.),
     ( -435.3039856 ,  -673.18603516, 5.),
     (  220.8440094 ,   796.9029541 , 5.),
     (  220.8440094 ,  -796.9029541 , 5.),
     (  662.53295898,   569.21600342, 5.),
     (  662.53295898,  -569.21600342, 5.),
     (  883.37701416,   227.68699646, 5.),
     (  883.37701416,  -227.68699646, 5.),
     ( -220.8440094 ,   796.9029541 , 5.),
     ( -220.8440094 ,  -796.9029541 , 5.),
     ( -662.53295898,   569.21600342, 5.),
     ( -662.53295898,  -569.21600342, 5.),
     ( -883.37701416,   227.68699646, 5.),
     ( -883.37701416,  -227.68699646, 5.),
     (    0.        ,   944.30102539, 5.),
     (    0.        ,  -944.30102539, 5.),
     (  915.92297363,   472.15100098, 5.),
     (  915.92297363,  -472.15100098, 5.),
     ( -915.92297363,   472.15100098, 5.),
     ( -915.92297363,  -472.15100098, 5.),
     ( 1100.        ,     0.        , 5.),
     (-1100.        ,     0.        , 5.),
     (  471.01199341,   971.21002197, 5.),
     (  471.01199341,  -971.21002197, 5.),
     (  706.51794434,   849.80895996, 5.),
     (  706.51794434,  -849.80895996, 5.),
     ( -471.01199341,   971.21002197, 5.),
     ( -471.01199341,  -971.21002197, 5.),
     ( -706.51794434,   849.80895996, 5.),
     ( -706.51794434,  -849.80895996, 5.),
     (  239.19699097,  1109.73498535, 5.),
     (  239.19699097, -1109.73498535, 5.),
     (  956.78704834,   739.82299805, 5.),
     (  956.78704834,  -739.82299805, 5.),
     ( -239.19699097,  1109.73498535, 5.),
     ( -239.19699097, -1109.73498535, 5.),
     ( -956.78704834,   739.82299805, 5.),
     ( -956.78704834,  -739.82299805, 5.),
     ( 1195.98400879,   369.9119873 , 5.),
     ( 1195.98400879,  -369.9119873 , 5.),
     (-1195.98400879,   369.9119873 , 5.),
     (-1195.98400879,  -369.9119873 , 5.)]>

so, with that method you can quickly get many telescope positions at once (the alternative is to use the dict positions which maps tel_id to a position on the ground

[27]:
subarray.positions[1]
[27]:
$[-20,~65,~16] \; \mathrm{m}$