processing_data_prisma.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # import datetime
  2. from collections import defaultdict
  3. import pandas as pd
  4. class ProccessingPrismaCl:
  5. def __init__(self, cluster, start_date, end_date, path_to_files):
  6. self.cluster = cluster
  7. if cluster == 1:
  8. self.cluster_n = ''
  9. else:
  10. self.cluster_n = '2'
  11. # self.a_crit = a_crit
  12. # self.freq = freq
  13. self.start_date = start_date
  14. self.end_date = end_date
  15. self.path_to_files = path_to_files
  16. self.amp_n_cols = []
  17. for i in range(1, 17):
  18. self.amp_n_cols.append(f'amp{i}')
  19. self.amp_n_cols.append(f'n{i}')
  20. def reading_p_file(self, single_date):
  21. """Метод, прочитывающий p-файлы, возвращающий датафрейм дня на выходе. Или возвращающий filenotfounderror, если
  22. файла нет"""
  23. try:
  24. p_file = pd.read_csv(
  25. f'{self.path_to_files}\\nv\\{self.cluster}p{single_date.date().month:02}' +
  26. f'-{single_date.date().day:02}.{single_date.date().year - 2000:02}',
  27. sep='\s[-]*\s*', header=None, skipinitialspace=True, engine='python')
  28. p_file.dropna(axis=1, how='all', inplace=True)
  29. return p_file
  30. except FileNotFoundError as error:
  31. print(f"File {self.path_to_files}\\nv\\{self.cluster}p{single_date.date().month:02}-" +
  32. f"{single_date.date().day:02}.{single_date.date().year - 2000:02} does not exist")
  33. return error.strerror
  34. def reading_n_file(self, single_date):
  35. """Метод, прочитывающий n-файлы, возвращающий датафрейм дня на выходе. Или возвращающий filenotfounderror, если
  36. файла нет"""
  37. try:
  38. n_file = pd.read_csv(
  39. f'{self.path_to_files}\\{self.cluster_n}n_{single_date.date().month:02}' +
  40. f'-{single_date.date().day:02}.{single_date.date().year - 2000:02}',
  41. sep=' ', header=None, skipinitialspace=True, index_col=False,
  42. names=['time', 'number', 'sum_n', 'tr'] + self.amp_n_cols)
  43. n_file.dropna(axis=1, how='all', inplace=True)
  44. return n_file
  45. except FileNotFoundError as error:
  46. print(
  47. f"File {self.path_to_files}\\{self.cluster_n}n_{single_date.date().month:02}-" +
  48. f"{single_date.date().day:02}.{single_date.date().year - 2000:02}', does not exist")
  49. return error.strerror
  50. def day_proccessing(self):
  51. """Функция, в которую помещается полная дневная обработка"""
  52. worktime_dict = defaultdict(list)
  53. n_vs_zero_tr_dict = defaultdict(list)
  54. event_counter_fr_4 = defaultdict(list)
  55. breaks_dict = defaultdict(list)
  56. count_rate_amp_5_fr_2 = defaultdict(list)
  57. count_rate_amp_10_fr_1 = defaultdict(list)
  58. amp_5_fr_2_frame = pd.DataFrame(columns=[f'amp{i}' for i in range(1, 17)])
  59. amp_10_fr_1_frame = pd.DataFrame(columns=[f'amp{i}' for i in range(1, 17)])
  60. for single_date in pd.date_range(self.start_date, self.end_date):
  61. n_file = self.reading_n_file(single_date)
  62. p_file = self.reading_p_file(single_date)
  63. worktime_dict['Date'].append(single_date)
  64. n_vs_zero_tr_dict['Date'].append(single_date)
  65. count_rate_amp_5_fr_2['Date'].append(single_date)
  66. count_rate_amp_10_fr_1['Date'].append(single_date)
  67. event_counter_fr_4['Date'].append(single_date)
  68. if type(p_file) != str:
  69. corr_p_file = self.correcting_p_file(p_file)
  70. worktime_dict['Worktime'].append(round(len(corr_p_file.index) * 5 / 60, 2))
  71. break_time_dict = self.counting_break_time(corr_p_file)
  72. if break_time_dict:
  73. breaks_dict['Date'].append(single_date)
  74. breaks_dict['StartMinutes'].extend(break_time_dict['StartMinutes'])
  75. breaks_dict['EndMinutes'].extend(break_time_dict['EndMinutes'])
  76. else:
  77. worktime_dict['Worktime'].append(0.00)
  78. if type(n_file) != str:
  79. neutron_to_zero_trigger = self.neutron_to_zero_trigger(n_file)
  80. for i in range(16):
  81. n_vs_zero_tr_dict[f'n{i + 1}'].append(neutron_to_zero_trigger[i])
  82. count_rate_amp_5_fr_2[f'amp{i + 1}'].append(
  83. self.set_event_counter(n_file, a_crit=6, freq=2)['count_rate'][i + 1])
  84. count_rate_amp_10_fr_1[f'amp{i + 1}'].append(
  85. self.set_event_counter(n_file, a_crit=11, freq=1)['count_rate'][i + 1])
  86. event_counter_fr_4['Events'].append(self.set_event_counter(n_file, a_crit=6, freq=4)['sum_events'])
  87. set_event_counter_frame_1 = self.set_event_counter(n_file, a_crit=6, freq=2)['DataFrame']
  88. set_event_counter_frame_2 = self.set_event_counter(n_file, a_crit=11, freq=1)['DataFrame']
  89. amp_5_fr_2_frame = pd.concat(
  90. [amp_5_fr_2_frame, set_event_counter_frame_1],
  91. ignore_index=True)
  92. amp_10_fr_1_frame = pd.concat(
  93. [amp_10_fr_1_frame, set_event_counter_frame_2],
  94. ignore_index=True)
  95. else:
  96. for i in range(16):
  97. n_vs_zero_tr_dict[f'n{i + 1}'].append(0.00)
  98. count_rate_amp_5_fr_2[f'amp{i + 1}'].append(0.00)
  99. count_rate_amp_10_fr_1[f'amp{i + 1}'].append(0.00)
  100. event_counter_fr_4['Events'].append(0.00)
  101. worktime_frame = pd.DataFrame(worktime_dict)
  102. n_vs_zero_tr_frame = pd.DataFrame(n_vs_zero_tr_dict)
  103. breaks_frame = pd.DataFrame(breaks_dict)
  104. event_counter_fr_4 = pd.DataFrame(event_counter_fr_4)
  105. count_rate_amp_5_fr_2 = pd.DataFrame(count_rate_amp_5_fr_2)
  106. count_rate_amp_10_fr_1 = pd.DataFrame(count_rate_amp_10_fr_1)
  107. for column in [f'amp{i}' for i in range(1,17)]:
  108. count_rate_amp_5_fr_2[column] = count_rate_amp_5_fr_2[column]/worktime_frame['Worktime']
  109. count_rate_amp_10_fr_1[column] = count_rate_amp_10_fr_1[column]/worktime_frame['Worktime']
  110. return worktime_frame, breaks_frame, n_vs_zero_tr_frame, event_counter_fr_4, amp_5_fr_2_frame, amp_10_fr_1_frame, count_rate_amp_5_fr_2, count_rate_amp_10_fr_1
  111. @staticmethod
  112. def correcting_p_file(p_file):
  113. """Метод, корректирующий старые файлы ПРИЗМА-32, возвращающий скорректированный датафрейм"""
  114. p_file['time'] = p_file[0]
  115. del p_file[0]
  116. p_file = p_file.sort_values(by='time')
  117. if len(p_file['time']) > len(p_file['time'].unique()):
  118. """Данный костыль нужен для старых p-файлов ПРИЗМА-32(до 14-15 гг.), в которых индексы строк,
  119. по сути обозначающие 5 минут реального времени между ранами, могут повторяться. """
  120. p_file.drop_duplicates(keep=False, inplace=True)
  121. """После удаления полных дубликатов ищем повторяющиеся индексы. Сначала удаляем строки,
  122. состоящие полностью из нулей и точек (value = len(p_file.columns)), потом ищем множество
  123. дубликатов индексов и множество строк, почти полностью (value > 30) состоящих из нулей и точек.
  124. Берем пересечение этих двух множеств и удаляем находящиеся в пересечении строки"""
  125. null_row = dict(p_file.isin([0, '.']).sum(axis=1)) # Проверяем на нули и точки
  126. all_null_index = list(
  127. {key: value for key, value in null_row.items() if value == len(p_file.columns)}.keys())
  128. p_file.drop(index=all_null_index, inplace=True)
  129. null_index = list(
  130. {key: value for key, value in null_row.items() if value > len(p_file.columns) - 5}.keys())
  131. same_index = dict(p_file['time'].duplicated(keep=False))
  132. same_index_row = list({key: value for key, value in same_index.items() if value is True}.keys())
  133. bad_index = list(set(null_index) & set(same_index_row))
  134. p_file.drop(index=bad_index, inplace=True)
  135. """Также может быть, что после фильтрации осталось больше строк, чем нужно, так как в старых
  136. p-файлах может быть больше индексов, чем минут в дне. Тогда оставляем только 288"""
  137. if len(p_file.index) == 289:
  138. p_file = p_file.head(288)
  139. return p_file
  140. @staticmethod
  141. def counting_break_time(p_file):
  142. """Метод, выявляющий в p-file 5-минутки, когда кластер не работал, возвращает начальное время остановки и
  143. конечное время остановки"""
  144. index = p_file['time'].tolist()
  145. daily_breaks_dict = defaultdict(list)
  146. if max(index) < 287:
  147. start_minutes = max(index) * 5
  148. end_minutes = 1435
  149. daily_breaks_dict['StartMinutes'].append(start_minutes)
  150. daily_breaks_dict['EndMinutes'].append(end_minutes)
  151. if min(index) != 0:
  152. start_minutes = 0
  153. end_minutes = min(index) * 5
  154. daily_breaks_dict['StartMinutes'].append(start_minutes)
  155. daily_breaks_dict['EndMinutes'].append(end_minutes)
  156. for i in range(1, len(index)):
  157. if index[i] - index[i - 1] > 1:
  158. start_minutes = index[i - 1] * 5
  159. end_minutes = index[i] * 5
  160. daily_breaks_dict['StartMinutes'].append(start_minutes)
  161. daily_breaks_dict['EndMinutes'].append(end_minutes)
  162. if daily_breaks_dict:
  163. return daily_breaks_dict
  164. else:
  165. return None
  166. @staticmethod
  167. def neutron_to_zero_trigger(n_file):
  168. """Метод, обрабатывающий данные n-файлов ПРИЗМА-32, дающий на выходе нормированное число в событии,
  169. отобранных как нейтрон, при самозапуске"""
  170. counter_zero_tr = len(n_file[n_file['tr'] == 0].index)
  171. zero_tr_frame = n_file[n_file['tr'] == 0]
  172. return [round(zero_tr_frame[f'n{i}'].sum() / counter_zero_tr, 3) for i in range(1, 17)]
  173. # except ZeroDivisionError: Нужно дописать, если допустим нет нулевых триггеров
  174. @staticmethod
  175. def set_event_counter(n_file, a_crit, freq):
  176. """Метод, обрабатывающий данные n-файлов ПРИЗМА-32, на вход подаются определенная амплитуда и количество
  177. детекторов, на которых амплитуда превышает заданную, на выходе метод возвращает словарь с параметрами:
  178. 1) суммарное число событий на кластере, подходящих под заданные условия;
  179. 2) датафрейм с амплитудами детекторов для каждого события, подходящего под заданные условия;
  180. 3) количество превышений заданной амплитуды у детектора в событиях, подходящих под заданные условия; """
  181. cluster_count_rate = {}
  182. amp_frame = n_file[[f'amp{i}' for i in range(1, 17)]]
  183. amp_frame['fr_sum'] = amp_frame.isin(range(a_crit, 520)).sum(axis=1, skipna=True) # noqa
  184. amp_frame = amp_frame[amp_frame['fr_sum'] >= freq].reset_index(drop=True)
  185. for i in range(1, 17):
  186. cluster_count_rate[i] = len(amp_frame[amp_frame[f'amp{i}'] >= a_crit])
  187. return {'sum_events': len(amp_frame.index),
  188. 'DataFrame': amp_frame[[f'amp{i}' for i in range(1, 17)]],
  189. 'count_rate': cluster_count_rate}