gea-program 0.80.0__tar.gz → 0.81.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 (428) hide show
  1. {gea_program-0.80.0/gea_program.egg-info → gea_program-0.81.0}/PKG-INFO +8 -5
  2. {gea_program-0.80.0 → gea_program-0.81.0}/README.md +7 -4
  3. {gea_program-0.80.0 → gea_program-0.81.0}/gea/__init__.py +1 -1
  4. {gea_program-0.80.0 → gea_program-0.81.0}/gea/acceptance_tests.py +175 -0
  5. {gea_program-0.80.0 → gea_program-0.81.0}/gea/driller_link.py +28 -8
  6. {gea_program-0.80.0 → gea_program-0.81.0}/gea/edr.py +3 -1
  7. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/driller.md +2 -2
  8. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/install.md +2 -2
  9. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/reader.md +1 -1
  10. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/recorder.md +1 -1
  11. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/01-install.md +2 -2
  12. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
  13. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/22-updates.md +1 -1
  14. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/25-install-recorder.md +2 -2
  15. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/28-driller-office.md +2 -2
  16. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/29-driller-rig.md +2 -2
  17. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial.md +2 -2
  18. {gea_program-0.80.0 → gea_program-0.81.0}/gea/web/app.html +1 -1
  19. {gea_program-0.80.0 → gea_program-0.81.0/gea_program.egg-info}/PKG-INFO +8 -5
  20. {gea_program-0.80.0 → gea_program-0.81.0}/pyproject.toml +1 -1
  21. {gea_program-0.80.0 → gea_program-0.81.0}/LICENSE +0 -0
  22. {gea_program-0.80.0 → gea_program-0.81.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  23. {gea_program-0.80.0 → gea_program-0.81.0}/gea/__main__.py +0 -0
  24. {gea_program-0.80.0 → gea_program-0.81.0}/gea/accuracy_statement.py +0 -0
  25. {gea_program-0.80.0 → gea_program-0.81.0}/gea/alarm_engine.py +0 -0
  26. {gea_program-0.80.0 → gea_program-0.81.0}/gea/alerts.py +0 -0
  27. {gea_program-0.80.0 → gea_program-0.81.0}/gea/backup.py +0 -0
  28. {gea_program-0.80.0 → gea_program-0.81.0}/gea/bench.py +0 -0
  29. {gea_program-0.80.0 → gea_program-0.81.0}/gea/bit_seismic.py +0 -0
  30. {gea_program-0.80.0 → gea_program-0.81.0}/gea/blind_harness.py +0 -0
  31. {gea_program-0.80.0 → gea_program-0.81.0}/gea/casing_design.py +0 -0
  32. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  33. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  34. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  35. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  36. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  37. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  38. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  39. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  40. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  41. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  42. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  43. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  44. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  45. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  46. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  47. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  48. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  49. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  50. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  51. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  52. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  53. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  54. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  55. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  56. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  57. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  58. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  59. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  60. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  61. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  62. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  63. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  64. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  65. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  66. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  67. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  68. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  69. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  70. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  71. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  72. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  73. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  74. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  75. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  76. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  77. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  78. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  79. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  80. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  81. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  82. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  83. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  84. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  85. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  86. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  87. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  88. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  89. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  90. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  91. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  92. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  93. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  94. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  95. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  96. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  97. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  98. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  99. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/med_160_sapropels.txt +0 -0
  100. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  101. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  102. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  103. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  104. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  105. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  106. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  107. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  108. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  109. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  110. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  111. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  112. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  113. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  114. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  115. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  116. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  117. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  118. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  119. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  120. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  121. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  122. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  123. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  124. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  125. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  126. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  127. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  128. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  129. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  130. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  131. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  132. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  133. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  134. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  135. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  136. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog_map.py +0 -0
  137. {gea_program-0.80.0 → gea_program-0.81.0}/gea/catalog_register.py +0 -0
  138. {gea_program-0.80.0 → gea_program-0.81.0}/gea/certificates.py +0 -0
  139. {gea_program-0.80.0 → gea_program-0.81.0}/gea/cli.py +0 -0
  140. {gea_program-0.80.0 → gea_program-0.81.0}/gea/client_reports.py +0 -0
  141. {gea_program-0.80.0 → gea_program-0.81.0}/gea/collision.py +0 -0
  142. {gea_program-0.80.0 → gea_program-0.81.0}/gea/config_versioning.py +0 -0
  143. {gea_program-0.80.0 → gea_program-0.81.0}/gea/conformance.py +0 -0
  144. {gea_program-0.80.0 → gea_program-0.81.0}/gea/control_room.py +0 -0
  145. {gea_program-0.80.0 → gea_program-0.81.0}/gea/correlation.py +0 -0
  146. {gea_program-0.80.0 → gea_program-0.81.0}/gea/dashboard.py +0 -0
  147. {gea_program-0.80.0 → gea_program-0.81.0}/gea/declarations.py +0 -0
  148. {gea_program-0.80.0 → gea_program-0.81.0}/gea/decline.py +0 -0
  149. {gea_program-0.80.0 → gea_program-0.81.0}/gea/deviation.py +0 -0
  150. {gea_program-0.80.0 → gea_program-0.81.0}/gea/dlis.py +0 -0
  151. {gea_program-0.80.0 → gea_program-0.81.0}/gea/dnp3.py +0 -0
  152. {gea_program-0.80.0 → gea_program-0.81.0}/gea/doctor.py +0 -0
  153. {gea_program-0.80.0 → gea_program-0.81.0}/gea/dossier.py +0 -0
  154. {gea_program-0.80.0 → gea_program-0.81.0}/gea/dossier_verify.py +0 -0
  155. {gea_program-0.80.0 → gea_program-0.81.0}/gea/downhole_engine.py +0 -0
  156. {gea_program-0.80.0 → gea_program-0.81.0}/gea/drift_monitor.py +0 -0
  157. {gea_program-0.80.0 → gea_program-0.81.0}/gea/drill_string.py +0 -0
  158. {gea_program-0.80.0 → gea_program-0.81.0}/gea/earth_model.py +0 -0
  159. {gea_program-0.80.0 → gea_program-0.81.0}/gea/economics.py +0 -0
  160. {gea_program-0.80.0 → gea_program-0.81.0}/gea/ed25519.py +0 -0
  161. {gea_program-0.80.0 → gea_program-0.81.0}/gea/elevation.py +0 -0
  162. {gea_program-0.80.0 → gea_program-0.81.0}/gea/etp.py +0 -0
  163. {gea_program-0.80.0 → gea_program-0.81.0}/gea/etp12_schemas.json +0 -0
  164. {gea_program-0.80.0 → gea_program-0.81.0}/gea/example_register_map.json +0 -0
  165. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fat_sat.py +0 -0
  166. {gea_program-0.80.0 → gea_program-0.81.0}/gea/field_pull.py +0 -0
  167. {gea_program-0.80.0 → gea_program-0.81.0}/gea/files.py +0 -0
  168. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fixtures/README.md +0 -0
  169. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  170. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  171. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  172. {gea_program-0.80.0 → gea_program-0.81.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  173. {gea_program-0.80.0 → gea_program-0.81.0}/gea/follower.py +0 -0
  174. {gea_program-0.80.0 → gea_program-0.81.0}/gea/forward_model.py +0 -0
  175. {gea_program-0.80.0 → gea_program-0.81.0}/gea/frac_hits.py +0 -0
  176. {gea_program-0.80.0 → gea_program-0.81.0}/gea/friction_priors.py +0 -0
  177. {gea_program-0.80.0 → gea_program-0.81.0}/gea/gamma.py +0 -0
  178. {gea_program-0.80.0 → gea_program-0.81.0}/gea/gauge_aging.py +0 -0
  179. {gea_program-0.80.0 → gea_program-0.81.0}/gea/gauge_specs.py +0 -0
  180. {gea_program-0.80.0 → gea_program-0.81.0}/gea/geodesy.py +0 -0
  181. {gea_program-0.80.0 → gea_program-0.81.0}/gea/geomag.py +0 -0
  182. {gea_program-0.80.0 → gea_program-0.81.0}/gea/gravity_reference.py +0 -0
  183. {gea_program-0.80.0 → gea_program-0.81.0}/gea/hartip.py +0 -0
  184. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/IT_SECURITY.md +0 -0
  185. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/TESTER_GUIDE.md +0 -0
  186. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/alarms.md +0 -0
  187. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/alerts.md +0 -0
  188. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/audit-update.md +0 -0
  189. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/backup.md +0 -0
  190. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/bit-image.md +0 -0
  191. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/casing.md +0 -0
  192. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/catalog.md +0 -0
  193. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/charts.md +0 -0
  194. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/collision.md +0 -0
  195. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/company-sign-in.md +0 -0
  196. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/conformance.md +0 -0
  197. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/control-room.md +0 -0
  198. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/data-in.md +0 -0
  199. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/declare.md +0 -0
  200. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/decline.md +0 -0
  201. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/dlis.md +0 -0
  202. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/doctor.md +0 -0
  203. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/dossier.md +0 -0
  204. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/drift.md +0 -0
  205. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/drillstring.md +0 -0
  206. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/economics.md +0 -0
  207. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/edr.md +0 -0
  208. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/etp.md +0 -0
  209. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/field-ports.md +0 -0
  210. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/files.md +0 -0
  211. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/frac-hits.md +0 -0
  212. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/historian.md +0 -0
  213. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/https.md +0 -0
  214. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/hydraulics.md +0 -0
  215. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/instruments.md +0 -0
  216. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/interval.md +0 -0
  217. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/invoice-check.md +0 -0
  218. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/map.md +0 -0
  219. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/month-end.md +0 -0
  220. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/notifications.md +0 -0
  221. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/opseis.md +0 -0
  222. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/osdu.md +0 -0
  223. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/pad-summary.md +0 -0
  224. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/patches.md +0 -0
  225. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/penetrator.md +0 -0
  226. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/plan.md +0 -0
  227. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/pore-pressure.md +0 -0
  228. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/ppdm.md +0 -0
  229. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/quakeml.md +0 -0
  230. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/quality.md +0 -0
  231. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/records.md +0 -0
  232. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/report-history.md +0 -0
  233. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/rig-time.md +0 -0
  234. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/rocks.md +0 -0
  235. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/seedlink.md +0 -0
  236. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/seismic.md +0 -0
  237. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/setup.md +0 -0
  238. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/simulation.md +0 -0
  239. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/site.md +0 -0
  240. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/sites.md +0 -0
  241. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/slip.md +0 -0
  242. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/soak.md +0 -0
  243. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/sra.md +0 -0
  244. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/start.md +0 -0
  245. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/structure.md +0 -0
  246. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tools.md +0 -0
  247. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/torque-drag.md +0 -0
  248. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/transients.md +0 -0
  249. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/02-sign-in.md +0 -0
  250. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/03-site.md +0 -0
  251. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/04-add-well.md +0 -0
  252. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/05-records.md +0 -0
  253. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/06-well-page.md +0 -0
  254. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/07-declare.md +0 -0
  255. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/08-patches.md +0 -0
  256. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/09-alarms.md +0 -0
  257. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/10-control-room.md +0 -0
  258. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/11-summary-month.md +0 -0
  259. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
  260. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
  261. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/14-production-pages.md +0 -0
  262. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/15-seismic.md +0 -0
  263. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/16-seismicity.md +0 -0
  264. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/17-recorder-office.md +0 -0
  265. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/18-reports.md +0 -0
  266. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/20-admin.md +0 -0
  267. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/21-upkeep.md +0 -0
  268. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/23-vpn.md +0 -0
  269. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/24-the-box.md +0 -0
  270. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/26-monitor.md +0 -0
  271. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
  272. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/upkeep.md +0 -0
  273. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/vibration.md +0 -0
  274. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/vpn.md +0 -0
  275. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/well-report.md +0 -0
  276. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/well-tests.md +0 -0
  277. {gea_program-0.80.0 → gea_program-0.81.0}/gea/help/well3d.md +0 -0
  278. {gea_program-0.80.0 → gea_program-0.81.0}/gea/helplib.py +0 -0
  279. {gea_program-0.80.0 → gea_program-0.81.0}/gea/housekeeping.py +0 -0
  280. {gea_program-0.80.0 → gea_program-0.81.0}/gea/hydraulics.py +0 -0
  281. {gea_program-0.80.0 → gea_program-0.81.0}/gea/icon.py +0 -0
  282. {gea_program-0.80.0 → gea_program-0.81.0}/gea/interval.py +0 -0
  283. {gea_program-0.80.0 → gea_program-0.81.0}/gea/inverse_engine.py +0 -0
  284. {gea_program-0.80.0 → gea_program-0.81.0}/gea/invoice_check.py +0 -0
  285. {gea_program-0.80.0 → gea_program-0.81.0}/gea/jobs.py +0 -0
  286. {gea_program-0.80.0 → gea_program-0.81.0}/gea/launcher.py +0 -0
  287. {gea_program-0.80.0 → gea_program-0.81.0}/gea/live_ports.py +0 -0
  288. {gea_program-0.80.0 → gea_program-0.81.0}/gea/loadtest.py +0 -0
  289. {gea_program-0.80.0 → gea_program-0.81.0}/gea/matplotlib_demo.py +0 -0
  290. {gea_program-0.80.0 → gea_program-0.81.0}/gea/modbus.py +0 -0
  291. {gea_program-0.80.0 → gea_program-0.81.0}/gea/modbus_rtu.py +0 -0
  292. {gea_program-0.80.0 → gea_program-0.81.0}/gea/model_card.py +0 -0
  293. {gea_program-0.80.0 → gea_program-0.81.0}/gea/month_end.py +0 -0
  294. {gea_program-0.80.0 → gea_program-0.81.0}/gea/mqtt_port.py +0 -0
  295. {gea_program-0.80.0 → gea_program-0.81.0}/gea/notify.py +0 -0
  296. {gea_program-0.80.0 → gea_program-0.81.0}/gea/oidc.py +0 -0
  297. {gea_program-0.80.0 → gea_program-0.81.0}/gea/oidc_mock.py +0 -0
  298. {gea_program-0.80.0 → gea_program-0.81.0}/gea/op_seismicity.py +0 -0
  299. {gea_program-0.80.0 → gea_program-0.81.0}/gea/opcua_port.py +0 -0
  300. {gea_program-0.80.0 → gea_program-0.81.0}/gea/operator_app.py +0 -0
  301. {gea_program-0.80.0 → gea_program-0.81.0}/gea/osdu.py +0 -0
  302. {gea_program-0.80.0 → gea_program-0.81.0}/gea/pad_summary.py +0 -0
  303. {gea_program-0.80.0 → gea_program-0.81.0}/gea/patches.py +0 -0
  304. {gea_program-0.80.0 → gea_program-0.81.0}/gea/pdf_report.py +0 -0
  305. {gea_program-0.80.0 → gea_program-0.81.0}/gea/penetrator.py +0 -0
  306. {gea_program-0.80.0 → gea_program-0.81.0}/gea/permits.py +0 -0
  307. {gea_program-0.80.0 → gea_program-0.81.0}/gea/piwebapi.py +0 -0
  308. {gea_program-0.80.0 → gea_program-0.81.0}/gea/pore_pressure.py +0 -0
  309. {gea_program-0.80.0 → gea_program-0.81.0}/gea/ports.py +0 -0
  310. {gea_program-0.80.0 → gea_program-0.81.0}/gea/ppdm.py +0 -0
  311. {gea_program-0.80.0 → gea_program-0.81.0}/gea/profile_catalog.py +0 -0
  312. {gea_program-0.80.0 → gea_program-0.81.0}/gea/project.py +0 -0
  313. {gea_program-0.80.0 → gea_program-0.81.0}/gea/qt6_downhole_app.py +0 -0
  314. {gea_program-0.80.0 → gea_program-0.81.0}/gea/quakeml.py +0 -0
  315. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reader.py +0 -0
  316. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reader_app.py +0 -0
  317. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reconciler.py +0 -0
  318. {gea_program-0.80.0 → gea_program-0.81.0}/gea/recorder_link.py +0 -0
  319. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  320. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  321. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/WMM2025.COF +0 -0
  322. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  323. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/eia_prices.provenance.json +0 -0
  324. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  325. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  326. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  327. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  328. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  329. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  330. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  331. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  332. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  333. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/mahoning_example.json +0 -0
  334. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/mud_motor_specs.json +0 -0
  335. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/owsg_tool_models.json +0 -0
  336. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/penetrator_ratings.json +0 -0
  337. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/seismicity_protocols.json +0 -0
  338. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/tool_sources.json +0 -0
  339. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/us_outline.json +0 -0
  340. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/us_outline.provenance.json +0 -0
  341. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_3d.provenance.json +0 -0
  342. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  343. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  344. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  345. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_surfaces.json.gz +0 -0
  346. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  347. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  348. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  349. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  350. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  351. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  352. {gea_program-0.80.0 → gea_program-0.81.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  353. {gea_program-0.80.0 → gea_program-0.81.0}/gea/report_history.py +0 -0
  354. {gea_program-0.80.0 → gea_program-0.81.0}/gea/rig_state.py +0 -0
  355. {gea_program-0.80.0 → gea_program-0.81.0}/gea/rock_inventory.py +0 -0
  356. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sample_record.py +0 -0
  357. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sample_well_profile.csv +0 -0
  358. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sbom.py +0 -0
  359. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seedlink.py +0 -0
  360. {gea_program-0.80.0 → gea_program-0.81.0}/gea/segy.py +0 -0
  361. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic.py +0 -0
  362. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_array.py +0 -0
  363. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_assoc.py +0 -0
  364. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_detect.py +0 -0
  365. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_film.py +0 -0
  366. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_harmonic.py +0 -0
  367. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_qc.py +0 -0
  368. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_response.py +0 -0
  369. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_signature.py +0 -0
  370. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_track.py +0 -0
  371. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_uncertainty.py +0 -0
  372. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_unlisted.py +0 -0
  373. {gea_program-0.80.0 → gea_program-0.81.0}/gea/seismic_watch.py +0 -0
  374. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sensor_swap.py +0 -0
  375. {gea_program-0.80.0 → gea_program-0.81.0}/gea/series_cache.py +0 -0
  376. {gea_program-0.80.0 → gea_program-0.81.0}/gea/service.py +0 -0
  377. {gea_program-0.80.0 → gea_program-0.81.0}/gea/service_life.py +0 -0
  378. {gea_program-0.80.0 → gea_program-0.81.0}/gea/setup_checklist.py +0 -0
  379. {gea_program-0.80.0 → gea_program-0.81.0}/gea/shapefile.py +0 -0
  380. {gea_program-0.80.0 → gea_program-0.81.0}/gea/shell.py +0 -0
  381. {gea_program-0.80.0 → gea_program-0.81.0}/gea/shut_in.py +0 -0
  382. {gea_program-0.80.0 → gea_program-0.81.0}/gea/simulation.py +0 -0
  383. {gea_program-0.80.0 → gea_program-0.81.0}/gea/site_map.py +0 -0
  384. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sla_report.py +0 -0
  385. {gea_program-0.80.0 → gea_program-0.81.0}/gea/slip.py +0 -0
  386. {gea_program-0.80.0 → gea_program-0.81.0}/gea/soak.py +0 -0
  387. {gea_program-0.80.0 → gea_program-0.81.0}/gea/sra.py +0 -0
  388. {gea_program-0.80.0 → gea_program-0.81.0}/gea/store_forward.py +0 -0
  389. {gea_program-0.80.0 → gea_program-0.81.0}/gea/strata_join.py +0 -0
  390. {gea_program-0.80.0 → gea_program-0.81.0}/gea/structure.py +0 -0
  391. {gea_program-0.80.0 → gea_program-0.81.0}/gea/supervisor.py +0 -0
  392. {gea_program-0.80.0 → gea_program-0.81.0}/gea/survey_cmd.py +0 -0
  393. {gea_program-0.80.0 → gea_program-0.81.0}/gea/survey_view.py +0 -0
  394. {gea_program-0.80.0 → gea_program-0.81.0}/gea/telemetry.py +0 -0
  395. {gea_program-0.80.0 → gea_program-0.81.0}/gea/timestamp.py +0 -0
  396. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tls.py +0 -0
  397. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tool_catalog.py +0 -0
  398. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tool_library.py +0 -0
  399. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tool_taxonomy.py +0 -0
  400. {gea_program-0.80.0 → gea_program-0.81.0}/gea/torque_drag.py +0 -0
  401. {gea_program-0.80.0 → gea_program-0.81.0}/gea/transient.py +0 -0
  402. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tray.py +0 -0
  403. {gea_program-0.80.0 → gea_program-0.81.0}/gea/tutorial.py +0 -0
  404. {gea_program-0.80.0 → gea_program-0.81.0}/gea/updates.py +0 -0
  405. {gea_program-0.80.0 → gea_program-0.81.0}/gea/vibration.py +0 -0
  406. {gea_program-0.80.0 → gea_program-0.81.0}/gea/vpn.py +0 -0
  407. {gea_program-0.80.0 → gea_program-0.81.0}/gea/web/reader.html +0 -0
  408. {gea_program-0.80.0 → gea_program-0.81.0}/gea/well3d.py +0 -0
  409. {gea_program-0.80.0 → gea_program-0.81.0}/gea/well_assembler.py +0 -0
  410. {gea_program-0.80.0 → gea_program-0.81.0}/gea/well_records.py +0 -0
  411. {gea_program-0.80.0 → gea_program-0.81.0}/gea/well_report.py +0 -0
  412. {gea_program-0.80.0 → gea_program-0.81.0}/gea/well_test_validation.py +0 -0
  413. {gea_program-0.80.0 → gea_program-0.81.0}/gea/wellplan.py +0 -0
  414. {gea_program-0.80.0 → gea_program-0.81.0}/gea/wellpos.py +0 -0
  415. {gea_program-0.80.0 → gea_program-0.81.0}/gea/winident.py +0 -0
  416. {gea_program-0.80.0 → gea_program-0.81.0}/gea/wits0.py +0 -0
  417. {gea_program-0.80.0 → gea_program-0.81.0}/gea/witsml.py +0 -0
  418. {gea_program-0.80.0 → gea_program-0.81.0}/gea/workspace.py +0 -0
  419. {gea_program-0.80.0 → gea_program-0.81.0}/gea/workspaces.py +0 -0
  420. {gea_program-0.80.0 → gea_program-0.81.0}/gea/x25519.py +0 -0
  421. {gea_program-0.80.0 → gea_program-0.81.0}/gea/xlsx_read.py +0 -0
  422. {gea_program-0.80.0 → gea_program-0.81.0}/gea_program.egg-info/SOURCES.txt +0 -0
  423. {gea_program-0.80.0 → gea_program-0.81.0}/gea_program.egg-info/dependency_links.txt +0 -0
  424. {gea_program-0.80.0 → gea_program-0.81.0}/gea_program.egg-info/entry_points.txt +0 -0
  425. {gea_program-0.80.0 → gea_program-0.81.0}/gea_program.egg-info/requires.txt +0 -0
  426. {gea_program-0.80.0 → gea_program-0.81.0}/gea_program.egg-info/top_level.txt +0 -0
  427. {gea_program-0.80.0 → gea_program-0.81.0}/setup.cfg +0 -0
  428. {gea_program-0.80.0 → gea_program-0.81.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.80.0
3
+ Version: 0.81.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
@@ -483,7 +483,10 @@ a dip across the plan line as well as along it, the hole is placed by
483
483
  minimum curvature through the surveys' azimuths, the corridor the lease
484
484
  and the offset wells leave the hole is in the twin and on the screen's
485
485
  plan view, and the config's model carries the plan's azimuth, the cross
486
- dip and the corridor. Every recommendation, answer and
486
+ dip and the corridor. A vibration index read off the surface torque,
487
+ weight and hook load (since 0.81.0) stands in for the downhole tool a
488
+ string does not carry, and the record says which the agent read. Every
489
+ recommendation, answer and
487
490
  command is on record with its hash, and GEA pulls the records into the
488
491
  well from the **Drill string** tab's card (`gea workspace --path C:\site
489
492
  --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
@@ -837,7 +840,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
837
840
  reader made from the workspace knows the site's key fingerprints, so it
838
841
  says whether a dossier is the site's; it allows no network request, and it
839
842
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
840
- it installed, every release also carries `GEA-Reader-Setup-0.80.0.exe`: GEA
843
+ it installed, every release also carries `GEA-Reader-Setup-0.81.0.exe`: GEA
841
844
  Reader as a Windows program of its own - its own icon and taskbar button,
842
845
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
843
846
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1602,7 +1605,7 @@ attaches the zips to the GitHub release of that tag.
1602
1605
 
1603
1606
  ### The Windows installer
1604
1607
 
1605
- Every release also carries `GEA-Program-Setup-0.80.0.exe` (for 0.80.0): the
1608
+ Every release also carries `GEA-Program-Setup-0.81.0.exe` (for 0.81.0): the
1606
1609
  same Windows kit installed like any Windows program, for the signed-in user
1607
1610
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1608
1611
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1621,7 +1624,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1621
1624
  software deployment:
1622
1625
 
1623
1626
  ```
1624
- GEA-Program-Setup-0.80.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1627
+ GEA-Program-Setup-0.81.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1625
1628
  ```
1626
1629
 
1627
1630
  The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
@@ -444,7 +444,10 @@ a dip across the plan line as well as along it, the hole is placed by
444
444
  minimum curvature through the surveys' azimuths, the corridor the lease
445
445
  and the offset wells leave the hole is in the twin and on the screen's
446
446
  plan view, and the config's model carries the plan's azimuth, the cross
447
- dip and the corridor. Every recommendation, answer and
447
+ dip and the corridor. A vibration index read off the surface torque,
448
+ weight and hook load (since 0.81.0) stands in for the downhole tool a
449
+ string does not carry, and the record says which the agent read. Every
450
+ recommendation, answer and
448
451
  command is on record with its hash, and GEA pulls the records into the
449
452
  well from the **Drill string** tab's card (`gea workspace --path C:\site
450
453
  --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
@@ -798,7 +801,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
798
801
  reader made from the workspace knows the site's key fingerprints, so it
799
802
  says whether a dossier is the site's; it allows no network request, and it
800
803
  leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
801
- it installed, every release also carries `GEA-Reader-Setup-0.80.0.exe`: GEA
804
+ it installed, every release also carries `GEA-Reader-Setup-0.81.0.exe`: GEA
802
805
  Reader as a Windows program of its own - its own icon and taskbar button,
803
806
  Check with GEA Reader on a dossier's right-click menu, fingerprints the client
804
807
  saves kept on that computer, nothing of GEA-Program. `gea help reader`.
@@ -1563,7 +1566,7 @@ attaches the zips to the GitHub release of that tag.
1563
1566
 
1564
1567
  ### The Windows installer
1565
1568
 
1566
- Every release also carries `GEA-Program-Setup-0.80.0.exe` (for 0.80.0): the
1569
+ Every release also carries `GEA-Program-Setup-0.81.0.exe` (for 0.81.0): the
1567
1570
  same Windows kit installed like any Windows program, for the signed-in user
1568
1571
  alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
1569
1572
  It asks for the site workspace (an existing one such as `C:\site` is used as
@@ -1582,7 +1585,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
1582
1585
  software deployment:
1583
1586
 
1584
1587
  ```
1585
- GEA-Program-Setup-0.80.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1588
+ GEA-Program-Setup-0.81.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
1586
1589
  ```
1587
1590
 
1588
1591
  The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.80.0"
126
+ __version__ = "0.81.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -16566,6 +16566,7 @@ def section_dv_driller(tmp: str) -> None:
16566
16566
  time.sleep(0.2)
16567
16567
  s_ov, _ = call("/api/answer", {"what": "override", "by": "tester", "note": "held", "override": {"build_deg_100ft": 0.0, "wob_klb": 25}})
16568
16568
  md = drl.feed.snapshot()["state"]["hole_depth"]
16569
+ drl.cfg["limits"]["vibration_index"] = 5.0 # the section's end alone ends this arming: the vibration index the feed now derives (0.81.0) may cross 1.2 in the shale
16569
16570
  s_long, _ = call("/api/arm", {"by": "tester", "to_md": md + 5000})
16570
16571
  s_arm, armed = call("/api/arm", {"by": "tester", "to_md": md + 150})
16571
16572
  t_end = time.monotonic() + 30
@@ -17011,6 +17012,179 @@ def section_dx_third_dimension(tmp: str) -> None:
17011
17012
  "plan azimuth and cross dip go through" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
17012
17013
 
17013
17014
 
17015
+ def section_dy_vibration(tmp: str) -> None:
17016
+ """Section DY - the vibration index from the feed: the index off the surface channels (a steady feed near zero, a
17017
+ torque swinging as the twin's limit swings it reading the limit, a weight swinging reading lateral, the statistics
17018
+ path equal to the samples path, pooled statistics, a window without torque or weight reading nothing); on the twin
17019
+ the derived index tracking the twin's own; the rig side (the twin as the rig publishing the surface channels and
17020
+ no downhole index, the advisor reading the derived one and saying so, the downhole item winning, a feed with
17021
+ neither reading none, the loop disarming on the derived index, the screen, the help); GEA's side (the lateral
17022
+ file from the self-test export with the statistics, the replay reading the stick-slip stretch over the limit
17023
+ and the advisor easing there, a record without the statistics unjudged, the card)."""
17024
+ import http.cookiejar
17025
+ import importlib
17026
+ import math as _m
17027
+ import urllib.error
17028
+ import urllib.request
17029
+ from . import driller_link as DL
17030
+ from . import edr as E
17031
+ from . import helplib as H
17032
+ from .service import Service, Users
17033
+ from .workspace import Workspace
17034
+ pkg = Path(__file__).parent
17035
+ d = Path(tmp, "dy"); d.mkdir()
17036
+ prog = DL.program()
17037
+ if prog is None:
17038
+ ok(True, "DY the driller's program (gea-driller) is not installed beside GEA in this install; nothing to check here")
17039
+ return
17040
+ if prog["env"] and prog["env"] not in sys.path:
17041
+ sys.path.insert(0, prog["env"])
17042
+ T = importlib.import_module("gea_driller.twin"); V = importlib.import_module("gea_driller.vibration"); P = importlib.import_module("gea_driller.policy")
17043
+ A = importlib.import_module("gea_driller.advisor"); C = importlib.import_module("gea_driller.config"); S = importlib.import_module("gea_driller.service")
17044
+ R = importlib.import_module("gea_driller.rig"); SH = importlib.import_module("gea_driller.shadow")
17045
+ np_ = importlib.import_module("numpy")
17046
+ # -- DY1 the index --------------------------------------------------------------------------------------------------------
17047
+ tt = np_.arange(60)
17048
+ steady = {"torque": 10 + 0.02 * np_.sin(tt), "rpm": 120 + 0 * tt, "wob": 25 + 0.05 * np_.cos(tt), "hkld": 175 - 0.05 * np_.cos(tt), "spp": 2800 + 0 * tt}
17049
+ ss = {"torque": 10 * (1 + 0.48 * np_.sin(2 * _m.pi * tt / 8)), "rpm": 120 + 0 * tt, "wob": 25 + 0 * tt, "hkld": 175 + 0 * tt, "spp": 2800 + 0 * tt}
17050
+ lat = {"torque": 10 + 0 * tt, "rpm": 120 + 0 * tt, "wob": 25 * (1 + 0.24 * np_.sin(2 * _m.pi * tt / 5)), "hkld": 175 - 25 * 0.24 * np_.sin(2 * _m.pi * tt / 5), "spp": 2800 + 0 * tt}
17051
+ v0 = V.index(steady); v1 = V.index(ss); v2 = V.index(lat)
17052
+ v1s = V.index_from_stats(V.stats(ss))
17053
+ pooled = V.index_from_stats(V.combine_stats([V.stats({k: v[:30] for k, v in ss.items()}), V.stats({k: v[30:] for k, v in ss.items()})]))
17054
+ none = V.index({"rpm": 120 + 0 * tt, "spp": 2800 + 0 * tt})
17055
+ short = V.index({k: v[:5] for k, v in ss.items()})
17056
+ # on the twin: the derived index against the twin's own, step by step over twenty scenes
17057
+ tr, de = [], []
17058
+ for sd in range(20):
17059
+ lt = T.Lateral(T.Scene(sd)); o = lt.reset()
17060
+ while not lt.done:
17061
+ o, _, _, inf = lt.step(T.textbook_action(o))
17062
+ if inf.get("conditioning") != "drill":
17063
+ continue
17064
+ smp = [lt.surface_sample() for _ in range(20)]
17065
+ v = V.index({"torque": [x["torque"] for x in smp], "rpm": [x["rpm"] for x in smp], "wob": [x["wob"] for x in smp], "hkld": [x["hookload"] for x in smp], "spp": [x["spp"] for x in smp]})
17066
+ tr.append(lt.vib); de.append(v["index"])
17067
+ tr_, de_ = np_.array(tr), np_.array(de)
17068
+ corr = float(np_.corrcoef(tr_, de_)[0, 1]); agree = float(((tr_ > T.VIB_LIMIT) == (de_ > T.VIB_LIMIT)).mean())
17069
+ c1 = {
17070
+ "steady": v0 is not None and v0["index"] < 0.1,
17071
+ "stick_slip": v1 is not None and abs(v1["index"] - 1.2) < 0.08 and v1["kind"] == "stick-slip" and abs(v1["torque_amplitude"] - 0.48) < 0.03,
17072
+ "lateral": v2 is not None and abs(v2["index"] - 1.2) < 0.1 and v2["kind"] == "lateral" and v2["stick_slip"] < 0.1,
17073
+ "paths": v1s["index"] == v1["index"] and abs(pooled["index"] - v1["index"]) < 0.08,
17074
+ "nothing": none is None and short is None,
17075
+ "twin": len(tr) > 1500 and corr > 0.95 and agree >= 0.95 and float(np_.median(np_.abs(tr_ - de_))) < 0.05,
17076
+ "words": "stick-slip" in V.words(v1, 1.2) and "over the limit" in V.words(v1, 1.0) and "over the limit" not in V.words(v0, 1.2),
17077
+ }
17078
+ failed1 = [k for k, v in c1.items() if not v]
17079
+ ok(not failed1,
17080
+ f"DY1 the vibration index off the surface channels: a steady feed reads {v0['index'] if v0 else 'none'}, a torque swinging ±48% reads {v1['index'] if v1 else 'none'} as stick-slip, "
17081
+ f"a weight swinging ±24% reads {v2['index'] if v2 else 'none'} as lateral, the statistics path equals the samples path and pooled windows agree, a window without torque "
17082
+ f"or weight reads nothing; on twenty twin scenes the derived index tracks the twin's own (correlation {corr:.3f}, the limit's crossings agreeing {100 * agree:.0f}%, "
17083
+ "SIMULATION - the twin's calibration, not a string's)" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
17084
+ # -- DY2 the rig side ---------------------------------------------------------------------------------------------------------
17085
+ shipped = P.Policy.load(S.SHIPPED_POLICY)
17086
+ cfg = json.loads(json.dumps(C.EXAMPLE)); cfg["output"]["dir"] = str(d / "rig"); cfg["status"]["port"] = 0; cfg["status"]["bind"] = "127.0.0.1"
17087
+ cfg["rig"]["transport"] = "sim"; cfg["closed_loop"]["allowed"] = True; cfg["closed_loop"]["stale_s"] = 30
17088
+ cfg = C.check(cfg)
17089
+ try:
17090
+ C.check(json.loads(json.dumps(cfg)) | {"rig": {**cfg["rig"], "vibration_window_s": 2}}); win_refused = False
17091
+ except C.ConfigError:
17092
+ win_refused = True
17093
+ drl = S.Driller(cfg, policy=shipped, twin_seed=11, twin_pace_s=0.6)
17094
+ drl.start()
17095
+ try:
17096
+ t_end = time.monotonic() + 25
17097
+ while time.monotonic() < t_end and len(drl.advisor.history) < 3:
17098
+ time.sleep(0.2)
17099
+ snap = drl.feed.snapshot(); live = drl.live()
17100
+ cur = dict(drl.advisor.history[-1]) if drl.advisor.history else None
17101
+ md = snap["state"].get("hole_depth")
17102
+ rq = urllib.request.Request(drl.url + "/api/arm", data=json.dumps({"by": "tester", "to_md": md + 400}).encode(), headers={"Content-Type": "application/json"}, method="POST")
17103
+ with urllib.request.urlopen(rq, timeout=5) as r_:
17104
+ armed = json.load(r_)
17105
+ drl.cfg["limits"]["vibration_index"] = 0.01 # the limit lowered under the loop: the derived index crosses it at the next look
17106
+ t_end = time.monotonic() + 8
17107
+ while time.monotonic() < t_end and drl.advisor.armed is not None:
17108
+ time.sleep(0.2)
17109
+ drl.cfg["limits"]["vibration_index"] = 1.2
17110
+ last = drl.advisor.arm_log[-1]
17111
+ with urllib.request.urlopen(drl.url + "/live", timeout=5) as r_:
17112
+ screen = r_.read().decode("utf-8")
17113
+ finally:
17114
+ drl.stop()
17115
+ # the downhole item wins; a feed with neither reads none
17116
+ feed = R.Feed(cfg); feed.state.update({"hole_depth": 10500.0, "gamma": 60.0, "continuous_inc": 90.0, "vibration": 1.7}); feed.last_utc = time.time(); feed.connected = True
17117
+ for k in range(30):
17118
+ feed.window.append(float(k), torque=10 * (1 + 0.1 * _m.sin(k)), rpm=120.0, wob=25.0, hkld=175.0, spp=2800.0)
17119
+ v_tool = A.Advisor.vibration_of(feed.snapshot())
17120
+ feed.state["vibration"] = None
17121
+ v_der = A.Advisor.vibration_of(feed.snapshot())
17122
+ feed2 = R.Feed(cfg); feed2.state.update({"hole_depth": 10500.0, "gamma": 60.0}); feed2.last_utc = time.time(); feed2.connected = True
17123
+ v_none = A.Advisor.vibration_of(feed2.snapshot())
17124
+ adv2 = A.Advisor(cfg, shipped, feed2, A.Records(json.loads(json.dumps(cfg)) | {"output": {"dir": str(d / "rig2")}}))
17125
+ rec2 = adv2.decide(feed2.snapshot())
17126
+ decs = [json.loads(l) for l in open(d / "rig" / "decisions.jsonl", encoding="utf-8")]
17127
+ c2 = {
17128
+ "twin_rig": snap["state"].get("torque") is not None and snap["state"].get("hookload") is not None and snap["state"].get("vibration") is None and snap.get("vibration") is not None
17129
+ and snap["vibration"]["index"] > 0 and snap.get("window_n", 0) >= 10 and abs(snap["vibration"]["index"] - drl.feed.lat.vib) < 0.25,
17130
+ "advisor": cur is not None and cur["context"]["vibration_source"] == V.SOURCE and cur["context"]["vibration"] > 0 and any("derived from the surface data" in r_ for r_ in cur["reasons"])
17131
+ and live["vibration"]["source"] == V.SOURCE and live["vibration"]["parts"]["kind"] in ("stick-slip", "lateral"),
17132
+ "wins": v_tool[0] == 1.7 and v_tool[1] == "the downhole tool" and v_der[1] == V.SOURCE and 0 < v_der[0] < 1.0,
17133
+ "none": v_none[0] == 0.0 and v_none[1].startswith("none") and rec2 is not None and any("vibration unread" in r_ for r_ in rec2["reasons"]),
17134
+ "disarms": armed.get("ok") and last["event"] == "disarmed" and "vibration" in last["reason"] and "surface data" in last["reason"],
17135
+ "records": any((x.get("context") or {}).get("vibration_source") == V.SOURCE for x in decs),
17136
+ "screen": "from surface data" in screen and "downhole tool" in screen,
17137
+ "refusal": win_refused,
17138
+ "help": not H.check("driller") and "The vibration index from the feed" in (pkg / "help" / "driller.md").read_text(encoding="utf-8")
17139
+ and "surface" in (pkg / "help" / "tutorial" / "29-driller-rig.md").read_text(encoding="utf-8"),
17140
+ }
17141
+ failed2 = [k for k, v in c2.items() if not v]
17142
+ ok(not failed2,
17143
+ "DY2 the twin as the rig publishes the surface torque, weight and hook load and no downhole index; the feed's window gives the derived index close to the "
17144
+ "twin's own, the advisor reads it and says so in its reasons, the records and the screen; the downhole tool's item wins when it comes, a feed with neither "
17145
+ "reads none and says so; the closed loop disarms on the derived index crossing the limit; a window too short is refused; the help and the tutorial say so"
17146
+ + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
17147
+ # -- DY3 GEA's side: the lateral file with the statistics, the replay over the limit, the card ---------------------------------------
17148
+ ws = Workspace.create(str(d / "ws"), "Pad 3 vibration", actor="tester")
17149
+ exp = E.selftest(str(d), 3000)
17150
+ w = ws.add_well_file(exp["path"], display="Well EDR", actor="tester")
17151
+ lat_csv = str(d / "lat.csv")
17152
+ info = DL.lateral_from_edr(ws, w["id"], lat_csv)
17153
+ head = Path(lat_csv).read_text(encoding="utf-8").splitlines()[0].split(",")
17154
+ rec = DL.shadow(ws, w["id"], actor="tester")
17155
+ sm = rec["summary"]
17156
+ # the twin's lateral with and without the statistics
17157
+ tw_csv = str(d / "tw.csv"); tw_no = str(d / "tw_no.csv")
17158
+ tinfo = SH.twin_lateral(tw_csv, seed=5, act_fn=P.policy_act_fn(shipped)); SH.twin_lateral(tw_no, seed=5, act_fn=P.policy_act_fn(shipped), with_stats=False)
17159
+ r_tw = SH.run(tw_csv, shipped, well="Twin 5"); r_no = SH.run(tw_no, shipped, well="Twin 5")
17160
+ tv = dict(tinfo["true_vibration"]); mds = np_.array(sorted(tv))
17161
+ tvv = np_.array([tv[m_] for m_ in mds])
17162
+ def true_over(md_): # the twin's own index averaged over the 30 ft the replay's window pooled
17163
+ j0, j1 = int(np_.searchsorted(mds, md_ - 30.0)), int(np_.searchsorted(mds, md_, side="right"))
17164
+ return float(tvv[j0:j1].mean()) if j1 > j0 else float("nan")
17165
+ pairs = np_.array([(x["vibration"], true_over(x["md"])) for x in r_tw["decisions"] if x["vibration"] is not None])
17166
+ pairs = pairs[np_.isfinite(pairs[:, 1])]
17167
+ corr_tw = float(np_.corrcoef(pairs[:, 0], pairs[:, 1])[0, 1]) if len(pairs) > 10 else 0.0
17168
+ md_text = Path(ws.reports_dir, rec["report"]["md"]).read_text(encoding="utf-8")
17169
+ app_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
17170
+ c3 = {
17171
+ "lateral_file": all(c in head for c in DL.LATERAL_STATS) and info["vibration_rows"] >= 1000,
17172
+ "over_limit": sm["vibration_in_record"] and sm["vibration_over_limit_pct"] is not None and 5.0 <= sm["vibration_over_limit_pct"] <= 40.0 and sm["vibration_mean"] > 0.3
17173
+ and sm["eased_when_over_pct"] is not None and sm["eased_when_over_pct"] >= 50.0,
17174
+ "report": "stood over the limit" in md_text and "| Vib |" in md_text,
17175
+ "twin_lateral": r_tw["summary"]["vibration_in_record"] and len(pairs) > 50 and corr_tw > 0.7 and float(np_.median(np_.abs(pairs[:, 0] - pairs[:, 1]))) < 0.12,
17176
+ "without": not r_no["summary"]["vibration_in_record"] and r_no["summary"]["vibration_over_limit_pct"] is None and all(x["vibration"] is None for x in r_no["decisions"]),
17177
+ "selftest_export": any(abs(float(r_.split(",")[12]) - 10.0) > 4.0 for r_ in Path(exp["path"]).read_text(encoding="utf-8").splitlines()[1:] if r_.split(",")[12] not in ("",)),
17178
+ "card": "Vibration over limit" in app_src and "eased" in app_src,
17179
+ }
17180
+ failed3 = [k for k, v in c3.items() if not v]
17181
+ ok(not failed3,
17182
+ f"DY3 GEA's lateral file carries the surface channels' statistics per foot ({info['vibration_rows']} feet of them from the self-test export), the replay reads the "
17183
+ f"stick-slip stretch over the limit at {sm['vibration_over_limit_pct'] or 0:.0f}% of the decisions and the advisor eases there {sm['eased_when_over_pct'] or 0:.0f}% of the "
17184
+ f"time, the report says so; on the twin's lateral the replayed index tracks the twin's own (correlation {corr_tw:.2f}); a record without the statistics is unjudged; "
17185
+ "the card carries the column" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
17186
+
17187
+
17014
17188
  def main() -> int:
17015
17189
  print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
17016
17190
  # a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
@@ -17142,6 +17316,7 @@ def main() -> int:
17142
17316
  section_dv_driller(tmp)
17143
17317
  section_dw_shadow(tmp)
17144
17318
  section_dx_third_dimension(tmp)
17319
+ section_dy_vibration(tmp)
17145
17320
  if _FAILS:
17146
17321
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
17147
17322
  for f in _FAILS:
@@ -281,6 +281,11 @@ def wells_with_records(ws) -> List[dict]:
281
281
  # -- shadow mode: a drilled well of this workspace replayed through the advisor ---------------------------------------------
282
282
 
283
283
  LATERAL_COLUMNS = ('md_ft', 'tvd_ft', 'gamma_api', 'wob_klb', 'rpm', 'flow_gpm', 'rop_ft_hr', 'spp_psi', 'hours')
284
+ # per foot, the surface channels' mean and RMS about it over the seconds since the foot before (since 0.81.0): what the
285
+ # driller's vibration index is read off when the string had no downhole tool - the same names the driller's program reads
286
+ LATERAL_STATS = ('torque_mean', 'torque_rms', 'rpm_mean', 'rpm_rms', 'wob_mean', 'wob_rms', 'hkld_mean', 'hkld_rms', 'spp_mean', 'spp_rms')
287
+ _STAT_CH = {'torque': 'torque', 'rpm': 'rpm', 'wob': 'wob', 'hkld': 'hkld', 'spp': 'spp'}
288
+ _STAT_MIN = 5 # seconds of a foot at least; the index pools the feet of a decision
284
289
 
285
290
 
286
291
  def lateral_from_edr(ws, well_id: str, out_csv: str) -> dict:
@@ -296,7 +301,7 @@ def lateral_from_edr(ws, well_id: str, out_csv: str) -> dict:
296
301
  if not src or not E.is_edr(src):
297
302
  raise ValueError(f"{well_id} has no drilling-recorder export (an EDR CSV) under its sources")
298
303
  st = E.read(src)
299
- ch = {k: E._ch(st, k) for k in ('hole', 'tvd', 'gamma', 'wob', 'rpm', 'flow', 'rop', 'spp', 'onb')}
304
+ ch = {k: E._ch(st, k) for k in ('hole', 'tvd', 'gamma', 'wob', 'rpm', 'flow', 'rop', 'spp', 'onb', 'torque', 'hkld')}
300
305
  hole = ch['hole']
301
306
  if hole is None or ch['tvd'] is None:
302
307
  raise ValueError('the export carries no hole depth or no interpolated TVD; the lateral cannot be placed')
@@ -308,32 +313,47 @@ def lateral_from_edr(ws, well_id: str, out_csv: str) -> dict:
308
313
  n = len(hole)
309
314
  rows = []
310
315
  seen = set(); g_acc = []
316
+ s_acc = {k: [] for k in _STAT_CH}
311
317
  for i in range(n):
312
318
  h = hole[i]
313
319
  if h is None or (isinstance(h, float) and (h != h)) or not keep_h[i]:
314
320
  continue
315
321
  if ch['gamma'] is not None and not (ch['gamma'][i] != ch['gamma'][i]):
316
322
  g_acc.append(float(ch['gamma'][i]))
323
+ for k, c in _STAT_CH.items():
324
+ v = _v(ch[c], i)
325
+ if v == v: # not NaN
326
+ s_acc[k].append(v)
317
327
  foot = int(h)
318
328
  if foot in seen:
319
329
  continue
320
330
  seen.add(foot)
321
331
  tvd = ch['tvd'][i]
322
- rows.append({'md_ft': float(h), 'tvd_ft': float(tvd) if not (tvd != tvd) else float('nan'),
323
- 'gamma_api': float(sorted(g_acc)[len(g_acc) // 2]) if g_acc else float('nan'),
324
- 'wob_klb': _v(ch['wob'], i), 'rpm': _v(ch['rpm'], i), 'flow_gpm': _v(ch['flow'], i), 'rop_ft_hr': _v(ch['rop'], i), 'spp_psi': _v(ch['spp'], i),
325
- 'hours': float(secs[i]) / 3600.0})
326
- g_acc = []
332
+ row = {'md_ft': float(h), 'tvd_ft': float(tvd) if not (tvd != tvd) else float('nan'),
333
+ 'gamma_api': float(sorted(g_acc)[len(g_acc) // 2]) if g_acc else float('nan'),
334
+ 'wob_klb': _v(ch['wob'], i), 'rpm': _v(ch['rpm'], i), 'flow_gpm': _v(ch['flow'], i), 'rop_ft_hr': _v(ch['rop'], i), 'spp_psi': _v(ch['spp'], i),
335
+ 'hours': float(secs[i]) / 3600.0}
336
+ for k in _STAT_CH:
337
+ a = s_acc[k]
338
+ if len(a) >= _STAT_MIN:
339
+ m = sum(a) / len(a)
340
+ row[f'{k}_mean'] = m; row[f'{k}_rms'] = (sum((x - m) ** 2 for x in a) / len(a)) ** 0.5
341
+ else:
342
+ row[f'{k}_mean'] = float('nan'); row[f'{k}_rms'] = float('nan')
343
+ rows.append(row)
344
+ g_acc = []; s_acc = {k: [] for k in _STAT_CH}
327
345
  if len(rows) < 100:
328
346
  raise ValueError(f'the export yields only {len(rows)} feet of new hole; a lateral is thousands')
329
347
  rows.sort(key=lambda r: r['md_ft'])
330
348
  os.makedirs(os.path.dirname(out_csv), exist_ok=True)
349
+ cols = list(LATERAL_COLUMNS) + list(LATERAL_STATS)
331
350
  with open(out_csv, 'w', encoding='utf-8', newline='') as f:
332
- w = _csv.DictWriter(f, fieldnames=list(LATERAL_COLUMNS)); w.writeheader()
351
+ w = _csv.DictWriter(f, fieldnames=cols); w.writeheader()
333
352
  for r in rows:
334
- w.writerow({c: ('' if (isinstance(r[c], float) and r[c] != r[c]) or r[c] is None else f'{r[c]:.3f}') for c in LATERAL_COLUMNS})
353
+ w.writerow({c: ('' if (isinstance(r[c], float) and r[c] != r[c]) or r[c] is None else f'{r[c]:.3f}') for c in cols})
335
354
  rows.sort(key=lambda r: r['md_ft'])
336
355
  return {'rows': len(rows), 'source': src, 'md_from': rows[0]['md_ft'], 'md_to': rows[-1]['md_ft'], 'gamma_rows': sum(1 for r in rows if r['gamma_api'] == r['gamma_api']),
356
+ 'vibration_rows': sum(1 for r in rows if r['torque_mean'] == r['torque_mean'] or r['wob_mean'] == r['wob_mean']),
337
357
  'seconds': int(n), 'excluded_rows': int((~keep_h).sum()), 'depth_events': {k: len(v) for k, v in de.items() if isinstance(v, list)}}
338
358
 
339
359
 
@@ -748,8 +748,10 @@ def selftest(tmp: str, rows_per_section: int = 3000) -> dict:
748
748
  if on:
749
749
  depth += 600.0 / 3600.0 # 600 ft/h while on bottom (a self-test cadence, not a rig's)
750
750
  tvd = depth if depth < 2000.0 else 2000.0 + (depth - 2000.0) * 0.02 # a lateral past 2,000 ft
751
+ # a stretch of stick-slip in the lateral: the surface torque swinging ±60% with an eight-second period (since 0.81.0)
752
+ tq = 10.0 * (1.0 + 0.6 * math.sin(2 * math.pi * i / 8.0)) if (s == 2 and 1000 <= i < 2000 and on) else 10.0
751
753
  row = [t.strftime('%Y/%m/%d'), t.strftime('%H:%M:%S'), f'{depth:.1f}', f'{depth - (0 if on else 30):.1f}', '600.00' if on else '0.00',
752
- '20.0' if on else '0.0', '60.00' if on else '0.00', '2500.00', '150.0', '400.00', '500.00', '50.00', '10.000', str(on),
754
+ '20.0' if on else '0.0', '60.00' if on else '0.00', '2500.00', '150.0', '400.00', '500.00', '50.00', f'{tq:.3f}', str(on),
753
755
  '-999.25' if s == 0 else f'{(45.0 if depth < 2300.0 else 115.0) + (i % 7):.2f}', '100', '0.00' if i % 500 == 0 else '45.00', '' if (i % 10 == 0) else f'{tvd:.2f}']
754
756
  w.writerow(row); t += timedelta(seconds=1)
755
757
  st = read(p)
@@ -2,12 +2,12 @@
2
2
 
3
3
  > A program on the rig PC that reads the rig's own feed and the pre-drill model, places the bit in the layer with a position filter, and, every 30 ft, recommends in the driller's units what to do next - a policy trained by reinforcement learning in a physics twin of the lateral - with the driller's answer, every command, and the records pulled into GEA.
4
4
 
5
- **The command**: on the rig PC, `GEA-Driller-0.80.0.tar.gz` from the release (or the kit's `installers` folder, fetched on the Audit / Update tab): unpack it and run `sudo sh install.sh` on Linux or `install.cmd` on Windows, once; edit its config - the EDR's WITS0 feed (`tcp`, the host and port; `serial`, the COM port), the pre-drill model (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the deep-resistivity tool, the heel's MD and TVD), the tool's cap, the limits - and restart it. The driller's screen is at port 8790 of the rig PC: `http://192.168.1.60:8790/live`. It shows the section with the model's layer window, the hole drilled through it and - since 0.78.0 - the **position filter**'s band: where the layer is from the readings, as a geosteerer places it (a particle filter over the layer's offset from the model, its dip error and its thickness, moved every decision and kept to the guesses that explain the gamma and the deep-resistivity distance), with the probability the bit is in the layer, above or below it and the distance to the top and the base with its spread, sixty feet ahead; the agent reads the same estimate, and so does the textbook driller it is judged against. Then the recommendation in words - *Build +1.5°/100 ft (toolface up, 25% steering); 25 klb WOB, 120 rpm, 500 gpm* - with its reasons (what the deep-resistivity tool says, the gamma against the model's values, the model's bracket, the limits) and the confidence of each choice, the rig's numbers against the limits, and **Accept**, **Reject** or **Did something else…** with the operator's name. In GEA: the **Drill string** tab's card **GEA Driller** - the rig PC's address and the well, **Pull**: the records come in checked against their hashes, and the table says how many decisions, accepted, rejected, done otherwise, the hole under advice, the armed sections and the commands. **Open the driller's screen** opens the rig PC's screen from its address. Before there is a rig PC: **Start the twin as the rig** runs the driller's program on this computer with a scene drilling itself under the agent - **Open its screen** is the driller's screen with the twin behind it, labelled SIMULATION - and **Pull from it** brings its records in; **Stop it** closes them. **Shadow a drilled well** (since 0.79.0): a well of this workspace with a drilling-recorder export is replayed through the advisor - every 30 ft the agent sees what the rig had shown to that point and nothing past it, and its recommendation is set beside what the record did next: the build actually made over the following 90 ft, the weight, speed and flow used, and at each stretch the gamma marks as out of the layer, whether the advisor called the way back at the first reading. The report, **SHADOW MODE**, is under the well's reports with a drawing of the lateral against the layer; the layer model is read off the well's own gamma in hindsight and says so - and grades how well it fits the well (good, fair, poor: a well steered to a rock that is not the low gamma reads poor, and the agent's calls against a poor model mean little) - unless the site's pre-drill model is given: a file `wells\Well-30636033\driller\model.json` with the config's `model` block (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the heel's MD and TVD) is used whenever it is there (`gea workspace --path C:\site --action driller-shadow --well Well-30636033`). The export is read on this computer and nothing of it leaves it. Agreement with the driller says the two would have done alike, not that either was right. **The third dimension** (since 0.80.0): the lateral has an azimuth. The config's model carries the plan's azimuth (`plan_azimuth_deg`; empty, the first survey's at the heel is taken), the layer's dip across the plan line (`cross_dip_deg`, positive deepening to the right), the corridor the hole may run in to the right and left of the plan line (`corridor_ft`, the lease line and the offset wells) and where the heel sits across it (`heel_offset_ft`); the feed's surveys and the continuous azimuth (WITS item 0832, or the config's mapping) place the bit by minimum curvature along the plan, right of its line and in depth, and the screen draws the plan view - the corridor as a band, the hole against the plan line - under the section. The recommendation gains the aim - where to point the azimuth, along the plan or 4° left or right of it, and the turn that asks from where the hole points: *Build +1.5°/100 ft and aim 4° right of the plan (azimuth 44.0°), turning right 2.0°/100 ft (toolface 53°, 42% steering)* - with the build and the turn held together inside the DLS limit, and **Did something else…** takes the aim, or the turn made instead; the position filter carries the cross dip and reads it only when the hole moves across the plan line, leaving the model's value standing until then. In the twin the layer is a surface, the faults have a strike, the tool walks, and a hole that leaves the corridor by 150 ft is lost; the agent is judged on the hole in the corridor as well as in the layer (`gea-driller evaluate` prints both). Shadow mode reads the record's `azimuth_deg` column when it has one and sets the turn the advisor would have asked beside the turn the record made; without it the record's turns are not judged, and the report says so. Over a cellular modem the rig PC joins GEA-VPN as a member of kind `driller` and GEA pulls from `http://10.77.0.4:8790`. The closed loop: `closed_loop.allowed` in the rig PC's config puts the switch on its screen; an operator arms it by name for one section of at most 500 ft (**Arm for this section**), every decision then goes to the downlink as a command, and the loop disarms itself on a stale feed, a crossed limit, the section's end or **Disarm now** - and this version's only downlink is the null one, which keeps every command on record and sends none, because no vendor's downlink protocol ships with it. From a terminal: `gea workspace --path C:\site --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`; on the rig PC `gea-driller sim --seed 7 --pace 3 --port 8790`, `gea-driller evaluate --scenes 20`, `gea-driller train --seconds 600 --out policy.json`, `gea-driller selftest`.
5
+ **The command**: on the rig PC, `GEA-Driller-0.81.0.tar.gz` from the release (or the kit's `installers` folder, fetched on the Audit / Update tab): unpack it and run `sudo sh install.sh` on Linux or `install.cmd` on Windows, once; edit its config - the EDR's WITS0 feed (`tcp`, the host and port; `serial`, the COM port), the pre-drill model (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the deep-resistivity tool, the heel's MD and TVD), the tool's cap, the limits - and restart it. The driller's screen is at port 8790 of the rig PC: `http://192.168.1.60:8790/live`. It shows the section with the model's layer window, the hole drilled through it and - since 0.78.0 - the **position filter**'s band: where the layer is from the readings, as a geosteerer places it (a particle filter over the layer's offset from the model, its dip error and its thickness, moved every decision and kept to the guesses that explain the gamma and the deep-resistivity distance), with the probability the bit is in the layer, above or below it and the distance to the top and the base with its spread, sixty feet ahead; the agent reads the same estimate, and so does the textbook driller it is judged against. Then the recommendation in words - *Build +1.5°/100 ft (toolface up, 25% steering); 25 klb WOB, 120 rpm, 500 gpm* - with its reasons (what the deep-resistivity tool says, the gamma against the model's values, the model's bracket, the limits) and the confidence of each choice, the rig's numbers against the limits, and **Accept**, **Reject** or **Did something else…** with the operator's name. In GEA: the **Drill string** tab's card **GEA Driller** - the rig PC's address and the well, **Pull**: the records come in checked against their hashes, and the table says how many decisions, accepted, rejected, done otherwise, the hole under advice, the armed sections and the commands. **Open the driller's screen** opens the rig PC's screen from its address. Before there is a rig PC: **Start the twin as the rig** runs the driller's program on this computer with a scene drilling itself under the agent - **Open its screen** is the driller's screen with the twin behind it, labelled SIMULATION - and **Pull from it** brings its records in; **Stop it** closes them. **Shadow a drilled well** (since 0.79.0): a well of this workspace with a drilling-recorder export is replayed through the advisor - every 30 ft the agent sees what the rig had shown to that point and nothing past it, and its recommendation is set beside what the record did next: the build actually made over the following 90 ft, the weight, speed and flow used, and at each stretch the gamma marks as out of the layer, whether the advisor called the way back at the first reading. The report, **SHADOW MODE**, is under the well's reports with a drawing of the lateral against the layer; the layer model is read off the well's own gamma in hindsight and says so - and grades how well it fits the well (good, fair, poor: a well steered to a rock that is not the low gamma reads poor, and the agent's calls against a poor model mean little) - unless the site's pre-drill model is given: a file `wells\Well-30636033\driller\model.json` with the config's `model` block (the target layer's top TVD at the heel, its thickness and dip, the gamma in, above and below, the heel's MD and TVD) is used whenever it is there (`gea workspace --path C:\site --action driller-shadow --well Well-30636033`). The export is read on this computer and nothing of it leaves it. Agreement with the driller says the two would have done alike, not that either was right. **The third dimension** (since 0.80.0): the lateral has an azimuth. The config's model carries the plan's azimuth (`plan_azimuth_deg`; empty, the first survey's at the heel is taken), the layer's dip across the plan line (`cross_dip_deg`, positive deepening to the right), the corridor the hole may run in to the right and left of the plan line (`corridor_ft`, the lease line and the offset wells) and where the heel sits across it (`heel_offset_ft`); the feed's surveys and the continuous azimuth (WITS item 0832, or the config's mapping) place the bit by minimum curvature along the plan, right of its line and in depth, and the screen draws the plan view - the corridor as a band, the hole against the plan line - under the section. The recommendation gains the aim - where to point the azimuth, along the plan or 4° left or right of it, and the turn that asks from where the hole points: *Build +1.5°/100 ft and aim 4° right of the plan (azimuth 44.0°), turning right 2.0°/100 ft (toolface 53°, 42% steering)* - with the build and the turn held together inside the DLS limit, and **Did something else…** takes the aim, or the turn made instead; the position filter carries the cross dip and reads it only when the hole moves across the plan line, leaving the model's value standing until then. In the twin the layer is a surface, the faults have a strike, the tool walks, and a hole that leaves the corridor by 150 ft is lost; the agent is judged on the hole in the corridor as well as in the layer (`gea-driller evaluate` prints both). Shadow mode reads the record's `azimuth_deg` column when it has one and sets the turn the advisor would have asked beside the turn the record made; without it the record's turns are not judged, and the report says so. **The vibration index from the feed** (since 0.81.0): a rig without a downhole vibration tool left the agent blind to the stick-slip and the whirl it was trained to ease, and the closed loop's vibration limit could never trip. Now the rig PC reads an index off the surface channels every EDR sends: over the last minute (`rig.vibration_window_s`), the surface torque's RMS about its mean as a fraction of the mean - the measure the Drill string page calls the oscillation index - times root two for the amplitude, and the same of the weight on bit and the hook load; stick-slip is the torque amplitude over 0.4, lateral vibration the weight amplitude over 0.2 (the twin's scale, where 1.2 is the limit), and the index is the larger. The downhole tool's item (WITS 0830) is taken instead whenever it comes, and every decision records which it read: the tile on the screen says *downhole tool* or *from surface data, stick-slip*, the reasons say *vibration 1.35 derived from the surface data (stick-slip, the surface torque swinging ±54%) over the limit 1.2*, and the limit disarms the loop on either. A surface proxy, labelled; on the twin as the rig it tracks the twin's own index within a few hundredths. The lateral file GEA writes for shadow mode carries, per foot, the surface channels' mean and RMS over the seconds of that foot (`torque_mean`, `torque_rms`, `wob_mean`, `wob_rms`, `hkld_mean`, `hkld_rms`, `rpm_mean`, `rpm_rms`, `spp_mean`, `spp_rms`), the replay reads the index off them for every decision, and the report says how often it stood over the limit and how often the advisor asked for less weight or more speed there than the record used; a record without torque or weight statistics says so and the advisor sees none. Over a cellular modem the rig PC joins GEA-VPN as a member of kind `driller` and GEA pulls from `http://10.77.0.4:8790`. The closed loop: `closed_loop.allowed` in the rig PC's config puts the switch on its screen; an operator arms it by name for one section of at most 500 ft (**Arm for this section**), every decision then goes to the downlink as a command, and the loop disarms itself on a stale feed, a crossed limit, the section's end or **Disarm now** - and this version's only downlink is the null one, which keeps every command on record and sends none, because no vendor's downlink protocol ships with it. From a terminal: `gea workspace --path C:\site --action driller-pull --box http://192.168.1.60:8790 --well SWD-1`; on the rig PC `gea-driller sim --seed 7 --pace 3 --port 8790`, `gea-driller evaluate --scenes 20`, `gea-driller train --seconds 600 --out policy.json`, `gea-driller selftest`.
6
6
 
7
7
  **What it writes**: on the rig PC, `decisions.jsonl` (every observation, recommendation, confidence, reasons and answer), `commands.jsonl` (every arming, command and disarming with its reason) and `surveys.csv`, each with a `.sha256` beside it, and `manifest.json`. In GEA, `wells\SWD-1\driller\` holds the same files as pulled, `manifest.json` and `last_pull.json` with the summary; the audit lines `driller.pull`, `driller.sim_start`, `driller.sim_stop`. The twin as the rig writes under `field\sim-driller\data`.
8
8
 
9
9
  **The number to check**: on the rig PC's screen, the feed's age (a decision is made only on a live feed) and, in GEA's table, accepted against rejected and done otherwise - an agent whose advice is rejected more than taken is not helping, and the records say so. For the agent itself, `gea-driller evaluate` prints the policy against a textbook driller on twenty held-out twin scenes - the hole in the layer, the sweet spot, feet a day, dogleg, stuck pipe, losses - labelled SIMULATION; the self-test refuses a policy that does not beat the textbook.
10
10
 
11
- **What this page will not call a measurement**: the twin's figures are a simulation's, however many scenes, and say nothing of a real formation; a recommendation is the agent's reading of the feed, the model and the filter's estimate, not a survey; the filter's band is a probability, not a log, and the hole's position on its screen is projected from the surveys and the continuous inclination and azimuth, not measured at the bit, and its offset from the plan line inherits every survey's azimuth error; the hole-cleaning and balling the agent reasons from are the model's estimates; and "commands sent" is zero in this version by construction.
11
+ **What this page will not call a measurement**: the twin's figures are a simulation's, however many scenes, and say nothing of a real formation; a recommendation is the agent's reading of the feed, the model and the filter's estimate, not a survey; the filter's band is a probability, not a log, and the hole's position on its screen is projected from the surveys and the continuous inclination and azimuth, not measured at the bit, and its offset from the plan line inherits every survey's azimuth error; the hole-cleaning and balling the agent reasons from are the model's estimates; the vibration index read off the surface data is a proxy for what a downhole tool would measure, calibrated on the twin, not on a string; and "commands sent" is zero in this version by construction.
12
12
 
13
13
  Related: `gea help drillstring`, `gea help recorder`, `gea help vpn`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  > GEA-Program-Setup: the program installed for you like any Windows program - a window of its own, an icon in the notification area, Start-menu and desktop shortcuts, an Add/Remove Programs entry, upgrades in place - with no administrator rights and the site's data left where it is.
4
4
 
5
- **The command**: download the setup from the release on GitHub (`GEA-Program-Setup-0.80.0.exe` for this version) and run it. It installs for you alone, under `%LOCALAPPDATA%\Programs\GEA-Program`, and asks for the site workspace - the folder that holds the wells, reports, records, accounts and keys. An existing one such as `C:\site` is used exactly as it is, its name included; for a new one (by default `%LOCALAPPDATA%\GEA-Program\site`) it also asks the site's name, which heads every report, and makes the workspace with it (left empty, the workspace is named after its folder; an administrator renames the site in Administration's site settings). Then the Start menu's **GEA-Program** (and the desktop shortcut) starts the control panel when it is not running and opens it in a window of its own. A newer setup installs over the older one: it stops the control panel, replaces the program, keeps the workspace and the choices made before. For a site's software deployment: `GEA-Program-Setup-0.80.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"` (`/SITENAME` names a workspace the setup makes; one that exists keeps its own name). From a terminal: `gea launch` does what the shortcut does, `gea launch --selftest` says what it would do, `gea tray --selftest` checks the icon.
5
+ **The command**: download the setup from the release on GitHub (`GEA-Program-Setup-0.81.0.exe` for this version) and run it. It installs for you alone, under `%LOCALAPPDATA%\Programs\GEA-Program`, and asks for the site workspace - the folder that holds the wells, reports, records, accounts and keys. An existing one such as `C:\site` is used exactly as it is, its name included; for a new one (by default `%LOCALAPPDATA%\GEA-Program\site`) it also asks the site's name, which heads every report, and makes the workspace with it (left empty, the workspace is named after its folder; an administrator renames the site in Administration's site settings). Then the Start menu's **GEA-Program** (and the desktop shortcut) starts the control panel when it is not running and opens it in a window of its own. A newer setup installs over the older one: it stops the control panel, replaces the program, keeps the workspace and the choices made before. For a site's software deployment: `GEA-Program-Setup-0.81.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"` (`/SITENAME` names a workspace the setup makes; one that exists keeps its own name). From a terminal: `gea launch` does what the shortcut does, `gea launch --selftest` says what it would do, `gea tray --selftest` checks the icon.
6
6
 
7
7
  **The window**: Microsoft Edge's app window (`msedge --app=`: the control panel with no tabs and no address bar, its own button on the taskbar, which shows the program's derrick and pins as GEA-Program, not as Edge), with a browser profile of its own (`%LOCALAPPDATA%\GEA-Program\window`, no extensions; the first time, Edge may say it signed that profile in to your Microsoft account - Got it), else Google Chrome's, else a tab in the default browser. Where the browser keeps no cookies (its settings or a policy block them), the sign-in page says so and the control panel holds the sign-in itself, in the window's address, until the window is closed. The control panel itself runs with no window of its own: `gea supervise` keeps it running in the background, starts it again when it asks for a restart, and writes everything it would have shown in a console - the start, the sign-ins, the jobs, a stop and why - to `records\console.log` in the workspace. No PowerShell or console window opens. The kit's `start-dashboard.cmd` still runs it in a console window, for a site that wants to watch it there.
8
8
 
@@ -18,7 +18,7 @@
18
18
 
19
19
  **The number to check**: Add/Remove Programs lists GEA-Program with the version you installed; `gea doctor --workspace C:\site` ends with `nothing blocks serving`; the Start menu's **Verify GEA-Program** runs the acceptance gate from the installation and ends with `[ACCEPTANCE] OK - N checks passed`. The release's build installs, upgrades and uninstalls the setup silently before it is published, with the control panel running, and checks the workspace untouched afterwards.
20
20
 
21
- **Signed**: when the publisher's code-signing certificate is configured for the build, the setup is signed with it (Authenticode, timestamped) and Windows names the publisher; until then it ships unsigned and Windows SmartScreen says "unknown publisher" (More info, then Run anyway). The build's provenance holds either way: `gh attestation verify GEA-Program-Setup-0.80.0.exe -R Daniel8Murphy0007/GEA-Program`. The uninstaller the setup leaves behind is Inno Setup's own and is not signed separately.
21
+ **Signed**: when the publisher's code-signing certificate is configured for the build, the setup is signed with it (Authenticode, timestamped) and Windows names the publisher; until then it ships unsigned and Windows SmartScreen says "unknown publisher" (More info, then Run anyway). The build's provenance holds either way: `gh attestation verify GEA-Program-Setup-0.81.0.exe -R Daniel8Murphy0007/GEA-Program`. The uninstaller the setup leaves behind is Inno Setup's own and is not signed separately.
22
22
 
23
23
  **What this page will not call a measurement**: the icon's running or stopped is whether the control panel's port answers on this computer, read every three seconds - not whether every patch, job or report behind it is healthy (Home and the Verification page say that).
24
24
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  **The command**: Reports tab -> Signed dossiers -> **Download GEA Reader for your clients**, or `gea reader --workspace C:\site --out C:\site\GEA-Reader.html`. Send the file once, by any channel (email, a USB stick, the client's portal); send the site's key fingerprint separately - by phone, email or in the contract - as for any dossier. The client opens GEA-Reader.html, drops a dossier on it (or chooses it), and reads the verdict: **Valid** (signed with the site's key, or with a newer key the site's key handed over to), **Valid, but signed by a key you were not given**, or **Not valid** with the reason. Below the verdict: each check, the signer's fingerprint, the key hand-overs, and every file the dossier holds - a report opens in the page as it was signed, a PDF in the browser's own viewer, a table or a log as text, and any file can be saved. A dossier that lists source records by hash without carrying them lets the client choose their copies and checks each against its hash.
6
6
 
7
- **The program**: for a client who wants it installed, **GEA-Reader-Setup-0.80.0.exe** on the release page installs GEA Reader as a Windows program of its own, for the signed-in user, with no administrator rights and nothing of GEA-Program: GEA Reader in the Start menu and on the desktop with its own icon (a white page with a green seal, on blue) and its own taskbar button, and **Check with GEA Reader** on the right-click menu of .zip files (on Windows 11, under Show more options), which opens the dossier at once. It opens the same page in Microsoft Edge's app window with a browser profile of its own (`%LOCALAPPDATA%\GEA-Reader\window`), so a fingerprint the client saves - **Remember this fingerprint**, with whose it is - stays on that computer, and every later dossier signed with that key reads **Valid** with the name the client gave it. `GEA-Reader-portable-0.80.0.zip` is the same program to unzip and run (`GEA-Reader.cmd`). `python\python.exe -m gea_reader --selftest`, in the installed folder, checks the page, the icon, the taskbar identity and the hand-over of a dossier without opening a window.
7
+ **The program**: for a client who wants it installed, **GEA-Reader-Setup-0.81.0.exe** on the release page installs GEA Reader as a Windows program of its own, for the signed-in user, with no administrator rights and nothing of GEA-Program: GEA Reader in the Start menu and on the desktop with its own icon (a white page with a green seal, on blue) and its own taskbar button, and **Check with GEA Reader** on the right-click menu of .zip files (on Windows 11, under Show more options), which opens the dossier at once. It opens the same page in Microsoft Edge's app window with a browser profile of its own (`%LOCALAPPDATA%\GEA-Reader\window`), so a fingerprint the client saves - **Remember this fingerprint**, with whose it is - stays on that computer, and every later dossier signed with that key reads **Valid** with the name the client gave it. `GEA-Reader-portable-0.81.0.zip` is the same program to unzip and run (`GEA-Reader.cmd`). `python\python.exe -m gea_reader --selftest`, in the installed folder, checks the page, the icon, the taskbar identity and the hand-over of a dossier without opening a window.
8
8
 
9
9
  **What it writes**: the one file, GEA-Reader.html (about 40 KB): the checks, written in the page's own script - Ed25519 (RFC 8032) in its own arithmetic, SHA-256 from the browser - and, when made from a workspace, the site's name and the fingerprints of every key it has signed with (the current one and each retired one from the key history: public halves only; the signing key never leaves `keys\`). The audit log records each download (`reader.download`) and each `gea reader` (`reader.write`) with the fingerprints the reader carried. The reader page writes nothing on the client's computer but the fingerprints a client saves (in the browser's storage for the page): it reads the zip it is given, in memory, and a saved copy goes where the client's browser saves downloads. The installed program also writes the page it opens to `%LOCALAPPDATA%\GEA-Reader\page` (with the dossier inside it when one was right-clicked; removed ten minutes later) and its right-click entry under the user's own registry keys, removed with the program.
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > GEA Recorder is the program on the pad: a Raspberry Pi in a sealed box that records the ground channels (geophones, accelerometers, electrode dipoles) through a 24-bit ADC and the rig's WITS0 feed, every sample on one GPS-disciplined clock, into hourly miniSEED files with a SHA-256 beside each and a manifest, and serves one status page on the pad network. Nothing to type: power it and it records. GEA pulls its files in and makes stations of them.
4
4
 
5
- **The command**: the **Seismic** tab, the card **Field recorder**: the box's address on the pad network (`http://192.168.1.50:8780` - the status page shows the address) or the folder of the USB mirror carried to the office, a station name if the site's is not wanted, then **Pull** (a job). GEA fetches the manifest, downloads every file it does not have, checks each against its SHA-256, and makes or updates two stations: the array of the ground-motion sensors (band 8-80 Hz, the sensors' positions from the box's config) and the electrode station (0.01-5 Hz); each sensor's hours are joined in order into one record, nothing re-sampled or filtered. Pull again later: only the new hours come across, and the stations are updated in place. From a terminal: `gea workspace --path C:\site --action field-pull --box http://192.168.1.50:8780`. On the box: `gea-recorder status`, `gea-recorder selftest`; `sudo sh kiosk.sh` once puts the live view full-screen on a monitor on the box's HDMI port from boot - RECORDING in green or what is wrong in red, the clock, the rig's depth, every channel's last minute and the ground sensors' spectrogram, nothing to press - and the same view is at `/live` on the box's page from any browser on the pad network; `sudo sh install.sh` once, from the release's `GEA-Recorder-0.80.0.tar.gz`; the box's README has the parts list, the wiring and the three chrony lines for the GPS clock.
5
+ **The command**: the **Seismic** tab, the card **Field recorder**: the box's address on the pad network (`http://192.168.1.50:8780` - the status page shows the address) or the folder of the USB mirror carried to the office, a station name if the site's is not wanted, then **Pull** (a job). GEA fetches the manifest, downloads every file it does not have, checks each against its SHA-256, and makes or updates two stations: the array of the ground-motion sensors (band 8-80 Hz, the sensors' positions from the box's config) and the electrode station (0.01-5 Hz); each sensor's hours are joined in order into one record, nothing re-sampled or filtered. Pull again later: only the new hours come across, and the stations are updated in place. From a terminal: `gea workspace --path C:\site --action field-pull --box http://192.168.1.50:8780`. On the box: `gea-recorder status`, `gea-recorder selftest`; `sudo sh kiosk.sh` once puts the live view full-screen on a monitor on the box's HDMI port from boot - RECORDING in green or what is wrong in red, the clock, the rig's depth, every channel's last minute and the ground sensors' spectrogram, nothing to press - and the same view is at `/live` on the box's page from any browser on the pad network; `sudo sh install.sh` once, from the release's `GEA-Recorder-0.81.0.tar.gz`; the box's README has the parts list, the wiring and the three chrony lines for the GPS clock.
6
6
 
7
7
  **Before there is a Pi**: on the same card, **Start the simulated box**: the recorder's own program runs on this computer with its test signal in place of the ADC (a process of its own, its files under `field\sim-box\` in the workspace, its page on port 8781), **Open its monitor** shows the live screen the attendant will see, **Pull from it** brings its files in as stations, **Stop it** closes every file and lists them. **Open the box's monitor** opens any real box's live screen from its address. The kit and the setup install the recorder's program beside GEA for this; a pip install adds it with `pip install gea-recorder`. **From the office, over the internet**: GEA-VPN (`gea help vpn`, Administration) gives every box a private address the office pulls from (`http://10.77.0.3:8780`) through a tunnel from the pad's cellular modem; the box's zip from that card holds `vpn.sh`, run once on the Pi.
8
8
 
@@ -5,10 +5,10 @@ Takes: 15 minutes
5
5
  > The program installed like any Windows program, with the site's folder chosen once.
6
6
 
7
7
  ## Before you start
8
- You need a Windows PC that will stay on while the site is watched (the office machine, or the doghouse PC), and the setup file for this version, `GEA-Program-Setup-0.80.0.exe`, from the release page on GitHub. No administrator rights are needed: the program installs for you alone.
8
+ You need a Windows PC that will stay on while the site is watched (the office machine, or the doghouse PC), and the setup file for this version, `GEA-Program-Setup-0.81.0.exe`, from the release page on GitHub. No administrator rights are needed: the program installs for you alone.
9
9
 
10
10
  ## Steps
11
- 1. Double-click `GEA-Program-Setup-0.80.0.exe`. If Windows asks whether to run it, choose **Run** - the setup is published by the site, not by a store.
11
+ 1. Double-click `GEA-Program-Setup-0.81.0.exe`. If Windows asks whether to run it, choose **Run** - the setup is published by the site, not by a store.
12
12
  2. The setup asks for the **site workspace**: the one folder that will hold the wells, the reports, the records, the accounts and the keys. For a new site keep the default or type `C:\site`. For a workspace that already exists, point at it - it is used exactly as it is, its name included.
13
13
  3. For a new workspace it asks the **site's name** (`Pad 3`). This name heads every report the program writes; an administrator can change it later in Administration, site settings.
14
14
  4. Tick the desktop shortcut and finish. The setup puts **GEA-Program** in the Start menu and an icon in the notification area by the clock.
@@ -8,7 +8,7 @@ Takes: 20 minutes
8
8
  1. On **Reports**, **Signed dossiers**: **Sign a dossier for the pad**, or one of the wells (the operator role). Tick *embed the source records* to carry the drilling records themselves rather than their hashes. The dossier is a zip: the reports as they stand, the declarations behind them, the audit log, the source records' hashes, the site's Ed25519 signature, and a checker inside (`verify_dossier.py`, plain Python).
9
9
  2. **Check** re-checks a dossier this site signed against the workspace as it now stands; a workspace that no longer matches a signed dossier raises an alert. *Check a dossier someone sent you* checks an uploaded one.
10
10
  3. **Download GEA Reader for your clients**: one HTML file. Send it to the client once by any channel - email, a USB stick, their portal. Send the site's **key fingerprint** separately - by phone, or in the contract - as for any dossier; the card shows it.
11
- 4. The client opens `GEA-Reader.html` in any current browser, offline, and drops a dossier on it. The verdict: **Valid** (signed with the site's key, or a newer key the site's key handed over to), **Valid, but signed by a key you were not given**, or **Not valid** with the reason. Below it, every file the dossier holds: a report opens in the page as it was signed, a PDF in the browser's own viewer. A client who wants it installed, with a right-click **Check with GEA Reader** on dossiers, gets `GEA-Reader-Setup-0.80.0.exe` from the release page.
11
+ 4. The client opens `GEA-Reader.html` in any current browser, offline, and drops a dossier on it. The verdict: **Valid** (signed with the site's key, or a newer key the site's key handed over to), **Valid, but signed by a key you were not given**, or **Not valid** with the reason. Below it, every file the dossier holds: a report opens in the page as it was signed, a PDF in the browser's own viewer. A client who wants it installed, with a right-click **Check with GEA Reader** on dossiers, gets `GEA-Reader-Setup-0.81.0.exe` from the release page.
12
12
  5. **The key**: it lives in `keys\dossier_ed25519.json` in the workspace. The backup carries it; nothing else does; never send it. An administrator **rotates** it with a reason when a person who had access leaves; the old key's history rides in every later dossier so a reader of an old dossier still knows it was the site's.
13
13
 
14
14
  ## You know it worked when
@@ -8,7 +8,7 @@ Takes: 10 minutes
8
8
  1. Open **Audit / Update**, the card **The release**: the newest release on GitHub against the version running, with the three kits it carries - `GEA-Program-Setup`, `GEA-Reader-Setup` and `GEA-Recorder` - each with the SHA-256 GitHub recorded.
9
9
  2. Press **Fetch the kits** (the button names the version). A job brings them into the workspace's `installers\` folder, checks each against its recorded hash (a kit altered after that is not kept), and moves older kits to `installers\_older`. The card marks every kit on hand ✓.
10
10
  3. Press **Install now** (the button names the version). The program's setup runs silently from there with this workspace, and the reader's setup with it; the control panel stops for about a minute and is started again by a helper outside the program. Sign in again. The card now shows the new version running.
11
- 4. The recorder's kit, `GEA-Recorder-0.80.0.tar.gz`, is in the same folder for the attendant to take to the box (lesson 25).
11
+ 4. The recorder's kit, `GEA-Recorder-0.81.0.tar.gz`, is in the same folder for the attendant to take to the box (lesson 25).
12
12
  5. On a computer that cannot reach GitHub, the setup from the release page installs over the old version the same way; the workspace is kept.
13
13
 
14
14
  ## You know it worked when
@@ -5,10 +5,10 @@ Takes: 30 minutes
5
5
  > One script, one config file, one restart.
6
6
 
7
7
  ## Before you start
8
- The box assembled (lesson 24), the Pi on the pad network, and the release's `GEA-Recorder-0.80.0.tar.gz` - from the office's `installers\` folder (lesson 22) or the release page - copied to the Pi.
8
+ The box assembled (lesson 24), the Pi on the pad network, and the release's `GEA-Recorder-0.81.0.tar.gz` - from the office's `installers\` folder (lesson 22) or the release page - copied to the Pi.
9
9
 
10
10
  ## Steps
11
- 1. On the Pi, unpack the kit and run the installer once: `tar xzf GEA-Recorder-0.80.0.tar.gz`, `cd GEA-Recorder-0.80.0`, `sudo sh install.sh`. It makes `/opt/gea-recorder` (a Python environment of its own), writes the example config to `/etc/gea-recorder/config.json`, makes `/var/lib/gea-recorder`, enables SPI, enables the service to start at boot and runs the self-test.
11
+ 1. On the Pi, unpack the kit and run the installer once: `tar xzf GEA-Recorder-0.81.0.tar.gz`, `cd GEA-Recorder-0.81.0`, `sudo sh install.sh`. It makes `/opt/gea-recorder` (a Python environment of its own), writes the example config to `/etc/gea-recorder/config.json`, makes `/var/lib/gea-recorder`, enables SPI, enables the service to start at boot and runs the self-test.
12
12
  2. The clock: wire the GPS as lesson 24 says, then the three lines the README gives - `dtoverlay=pps-gpio,gpiopin=18` and `enable_uart=1` in `/boot/firmware/config.txt`, the two `refclock` lines in `/etc/chrony/chrony.conf` - `sudo apt install gpsd pps-tools`, and reboot. `chronyc tracking` then names PPS as the reference with an offset of microseconds.
13
13
  3. Edit the config: `sudo nano /etc/gea-recorder/config.json`. The site's name as the office spells it; the station id; the wellhead's latitude and longitude; each channel's ADC input, its id (`REF`, `S01`...), its kind (`geophone` or `electrode`) and its place in feet east and north of the wellhead; the ADC driver `ads1256` (`sim` records a test signal with no hardware); the rig feed - `rig.enabled`, the serial port or the TCP host and port the EDR offers; the mirror path for the USB stick.
14
14
  4. `sudo systemctl restart gea-recorder`. Open the box's page from any computer on the pad network: port 8780 of the box's address - `http://192.168.1.50:8780/` when that is its address. It shows the site, the station, RECORDING, the clock and what its time is worth, every channel's level, the files closed, the free space, the rig feed.
@@ -9,11 +9,11 @@ GEA Driller is a program for the rig PC. It reads the rig's own feed and the pre
9
9
 
10
10
  ## Steps
11
11
  1. Open **Drill string**; the card **GEA Driller** is at the bottom. Press **Start the twin as the rig**: the driller's own program runs on this computer with a scene drilling itself under the agent, one step every three seconds. Press **Open its screen**.
12
- 2. Read the screen: the green band is the model's layer window, the blue line the hole from the surveys, the orange dot the bit, the dotted stub where the recommendation points, and the orange band where the position filter puts the layer from the readings - the tile beside it says how sure it is that the bit is in the layer and how far the top and the base are. Under the section, the plan view: looking down, the plan line across the middle, the corridor as a green band each side of it, the hole from the surveys' azimuths, and the stub of the turn the recommendation's aim asks for; the tile **off the plan line** says how far right or left the bit sits. The recommendation in words - the build or drop and the aim of the azimuth, with the turn it asks, as one toolface - with its reasons - what the deep-resistivity tool says when the scene has one, the gamma against the model's values, the model's bracket, the azimuth against the plan's and the offset in the corridor, the limits - and the confidence of each choice. The rig's numbers against the limits. The decisions so far, and whether they were answered.
12
+ 2. Read the screen: the green band is the model's layer window, the blue line the hole from the surveys, the orange dot the bit, the dotted stub where the recommendation points, and the orange band where the position filter puts the layer from the readings - the tile beside it says how sure it is that the bit is in the layer and how far the top and the base are. Under the section, the plan view: looking down, the plan line across the middle, the corridor as a green band each side of it, the hole from the surveys' azimuths, and the stub of the turn the recommendation's aim asks for; the tile **off the plan line** says how far right or left the bit sits. The recommendation in words - the build or drop and the aim of the azimuth, with the turn it asks, as one toolface - with its reasons - what the deep-resistivity tool says when the scene has one, the gamma against the model's values, the model's bracket, the azimuth against the plan's and the offset in the corridor, the limits - and the confidence of each choice. The rig's numbers against the limits - the vibration tile says where its index came from: the downhole tool, or read off the surface torque, weight and hook load when the string has none. The decisions so far, and whether they were answered.
13
13
  3. Type your name and press **Accept** on a recommendation; press **Reject** on the next; press **Did something else…** and record a build of +1.5°/100 ft aimed 4° left of the plan at 25 klb on a third. Each answer is on the record with your name; the twin drills on under the agent.
14
14
  4. The closed loop: **Arm for this section** to 300 ft further, confirm. The panel turns red: every decision is now a command, and the agent's panel says the null downlink kept it and sent nothing. **Disarm now**, or wait for the section's end - it disarms itself, and says why.
15
15
  5. Back in GEA, choose the well the records go under and press **Pull from it**: a job fetches the records, checks each against its SHA-256 and keeps them under the well. The table says how many decisions, accepted, rejected, done otherwise, the hole under advice, the armed sections and the commands; the last decisions are listed below. **Stop it** closes the twin's records.
16
- 6. **Shadow a drilled well**: choose a well with a drilling-recorder export and press it. A job replays the drilled lateral through the advisor - at every 30 ft the agent sees only what the rig had shown to that point - and sets its recommendation beside what the record did next; the table says how often the steer agreed or opposed, the weight, speed and flow, and at each stretch the gamma marks as out of the layer whether the advisor called the way back at the first reading; the **SHADOW MODE** report under the well's reports has the drawing. Nothing of the export leaves this computer.
16
+ 6. **Shadow a drilled well**: choose a well with a drilling-recorder export and press it. A job replays the drilled lateral through the advisor - at every 30 ft the agent sees only what the rig had shown to that point - and sets its recommendation beside what the record did next; the table says how often the steer agreed or opposed, the weight, speed and flow, at each stretch the gamma marks as out of the layer whether the advisor called the way back at the first reading, and how often the vibration index read off the record's surface torque and weight stood over the limit and the advisor eased there; the **SHADOW MODE** report under the well's reports has the drawing. Nothing of the export leaves this computer.
17
17
  7. A real rig PC: its address in **The rig PC's address** (`http://192.168.1.60:8790`), the well, **Pull** - the same table. **Open the driller's screen** opens its screen from here. Over a modem, the rig PC joins GEA-VPN as a member of kind `driller` (lesson 23) and the address is its private one, `http://10.77.0.4:8790`.
18
18
 
19
19
  ## You know it worked when