fork download
  1. def generate_total_potential_report(all_res_names, all_predictions, source_data, pre_history_stats, reserves, output_file='field_potential_report.xlsx'):
  2. """
  3. Формирует итоговый отчет.
  4. Разделяет Газ Шапки (нефтяные скважины) и Природный Газ (газовые скважины).
  5. """
  6. res_stats = defaultdict(lambda: {
  7. 'fact_gas_cap': 0.0, # ГШ
  8. 'fact_nat_gas': 0.0, # СГ
  9. 'future_gas_cap': 0.0,
  10. 'future_nat_gas': 0.0,
  11. 'act_cnt': 0,
  12. 'arch_cnt': 0,
  13. 'finite_forecast_gas_cap': 0.0,
  14. 'finite_forecast_nat_gas': 0.0
  15. })
  16. processed_wells = set()
  17. details = []
  18.  
  19. # Активные (по которым построился прогноз)
  20. for p in all_predictions:
  21. res = p['reservoir']
  22. well = p['well_name']
  23. well_type = p.get('well_type', 'НЕФ') # Получаем тип из main.py
  24. model_type = p.get('model_type', config.model_type)
  25.  
  26. processed_wells.add((res, well))
  27.  
  28. # Данные из предыстории
  29. pre_val_cap = pre_history_stats[res][well]['GAS_CAP_M3']
  30. pre_val_nat = pre_history_stats[res][well]['GAS_NAT_M3']
  31.  
  32. # Данные периода анализа (Факт)
  33. fact_vec_last = p['fact'][1][-1]
  34.  
  35. # Определяем, куда записать факт периода
  36. per_val_cap = 0.0
  37. per_val_nat = 0.0
  38.  
  39. if well_type == 'ГАЗ':
  40. per_val_nat = fact_vec_last
  41. else:
  42. per_val_cap = fact_vec_last
  43.  
  44. # Будущее (Остаточные)
  45. params = p['params']
  46. q0 = params[0]
  47. raw_a = params[1]
  48.  
  49. a_val = raw_a
  50. b_val = None
  51. if isinstance(raw_a, tuple):
  52. a_val = raw_a[0]
  53. b_val = raw_a[1]
  54.  
  55. m0 = p['m0_date']
  56. last_date = p['fact'][0][-1]
  57.  
  58. fc_Q_vec = p['forecast'][1]
  59. fact_Q_last = p['fact'][1][-1]
  60.  
  61. forecast_period_val = 0
  62. if fc_Q_vec:
  63. val = fc_Q_vec[-1] - fact_Q_last
  64. if val > 0:
  65. forecast_period_val = val
  66.  
  67. # Время t на конец факта
  68. from calendar import monthrange
  69. days_in_last = monthrange(last_date.year, last_date.month)[1]
  70. t_end = (last_date - m0).days + days_in_last
  71.  
  72. # Полный хвост (EUR Future)
  73. # ВАЖНО: передаем model_type и b_val, иначе расчет будет неверен для Hyp/Pow
  74. future_val_total = calculate_eur_future(q0, a_val, t_end, b=b_val, model_type=model_type)
  75.  
  76. # Распределяем будущее и накопленную
  77. total_hist_cap = pre_val_cap + per_val_cap
  78. total_hist_nat = pre_val_nat + per_val_nat
  79.  
  80. cur_future_cap = 0.0
  81. cur_future_nat = 0.0
  82.  
  83. if well_type == 'ГАЗ':
  84. cur_future_nat = future_val_total
  85. res_stats[res]['finite_forecast_nat_gas'] += forecast_period_val
  86. else:
  87. cur_future_cap = future_val_total
  88. res_stats[res]['finite_forecast_gas_cap'] += forecast_period_val
  89.  
  90. res_stats[res]['fact_gas_cap'] += total_hist_cap
  91. res_stats[res]['fact_nat_gas'] += total_hist_nat
  92.  
  93. res_stats[res]['future_gas_cap'] += cur_future_cap
  94. res_stats[res]['future_nat_gas'] += cur_future_nat
  95.  
  96. res_stats[res]['act_cnt'] += 1
  97.  
  98. # Формируем красивый вывод параметра a
  99. a_str = f"{a_val:.6f}"
  100. if b_val is not None:
  101. a_str += f" (b={b_val:.2f})"
  102.  
  103. details.append({
  104. 'Пласт': res, 'Скважина': well, 'Тип': 'Прогноз', 'Характер': well_type,
  105. 'Модель': model_type,
  106. 'Факт ГШ': total_hist_cap, 'Факт СГ': total_hist_nat,
  107. 'Остаточные ГШ': cur_future_cap, 'Остаточные СГ': cur_future_nat,
  108. 'a': a_str
  109. })
  110.  
  111. # Скважины, которые в прогнозе не участвовали
  112. all_wells = set()
  113. for r in source_data:
  114. for w in source_data[r]:
  115. all_wells.add((r, w))
  116. for r in pre_history_stats:
  117. for w in pre_history_stats[r]:
  118. all_wells.add((r, w))
  119.  
  120. for res, well in all_wells:
  121. if (res, well) in processed_wells:
  122. continue
  123.  
  124. # Предыстория
  125. pre_cap = pre_history_stats.get(res, {}).get(well, {}).get('GAS_CAP_M3', 0)
  126. pre_nat = pre_history_stats.get(res, {}).get(well, {}).get('GAS_NAT_M3', 0)
  127.  
  128. # Период анализа
  129. per_cap = 0
  130. per_nat = 0
  131. well_type_arch = "НЕФ" # По умолчанию
  132.  
  133. if res in source_data and well in source_data[res]:
  134. mer_list = source_data[res][well]
  135. if mer_list:
  136. # Смотрим последний статус, чтобы понять тип
  137. if mer_list[-1].CHARWORK == 'ГАЗ':
  138. well_type_arch = 'ГАЗ'
  139.  
  140. per_cap = sum(m.GAS_CAP_M3 for m in mer_list)
  141. per_nat = sum(m.GAS_NAT_M3 for m in mer_list)
  142.  
  143. hist_cap = pre_cap + per_cap
  144. hist_nat = pre_nat + per_nat
  145.  
  146. if (hist_cap + hist_nat) > 0:
  147. res_stats[res]['fact_gas_cap'] += hist_cap
  148. res_stats[res]['fact_nat_gas'] += hist_nat
  149. res_stats[res]['arch_cnt'] += 1
  150.  
  151. details.append({
  152. 'Пласт': res, 'Скважина': well, 'Тип': 'Архив', 'Характер': well_type_arch,
  153. 'Модель': '-',
  154. 'Факт ГШ': hist_cap, 'Факт СГ': hist_nat,
  155. 'Всего прогноз ГШ': 0, 'Всего прогноз СГ': 0,
  156. 'a': 0
  157. })
  158.  
  159. # Сводная
  160. summary = []
  161. for res in sorted(res_stats):
  162. s = res_stats[res]
  163. reserves_list = reserves.get(res, {'geo_reserves': 0, 'extract_reserves': 0, 'cum_prod_f6': 0, 'last_year_prod_f6': 0})
  164.  
  165. total_eur_cap = s['fact_gas_cap'] + s['future_gas_cap']
  166. total_eur_nat = s['fact_nat_gas'] + s['future_nat_gas']
  167.  
  168. summary.append({
  169. 'Пласт': res,
  170. 'Активных скважин, шт.': s['act_cnt'],
  171. 'Выбывших скважин, шт.': s['arch_cnt'],
  172.  
  173. # ГШ
  174. 'Накопленная добыча ГШ МЭР, млн. м3': s['fact_gas_cap'] / 1000000,
  175. f'Прогноз добычи газа ГШ активным фондом нефтяных скважин на {config.forecast_months} мес., млн. м3': s['finite_forecast_gas_cap'] / 1000000,
  176. 'Всего прогнозируемая добыча газа ГШ активным фондом нефтяных скважин, млн. м3': s['future_gas_cap'] / 1000000,
  177.  
  178. # СГ
  179. 'Накопленная добыча природного газа, млн. м3': s['fact_nat_gas'] / 1000000,
  180. f'Прогноз добычи природного газа активным фондом газовых скважин на {config.forecast_months} мес., млн. м3': s['finite_forecast_nat_gas'] / 1000000,
  181. 'Всего прогнозируемая добыча природного газа активным фондом газовых скважин, млн. м3': s['future_nat_gas'] / 1000000,
  182.  
  183. # 6гр
  184. 'НГЗ газа ГШ (6гр), млн. м3': reserves_list['geo_reserves'] / 1000000,
  185. 'НИЗ газа ГШ (6гр), млн. м3': reserves_list['extract_reserves'] / 1000000,
  186. 'Накопленная добыча газа ГШ (6гр), млн. м3': reserves_list['cum_prod_f6'] / 1000000,
  187. 'Вовлекаемые запасы, млн. м3': (total_eur_cap + total_eur_nat) / 1000000,
  188. })
  189.  
  190. with pd.ExcelWriter(output_file) as writer:
  191. pd.DataFrame(summary).to_excel(writer, 'Итоги', index=False)
  192. pd.DataFrame(details).to_excel(writer, 'Детали', index=False)
  193. print(f"Отчет сохранен: {output_file}")
  194.  
  195.  
Success #stdin #stdout 0.11s 14112KB
stdin
Standard input is empty
stdout
Standard output is empty