Use case 0: Playing around with ShowerModel

[1]:
import showermodel as sm
import numpy as np
import matplotlib.pyplot as plt

Showers

Let’s generate a 1 TeV gamma-induced shower with 20 degrees zenith angle impacting 0.1 km east and 0.2 km north from some ground-based telescope located at 2.2 km above sea level.

[2]:
shower = sm.Shower(1.e6, theta=20., az=45., x0=0.1, y0=0.2, h0=2.2)

Shower contains information on the shower track geometry, energy deposit profile and both Cherenkov and fluorescence light production.

[3]:
#shower.track
shower.profile
#shower.cherenkov
#shower.fluorescence
[3]:
X s dX E_dep N_ch
0 833.809519 1.639942e+00 20.886275 1745.333331 31.730952
1 813.133112 1.621252e+00 20.467949 2162.692406 40.159662
2 792.870827 1.602432e+00 20.058002 2655.502849 50.365789
3 773.014371 1.583483e+00 19.656266 3231.401894 62.600293
4 753.555613 1.564409e+00 19.262576 3897.468497 77.120065
... ... ... ... ... ...
545 0.000096 4.178872e-07 0.000021 0.000009 0.090310
546 0.000075 3.250234e-07 0.000021 0.000009 0.090309
547 0.000054 2.321596e-07 0.000021 0.000009 0.090308
548 0.000032 1.392957e-07 0.000021 0.000009 0.090307
549 0.000011 4.643192e-08 0.000021 0.000009 0.090305

550 rows × 5 columns

This object also has some atributes and methods to make calculations and plot data.

[4]:
X_max = shower.X_max
x, y, z = shower.track.X_to_xyz(X_max)
print("Depth of maximum (g/cm^2):", np.around(X_max, 3))
print("Height of shower maximum (km):", np.around(z, 3))
shower.show_light_production();
Depth of maximum (g/cm^2): 345.753
Height of shower maximum (km): 6.61
../_images/tutorials_UC0_Playing_around_with_ShowerModel_8_1.png

For example, you may be interested in evaluating the photon density on horizontal planes at different heights (0, 5 and 10 km above ground level). A full MC simulation would take a long time, but ShowerModel allows you to do this calculation in a relatively short time.

[5]:
for z in [0., 5., 10.]:
    shower.show_distribution(x_c=shower.x0, y_c=shower.y0, z_c=z, size_x=4., size_y=4., N_x=10, N_y=10);
../_images/tutorials_UC0_Playing_around_with_ShowerModel_10_0.png
../_images/tutorials_UC0_Playing_around_with_ShowerModel_10_1.png
../_images/tutorials_UC0_Playing_around_with_ShowerModel_10_2.png

Observatory events

Now, we can generate an observatory consisting in a 500 m radius circular array of 25 IACTs pointing at the shower arrival direction. There exists a function to do that with default telescope parameters.

[6]:
observatory = sm.Array25(R=0.5, theta=20., az=45.)
observatory.show();
../_images/tutorials_UC0_Playing_around_with_ShowerModel_13_0.png

Some characteristics of the default IACT.

[7]:
print("Angular aperture (deg):", observatory[0].apert)
print("Number of pixels:", observatory[0].N_pix)
print("Collection area (m^2):", observatory[0].area)
print("Position of telescope #8 (km):", np.around([observatory[8].x, observatory[8].y], 3))
Angular aperture (deg): 8.0
Number of pixels: 1800
Collection area (m^2): 113.097
Position of telescope #8 (km): [ 0.236 -0.236]

An Event object can be generated from the above-defined Shower and Observatory objects.

[8]:
event = sm.Event(shower, observatory)

It contains the shower track projection and signal at each telescope.

[9]:
event.projections[8]
#event.signals[8]
[9]:
distance alt az theta phi beta time FoV
0 0.485012 11.967679 346.617250 68.268420 16.959319 68.268420 1.015937 False
1 0.598276 30.285485 353.548306 48.856659 16.959319 48.856659 0.679743 False
2 0.756485 41.661785 359.362985 36.553427 16.959319 36.553427 0.493467 False
3 0.937146 48.696291 4.216889 28.734994 16.959319 28.734994 0.382082 False
4 1.129536 53.258711 8.275287 23.507737 16.959319 23.507737 0.309824 False
... ... ... ... ... ... ... ... ...
545 116.839319 69.901311 44.423409 0.220937 16.959319 0.220937 0.000024 True
546 117.053371 69.901493 44.424458 0.220533 16.959319 0.220533 0.000018 True
547 117.267422 69.901675 44.425504 0.220131 16.959319 0.220131 0.000013 True
548 117.481474 69.901856 44.426545 0.219730 16.959319 0.219730 0.000008 True
549 117.695525 69.902036 44.427583 0.219330 16.959319 0.219330 0.000003 True

550 rows × 8 columns

There are methods to visualize the event geometry and time evolution of signals.

[10]:
event.show_geometry3D(x_min=-1., x_max=2., y_min=-1., y_max=2.);
event.signals[8].show();
../_images/tutorials_UC0_Playing_around_with_ShowerModel_21_0.png
../_images/tutorials_UC0_Playing_around_with_ShowerModel_21_1.png

For example, you may want to obtain the number of telescopes having an integrated signal greater than 100 photoelectrons as a function shower energy. Below, observatory events are generated for 10 showers with energies from 50 GeV to 5 PeV. The trigger condition is evaluated for each telescope of the observatory (25 telescopes). Calculations may take a while.

[11]:
energy = np.linspace(50.e3, 50.e5, 10)
trig_tel = np.zeros_like(energy)
for (i, E) in enumerate(energy):
    event = sm.Event(shower.copy(E=E), observatory)
    Npe_sum = np.array([event.signals[tel].Npe_total_sum for tel in range(25)])
    trig_tel[i] = len(Npe_sum[Npe_sum>100])
plt.plot(energy, trig_tel);
plt.xlabel("Energy (MeV)");
plt.ylabel("Number of triggered telescopes");
plt.ylim(0, 25);
../_images/tutorials_UC0_Playing_around_with_ShowerModel_23_0.png

Camera images

Camera images (actually, image sequences) are generated assuming a Nishimura-Kamata-Greisen lateral distribution of electrons in the shower. A night sky background of 40 MHz/m\(^2\)/deg:math:^2 is assumed by default, but this parameter can be changed. The integration time (in \(\mu\)s) per camera frame can be set too.

In the example below, the integrated image is shown for one of the telescopes (tel_index=12) of the observatory. The camera has 1800 pixels (default). Then, the image sequence (17 frames) is shown.

[12]:
image = sm.Image(event.signals[12], int_time=0.002)
image.show();
../_images/tutorials_UC0_Playing_around_with_ShowerModel_26_0.png
[13]:
image.animate()
[13]:
../_images/tutorials_UC0_Playing_around_with_ShowerModel_27_1.png

Event includes a method to show the images of all the telescopes in the same figure. Again, calculations may take a while, because there are 25 telescopes with 1800 pixels each, and each image is the sum of several frames.

[14]:
event.make_images(NSB=50.)
event.show_images();
../_images/tutorials_UC0_Playing_around_with_ShowerModel_29_0.png
[ ]: