gea-program 0.48.0__tar.gz → 0.49.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 (348) hide show
  1. {gea_program-0.48.0 → gea_program-0.49.0}/PKG-INFO +17 -1
  2. {gea_program-0.48.0 → gea_program-0.49.0}/README.md +16 -0
  3. {gea_program-0.48.0 → gea_program-0.49.0}/gea/__init__.py +1 -1
  4. {gea_program-0.48.0 → gea_program-0.49.0}/gea/__main__.py +50 -0
  5. {gea_program-0.48.0 → gea_program-0.49.0}/gea/acceptance_tests.py +184 -0
  6. gea_program-0.49.0/gea/collision.py +344 -0
  7. gea_program-0.49.0/gea/geomag.py +122 -0
  8. gea_program-0.49.0/gea/help/collision.md +19 -0
  9. {gea_program-0.48.0 → gea_program-0.49.0}/gea/helplib.py +2 -1
  10. gea_program-0.49.0/gea/reference/WMM2025.COF +93 -0
  11. gea_program-0.49.0/gea/reference/iscwsa_rev4_example.json +1751 -0
  12. {gea_program-0.48.0 → gea_program-0.49.0}/gea/service.py +14 -0
  13. {gea_program-0.48.0 → gea_program-0.49.0}/gea/web/app.html +47 -1
  14. gea_program-0.49.0/gea/wellpos.py +286 -0
  15. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/PKG-INFO +17 -1
  16. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/SOURCES.txt +6 -0
  17. {gea_program-0.48.0 → gea_program-0.49.0}/pyproject.toml +1 -1
  18. {gea_program-0.48.0 → gea_program-0.49.0}/LICENSE +0 -0
  19. {gea_program-0.48.0 → gea_program-0.49.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  20. {gea_program-0.48.0 → gea_program-0.49.0}/gea/accuracy_statement.py +0 -0
  21. {gea_program-0.48.0 → gea_program-0.49.0}/gea/alarm_engine.py +0 -0
  22. {gea_program-0.48.0 → gea_program-0.49.0}/gea/alerts.py +0 -0
  23. {gea_program-0.48.0 → gea_program-0.49.0}/gea/backup.py +0 -0
  24. {gea_program-0.48.0 → gea_program-0.49.0}/gea/bench.py +0 -0
  25. {gea_program-0.48.0 → gea_program-0.49.0}/gea/blind_harness.py +0 -0
  26. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  27. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  28. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  29. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  30. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  31. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  32. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  33. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  34. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  35. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  36. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  37. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  38. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  39. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  40. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  41. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  42. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  43. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  44. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  45. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  46. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  47. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  48. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  49. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  50. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  51. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  52. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  53. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  54. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  55. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  56. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  57. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  58. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  59. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  60. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  61. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  62. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  63. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  64. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  65. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  66. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  67. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  68. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  69. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  70. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  71. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  72. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  73. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  74. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  75. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  76. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  77. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  78. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  79. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  80. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  81. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  82. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  83. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  84. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  85. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  86. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  87. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  88. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  89. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  90. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  91. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  92. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  93. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/med_160_sapropels.txt +0 -0
  94. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  95. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  96. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  97. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  98. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  99. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  100. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  101. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  102. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  103. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  104. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  105. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  106. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  107. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  108. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  109. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  110. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  111. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  112. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  113. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  114. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  115. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  116. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  117. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  118. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  119. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  120. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  121. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  122. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  123. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  124. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  125. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  126. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  127. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  128. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  129. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  130. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog_map.py +0 -0
  131. {gea_program-0.48.0 → gea_program-0.49.0}/gea/catalog_register.py +0 -0
  132. {gea_program-0.48.0 → gea_program-0.49.0}/gea/certificates.py +0 -0
  133. {gea_program-0.48.0 → gea_program-0.49.0}/gea/cli.py +0 -0
  134. {gea_program-0.48.0 → gea_program-0.49.0}/gea/client_reports.py +0 -0
  135. {gea_program-0.48.0 → gea_program-0.49.0}/gea/config_versioning.py +0 -0
  136. {gea_program-0.48.0 → gea_program-0.49.0}/gea/conformance.py +0 -0
  137. {gea_program-0.48.0 → gea_program-0.49.0}/gea/control_room.py +0 -0
  138. {gea_program-0.48.0 → gea_program-0.49.0}/gea/correlation.py +0 -0
  139. {gea_program-0.48.0 → gea_program-0.49.0}/gea/dashboard.py +0 -0
  140. {gea_program-0.48.0 → gea_program-0.49.0}/gea/declarations.py +0 -0
  141. {gea_program-0.48.0 → gea_program-0.49.0}/gea/deviation.py +0 -0
  142. {gea_program-0.48.0 → gea_program-0.49.0}/gea/dlis.py +0 -0
  143. {gea_program-0.48.0 → gea_program-0.49.0}/gea/dnp3.py +0 -0
  144. {gea_program-0.48.0 → gea_program-0.49.0}/gea/doctor.py +0 -0
  145. {gea_program-0.48.0 → gea_program-0.49.0}/gea/dossier.py +0 -0
  146. {gea_program-0.48.0 → gea_program-0.49.0}/gea/dossier_verify.py +0 -0
  147. {gea_program-0.48.0 → gea_program-0.49.0}/gea/downhole_engine.py +0 -0
  148. {gea_program-0.48.0 → gea_program-0.49.0}/gea/drift_monitor.py +0 -0
  149. {gea_program-0.48.0 → gea_program-0.49.0}/gea/drill_string.py +0 -0
  150. {gea_program-0.48.0 → gea_program-0.49.0}/gea/earth_model.py +0 -0
  151. {gea_program-0.48.0 → gea_program-0.49.0}/gea/economics.py +0 -0
  152. {gea_program-0.48.0 → gea_program-0.49.0}/gea/ed25519.py +0 -0
  153. {gea_program-0.48.0 → gea_program-0.49.0}/gea/edr.py +0 -0
  154. {gea_program-0.48.0 → gea_program-0.49.0}/gea/elevation.py +0 -0
  155. {gea_program-0.48.0 → gea_program-0.49.0}/gea/etp.py +0 -0
  156. {gea_program-0.48.0 → gea_program-0.49.0}/gea/etp12_schemas.json +0 -0
  157. {gea_program-0.48.0 → gea_program-0.49.0}/gea/example_register_map.json +0 -0
  158. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fat_sat.py +0 -0
  159. {gea_program-0.48.0 → gea_program-0.49.0}/gea/files.py +0 -0
  160. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fixtures/README.md +0 -0
  161. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  162. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  163. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  164. {gea_program-0.48.0 → gea_program-0.49.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  165. {gea_program-0.48.0 → gea_program-0.49.0}/gea/follower.py +0 -0
  166. {gea_program-0.48.0 → gea_program-0.49.0}/gea/forward_model.py +0 -0
  167. {gea_program-0.48.0 → gea_program-0.49.0}/gea/friction_priors.py +0 -0
  168. {gea_program-0.48.0 → gea_program-0.49.0}/gea/gamma.py +0 -0
  169. {gea_program-0.48.0 → gea_program-0.49.0}/gea/gauge_aging.py +0 -0
  170. {gea_program-0.48.0 → gea_program-0.49.0}/gea/gauge_specs.py +0 -0
  171. {gea_program-0.48.0 → gea_program-0.49.0}/gea/geodesy.py +0 -0
  172. {gea_program-0.48.0 → gea_program-0.49.0}/gea/gravity_reference.py +0 -0
  173. {gea_program-0.48.0 → gea_program-0.49.0}/gea/hartip.py +0 -0
  174. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/TESTER_GUIDE.md +0 -0
  175. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/alarms.md +0 -0
  176. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/alerts.md +0 -0
  177. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/audit-update.md +0 -0
  178. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/backup.md +0 -0
  179. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/catalog.md +0 -0
  180. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/charts.md +0 -0
  181. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/conformance.md +0 -0
  182. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/control-room.md +0 -0
  183. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/data-in.md +0 -0
  184. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/declare.md +0 -0
  185. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/dlis.md +0 -0
  186. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/doctor.md +0 -0
  187. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/dossier.md +0 -0
  188. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/drift.md +0 -0
  189. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/drillstring.md +0 -0
  190. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/economics.md +0 -0
  191. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/edr.md +0 -0
  192. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/etp.md +0 -0
  193. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/field-ports.md +0 -0
  194. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/files.md +0 -0
  195. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/historian.md +0 -0
  196. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/instruments.md +0 -0
  197. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/interval.md +0 -0
  198. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/invoice-check.md +0 -0
  199. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/map.md +0 -0
  200. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/month-end.md +0 -0
  201. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/notifications.md +0 -0
  202. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/opseis.md +0 -0
  203. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/osdu.md +0 -0
  204. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/pad-summary.md +0 -0
  205. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/patches.md +0 -0
  206. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/penetrator.md +0 -0
  207. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/ppdm.md +0 -0
  208. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/quakeml.md +0 -0
  209. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/quality.md +0 -0
  210. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/report-history.md +0 -0
  211. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/rig-time.md +0 -0
  212. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/seedlink.md +0 -0
  213. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/seismic.md +0 -0
  214. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/setup.md +0 -0
  215. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/simulation.md +0 -0
  216. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/site.md +0 -0
  217. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/sites.md +0 -0
  218. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/slip.md +0 -0
  219. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/soak.md +0 -0
  220. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/sra.md +0 -0
  221. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/start.md +0 -0
  222. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/structure.md +0 -0
  223. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/tools.md +0 -0
  224. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/transients.md +0 -0
  225. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/upkeep.md +0 -0
  226. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/vibration.md +0 -0
  227. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/well-report.md +0 -0
  228. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/well-tests.md +0 -0
  229. {gea_program-0.48.0 → gea_program-0.49.0}/gea/help/well3d.md +0 -0
  230. {gea_program-0.48.0 → gea_program-0.49.0}/gea/housekeeping.py +0 -0
  231. {gea_program-0.48.0 → gea_program-0.49.0}/gea/interval.py +0 -0
  232. {gea_program-0.48.0 → gea_program-0.49.0}/gea/inverse_engine.py +0 -0
  233. {gea_program-0.48.0 → gea_program-0.49.0}/gea/invoice_check.py +0 -0
  234. {gea_program-0.48.0 → gea_program-0.49.0}/gea/jobs.py +0 -0
  235. {gea_program-0.48.0 → gea_program-0.49.0}/gea/live_ports.py +0 -0
  236. {gea_program-0.48.0 → gea_program-0.49.0}/gea/loadtest.py +0 -0
  237. {gea_program-0.48.0 → gea_program-0.49.0}/gea/matplotlib_demo.py +0 -0
  238. {gea_program-0.48.0 → gea_program-0.49.0}/gea/modbus.py +0 -0
  239. {gea_program-0.48.0 → gea_program-0.49.0}/gea/modbus_rtu.py +0 -0
  240. {gea_program-0.48.0 → gea_program-0.49.0}/gea/model_card.py +0 -0
  241. {gea_program-0.48.0 → gea_program-0.49.0}/gea/month_end.py +0 -0
  242. {gea_program-0.48.0 → gea_program-0.49.0}/gea/mqtt_port.py +0 -0
  243. {gea_program-0.48.0 → gea_program-0.49.0}/gea/notify.py +0 -0
  244. {gea_program-0.48.0 → gea_program-0.49.0}/gea/op_seismicity.py +0 -0
  245. {gea_program-0.48.0 → gea_program-0.49.0}/gea/opcua_port.py +0 -0
  246. {gea_program-0.48.0 → gea_program-0.49.0}/gea/operator_app.py +0 -0
  247. {gea_program-0.48.0 → gea_program-0.49.0}/gea/osdu.py +0 -0
  248. {gea_program-0.48.0 → gea_program-0.49.0}/gea/pad_summary.py +0 -0
  249. {gea_program-0.48.0 → gea_program-0.49.0}/gea/patches.py +0 -0
  250. {gea_program-0.48.0 → gea_program-0.49.0}/gea/pdf_report.py +0 -0
  251. {gea_program-0.48.0 → gea_program-0.49.0}/gea/penetrator.py +0 -0
  252. {gea_program-0.48.0 → gea_program-0.49.0}/gea/permits.py +0 -0
  253. {gea_program-0.48.0 → gea_program-0.49.0}/gea/piwebapi.py +0 -0
  254. {gea_program-0.48.0 → gea_program-0.49.0}/gea/ports.py +0 -0
  255. {gea_program-0.48.0 → gea_program-0.49.0}/gea/ppdm.py +0 -0
  256. {gea_program-0.48.0 → gea_program-0.49.0}/gea/profile_catalog.py +0 -0
  257. {gea_program-0.48.0 → gea_program-0.49.0}/gea/project.py +0 -0
  258. {gea_program-0.48.0 → gea_program-0.49.0}/gea/qt6_downhole_app.py +0 -0
  259. {gea_program-0.48.0 → gea_program-0.49.0}/gea/quakeml.py +0 -0
  260. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reconciler.py +0 -0
  261. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  262. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  263. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  264. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/eia_prices.provenance.json +0 -0
  265. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  266. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  267. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  268. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  269. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  270. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/mahoning_example.json +0 -0
  271. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/mud_motor_specs.json +0 -0
  272. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/penetrator_ratings.json +0 -0
  273. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/seismicity_protocols.json +0 -0
  274. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/tool_sources.json +0 -0
  275. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/us_outline.json +0 -0
  276. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/us_outline.provenance.json +0 -0
  277. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_3d.provenance.json +0 -0
  278. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  279. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  280. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  281. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_surfaces.json.gz +0 -0
  282. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  283. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  284. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  285. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  286. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  287. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  288. {gea_program-0.48.0 → gea_program-0.49.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  289. {gea_program-0.48.0 → gea_program-0.49.0}/gea/report_history.py +0 -0
  290. {gea_program-0.48.0 → gea_program-0.49.0}/gea/rig_state.py +0 -0
  291. {gea_program-0.48.0 → gea_program-0.49.0}/gea/rock_inventory.py +0 -0
  292. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sample_record.py +0 -0
  293. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sample_well_profile.csv +0 -0
  294. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sbom.py +0 -0
  295. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seedlink.py +0 -0
  296. {gea_program-0.48.0 → gea_program-0.49.0}/gea/segy.py +0 -0
  297. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic.py +0 -0
  298. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_array.py +0 -0
  299. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_assoc.py +0 -0
  300. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_detect.py +0 -0
  301. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_film.py +0 -0
  302. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_harmonic.py +0 -0
  303. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_qc.py +0 -0
  304. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_response.py +0 -0
  305. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_signature.py +0 -0
  306. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_track.py +0 -0
  307. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_uncertainty.py +0 -0
  308. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_unlisted.py +0 -0
  309. {gea_program-0.48.0 → gea_program-0.49.0}/gea/seismic_watch.py +0 -0
  310. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sensor_swap.py +0 -0
  311. {gea_program-0.48.0 → gea_program-0.49.0}/gea/series_cache.py +0 -0
  312. {gea_program-0.48.0 → gea_program-0.49.0}/gea/service_life.py +0 -0
  313. {gea_program-0.48.0 → gea_program-0.49.0}/gea/setup_checklist.py +0 -0
  314. {gea_program-0.48.0 → gea_program-0.49.0}/gea/shapefile.py +0 -0
  315. {gea_program-0.48.0 → gea_program-0.49.0}/gea/shell.py +0 -0
  316. {gea_program-0.48.0 → gea_program-0.49.0}/gea/shut_in.py +0 -0
  317. {gea_program-0.48.0 → gea_program-0.49.0}/gea/simulation.py +0 -0
  318. {gea_program-0.48.0 → gea_program-0.49.0}/gea/site_map.py +0 -0
  319. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sla_report.py +0 -0
  320. {gea_program-0.48.0 → gea_program-0.49.0}/gea/slip.py +0 -0
  321. {gea_program-0.48.0 → gea_program-0.49.0}/gea/soak.py +0 -0
  322. {gea_program-0.48.0 → gea_program-0.49.0}/gea/sra.py +0 -0
  323. {gea_program-0.48.0 → gea_program-0.49.0}/gea/store_forward.py +0 -0
  324. {gea_program-0.48.0 → gea_program-0.49.0}/gea/strata_join.py +0 -0
  325. {gea_program-0.48.0 → gea_program-0.49.0}/gea/structure.py +0 -0
  326. {gea_program-0.48.0 → gea_program-0.49.0}/gea/supervisor.py +0 -0
  327. {gea_program-0.48.0 → gea_program-0.49.0}/gea/survey_cmd.py +0 -0
  328. {gea_program-0.48.0 → gea_program-0.49.0}/gea/survey_view.py +0 -0
  329. {gea_program-0.48.0 → gea_program-0.49.0}/gea/telemetry.py +0 -0
  330. {gea_program-0.48.0 → gea_program-0.49.0}/gea/tool_catalog.py +0 -0
  331. {gea_program-0.48.0 → gea_program-0.49.0}/gea/tool_library.py +0 -0
  332. {gea_program-0.48.0 → gea_program-0.49.0}/gea/tool_taxonomy.py +0 -0
  333. {gea_program-0.48.0 → gea_program-0.49.0}/gea/transient.py +0 -0
  334. {gea_program-0.48.0 → gea_program-0.49.0}/gea/vibration.py +0 -0
  335. {gea_program-0.48.0 → gea_program-0.49.0}/gea/well3d.py +0 -0
  336. {gea_program-0.48.0 → gea_program-0.49.0}/gea/well_assembler.py +0 -0
  337. {gea_program-0.48.0 → gea_program-0.49.0}/gea/well_report.py +0 -0
  338. {gea_program-0.48.0 → gea_program-0.49.0}/gea/well_test_validation.py +0 -0
  339. {gea_program-0.48.0 → gea_program-0.49.0}/gea/wits0.py +0 -0
  340. {gea_program-0.48.0 → gea_program-0.49.0}/gea/witsml.py +0 -0
  341. {gea_program-0.48.0 → gea_program-0.49.0}/gea/workspace.py +0 -0
  342. {gea_program-0.48.0 → gea_program-0.49.0}/gea/xlsx_read.py +0 -0
  343. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/dependency_links.txt +0 -0
  344. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/entry_points.txt +0 -0
  345. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/requires.txt +0 -0
  346. {gea_program-0.48.0 → gea_program-0.49.0}/gea_program.egg-info/top_level.txt +0 -0
  347. {gea_program-0.48.0 → gea_program-0.49.0}/setup.cfg +0 -0
  348. {gea_program-0.48.0 → gea_program-0.49.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.48.0
3
+ Version: 0.49.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,22 @@ 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
+ ### Well collision checks
652
+
653
+ Every well scanned against every other: at each point of one well, the
654
+ closest point of the other, and the ISCWSA separation factor - the distance
655
+ between them less the holes and a surface margin, over k times the
656
+ uncertainty of that distance. Each well's position uncertainty comes from
657
+ the ISCWSA MWD Rev 4 error model (27 error sources, propagated as the model
658
+ says, the errors two wells share taken out of the distance between them),
659
+ checked against all 112 rows of the ISCWSA's own example; the Earth's field
660
+ at each well comes from the World Magnetic Model 2025. Each pair is levelled
661
+ as the ISCWSA's separation rule does - reported below 4.0, the approach
662
+ limit below 1.5, revise the plan below 1.25, below 1.0 only by the
663
+ operator's dispensation - with a company standard's k and margin kept with
664
+ its source. The Volve template's three wells are the worked example. The
665
+ **Collision** tab, `gea collision`, `gea help collision`.
666
+
651
667
  ### One record, tied together
652
668
 
653
669
  The invoice check, rig time, the daily summary, the alerts, the signed
@@ -609,6 +609,22 @@ 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
+ ### Well collision checks
613
+
614
+ Every well scanned against every other: at each point of one well, the
615
+ closest point of the other, and the ISCWSA separation factor - the distance
616
+ between them less the holes and a surface margin, over k times the
617
+ uncertainty of that distance. Each well's position uncertainty comes from
618
+ the ISCWSA MWD Rev 4 error model (27 error sources, propagated as the model
619
+ says, the errors two wells share taken out of the distance between them),
620
+ checked against all 112 rows of the ISCWSA's own example; the Earth's field
621
+ at each well comes from the World Magnetic Model 2025. Each pair is levelled
622
+ as the ISCWSA's separation rule does - reported below 4.0, the approach
623
+ limit below 1.5, revise the plan below 1.25, below 1.0 only by the
624
+ operator's dispensation - with a company standard's k and margin kept with
625
+ its source. The Volve template's three wells are the worked example. The
626
+ **Collision** tab, `gea collision`, `gea help collision`.
627
+
612
628
  ### One record, tied together
613
629
 
614
630
  The invoice check, rig time, the daily summary, the alerts, the signed
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.48.0"
126
+ __version__ = "0.49.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -590,6 +590,20 @@ def main(argv=None) -> int:
590
590
  p_dz.add_argument("--actor", type=str, default="cli")
591
591
  p_dz.add_argument("--json", action="store_true")
592
592
 
593
+ p_co = sub.add_parser("collision", help="every well scanned against every other: the closest approach and the ISCWSA separation factor, each well's position uncertainty by the ISCWSA MWD model and the field by WMM2025")
594
+ p_co.add_argument("--workspace", type=str, default=None)
595
+ p_co.add_argument("--scene", type=str, default=None, help="workspace (your wells) or volve (the worked example)")
596
+ p_co.add_argument("--write", action="store_true", help="write the client report")
597
+ p_co.add_argument("--k", type=str, default=None, help="declare the rule's scaling factor")
598
+ p_co.add_argument("--surface-margin", type=str, default=None, help="declare the surface margin, m")
599
+ p_co.add_argument("--sigma-pa", type=str, default=None, help="declare the project-ahead uncertainty, m")
600
+ p_co.add_argument("--source", type=str, default="", help="where the rule's values came from")
601
+ p_co.add_argument("--well", type=str, default=None)
602
+ p_co.add_argument("--hole", type=str, default=None, help="with --well: the hole size in inches ('' removes it)")
603
+ p_co.add_argument("--field", type=str, default=None, help="the magnetic field at LAT,LON[,YYYY-MM-DD] by WMM2025, and nothing else")
604
+ p_co.add_argument("--actor", type=str, default="cli")
605
+ p_co.add_argument("--json", action="store_true")
606
+
593
607
  p_rt = sub.add_parser("rig-time", help="what the rig did each second of the drilling record - drilling, connections, trips, the slips - and the time lost against the pad's own best")
594
608
  p_rt.add_argument("--workspace", type=str, required=True)
595
609
  p_rt.add_argument("--well", type=str, default=None, help="with --write: one well's report (without it, the pad's)")
@@ -2372,6 +2386,42 @@ def main(argv=None) -> int:
2372
2386
  print(f" {os.path.join(ws.reports_dir, e['path'])}")
2373
2387
  print(f" key fingerprint {e['fingerprint']}")
2374
2388
  return 0
2389
+ elif a.cmd == "collision":
2390
+ import json as _json
2391
+ from . import collision as _CO
2392
+ from .cli import _safe_stdout
2393
+ from .workspace import Workspace, WorkspaceError
2394
+ _safe_stdout()
2395
+ try:
2396
+ if a.field:
2397
+ from . import geomag as _GM
2398
+ parts = [x.strip() for x in a.field.split(",")]
2399
+ f_ = _GM.field(float(parts[0]), float(parts[1]), 0.0, parts[2] if len(parts) > 2 else None)
2400
+ print(f"{f_['model']} at {float(parts[0]):.4f}, {float(parts[1]):.4f} for {f_['decimal_year']:.2f}: declination {f_['declination_deg']:+.3f} deg, "
2401
+ f"dip {f_['dip_deg']:.3f} deg, total {f_['total_nT']:,.1f} nT" + (f" ({f_['note']})" if f_['note'] else ""))
2402
+ return 0
2403
+ ws = Workspace(a.workspace) if a.workspace else None
2404
+ if ws is not None and (a.k is not None or a.surface_margin is not None or a.sigma_pa is not None or a.hole is not None):
2405
+ if a.hole is not None and not a.well:
2406
+ raise ValueError("--hole needs --well")
2407
+ s_ = _CO.set_settings(ws, a.actor, a.k, a.surface_margin, a.sigma_pa, (a.well, a.hole) if a.hole is not None else None, a.source)
2408
+ print(f"rule: k {s_['k']:g}, surface margin {s_['surface_margin_m']:g} m, project-ahead {s_['sigma_pa_m']:g} m; holes: "
2409
+ + (", ".join(f"{k} {v:g} in" for k, v in s_['holes_in'].items()) or "8.5 in by default"))
2410
+ return 0
2411
+ scene = a.scene or ("workspace" if ws is not None else "volve")
2412
+ if a.write:
2413
+ if ws is None:
2414
+ raise ValueError("--write needs --workspace")
2415
+ r_ = _CO.write_report(ws, __version__, a.actor, scene)
2416
+ print(f"wrote {r_['report_id']}: {r_['paths']['html']}")
2417
+ if r_['paths'].get('pdf'):
2418
+ print(f" printable: {r_['paths']['pdf']}")
2419
+ return 0
2420
+ r = _CO.page(ws, scene)
2421
+ except (KeyError, ValueError, OSError, WorkspaceError) as e:
2422
+ raise SystemExit(f"collision: {e.args[0] if e.args else e}")
2423
+ print(_json.dumps({k: v for k, v in r.items()}, default=str) if a.json else _CO.text(r))
2424
+ return 0
2375
2425
  elif a.cmd == "rig-time":
2376
2426
  import json as _json
2377
2427
  from . import rig_state as _RS
@@ -11113,6 +11113,189 @@ def section_cq_tied_together(tmp: str) -> None:
11113
11113
  + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
11114
11114
 
11115
11115
 
11116
+ def section_cr_collision(tmp: str) -> None:
11117
+ """Section CR - well collision checks: each well's position uncertainty by the ISCWSA MWD Rev 4 error model,
11118
+ checked against all 112 rows of the ISCWSA's own example; the Earth's field from WMM2025, checked against a
11119
+ published example; the ISCWSA separation factor, its arithmetic recomputed by hand with the errors two wells share
11120
+ taken out; the Volve template as the worked example; a workspace's wells checked, the rule and the hole sizes kept
11121
+ by an operator only; the API, the CLI, the report, the tab and the help."""
11122
+ import hashlib as _hl
11123
+ import http.cookiejar
11124
+ import math as _m
11125
+ import subprocess as _sp
11126
+ import time as _t
11127
+ import urllib.request
11128
+ import urllib.error
11129
+ import numpy as _np
11130
+ from . import collision as CO
11131
+ from . import edr as E
11132
+ from . import geomag as GM
11133
+ from . import helplib as H
11134
+ from . import pdf_report as PR
11135
+ from . import well3d as W
11136
+ from . import wellpos as WP
11137
+ from .workspace import Workspace
11138
+ from .service import Service, Users
11139
+ pkg = Path(__file__).parent
11140
+ d = Path(tmp, "collision"); d.mkdir()
11141
+
11142
+ # -- CR1 the error model and the field against their published examples --------------------------------------------
11143
+ ex = WP.check_example()
11144
+ tot8 = ex["totals"]["8000"]
11145
+ f1 = GM.field(42.283, -71.35, 1000.0, "2028-07-04")
11146
+ f2 = GM.field(31.42, -104.10, 0.0, 2031.5)
11147
+ c1 = {
11148
+ "example": ex["rows"] == 112 and ex["sources"] == 27 and ex["depths_m"] == [1200, 2100, 5100, 8000] and not ex["disagree"] and ex["worst_relative"] < 1e-3,
11149
+ "totals": abs(tot8[0] - 8547.78) < 0.05 and abs(tot8[1] - 712.69) < 0.05 and abs(tot8[2] - 468.13) < 0.05 and abs(tot8[3] + 2252.31) < 0.05,
11150
+ "attribution": "ISCWSA" in ex["source"] and "welleng" in ex["source"] and "Apache" in ex["license"],
11151
+ "wmm": abs(f1["declination_deg"] + 13.6891) < 5e-4 and abs(f1["dip_deg"] - 65.9899) < 5e-4 and abs(f1["total_nT"] - 50940) < 1.0
11152
+ and abs(f1["north_nT"] - 20139) < 1.0 and abs(f1["east_nT"] + 4905) < 1.0 and abs(f1["down_nT"] - 46532) < 1.0 and f1["in_range"],
11153
+ "wmm_range": not f2["in_range"] and "extrapolated" in f2["note"] and abs(GM.decimal_year("2026-07-02") - (2026 + 182 / 365)) < 1e-9,
11154
+ "coefficients": _hl.md5((pkg / "reference" / "WMM2025.COF").read_bytes()).hexdigest() == "a1b6402dd23658d15affb0f31babccc7",
11155
+ }
11156
+ failed1 = [k for k, v in c1.items() if not v]
11157
+ ok(not failed1,
11158
+ "CR1 each well's uncertainty by the ISCWSA MWD Rev 4 error model: all 112 rows of the ISCWSA's own example (27 error sources "
11159
+ "and the total, at 1,200, 2,100, 5,100 and 8,000 m MD) recomputed and agreeing to the printed digits, its source and licence "
11160
+ "carried; the field by WMM2025 agreeing with a published example (declination -13.6891, dip 65.9899 deg, 50,940 nT), a date "
11161
+ "past the model's years answered and called extrapolated, the coefficients as NOAA published them"
11162
+ + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
11163
+
11164
+ # -- CR2 the separation factor's arithmetic ----------------------------------------------------------------------------
11165
+ fld = {"declination_deg": 6.0, "dip_deg": 60.0, "total_nT": 48000.0}
11166
+ md = [0.0, 500.0, 1000.0, 2000.0]
11167
+ mk = lambda i, x, inc=(0, 0, 0, 0), az=(0, 0, 0, 0), y=0.0: {"id": i, "display": i, "md": md, "inc": list(inc), "az": list(az), "x0": x, "y0": y,
11168
+ "ref_elev_m": 0.0, "field": fld, "hole_in": 8.5}
11169
+ rule = {**CO.DEFAULTS}
11170
+ A, B = CO.prepare(mk("A", 0.0)), CO.prepare(mk("B", 10.0))
11171
+ sAB, sBA = CO.scan(A, B, rule), CO.scan(B, A, rule)
11172
+ u = WP.well_uncertainty(_np.array(md), _np.zeros(4), _np.zeros(4), _np.array(md), 6.0, 60.0, 48000.0)
11173
+ Cee = float(u["cov"][-1][1, 1]); Gee = sum(float(g[-1][1]) ** 2 for g in u["global"].values())
11174
+ sig_hand = _m.sqrt(2.0 * (Cee - Gee))
11175
+ sf_hand = (10.0 - 2 * 8.5 * 0.0254 / 2 - 0.3) / (3.5 * _m.sqrt(sig_hand ** 2 + 0.25))
11176
+ i_td = len(sAB["profile"]["md_m"]) - 1
11177
+ E1, E2 = CO.prepare(mk("E1", 0.0, (0, 0, 30, 30), (90, 90, 90, 90))), CO.prepare(mk("E2", 0.0, (0, 0, 30, 30), (90, 90, 90, 90), 10.0))
11178
+ s_sh = CO.scan(E1, E2, rule) # parallel, inclined east, 10 m apart north-south: the declination moves both
11179
+ s_ng = CO.scan({**E1, "glob": {k: v * 0 for k, v in E1["glob"].items()}}, {**E2, "glob": {k: v * 0 for k, v in E2["glob"].items()}}, rule)
11180
+ j_td = len(s_sh["profile"]["md_m"]) - 1
11181
+ ue = WP.well_uncertainty(_np.array(md), _np.array([0.0, 0.0, 30.0, 30.0]), _np.full(4, 90.0), _np.array(W.Path(md, [0, 0, 30, 30], [90] * 4, 0.0, 0.0, 0.0, 0.0).tvd), 6.0, 60.0, 48000.0)
11182
+ Cnn = float(ue["cov"][-1][0, 0]); Gnn = sum(float(g[-1][0]) ** 2 for g in ue["global"].values())
11183
+ C_, D_ = CO.prepare(mk("C", 0.0, (0, 0, 30, 30), (0, 0, 90, 90))), CO.prepare(mk("D", 30.0, (0, 0, 30, 30), (0, 0, 270, 270)))
11184
+ sCD = CO.scan(C_, D_, rule)
11185
+ c2 = {
11186
+ "hand": abs(sAB["profile"]["sigma_m"][i_td] - sig_hand) < 2e-3 and abs(sAB["profile"]["sf"][i_td] - sf_hand) < 2e-3 and abs(sAB["profile"]["distance_m"][i_td] - 10.0) < 1e-6,
11187
+ "shared_out": set(u["global"]) == {"DECG", "DBHG", "DSTG"} and Gnn > 0.01 and abs(s_sh["profile"]["sigma_m"][j_td] - _m.sqrt(2.0 * (Cnn - Gnn))) < 2e-3
11188
+ and abs(s_ng["profile"]["sigma_m"][j_td] - _m.sqrt(2.0 * Cnn)) < 2e-3 and abs(s_sh["profile"]["distance_m"][j_td] - 10.0) < 1e-3,
11189
+ "symmetric": abs(sAB["min_sf"] - sBA["min_sf"]) < 1e-6 and sAB["at_md_m"] == 2000.0,
11190
+ "crossing": sCD["min_sf"] < 1.0 and sCD["level"] == "BELOW 1.0" and sCD["closest_m"] < 1.0 and sCD["sections"] and sCD["sections"][0]["from_md_m"] < sCD["at_md_m"],
11191
+ "levels": [CO.level(x)[0] for x in (0.99, 1.0, 1.2, 1.25, 1.4, 1.5, 3.99, 4.0)]
11192
+ == ["BELOW 1.0", "REVISE THE PLAN", "REVISE THE PLAN", "APPROACH LIMIT", "APPROACH LIMIT", "REPORTED", "REPORTED", "CLEAR"],
11193
+ }
11194
+ failed2 = [k for k, v in c2.items() if not v]
11195
+ ok(not failed2,
11196
+ "CR2 the separation factor's arithmetic: two vertical wells 10 m apart recomputed by hand at TD - sigma along the line between "
11197
+ "them from each well's covariance less the errors both share (declination, the global magnetic and depth terms), the holes' "
11198
+ "radii, the surface margin, project-ahead and k; leaving the shared errors in widens sigma; the same from either well; two wells "
11199
+ "steered at each other found below 1.0 where they cross; the four levels at their edges"
11200
+ + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
11201
+
11202
+ # -- CR3 the worked example: the Volve template ------------------------------------------------------------------------
11203
+ t0 = _t.time()
11204
+ v = CO.page(None, "volve")
11205
+ dt = _t.time() - t0
11206
+ w_ = v["worst"]; wl = {x["display"]: x for x in v["wells"]}
11207
+ c3 = {
11208
+ "wells": len(v["wells"]) == 3 and len(v["pairs"]) == 6 and abs(wl["15/9-F-10"]["td_md_m"] - 5300.1) < 0.1
11209
+ and all(abs(x["field"]["declination_deg"] - 1.12) < 0.05 for x in v["wells"]) and all("grid convergence" in x["azimuth_note"] for x in v["wells"]),
11210
+ "worst": w_["level"] == "BELOW 1.0" and abs(w_["min_sf"] - 0.29) < 0.01 and {w_["reference_name"], w_["offset_name"]} == {"15/9-F-5", "15/9-F-10"}
11211
+ and abs(w_["at_md_m"] - 250) < 15 and abs(w_["distance_m"] - 1.20) < 0.05,
11212
+ "order": [p["min_sf"] for p in v["pairs"]] == sorted(p["min_sf"] for p in v["pairs"]) and all(len(p["profile"]["md_m"]) == len(p["profile"]["sf"]) for p in v["pairs"]),
11213
+ "ellipses": wl["15/9-F-10"]["td_ellipse_1sigma"]["major_m"] > wl["15/9-F-5"]["td_ellipse_1sigma"]["major_m"] > wl["NO 15/9-F-4"]["td_ellipse_1sigma"]["major_m"] > 1.0,
11214
+ "fast": dt < 20.0,
11215
+ }
11216
+ failed3 = [k for k, v_ in c3.items() if not v_]
11217
+ ok(not failed3,
11218
+ "CR3 the worked example, the Volve template's three wells (Equinor's released data): every pair scanned both ways, the field from "
11219
+ "WMM2025 at the template and the grid convergence applied; the closest, 15/9-F-5 and 15/9-F-10 near the surface where the slots "
11220
+ "sit 1.2 m apart, below 1.0; the longest well the widest ellipse at TD"
11221
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
11222
+
11223
+ # -- CR4 a workspace's wells, the API, the CLI, the report, the tab and the help ----------------------------------------
11224
+ ev = E.selftest_events(str(d))
11225
+ wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
11226
+ ids = []
11227
+ for i, n in enumerate(("Well A", "Well B", "Well C")):
11228
+ w = ws.add_well_file(ev["path"], display=n, actor="tester"); ids.append(w["id"])
11229
+ ws.set_well(w["id"], surface={"lat": 31.42, "lon": -104.10 + 0.0001 * i, "datum": "NAD83", "elevation": {"ft": 3000.0, "datum": "KB", "source": "test plat"}}, actor="tester")
11230
+ W.attach_trajectory(ws, ids[0], "a.csv", b"MD (ft),Inc (deg),Azi (deg)\n0,0,0\n1000,0,0\n2000,10,90\n3000,30,90\n4000,45,95\n5750,60,100\n", "tester", "true", "ft", None, None, None, "test survey")
11231
+ W.attach_trajectory(ws, ids[1], "b.csv", b"MD (ft),Inc (deg),Azi (deg)\n0,0,0\n1200,0,0\n2200,12,270\n3500,35,265\n5500,55,260\n", "tester", "true", "ft", None, None, None, "test survey")
11232
+ p0 = CO.page(ws)
11233
+ Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
11234
+ svc = Service(wsp, port=0, scheduler=False).start()
11235
+ base_url = svc.url.rstrip("/")
11236
+
11237
+ def opener(name, pw_):
11238
+ o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
11239
+ rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
11240
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
11241
+ return o
11242
+
11243
+ def call(o, method, path, body=None):
11244
+ rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
11245
+ if method == "POST":
11246
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
11247
+ try:
11248
+ with o.open(rq, timeout=120) as rr_:
11249
+ return rr_.status, json.loads(rr_.read())
11250
+ except urllib.error.HTTPError as e:
11251
+ return e.code, json.loads(e.read())
11252
+ try:
11253
+ V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
11254
+ s_vg, vg = call(V, "GET", "/api/collision")
11255
+ s_vv, vv = call(V, "GET", "/api/collision?scene=volve")
11256
+ s_bad, _ = call(V, "GET", "/api/collision?scene=nowhere")
11257
+ s_vs, _ = call(V, "POST", "/api/collision/settings", {"k": 3.0, "source": "x"})
11258
+ s_ns, _ = call(O, "POST", "/api/collision/settings", {"k": 3.0})
11259
+ s_lk, _ = call(O, "POST", "/api/collision/settings", {"k": 0.1, "source": "standard"})
11260
+ s_ok, okj = call(O, "POST", "/api/collision/settings", {"k": 3.0, "surface_margin_m": 0.5, "source": "company anti-collision standard, rev 3"})
11261
+ s_hb, _ = call(O, "POST", "/api/collision/settings", {"well_id": ids[0], "hole_in": 99})
11262
+ s_ho, hoj = call(O, "POST", "/api/collision/settings", {"well_id": ids[0], "hole_in": 12.25})
11263
+ s_ag, ag = call(V, "GET", "/api/collision")
11264
+ s_vw, _ = call(V, "POST", "/api/collision/write", {})
11265
+ s_ow, owj = call(O, "POST", "/api/collision/write", {})
11266
+ finally:
11267
+ svc.stop()
11268
+ cli_v = _sp.run([sys.executable, "-m", "gea", "collision", "--scene", "volve"], capture_output=True, text=True, cwd=str(pkg.parent))
11269
+ cli_f = _sp.run([sys.executable, "-m", "gea", "collision", "--field", "42.283,-71.35,2028-07-04"], capture_output=True, text=True, cwd=str(pkg.parent))
11270
+ cli_w = _sp.run([sys.executable, "-m", "gea", "collision", "--workspace", wsp, "--write"], capture_output=True, text=True, cwd=str(pkg.parent))
11271
+ pdf = Path(wsp, "reports", "collision.pdf")
11272
+ rd = PR.read(pdf.read_bytes()) if pdf.exists() else {"ok": False, "text": []}
11273
+ audit = Path(ws.audit_path).read_text(encoding="utf-8")
11274
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
11275
+ wa = next((p for p in ag.get("pairs", []) if p["reference"] == ids[0]), {}) if s_ag == 200 else {}
11276
+ c4 = {
11277
+ "workspace": len(p0["wells"]) == 2 and len(p0["pairs"]) == 2 and [x["id"] for x in p0["left_out"]] == [ids[2]] and "survey" in p0["left_out"][0]["why"]
11278
+ and all("WMM2025 at the well" in x["field_note"] for x in p0["wells"]) and p0["worst"]["level"] == "BELOW 1.0",
11279
+ "api": s_vg == 200 and vg["scene"] == "workspace" and len(vg["pairs"]) == 2 and s_vv == 200 and len(vv["pairs"]) == 6 and s_bad in (400, 404)
11280
+ and s_vs == 403 and s_ns == 400 and s_lk == 400 and s_ok == 200 and okj["k"] == 3.0 and s_hb == 400 and s_ho == 200 and hoj["holes_in"][ids[0]] == 12.25
11281
+ and s_ag == 200 and ag["rule"]["k"] == 3.0 and ag["rule_source"].startswith("company") and wa.get("min_sf", 0) < p0["pairs"][0]["min_sf"] + 1
11282
+ and next(x for x in ag["wells"] if x["id"] == ids[0])["hole_in"] == 12.25 and s_vw == 403 and s_ow == 200 and owj["report_id"].startswith("COL-"),
11283
+ "cli": cli_v.returncode == 0 and "15/9-F-5" in cli_v.stdout and "BELOW 1.0" in cli_v.stdout and cli_f.returncode == 0 and "declination -13.69" in cli_f.stdout
11284
+ and cli_w.returncode == 0 and "collision" in cli_w.stdout,
11285
+ "report": rd["ok"] and any("separation factor" in t_ for t_ in rd["text"]) and any("Well A" in t_ for t_ in rd["text"])
11286
+ and "collision.settings" in audit and "report.collision" in audit,
11287
+ "page": all(x in page_src for x in ("VIEWS.collision", "['#/collision', 'Collision']", "/api/collision/settings", "/api/collision/write", "coChart")),
11288
+ "help": not H.check("collision") and H.VIEW_TOPIC.get("collision") == "collision" and "WMM2025" in (pkg / "help" / "collision.md").read_text(encoding="utf-8"),
11289
+ }
11290
+ failed4 = [k for k, v_ in c4.items() if not v_]
11291
+ ok(not failed4,
11292
+ "CR4 a workspace's wells: those with a position, an elevation and a survey checked, the one without listed with why, the field "
11293
+ "at each well; on the API anyone reads it and only an operator keeps a rule (with its source; a k below 0.5 refused) or a hole size "
11294
+ "(inches, 2 to 40) or writes the report; the CLI (the worked example, the field at a place and date, the report); the report as "
11295
+ "PDF; the tab and the help"
11296
+ + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
11297
+
11298
+
11116
11299
  def main() -> int:
11117
11300
  print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
11118
11301
  # a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
@@ -11211,6 +11394,7 @@ def main() -> int:
11211
11394
  section_co_invoice_check(tmp)
11212
11395
  section_cp_rig_time(tmp)
11213
11396
  section_cq_tied_together(tmp)
11397
+ section_cr_collision(tmp)
11214
11398
  if _FAILS:
11215
11399
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
11216
11400
  for f in _FAILS: