|
| 1 | +# --- |
| 2 | +# jupyter: |
| 3 | +# jupytext: |
| 4 | +# text_representation: |
| 5 | +# extension: .py |
| 6 | +# format_name: percent |
| 7 | +# format_version: '1.3' |
| 8 | +# jupytext_version: 1.14.6 |
| 9 | +# kernelspec: |
| 10 | +# display_name: nectardev2 |
| 11 | +# language: python |
| 12 | +# name: python3 |
| 13 | +# --- |
| 14 | + |
| 15 | +# %% |
| 16 | +try: |
| 17 | + import datetime |
| 18 | + import warnings |
| 19 | + |
| 20 | + import matplotlib.pyplot as plt |
| 21 | + import numpy as np |
| 22 | + from ctapipe.coordinates import EngineeringCameraFrame |
| 23 | + from ctapipe.instrument import CameraGeometry |
| 24 | + from ctapipe.visualization import CameraDisplay |
| 25 | + from dateutil.parser import ParserError, parse |
| 26 | + from matplotlib import dates |
| 27 | + |
| 28 | + # in vmarandon scripts at the moment |
| 29 | + from nectarchain.utils.dbhandler import DBInfos, to_datetime |
| 30 | + |
| 31 | + # from CalibrationCameraDisplay import CalibrationCameraDisplay |
| 32 | + # from Utils import GetCamera |
| 33 | + |
| 34 | +except ImportError as err: |
| 35 | + print(err) |
| 36 | + |
| 37 | +try: |
| 38 | + from ctapipe.instrument.warnings import FromNameWarning |
| 39 | + |
| 40 | + CTAPipeWarningExist = True |
| 41 | +except ImportError: |
| 42 | + CTAPipeWarningExist = False |
| 43 | + |
| 44 | + |
| 45 | +def GetCamera(cam_name="NectarCam-003"): # Copied from my Utils code |
| 46 | + if CTAPipeWarningExist: |
| 47 | + with warnings.catch_warnings(): |
| 48 | + warnings.filterwarnings(action="ignore", category=FromNameWarning) |
| 49 | + # Let's ignore the warning for the moment |
| 50 | + cam = CameraGeometry.from_name(cam_name).transform_to( |
| 51 | + EngineeringCameraFrame() |
| 52 | + ) |
| 53 | + else: |
| 54 | + cam = CameraGeometry.from_name(cam_name).transform_to(EngineeringCameraFrame()) |
| 55 | + |
| 56 | + return cam |
| 57 | + |
| 58 | + |
| 59 | +# %% |
| 60 | +# path where the data are if using a run number |
| 61 | +path = "/Users/vm273425/Programs/NectarCAM/data_ssd/camera2/" |
| 62 | + |
| 63 | +# path of where is the sqlite file (can be in a sub-directory) |
| 64 | +db_data_path = "/Users/vm273425/Programs/NectarCAM/data_ssd/camera2/monitoring" |
| 65 | + |
| 66 | +telid = 2 |
| 67 | + |
| 68 | +# %% |
| 69 | +# define the time interval |
| 70 | +try: |
| 71 | + # expected date in UTC |
| 72 | + begin_time = to_datetime(parse("2025-11-10 16:00:00")) |
| 73 | + end_time = to_datetime(parse("2025-11-11 14:00:00")) |
| 74 | +except ParserError as err: |
| 75 | + print(err) |
| 76 | + |
| 77 | +print(begin_time, end_time) |
| 78 | + |
| 79 | +# %% |
| 80 | +# Create DB Instance |
| 81 | +dbinfos = DBInfos.init_from_time( |
| 82 | + begin_time, end_time, dbpath=db_data_path, verbose=False |
| 83 | +) |
| 84 | + |
| 85 | +# Could be done using a run number way also, it will look for a run: |
| 86 | +# dbinfos = DBInfos.init_from_run(run, path=path, dbpath=db_data_path,verbose=False) |
| 87 | + |
| 88 | +# %% |
| 89 | +# show available tables |
| 90 | +dbinfos.show_available_tables() |
| 91 | + |
| 92 | +# %% |
| 93 | +# Show available infos per table |
| 94 | +dbinfos.show_available_infos() |
| 95 | + |
| 96 | +# %% |
| 97 | +# Load the information in memory (can be long :-( ) |
| 98 | +dbinfos.connect( |
| 99 | + "monitoring_ffcls", "monitoring_drawer_temperatures", "monitoring_channel_voltages" |
| 100 | +) # Add any table that are present in the DB |
| 101 | +# dbinfos.connect("*") # Load everything |
| 102 | + |
| 103 | +# %% |
| 104 | +# Retrieve temperature of the modules |
| 105 | +temperatures = dbinfos.tel[telid].monitoring_drawer_temperatures.tfeb1.datas |
| 106 | +temperatures_times = dbinfos.tel[telid].monitoring_drawer_temperatures.tfeb1.times |
| 107 | +print(type(temperatures)) |
| 108 | + |
| 109 | +# %% |
| 110 | +# Interpolation can be done with the method "at" |
| 111 | +delta_t = (end_time - begin_time).total_seconds() |
| 112 | +steps = 100 |
| 113 | + |
| 114 | +interp_times = [ |
| 115 | + begin_time + n * datetime.timedelta(seconds=delta_t / steps) for n in range(steps) |
| 116 | +] |
| 117 | +interp_tfeb1_temps = dbinfos.tel[telid].monitoring_drawer_temperatures.tfeb1.at( |
| 118 | + interp_times |
| 119 | +) |
| 120 | + |
| 121 | +pix = 1855 // 2 |
| 122 | +central_interp_tfeb1 = interp_tfeb1_temps.to_pixel()[pix] |
| 123 | +central_datas_tfeb1 = dbinfos.tel[ |
| 124 | + telid |
| 125 | +].monitoring_drawer_temperatures.tfeb1.datas.to_pixel()[pix] |
| 126 | +central_times_tfeb1 = dbinfos.tel[telid].monitoring_drawer_temperatures.tfeb1.times |
| 127 | + |
| 128 | +plt.figure(figsize=(18, 6)) |
| 129 | +plt.plot(central_times_tfeb1, central_datas_tfeb1) |
| 130 | +plt.plot(interp_times, central_interp_tfeb1, "o") |
| 131 | + |
| 132 | +# %% |
| 133 | +nrows = 1 |
| 134 | +ncols = 1 |
| 135 | +size_y = 4 |
| 136 | +size_x = 3 * size_y |
| 137 | +fig, axs = plt.subplots( |
| 138 | + nrows=nrows, ncols=ncols, figsize=(size_x * ncols, size_y * nrows) |
| 139 | +) |
| 140 | + |
| 141 | +ax = axs |
| 142 | +modules = [124, 132, 140] |
| 143 | +for m in modules: |
| 144 | + ax.plot(temperatures_times, temperatures[m], label=f"Module: {m}") |
| 145 | +ax.set_xlabel("Time (UTC)") |
| 146 | +ax.set_ylabel("FEB 1 Temperature") |
| 147 | +ax.set_title("FEB 1 Temperature Evolution") |
| 148 | +ax.xaxis.set_major_formatter(dates.DateFormatter("%d/%m %H:%M")) |
| 149 | +ax.tick_params("x", rotation=30) |
| 150 | +ax.legend() |
| 151 | +ax.grid() |
| 152 | +fig.tight_layout() |
| 153 | + |
| 154 | +# %% |
| 155 | +# Plot temperature in the camera |
| 156 | + |
| 157 | +pix_temperature = np.nanmean(temperatures, axis=-1).to_pixel() |
| 158 | +# temperatures is of type ModuleArray |
| 159 | +# this is a numpy array with an additionnal function to convert to pixel |
| 160 | + |
| 161 | +nrows = 1 |
| 162 | +ncols = 1 |
| 163 | +size = 6 |
| 164 | +fig, axs = plt.subplots(nrows=nrows, ncols=ncols, figsize=(size * ncols, size * nrows)) |
| 165 | +cam = CameraDisplay( |
| 166 | + geometry=GetCamera(), |
| 167 | + cmap="turbo", |
| 168 | + image=pix_temperature, |
| 169 | + title="FEB 1 Temperature", |
| 170 | + ax=axs, |
| 171 | + show_frame=False, |
| 172 | + allow_pick=True, |
| 173 | + norm="lin", |
| 174 | +) |
| 175 | +cam.highlight_pixels(range(1855), color="grey", linewidth=0.2) |
| 176 | +# CalibrationCameraDisplay is an overload of the CameraDisplay |
| 177 | +# that can highlight differently pixels and easily add function |
| 178 | +# if pixels are clicked |
| 179 | +cam.add_colorbar() |
| 180 | +fig.tight_layout() |
| 181 | +# cam1.colorbar.set_label(f'%') |
| 182 | + |
| 183 | +# %% |
| 184 | +# Retrieve hv of the pixels |
| 185 | +hvs = dbinfos.tel[telid].monitoring_channel_voltages.voltage.datas |
| 186 | +hvs_times = dbinfos.tel[telid].monitoring_channel_voltages.voltage.times |
| 187 | +print(type(hvs)) |
| 188 | + |
| 189 | +# %% |
| 190 | +nrows = 1 |
| 191 | +ncols = 1 |
| 192 | +size_y = 4 |
| 193 | +size_x = 3 * size_y |
| 194 | +fig, axs = plt.subplots( |
| 195 | + nrows=nrows, ncols=ncols, figsize=(size_x * ncols, size_y * nrows) |
| 196 | +) |
| 197 | + |
| 198 | +ax = axs |
| 199 | +pixels = [124 * 7 + 3, 132 * 7 + 3, 140 * 7 + 3] |
| 200 | +for p in pixels: |
| 201 | + ax.plot(hvs_times, hvs[p], label=f"Pixel: {p}") |
| 202 | +ax.set_xlabel("Time (UTC)") |
| 203 | +ax.set_ylabel("HV (V)") |
| 204 | +ax.set_title("HV Evolution") |
| 205 | +ax.xaxis.set_major_formatter(dates.DateFormatter("%d/%m %H:%M")) |
| 206 | +ax.tick_params("x", rotation=30) |
| 207 | +ax.legend() |
| 208 | +ax.grid() |
| 209 | +fig.tight_layout() |
| 210 | + |
| 211 | +# %% |
| 212 | +# Plot HV in the camera |
| 213 | + |
| 214 | +hv_means = np.nanmean(hvs, where=hvs > 400, axis=-1) |
| 215 | +hv_stds = np.nanstd(hvs, where=hvs > 400, axis=-1, ddof=1) |
| 216 | + |
| 217 | +# hv is of type PixelArray which is a numpy array |
| 218 | +# with additionnal feature |
| 219 | + |
| 220 | +nrows = 1 |
| 221 | +ncols = 2 |
| 222 | +size = 6 |
| 223 | +fig, axs = plt.subplots(nrows=nrows, ncols=ncols, figsize=(size * ncols, size * nrows)) |
| 224 | + |
| 225 | +ax = axs[0] |
| 226 | +cam = CameraDisplay( |
| 227 | + geometry=GetCamera(), |
| 228 | + cmap="turbo", |
| 229 | + image=hv_means, |
| 230 | + title="Average HV", |
| 231 | + ax=ax, |
| 232 | + show_frame=False, |
| 233 | + allow_pick=True, |
| 234 | + norm="lin", |
| 235 | +) |
| 236 | +cam.highlight_pixels(range(1855), color="grey", linewidth=0.2) |
| 237 | +cam.add_colorbar() |
| 238 | + |
| 239 | +ax = axs[1] |
| 240 | +cams = CameraDisplay( |
| 241 | + geometry=GetCamera(), |
| 242 | + cmap="turbo", |
| 243 | + image=hv_stds, |
| 244 | + title="Std HV", |
| 245 | + ax=ax, |
| 246 | + show_frame=False, |
| 247 | + allow_pick=True, |
| 248 | + norm="lin", |
| 249 | +) |
| 250 | +cams.highlight_pixels(range(1855), color="grey", linewidth=0.2) |
| 251 | +cams.add_colorbar() |
| 252 | +# CalibrationCameraDisplay is an overload of the CameraDisplay |
| 253 | +# that can highlight differently pixels and easily add function |
| 254 | +# if pixels are clicked |
| 255 | + |
| 256 | + |
| 257 | +fig.tight_layout() |
| 258 | + |
| 259 | +# %% |
0 commit comments