Use case 4: Observatory events
[1]:
import showermodel as sm
This notebook describes how to construct an observatory made of several telescopes using the Observatory class (and its subclasses) and how to use the Event class, which uses the Signal and Observatory classes. These classes include advanced methods to show the geometry of an observatory that detects a shower.
Construction of an Observatory object
An Observatory object is a list of telescopes with some additional attributes and methods.
[2]:
telescope1 = sm.Telescope(x=0.1, y=0.2, theta=20.)
telescope2 = telescope1.copy(x=0.2, y=0.1)
telescope3 = telescope1.copy(x=-0.3, y=-0.1)
observatory = sm.Observatory(telescope1, telescope2, telescope3, obs_type="MyObservatory")
# Some attributes of Observatory objects
print("Observatory type:", observatory.obs_type)
print("Number of telescopes:", observatory.N_tel)
print("Type of telescopes:", observatory.tel_type)
print("Aperture of telescopes in degrees:", observatory.tel_apert)
print("Central position of the observatory:", (observatory.x_c, observatory.y_c, observatory.z_c))
Observatory type: MyObservatory
Number of telescopes: 3
Type of telescopes: None
Aperture of telescopes in degrees: 10.0
Central position of the observatory: (0.1, 0.2, 0.0)
Note: The Observatory attributes tel_type, tel_apert, etc. are set to be equal to those of the first input Telescope object, even if the Observatory object is made up of Telescopes objects with different parameters.
More Telescope objects can be added later.
[3]:
observatory.append(telescope1.copy(x=0., y=0., apert=5., theta=10., az=56.))
A show method is available to show a 2D plot of telescope positions and indexes.
[4]:
observatory.show();
Individual Telescope objects can be accessed via an index (starting at 0).
[5]:
print("Pointing of second telescope:", (observatory[1].theta, observatory[1].az))
print("Pointing of last telescope:", (observatory[-1].theta, observatory[-1].az))
Pointing of second telescope: (20.0, 0.0)
Pointing of last telescope: (10.0, 56.0)
Help on Observatory.
[6]:
# sm.Observatory?
Predefined Observatory objects: Circular array of 25 telescopes
By default, a radius of 341 m and IACT telescopes pointing at zenith are assumed, but the observatory position (center), the radius, the telescope pointing and the array orientation can be modified.
[7]:
# Default Array25 object
# observatory2 = sm.Array25()
# User-defined
observatory2 = sm.Array25(x_c=0.2, y_c=0.2, z_c=0.5, R=1., theta=20., az= 120., rot_angle=15.)
print("Observatory type:", observatory2.obs_type)
print("Number of telescopes:", observatory2.N_tel)
print("Type of telescopes:", observatory2.tel_type)
print("Center of the array:", (observatory2.x_c, observatory2.y_c, observatory2.z_c))
observatory2.show();
Observatory type: Array25
Number of telescopes: 50
Type of telescopes: IACT
Center of the array: (0.2, 0.2, 0.5)
The type of telescopes of the array can also be modified.
[8]:
# telescope1 = sm.Telescope(theta=30., az= 10.) # Instead of IACT
# observatory2 = sm.Array25(telescope=telescope1, R=1., theta=20., az= 120.) # theta and az are overwritten
Help on Array25.
[9]:
# sm.Array25?
Predefined Observatory objects: Rectangular grid of telescopes
The default Grid object is made of objects of class GridElement, which is a subclass of Telescope, with 100 % efficiency in the 290-430 nm range and 180 degrees aperture around zenith. As a Grid object is constructed, the detection area of the constituent GridElement objects is set equal to the grid cell area.
[10]:
# Default Grid object
observatory3 = sm.Grid()
print("Observatory type:", observatory3.obs_type)
print("Number of telescopes:", observatory3.N_tel)
print("Type of telescopes:", observatory3.tel_type)
print("Center of the array:", (observatory3.x_c, observatory3.y_c, observatory3.z_c))
print("Telescope detection area in m^2:", observatory3.tel_area)
observatory3.show();
Observatory type: Grid
Number of telescopes: 200
Type of telescopes: GridElement
Center of the array: (0.0, 0.0, 0.0)
Telescope detection area in m^2: 40000.00000000001
Note: A Grid object is generated when calling the show_distribution method of Shower (see UC3).
The grid position, dimensions, granularity and telescope type can be modified.
[11]:
# 1D grid of IACT telescopes along the x axis
# observatory3 = sm.Grid(telescope=sm.IACT(), theta=20., az= 10., x_c=0.1, y_c=-0.3, size_x=4., size_y=0.1, N_x=10, N_y=1)
Note: If a telescope is input (not None), the telescope detection area is used instead of the grid cell area.
Help on Grid.
[12]:
# sm.Grid?
Event objects
An Event object contains a Shower object, an Observatory object as well as lists of Projection and Signal objects. By default, signals are calculated including both atmospheric transmission and detection efficiency.
[13]:
shower = sm.Shower(x0=0.2, y0=0.1, theta=20., az=45.)
observatory = sm.Array25(R=1., theta=22., az= 45.)
event1 = sm.Event(observatory, shower)
# Equivalent method of Shower
# event1 = shower.Event(observatory)
Both the atmospheric transmission and detection efficiency may be turned off. In case that the detection efficiency is turned off, the wavelength range can also modified (see UC3).
[14]:
event2 = sm.Event(observatory, shower, atm_trans=False, tel_eff=False)
The Atmosphere, Track, Profile, Fluorescence and Cherenkov objects contained in the Shower object can be accessed by attributes of Event as well.
[15]:
event1.track # Equivalent to event1.shower.track
# event1.profile.show();
[15]:
| x | y | z | t | |
|---|---|---|---|---|
| 0 | 0.225884 | 0.125884 | 0.100572 | 392.335254 |
| 1 | 0.277651 | 0.177651 | 0.301716 | 391.621268 |
| 2 | 0.329419 | 0.229419 | 0.502860 | 390.907282 |
| 3 | 0.381187 | 0.281187 | 0.704004 | 390.193296 |
| 4 | 0.432954 | 0.332954 | 0.905148 | 389.479310 |
| ... | ... | ... | ... | ... |
| 545 | 28.439221 | 28.339221 | 109.724052 | 3.212937 |
| 546 | 28.490988 | 28.390988 | 109.925196 | 2.498951 |
| 547 | 28.542756 | 28.442756 | 110.126340 | 1.784965 |
| 548 | 28.594523 | 28.494523 | 110.327484 | 1.070979 |
| 549 | 28.646291 | 28.546291 | 110.528628 | 0.356993 |
550 rows × 4 columns
Telescope, Signal and Projection objects are elements of the lists observatory, signals and projections, respectively.
[16]:
signals1 = event1.signals
signals2 = event2.signals
projections = event1.projections
print("Position of sixth telescope:", (observatory[5].x, observatory[5].y, observatory[5].z))
print("Total number of photoelectrons in sixth telescope:", signals1[5].Npe_total_sum)
print("The same but without atmospheric transmission or detection efficiency:", signals2[5].Npe_total_sum)
projections[5]
Position of sixth telescope: (0.0, 0.6666666666666666, 0.0)
Total number of photoelectrons in sixth telescope: 13.833232485684189
The same but without atmospheric transmission or detection efficiency: 75.54733842334073
[16]:
| distance | alt | az | theta | phi | beta | time | FoV | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0.594630 | 9.737464 | 157.329815 | 89.052195 | 198.592918 | 88.231590 | 1.917205 | False |
| 1 | 0.638168 | 28.215188 | 150.413108 | 69.474364 | 197.939897 | 68.643363 | 1.348445 | False |
| 2 | 0.743351 | 42.568974 | 143.005917 | 53.928459 | 197.293713 | 53.087170 | 0.985302 | False |
| 3 | 0.888549 | 52.401654 | 135.320868 | 42.833326 | 196.654419 | 41.981857 | 0.755633 | False |
| 4 | 1.057405 | 58.871325 | 127.624325 | 35.061301 | 196.022063 | 34.199761 | 0.604877 | False |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 545 | 116.678735 | 70.117930 | 45.782795 | 2.136284 | 139.996259 | 0.291859 | 0.000041 | True |
| 546 | 116.892785 | 70.117718 | 45.781354 | 2.136006 | 139.984014 | 0.291324 | 0.000032 | True |
| 547 | 117.106835 | 70.117505 | 45.779917 | 2.135729 | 139.971810 | 0.290792 | 0.000023 | True |
| 548 | 117.320885 | 70.117294 | 45.778486 | 2.135454 | 139.959648 | 0.290261 | 0.000014 | True |
| 549 | 117.534935 | 70.117084 | 45.777061 | 2.135179 | 139.947528 | 0.289732 | 0.000005 | True |
550 rows × 8 columns
Help on Event.
[17]:
# sm.Event?
Special methods of Event objects
The event geometry can be shown in either a 2D or 3D plot. By default, an area of 1x1 km\(^2\) centered at the origin is shown, but this can be changed.
[18]:
# Default 2D and 3D plots
# event1.show_geometry2D();
# event1.show_geometry3D();
# Setting visualization area at ground level
event1.show_geometry2D(x_min=-1.1, x_max=2., y_min=-1.1, y_max=2.);
event1.show_geometry3D(x_min=-1.1, x_max=2., y_min=-1.1, y_max=2.);
N_ch of Profile) and the size of telescope points are proportional to the integrated signal.More options of show_geometry2D and show_geometry3D are described in the help.
[19]:
# event1.show_geometry2D?
# event1.show_geometry3D?
Event objects have the method show_projection which is equivalent to the method show of Projection. The telescope index can be passed as an argument. If not given, the first telescope (tel_index=0) is assumed.
[20]:
event1.show_projection(tel_index=2, max_theta=10.);
Help on show_projection method.
[21]:
# event1.show_projection?
In addition, a show_distribution method is defined in a similar way as in Shower objects but with different default options. It generates a Grid object based on the first telescope (tel_index=0) of the Observatory object used to construct the Event object.
[22]:
shower = sm.Shower(x0=0.2, y0=0.1, theta=20., az=45.)
observatory = sm.Array25(R=1., theta=22., az= 45.)
event1 = sm.Event(observatory, shower)
event1.show_distribution(size_x=2., size_y=2., N_x=10, N_y=10);
The telescope efficiency can be turned off to obtain the distribution of photons (instead of photoelectrons).
[23]:
# event1.show_distribution(size_x=2., size_y=0.1, N_x=30, N_y=1, tel_eff=False, wvl_ini=290., wvl_fin=450.);
# Equivalent to
# event2 = sm.Event(observatory, shower, tel_eff=False, wvl_ini=290., wvl_fin=450.)
# event2.show_distribution(x_size=1., y_size=0.1, N_x=10, N_y=1)
Alternatively, an existing Grid object can be passed as argument to the GridEvent class, which is a subclass of Event but using a Grid object as observatory. The method show_distribution of GridEvent objects has no input parameters.
[24]:
grid = sm.Grid(telescope=sm.IACT(), size_x=2., size_y=0.1, theta=22., az= 45., N_x=30, N_y=1)
grid_event = sm.GridEvent(grid, shower)
grid_event.show_geometry3D(y_min=-0.2, y_max=2.);
grid_event.show_distribution();
[ ]: