gea-program 0.53.0__tar.gz → 0.54.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. {gea_program-0.53.0 → gea_program-0.54.0}/PKG-INFO +12 -1
  2. {gea_program-0.53.0 → gea_program-0.54.0}/README.md +11 -0
  3. {gea_program-0.53.0 → gea_program-0.54.0}/gea/__init__.py +1 -1
  4. {gea_program-0.53.0 → gea_program-0.54.0}/gea/__main__.py +51 -0
  5. {gea_program-0.53.0 → gea_program-0.54.0}/gea/acceptance_tests.py +175 -0
  6. gea_program-0.54.0/gea/decline.py +553 -0
  7. {gea_program-0.53.0 → gea_program-0.54.0}/gea/dossier.py +14 -2
  8. gea_program-0.54.0/gea/help/decline.md +17 -0
  9. {gea_program-0.53.0 → gea_program-0.54.0}/gea/helplib.py +2 -1
  10. {gea_program-0.53.0 → gea_program-0.54.0}/gea/service.py +20 -0
  11. {gea_program-0.53.0 → gea_program-0.54.0}/gea/web/app.html +56 -1
  12. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/PKG-INFO +12 -1
  13. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/SOURCES.txt +2 -0
  14. {gea_program-0.53.0 → gea_program-0.54.0}/pyproject.toml +1 -1
  15. {gea_program-0.53.0 → gea_program-0.54.0}/LICENSE +0 -0
  16. {gea_program-0.53.0 → gea_program-0.54.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  17. {gea_program-0.53.0 → gea_program-0.54.0}/gea/accuracy_statement.py +0 -0
  18. {gea_program-0.53.0 → gea_program-0.54.0}/gea/alarm_engine.py +0 -0
  19. {gea_program-0.53.0 → gea_program-0.54.0}/gea/alerts.py +0 -0
  20. {gea_program-0.53.0 → gea_program-0.54.0}/gea/backup.py +0 -0
  21. {gea_program-0.53.0 → gea_program-0.54.0}/gea/bench.py +0 -0
  22. {gea_program-0.53.0 → gea_program-0.54.0}/gea/blind_harness.py +0 -0
  23. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  24. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  25. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  26. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  27. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  28. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  29. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  30. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  31. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  32. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  33. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  34. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  35. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  36. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  37. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  38. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  39. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  40. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  41. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  42. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  43. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  44. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  45. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  46. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  47. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  48. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  49. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  50. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  51. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  52. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  53. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  54. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  55. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  56. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  57. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  58. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  59. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  60. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  61. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  62. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  63. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  64. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  65. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  66. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  67. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  68. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  69. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  70. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  71. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  72. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  73. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  74. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  75. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  76. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  77. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  78. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  79. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  80. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  81. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  82. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  83. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  84. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  85. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  86. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  87. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  88. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  89. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  90. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/med_160_sapropels.txt +0 -0
  91. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  92. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  93. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  94. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  95. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  96. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  97. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  98. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  99. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  100. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  101. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  102. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  103. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  104. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  105. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  106. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  107. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  108. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  109. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  110. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  111. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  112. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  113. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  114. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  115. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  116. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  117. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  118. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  119. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  120. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  121. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  122. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  123. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  124. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  125. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  126. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  127. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog_map.py +0 -0
  128. {gea_program-0.53.0 → gea_program-0.54.0}/gea/catalog_register.py +0 -0
  129. {gea_program-0.53.0 → gea_program-0.54.0}/gea/certificates.py +0 -0
  130. {gea_program-0.53.0 → gea_program-0.54.0}/gea/cli.py +0 -0
  131. {gea_program-0.53.0 → gea_program-0.54.0}/gea/client_reports.py +0 -0
  132. {gea_program-0.53.0 → gea_program-0.54.0}/gea/collision.py +0 -0
  133. {gea_program-0.53.0 → gea_program-0.54.0}/gea/config_versioning.py +0 -0
  134. {gea_program-0.53.0 → gea_program-0.54.0}/gea/conformance.py +0 -0
  135. {gea_program-0.53.0 → gea_program-0.54.0}/gea/control_room.py +0 -0
  136. {gea_program-0.53.0 → gea_program-0.54.0}/gea/correlation.py +0 -0
  137. {gea_program-0.53.0 → gea_program-0.54.0}/gea/dashboard.py +0 -0
  138. {gea_program-0.53.0 → gea_program-0.54.0}/gea/declarations.py +0 -0
  139. {gea_program-0.53.0 → gea_program-0.54.0}/gea/deviation.py +0 -0
  140. {gea_program-0.53.0 → gea_program-0.54.0}/gea/dlis.py +0 -0
  141. {gea_program-0.53.0 → gea_program-0.54.0}/gea/dnp3.py +0 -0
  142. {gea_program-0.53.0 → gea_program-0.54.0}/gea/doctor.py +0 -0
  143. {gea_program-0.53.0 → gea_program-0.54.0}/gea/dossier_verify.py +0 -0
  144. {gea_program-0.53.0 → gea_program-0.54.0}/gea/downhole_engine.py +0 -0
  145. {gea_program-0.53.0 → gea_program-0.54.0}/gea/drift_monitor.py +0 -0
  146. {gea_program-0.53.0 → gea_program-0.54.0}/gea/drill_string.py +0 -0
  147. {gea_program-0.53.0 → gea_program-0.54.0}/gea/earth_model.py +0 -0
  148. {gea_program-0.53.0 → gea_program-0.54.0}/gea/economics.py +0 -0
  149. {gea_program-0.53.0 → gea_program-0.54.0}/gea/ed25519.py +0 -0
  150. {gea_program-0.53.0 → gea_program-0.54.0}/gea/edr.py +0 -0
  151. {gea_program-0.53.0 → gea_program-0.54.0}/gea/elevation.py +0 -0
  152. {gea_program-0.53.0 → gea_program-0.54.0}/gea/etp.py +0 -0
  153. {gea_program-0.53.0 → gea_program-0.54.0}/gea/etp12_schemas.json +0 -0
  154. {gea_program-0.53.0 → gea_program-0.54.0}/gea/example_register_map.json +0 -0
  155. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fat_sat.py +0 -0
  156. {gea_program-0.53.0 → gea_program-0.54.0}/gea/files.py +0 -0
  157. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fixtures/README.md +0 -0
  158. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  159. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  160. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  161. {gea_program-0.53.0 → gea_program-0.54.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  162. {gea_program-0.53.0 → gea_program-0.54.0}/gea/follower.py +0 -0
  163. {gea_program-0.53.0 → gea_program-0.54.0}/gea/forward_model.py +0 -0
  164. {gea_program-0.53.0 → gea_program-0.54.0}/gea/frac_hits.py +0 -0
  165. {gea_program-0.53.0 → gea_program-0.54.0}/gea/friction_priors.py +0 -0
  166. {gea_program-0.53.0 → gea_program-0.54.0}/gea/gamma.py +0 -0
  167. {gea_program-0.53.0 → gea_program-0.54.0}/gea/gauge_aging.py +0 -0
  168. {gea_program-0.53.0 → gea_program-0.54.0}/gea/gauge_specs.py +0 -0
  169. {gea_program-0.53.0 → gea_program-0.54.0}/gea/geodesy.py +0 -0
  170. {gea_program-0.53.0 → gea_program-0.54.0}/gea/geomag.py +0 -0
  171. {gea_program-0.53.0 → gea_program-0.54.0}/gea/gravity_reference.py +0 -0
  172. {gea_program-0.53.0 → gea_program-0.54.0}/gea/hartip.py +0 -0
  173. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/TESTER_GUIDE.md +0 -0
  174. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/alarms.md +0 -0
  175. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/alerts.md +0 -0
  176. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/audit-update.md +0 -0
  177. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/backup.md +0 -0
  178. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/catalog.md +0 -0
  179. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/charts.md +0 -0
  180. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/collision.md +0 -0
  181. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/conformance.md +0 -0
  182. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/control-room.md +0 -0
  183. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/data-in.md +0 -0
  184. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/declare.md +0 -0
  185. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/dlis.md +0 -0
  186. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/doctor.md +0 -0
  187. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/dossier.md +0 -0
  188. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/drift.md +0 -0
  189. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/drillstring.md +0 -0
  190. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/economics.md +0 -0
  191. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/edr.md +0 -0
  192. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/etp.md +0 -0
  193. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/field-ports.md +0 -0
  194. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/files.md +0 -0
  195. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/frac-hits.md +0 -0
  196. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/historian.md +0 -0
  197. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/instruments.md +0 -0
  198. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/interval.md +0 -0
  199. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/invoice-check.md +0 -0
  200. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/map.md +0 -0
  201. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/month-end.md +0 -0
  202. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/notifications.md +0 -0
  203. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/opseis.md +0 -0
  204. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/osdu.md +0 -0
  205. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/pad-summary.md +0 -0
  206. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/patches.md +0 -0
  207. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/penetrator.md +0 -0
  208. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/plan.md +0 -0
  209. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/pore-pressure.md +0 -0
  210. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/ppdm.md +0 -0
  211. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/quakeml.md +0 -0
  212. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/quality.md +0 -0
  213. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/report-history.md +0 -0
  214. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/rig-time.md +0 -0
  215. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/seedlink.md +0 -0
  216. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/seismic.md +0 -0
  217. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/setup.md +0 -0
  218. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/simulation.md +0 -0
  219. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/site.md +0 -0
  220. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/sites.md +0 -0
  221. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/slip.md +0 -0
  222. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/soak.md +0 -0
  223. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/sra.md +0 -0
  224. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/start.md +0 -0
  225. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/structure.md +0 -0
  226. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/tools.md +0 -0
  227. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/torque-drag.md +0 -0
  228. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/transients.md +0 -0
  229. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/upkeep.md +0 -0
  230. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/vibration.md +0 -0
  231. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/well-report.md +0 -0
  232. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/well-tests.md +0 -0
  233. {gea_program-0.53.0 → gea_program-0.54.0}/gea/help/well3d.md +0 -0
  234. {gea_program-0.53.0 → gea_program-0.54.0}/gea/housekeeping.py +0 -0
  235. {gea_program-0.53.0 → gea_program-0.54.0}/gea/interval.py +0 -0
  236. {gea_program-0.53.0 → gea_program-0.54.0}/gea/inverse_engine.py +0 -0
  237. {gea_program-0.53.0 → gea_program-0.54.0}/gea/invoice_check.py +0 -0
  238. {gea_program-0.53.0 → gea_program-0.54.0}/gea/jobs.py +0 -0
  239. {gea_program-0.53.0 → gea_program-0.54.0}/gea/live_ports.py +0 -0
  240. {gea_program-0.53.0 → gea_program-0.54.0}/gea/loadtest.py +0 -0
  241. {gea_program-0.53.0 → gea_program-0.54.0}/gea/matplotlib_demo.py +0 -0
  242. {gea_program-0.53.0 → gea_program-0.54.0}/gea/modbus.py +0 -0
  243. {gea_program-0.53.0 → gea_program-0.54.0}/gea/modbus_rtu.py +0 -0
  244. {gea_program-0.53.0 → gea_program-0.54.0}/gea/model_card.py +0 -0
  245. {gea_program-0.53.0 → gea_program-0.54.0}/gea/month_end.py +0 -0
  246. {gea_program-0.53.0 → gea_program-0.54.0}/gea/mqtt_port.py +0 -0
  247. {gea_program-0.53.0 → gea_program-0.54.0}/gea/notify.py +0 -0
  248. {gea_program-0.53.0 → gea_program-0.54.0}/gea/op_seismicity.py +0 -0
  249. {gea_program-0.53.0 → gea_program-0.54.0}/gea/opcua_port.py +0 -0
  250. {gea_program-0.53.0 → gea_program-0.54.0}/gea/operator_app.py +0 -0
  251. {gea_program-0.53.0 → gea_program-0.54.0}/gea/osdu.py +0 -0
  252. {gea_program-0.53.0 → gea_program-0.54.0}/gea/pad_summary.py +0 -0
  253. {gea_program-0.53.0 → gea_program-0.54.0}/gea/patches.py +0 -0
  254. {gea_program-0.53.0 → gea_program-0.54.0}/gea/pdf_report.py +0 -0
  255. {gea_program-0.53.0 → gea_program-0.54.0}/gea/penetrator.py +0 -0
  256. {gea_program-0.53.0 → gea_program-0.54.0}/gea/permits.py +0 -0
  257. {gea_program-0.53.0 → gea_program-0.54.0}/gea/piwebapi.py +0 -0
  258. {gea_program-0.53.0 → gea_program-0.54.0}/gea/pore_pressure.py +0 -0
  259. {gea_program-0.53.0 → gea_program-0.54.0}/gea/ports.py +0 -0
  260. {gea_program-0.53.0 → gea_program-0.54.0}/gea/ppdm.py +0 -0
  261. {gea_program-0.53.0 → gea_program-0.54.0}/gea/profile_catalog.py +0 -0
  262. {gea_program-0.53.0 → gea_program-0.54.0}/gea/project.py +0 -0
  263. {gea_program-0.53.0 → gea_program-0.54.0}/gea/qt6_downhole_app.py +0 -0
  264. {gea_program-0.53.0 → gea_program-0.54.0}/gea/quakeml.py +0 -0
  265. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reconciler.py +0 -0
  266. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  267. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  268. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/WMM2025.COF +0 -0
  269. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  270. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/eia_prices.provenance.json +0 -0
  271. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  272. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  273. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  274. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  275. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  276. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  277. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  278. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  279. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  280. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/mahoning_example.json +0 -0
  281. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/mud_motor_specs.json +0 -0
  282. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/owsg_tool_models.json +0 -0
  283. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/penetrator_ratings.json +0 -0
  284. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/seismicity_protocols.json +0 -0
  285. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/tool_sources.json +0 -0
  286. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/us_outline.json +0 -0
  287. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/us_outline.provenance.json +0 -0
  288. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_3d.provenance.json +0 -0
  289. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  290. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  291. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  292. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_surfaces.json.gz +0 -0
  293. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  294. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  295. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  296. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  297. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  298. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  299. {gea_program-0.53.0 → gea_program-0.54.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  300. {gea_program-0.53.0 → gea_program-0.54.0}/gea/report_history.py +0 -0
  301. {gea_program-0.53.0 → gea_program-0.54.0}/gea/rig_state.py +0 -0
  302. {gea_program-0.53.0 → gea_program-0.54.0}/gea/rock_inventory.py +0 -0
  303. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sample_record.py +0 -0
  304. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sample_well_profile.csv +0 -0
  305. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sbom.py +0 -0
  306. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seedlink.py +0 -0
  307. {gea_program-0.53.0 → gea_program-0.54.0}/gea/segy.py +0 -0
  308. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic.py +0 -0
  309. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_array.py +0 -0
  310. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_assoc.py +0 -0
  311. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_detect.py +0 -0
  312. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_film.py +0 -0
  313. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_harmonic.py +0 -0
  314. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_qc.py +0 -0
  315. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_response.py +0 -0
  316. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_signature.py +0 -0
  317. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_track.py +0 -0
  318. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_uncertainty.py +0 -0
  319. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_unlisted.py +0 -0
  320. {gea_program-0.53.0 → gea_program-0.54.0}/gea/seismic_watch.py +0 -0
  321. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sensor_swap.py +0 -0
  322. {gea_program-0.53.0 → gea_program-0.54.0}/gea/series_cache.py +0 -0
  323. {gea_program-0.53.0 → gea_program-0.54.0}/gea/service_life.py +0 -0
  324. {gea_program-0.53.0 → gea_program-0.54.0}/gea/setup_checklist.py +0 -0
  325. {gea_program-0.53.0 → gea_program-0.54.0}/gea/shapefile.py +0 -0
  326. {gea_program-0.53.0 → gea_program-0.54.0}/gea/shell.py +0 -0
  327. {gea_program-0.53.0 → gea_program-0.54.0}/gea/shut_in.py +0 -0
  328. {gea_program-0.53.0 → gea_program-0.54.0}/gea/simulation.py +0 -0
  329. {gea_program-0.53.0 → gea_program-0.54.0}/gea/site_map.py +0 -0
  330. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sla_report.py +0 -0
  331. {gea_program-0.53.0 → gea_program-0.54.0}/gea/slip.py +0 -0
  332. {gea_program-0.53.0 → gea_program-0.54.0}/gea/soak.py +0 -0
  333. {gea_program-0.53.0 → gea_program-0.54.0}/gea/sra.py +0 -0
  334. {gea_program-0.53.0 → gea_program-0.54.0}/gea/store_forward.py +0 -0
  335. {gea_program-0.53.0 → gea_program-0.54.0}/gea/strata_join.py +0 -0
  336. {gea_program-0.53.0 → gea_program-0.54.0}/gea/structure.py +0 -0
  337. {gea_program-0.53.0 → gea_program-0.54.0}/gea/supervisor.py +0 -0
  338. {gea_program-0.53.0 → gea_program-0.54.0}/gea/survey_cmd.py +0 -0
  339. {gea_program-0.53.0 → gea_program-0.54.0}/gea/survey_view.py +0 -0
  340. {gea_program-0.53.0 → gea_program-0.54.0}/gea/telemetry.py +0 -0
  341. {gea_program-0.53.0 → gea_program-0.54.0}/gea/tool_catalog.py +0 -0
  342. {gea_program-0.53.0 → gea_program-0.54.0}/gea/tool_library.py +0 -0
  343. {gea_program-0.53.0 → gea_program-0.54.0}/gea/tool_taxonomy.py +0 -0
  344. {gea_program-0.53.0 → gea_program-0.54.0}/gea/torque_drag.py +0 -0
  345. {gea_program-0.53.0 → gea_program-0.54.0}/gea/transient.py +0 -0
  346. {gea_program-0.53.0 → gea_program-0.54.0}/gea/vibration.py +0 -0
  347. {gea_program-0.53.0 → gea_program-0.54.0}/gea/well3d.py +0 -0
  348. {gea_program-0.53.0 → gea_program-0.54.0}/gea/well_assembler.py +0 -0
  349. {gea_program-0.53.0 → gea_program-0.54.0}/gea/well_report.py +0 -0
  350. {gea_program-0.53.0 → gea_program-0.54.0}/gea/well_test_validation.py +0 -0
  351. {gea_program-0.53.0 → gea_program-0.54.0}/gea/wellplan.py +0 -0
  352. {gea_program-0.53.0 → gea_program-0.54.0}/gea/wellpos.py +0 -0
  353. {gea_program-0.53.0 → gea_program-0.54.0}/gea/wits0.py +0 -0
  354. {gea_program-0.53.0 → gea_program-0.54.0}/gea/witsml.py +0 -0
  355. {gea_program-0.53.0 → gea_program-0.54.0}/gea/workspace.py +0 -0
  356. {gea_program-0.53.0 → gea_program-0.54.0}/gea/xlsx_read.py +0 -0
  357. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/dependency_links.txt +0 -0
  358. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/entry_points.txt +0 -0
  359. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/requires.txt +0 -0
  360. {gea_program-0.53.0 → gea_program-0.54.0}/gea_program.egg-info/top_level.txt +0 -0
  361. {gea_program-0.53.0 → gea_program-0.54.0}/setup.cfg +0 -0
  362. {gea_program-0.53.0 → gea_program-0.54.0}/tests/test_acceptance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gea-program
3
- Version: 0.53.0
3
+ Version: 0.54.0
4
4
  Summary: GEA-Program: downhole gauge monitoring - canonical measurement records, quality rules, drift evaluation with a re-fit change log, well-test validation, alarm management, model cards, store-and-forward, monthly SLA measurement, FAT/SAT protocols and a dashboard, generated from live objects in the client's reporting outline.
5
5
  Author: Daniel T. Murphy
6
6
  License: MPL-2.0
@@ -648,6 +648,17 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
648
648
  itself; `gea help seedlink`. A TexNet station is served by EarthScope at
649
649
  `rtserve.iris.washington.edu:18000`, network `TX`.
650
650
 
651
+ ### Decline curves
652
+
653
+ Each well's monthly production fitted by Arps's curves - the modified
654
+ hyperbolic, turned exponential at a terminal decline - forecast month by
655
+ month to its economic limit and valued: the estimated ultimate recovery,
656
+ and the net cash flow discounted at the declared rate, at the SEC 12-month
657
+ average of the first-of-month WTI and Henry Hub prices (shipped from the
658
+ EIA) or a declared price, with the net revenue interest, severance tax and
659
+ operating cost declared. A forecast is not a reserves report, and the page
660
+ says so. The **Decline curves** tab, `gea decline`, `gea help decline`.
661
+
651
662
  ### Torque and drag
652
663
 
653
664
  The hook load and torque the drill string should take at each bit depth, by
@@ -609,6 +609,17 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
609
609
  itself; `gea help seedlink`. A TexNet station is served by EarthScope at
610
610
  `rtserve.iris.washington.edu:18000`, network `TX`.
611
611
 
612
+ ### Decline curves
613
+
614
+ Each well's monthly production fitted by Arps's curves - the modified
615
+ hyperbolic, turned exponential at a terminal decline - forecast month by
616
+ month to its economic limit and valued: the estimated ultimate recovery,
617
+ and the net cash flow discounted at the declared rate, at the SEC 12-month
618
+ average of the first-of-month WTI and Henry Hub prices (shipped from the
619
+ EIA) or a declared price, with the net revenue interest, severance tax and
620
+ operating cost declared. A forecast is not a reserves report, and the page
621
+ says so. The **Decline curves** tab, `gea decline`, `gea help decline`.
622
+
612
623
  ### Torque and drag
613
624
 
614
625
  The hook load and torque the drill string should take at each bit depth, by
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.53.0"
126
+ __version__ = "0.54.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -622,6 +622,21 @@ def main(argv=None) -> int:
622
622
  p_pl.add_argument("--actor", type=str, default="cli")
623
623
  p_pl.add_argument("--json", action="store_true")
624
624
 
625
+ p_dc = sub.add_parser("decline", help="each well's monthly production fitted by Arps's curves, forecast to its economic limit and valued at the SEC 12-month price or a declared one")
626
+ p_dc.add_argument("--workspace", type=str, required=True)
627
+ p_dc.add_argument("--well", type=str, default=None)
628
+ p_dc.add_argument("--attach", type=str, default=None, help="attach FILE as the well's monthly production (CSV or Excel)")
629
+ p_dc.add_argument("--remove", action="store_true")
630
+ for k_, h_ in (("terminal-decline", "the terminal decline, effective annual (0.08 = 8 %%)"), ("b-max", "the largest b fitted"), ("oil-price", "USD/bbl"),
631
+ ("gas-price", "USD/MMBtu"), ("price-basis", "sec or flat"), ("nri", "the net revenue interest"), ("severance", "the severance tax (0.046 = 4.6 %%)"),
632
+ ("opex", "the operating cost, USD a month"), ("discount", "the discount rate (0.10)"), ("start", "fit from this month (YYYY-MM)"),
633
+ ("as-of", "value as of this date (YYYY-MM-DD)")):
634
+ p_dc.add_argument("--" + k_, type=str, default=None, help=h_)
635
+ p_dc.add_argument("--source", type=str, default="", help="where the production or the terms came from")
636
+ p_dc.add_argument("--write", action="store_true")
637
+ p_dc.add_argument("--actor", type=str, default="cli")
638
+ p_dc.add_argument("--json", action="store_true")
639
+
625
640
  p_td = sub.add_parser("torque-drag", help="the hook load and torque the string should take at each bit depth (soft-string model), the broomstick, and the friction factors that fit the rig's own trips")
626
641
  p_td.add_argument("--workspace", type=str, default=None)
627
642
  p_td.add_argument("--well", type=str, default=None)
@@ -2486,6 +2501,42 @@ def main(argv=None) -> int:
2486
2501
  raise SystemExit(f"collision: {e.args[0] if e.args else e}")
2487
2502
  print(_json.dumps({k: v for k, v in r.items()}, default=str) if a.json else _CO.text(r))
2488
2503
  return 0
2504
+ elif a.cmd == "decline":
2505
+ import json as _json
2506
+ from . import decline as _DCA
2507
+ from .cli import _safe_stdout
2508
+ from .workspace import Workspace, WorkspaceError
2509
+ _safe_stdout()
2510
+ try:
2511
+ ws = Workspace(a.workspace)
2512
+ terms = {"terminal_decline": a.terminal_decline, "b_max": a.b_max, "oil_price": a.oil_price, "gas_price": a.gas_price, "price_basis": a.price_basis,
2513
+ "nri": a.nri, "severance": a.severance, "opex_month": a.opex, "discount": a.discount, "start": a.start}
2514
+ if (a.attach or a.remove or any(v is not None for v in terms.values()) or a.write) and not a.well:
2515
+ raise ValueError("--well is needed")
2516
+ if a.attach:
2517
+ with open(a.attach, "rb") as f_:
2518
+ r_ = _DCA.attach(ws, a.well, os.path.basename(a.attach), f_.read(), a.actor, a.source)
2519
+ print(f"production attached to {a.well}: {r_['months']} months, {r_['first']} to {r_['last']}")
2520
+ return 0
2521
+ if a.remove:
2522
+ _DCA.remove(ws, a.well, a.actor)
2523
+ print(f"production removed from {a.well}")
2524
+ return 0
2525
+ if any(v is not None for v in terms.values()):
2526
+ c_ = _DCA.set_config(ws, a.actor, a.well, a.source, **{k: v for k, v in terms.items() if v is not None})
2527
+ print(f"{a.well}: terminal {c_['terminal_decline']:g}, price {c_['price_basis']}, NRI {c_['nri']:g}, severance {c_['severance']:g}, opex {c_['opex_month']:,.0f}/month, discount {c_['discount']:g}")
2528
+ return 0
2529
+ if a.write:
2530
+ r_ = _DCA.write_report(ws, __version__, a.well, a.actor)
2531
+ print(f"wrote {r_['report_id']}: {r_['paths']['html']}")
2532
+ if r_['paths'].get('pdf'):
2533
+ print(f" printable: {r_['paths']['pdf']}")
2534
+ return 0
2535
+ r = _DCA.page(ws, a.well, a.as_of)
2536
+ except (KeyError, ValueError, OSError, WorkspaceError) as e:
2537
+ raise SystemExit(f"decline: {e.args[0] if e.args else e}")
2538
+ print(_json.dumps(r, default=str) if a.json else _DCA.text(r))
2539
+ return 0
2489
2540
  elif a.cmd == "torque-drag":
2490
2541
  import json as _json
2491
2542
  from . import torque_drag as _TND
@@ -12065,6 +12065,180 @@ def section_cv_torque_drag(tmp: str) -> None:
12065
12065
  + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
12066
12066
 
12067
12067
 
12068
+ def section_cw_decline(tmp: str) -> None:
12069
+ """Section CW - decline curves: Arps's rate and cumulative and the modified hyperbolic against their closed forms
12070
+ and the decline conversions; a production table built on known curves fitted back and forecast; the economic limit,
12071
+ the discounted value and the SEC 12-month price; the API, the CLI, the report, the dossier, the tab and the help."""
12072
+ import http.cookiejar
12073
+ import math as _m
12074
+ import subprocess as _sp
12075
+ import urllib.request
12076
+ import urllib.error
12077
+ import zipfile as _zf
12078
+ from datetime import date as _date
12079
+ import numpy as _np
12080
+ from . import __version__ as _ver
12081
+ from . import decline as DCA
12082
+ from . import dossier as DZ
12083
+ from . import edr as E
12084
+ from . import helplib as H
12085
+ from . import xlsx_read as XR
12086
+ from .workspace import Workspace
12087
+ from .service import Service, Users
12088
+ pkg = Path(__file__).parent
12089
+ d = Path(tmp, "decline"); d.mkdir()
12090
+
12091
+ # -- CW1 the curves by hand --------------------------------------------------------------------------------------------
12092
+ qi, Di = 1000.0, 0.002
12093
+ t = _np.array([0.0, 100.0, 1000.0])
12094
+ e_ok = _np.allclose(DCA.rate(t, qi, Di, 0.0), qi * _np.exp(-Di * t)) and _np.allclose(DCA.cum(t, qi, Di, 0.0), qi / Di * (1 - _np.exp(-Di * t)))
12095
+ h_ok = _np.allclose(DCA.rate(t, qi, Di, 0.5), qi / (1 + 0.5 * Di * t) ** 2) and _np.allclose(DCA.cum(t, qi, Di, 0.5), qi / (0.5 * Di) * (1 - (1 + 0.5 * Di * t) ** -1))
12096
+ a_ok = _np.allclose(DCA.cum(t, qi, Di, 1.0), qi / Di * _np.log(1 + Di * t))
12097
+ tt = _np.linspace(0, 20000, 200001)
12098
+ q_mh = DCA.rate(tt, qi, Di, 1.5, 0.0002)
12099
+ trap = float(_np.sum(0.5 * (q_mh[1:] + q_mh[:-1]) * _np.diff(tt)))
12100
+ ts = (Di / 0.0002 - 1) / (1.5 * Di)
12101
+ i_s = int(_np.searchsorted(tt, ts))
12102
+ dq = _np.diff(_np.log(q_mh))
12103
+ c1 = {
12104
+ "arps": e_ok and h_ok and a_ok,
12105
+ "modified": abs(float(DCA.cum(_np.array([20000.0]), qi, Di, 1.5, 0.0002)[0]) / trap - 1) < 1e-6 and abs(dq[i_s + 5] / 0.1 + 0.0002) < 1e-9 and q_mh[i_s - 1] > q_mh[i_s],
12106
+ "conversions": abs(DCA.effective_annual(DCA.nominal_daily(0.65, 1.1), 1.1) - 0.65) < 1e-12 and abs(DCA.effective_annual(DCA.nominal_daily(0.08, 0.0), 0.0) - 0.08) < 1e-12
12107
+ and abs(DCA.effective_annual(0.001, 0.0) - (1 - _m.exp(-0.36525))) < 1e-12,
12108
+ "sec": DCA.sec_price([f"2025-{m:02d}-0{k}" for m in range(1, 13) for k in (2, 3)] + ["2024-12-31"], [float(m * 10 + k) for m in range(1, 13) for k in (2, 3)] + [999.0],
12109
+ _date(2026, 1, 1))["price"] == round(sum(m * 10 + 2 for m in range(1, 13)) / 12.0, 4)
12110
+ and DCA.sec_price(["2025-06-01"], [50.0], _date(2026, 1, 1)) is None,
12111
+ }
12112
+ failed1 = [k for k, v in c1.items() if not v]
12113
+ ok(not failed1,
12114
+ "CW1 Arps's curves by hand: the exponential, hyperbolic and harmonic rates and cumulatives in closed form; the modified "
12115
+ "hyperbolic's cumulative equal to the integral of its rate, exponential at the terminal decline from the switch; the "
12116
+ "effective and nominal declines inverse to each other; the SEC price the average of each month's first quote of the 12 "
12117
+ "months before, and none when a month is missing"
12118
+ + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
12119
+
12120
+ # -- CW2 a table built on known curves, fitted back ---------------------------------------------------------------------
12121
+ f = DCA.selftest_files(str(d))
12122
+ prod = DCA.read_production(Path(f["path"]).read_bytes())
12123
+ so = DCA.analyse_stream(prod, "oil", {**DCA.DEFAULTS})
12124
+ Dn, Dm = DCA.nominal_daily(f["De"], f["b"]), DCA.nominal_daily(f["Dterm"], 0.0)
12125
+ th = _np.array(so["history"]["t"])
12126
+ q_true = DCA.rate(th, f["qi"], Dn, f["b"], Dm)
12127
+ q_fit = DCA.rate(th - so["t0_days"], so["fit"]["qi"], so["fit"]["Di"], so["fit"]["b"], so["Dmin"])
12128
+ t_end = th[-1] + 30 * 365.25
12129
+ eur_true = float(DCA.cum(_np.array([t_end]), f["qi"], Dn, f["b"], Dm)[0])
12130
+ eur_fit = float(DCA.cum(_np.array([t_end - so["t0_days"]]), so["fit"]["qi"], so["fit"]["Di"], so["fit"]["b"], so["Dmin"])[0])
12131
+ days_ok = all(abs(so["history"]["q"][i] - so["history"]["v"][i] / prod[i]["days"]) < 1e-3 for i in (7, 19))
12132
+ XR.write_simple(str(d / "p.xlsx"), [["Production Month", "Oil Volume", "Gas Volume", "Days On"], ["2024-01", 3000, 6000, 31], ["2024-02", 2700, 5500, 29]])
12133
+ px = DCA.read_production((d / "p.xlsx").read_bytes())
12134
+ refused = 0
12135
+ for bad in ("Month,Oil\n2024-01,-5\n", "Month,Oil\n2024-01,5\n2024-01,6\n", "Oil,Gas\n1,2\n", "Month,Oil,Days\n2024-01,5,40\n", "Month,Note\n2024-01,x\n"):
12136
+ try:
12137
+ DCA.read_production(bad.encode())
12138
+ except ValueError:
12139
+ refused += 1
12140
+ c2 = {
12141
+ "fit": abs(so["fit"]["b"] - f["b"]) <= 0.15 and float(_np.max(_np.abs(q_fit - q_true) / q_true)) < 0.04 and so["months_fitted"] == 48,
12142
+ "eur": abs(eur_fit / eur_true - 1) < 0.05,
12143
+ "days": days_ok,
12144
+ "table": len(prod) == 48 and prod[0]["month"] == "2022-01" and px[1]["days"] == 29 and px[0]["oil"] == 3000 and refused == 5,
12145
+ }
12146
+ failed2 = [k for k, v in c2.items() if not v]
12147
+ ok(not failed2,
12148
+ "CW2 a well's 48 months built on a known curve (900 bbl/d, b 1.1, 65 % a year, 8 % terminal, 3 % noise, four months part "
12149
+ "shut in) fitted back: b within 0.15, the rate within 4 % over the history, the 30-year recovery within 5 %; a part month's "
12150
+ "rate its volume over its producing days; a table read from Excel by its names; a negative volume, a month twice, no month, "
12151
+ "more than 31 days or no stream refused"
12152
+ + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
12153
+
12154
+ # -- CW3 the forecast, the limit and the value ---------------------------------------------------------------------------
12155
+ one = [{"month": f"2020-{m:02d}", "oil": 3000.0 * _m.exp(-0.01 * 30.4375 * (m - 1)), "gas": None, "water": None, "days": None} for m in range(1, 13)]
12156
+ cfg = {**DCA.DEFAULTS, "terminal_decline": None, "nri": 1.0, "severance": 0.0, "opex_month": 0.0, "discount": 0.0, "years": 1.0}
12157
+ r1 = DCA.analyse(one, cfg, {"oil": 50.0, "gas": 0.0})
12158
+ vol12 = sum(m_["oil"] for m_ in r1["forecast"]["months"])
12159
+ cfg2 = {**cfg, "opex_month": 500.0, "years": 20.0}
12160
+ r2 = DCA.analyse(one, cfg2, {"oil": 50.0, "gas": 0.0})
12161
+ last_net = r2["forecast"]["months"][-1]["net_usd"]
12162
+ cfg3 = {**cfg, "discount": 0.10, "years": 1.0}
12163
+ r3 = DCA.analyse(one, cfg3, {"oil": 50.0, "gas": 0.0})
12164
+ pv_hand = sum(m_["net_usd"] * 1.1 ** (-((i + 0.5) / 12)) for i, m_ in enumerate(r3["forecast"]["months"]))
12165
+ c3 = {
12166
+ "exponential": r1["streams"]["oil"]["fit"]["b"] == 0.0 and abs(r1["streams"]["oil"]["fit"]["Di"] / (0.01) - 1) < 0.01 and len(r1["forecast"]["months"]) == 12
12167
+ and abs(r1["forecast"]["undiscounted_usd"] / (50.0 * vol12) - 1) < 1e-3,
12168
+ "limit": r2["forecast"]["limit_month"] is not None and r2["forecast"]["stopped_by"] == "the economic limit" and last_net > 0
12169
+ and 3 <= len(r2["forecast"]["months"]) <= 12 and 50.0 * r2["forecast"]["months"][-1]["oil"] > 500.0,
12170
+ "pv": abs(r3["forecast"]["pv_usd"] - pv_hand) < 2.0 and r3["forecast"]["pv_usd"] < r3["forecast"]["undiscounted_usd"],
12171
+ }
12172
+ failed3 = [k for k, v in c3.items() if not v]
12173
+ ok(not failed3,
12174
+ "CW3 the forecast: a year of exponential decline at 1 % a day fitted as exponential and carried a year forward, its revenue "
12175
+ "the volume times the price; an operating cost stopping it at the economic limit on the last month that still pays; the "
12176
+ "value discounted mid-month as by hand"
12177
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
12178
+
12179
+ # -- CW4 the API, the CLI, the report, the dossier, the tab and the help -------------------------------------------------
12180
+ ev = E.selftest_events(str(d))
12181
+ wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
12182
+ wid = ws.add_well_file(ev["path"], display="PROD-1", actor="tester")["id"]
12183
+ nothing = DCA.page(ws, wid)["detail"]
12184
+ Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
12185
+ svc = Service(wsp, port=0, scheduler=False).start()
12186
+ base_url = svc.url.rstrip("/")
12187
+
12188
+ def opener(name, pw_):
12189
+ o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
12190
+ rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
12191
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
12192
+ return o
12193
+
12194
+ def call(o, method, path, body=None):
12195
+ rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
12196
+ if method == "POST":
12197
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
12198
+ try:
12199
+ with o.open(rq, timeout=120) as rr_:
12200
+ return rr_.status, json.loads(rr_.read())
12201
+ except urllib.error.HTTPError as e:
12202
+ return e.code, json.loads(e.read())
12203
+ content = Path(f["path"]).read_text(encoding="utf-8")
12204
+ try:
12205
+ V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
12206
+ s_va, _ = call(V, "POST", "/api/decline/attach", {"well_id": wid, "filename": "p.csv", "content": content, "source": "x"})
12207
+ s_ns, _ = call(O, "POST", "/api/decline/attach", {"well_id": wid, "filename": "p.csv", "content": content, "source": ""})
12208
+ s_oa, oa = call(O, "POST", "/api/decline/attach", {"well_id": wid, "filename": "p.csv", "content": content, "source": "monthly report (test)"})
12209
+ s_vg, vg = call(V, "GET", "/api/decline?well=" + wid + "&as_of=2026-01-01")
12210
+ s_bt, _ = call(O, "POST", "/api/decline/settings", {"well_id": wid, "nri": 1.5, "source": "x"})
12211
+ s_bp, _ = call(O, "POST", "/api/decline/settings", {"well_id": wid, "price_basis": "spot", "source": "x"})
12212
+ s_ot, ot = call(O, "POST", "/api/decline/settings", {"well_id": wid, "price_basis": "flat", "oil_price": "70", "gas_price": "3", "source": "budget deck (test)"})
12213
+ s_fg, fg = call(V, "GET", "/api/decline?well=" + wid)
12214
+ s_vw, _ = call(V, "POST", "/api/decline/write", {"well_id": wid})
12215
+ s_ow, ow = call(O, "POST", "/api/decline/write", {"well_id": wid})
12216
+ finally:
12217
+ svc.stop()
12218
+ cli_t = _sp.run([sys.executable, "-m", "gea", "decline", "--workspace", wsp, "--well", wid], capture_output=True, text=True, cwd=str(pkg.parent))
12219
+ cli_s = _sp.run([sys.executable, "-m", "gea", "decline", "--workspace", wsp, "--well", wid, "--opex", "9000", "--source", "LOE (test)"], capture_output=True, text=True, cwd=str(pkg.parent))
12220
+ dz = DZ.build(ws, "tester", _ver, None)
12221
+ names = _zf.ZipFile(Path(ws.reports_dir, dz["path"])).namelist()
12222
+ audit = Path(ws.audit_path).read_text(encoding="utf-8")
12223
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
12224
+ c4 = {
12225
+ "api": "production" in nothing and s_va == 403 and s_ns == 400 and s_oa == 200 and oa["months"] == 48 and s_vg == 200 and vg["result"]["as_of"] == "2026-01-01"
12226
+ and "SEC average" in vg["result"]["price_how"]["oil"] and s_bt == 400 and s_bp == 400 and s_ot == 200 and ot["oil_price"] == 70.0
12227
+ and s_fg == 200 and fg["result"]["prices"]["oil"] == 70.0 and s_vw == 403 and s_ow == 200 and ow["report_id"].startswith("DCA-"),
12228
+ "cli": cli_t.returncode == 0 and "EUR" in cli_t.stdout and "70 USD/bbl declared" in cli_t.stdout and cli_s.returncode == 0 and "opex 9,000/month" in cli_s.stdout,
12229
+ "report": PR_read_ok(Path(ws.reports_dir, "wells", wid, "decline_curves.pdf")) and all(x in audit for x in ("production.attach", "production.terms", "report.decline_curves")),
12230
+ "dossier": "declarations/economics/production/production.json" in names and f"declarations/economics/production/{wid}/p.csv" in names and f"results/decline/{wid}.json" in names,
12231
+ "page": all(x in page_src for x in ("VIEWS.decline", "['#/decline', 'Decline curves']", "/api/decline/attach", "dcChart")),
12232
+ "help": not H.check("decline") and H.VIEW_TOPIC.get("decline") == "decline",
12233
+ }
12234
+ failed4 = [k for k, v in c4.items() if not v]
12235
+ ok(not failed4,
12236
+ "CW4 on the API (anyone reads a well's curves at a chosen date, valued at the SEC price; only an operator attaches production "
12237
+ "- with its source - or declares terms - a net revenue interest of 1.5 or an unknown price basis refused - or writes the "
12238
+ "report), the CLI, the report as PDF, a signed dossier carrying the production and the curves, the tab and the help"
12239
+ + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
12240
+
12241
+
12068
12242
  def PR_read_ok(path) -> bool:
12069
12243
  from . import pdf_report as PR
12070
12244
  try:
@@ -12176,6 +12350,7 @@ def main() -> int:
12176
12350
  section_ct_frac_hits(tmp)
12177
12351
  section_cu_pore_pressure(tmp)
12178
12352
  section_cv_torque_drag(tmp)
12353
+ section_cw_decline(tmp)
12179
12354
  if _FAILS:
12180
12355
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
12181
12356
  for f in _FAILS: