gea-program 0.80.0__tar.gz → 0.82.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.
- {gea_program-0.80.0/gea_program.egg-info → gea_program-0.82.0}/PKG-INFO +13 -7
- {gea_program-0.80.0 → gea_program-0.82.0}/README.md +12 -6
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/__init__.py +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/acceptance_tests.py +275 -4
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/driller_link.py +28 -8
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/edr.py +3 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/driller.md +3 -3
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/install.md +2 -2
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/reader.md +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/recorder.md +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/01-install.md +2 -2
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/22-updates.md +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/25-install-recorder.md +2 -2
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/28-driller-office.md +3 -3
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/29-driller-rig.md +2 -2
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial.md +2 -2
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/web/app.html +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0/gea_program.egg-info}/PKG-INFO +13 -7
- {gea_program-0.80.0 → gea_program-0.82.0}/pyproject.toml +1 -1
- {gea_program-0.80.0 → gea_program-0.82.0}/LICENSE +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/__main__.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/alerts.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/backup.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/bench.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/bit_seismic.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/blind_harness.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/casing_design.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog_map.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/catalog_register.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/certificates.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/cli.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/client_reports.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/collision.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/config_versioning.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/conformance.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/control_room.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/correlation.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/dashboard.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/declarations.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/decline.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/deviation.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/dlis.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/dnp3.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/doctor.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/dossier.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/dossier_verify.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/drill_string.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/earth_model.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/economics.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/ed25519.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/elevation.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/etp.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/example_register_map.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fat_sat.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/field_pull.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/files.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/follower.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/forward_model.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/frac_hits.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/friction_priors.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/gamma.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/geodesy.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/geomag.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/hartip.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/IT_SECURITY.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/alarms.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/alerts.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/backup.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/bit-image.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/casing.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/catalog.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/charts.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/collision.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/company-sign-in.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/conformance.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/control-room.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/data-in.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/declare.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/decline.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/dlis.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/doctor.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/dossier.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/drift.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/drillstring.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/economics.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/edr.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/etp.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/files.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/frac-hits.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/historian.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/https.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/hydraulics.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/instruments.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/interval.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/invoice-check.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/map.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/month-end.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/notifications.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/opseis.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/osdu.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/pad-summary.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/patches.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/penetrator.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/plan.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/pore-pressure.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/quality.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/records.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/report-history.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/rig-time.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/rocks.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/seismic.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/setup.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/simulation.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/site.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/sites.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/slip.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/soak.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/sra.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/start.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/structure.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tools.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/torque-drag.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/transients.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/02-sign-in.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/03-site.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/04-add-well.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/05-records.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/06-well-page.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/07-declare.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/08-patches.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/09-alarms.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/10-control-room.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/11-summary-month.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/14-production-pages.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/15-seismic.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/16-seismicity.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/17-recorder-office.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/18-reports.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/20-admin.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/21-upkeep.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/23-vpn.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/24-the-box.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/26-monitor.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/vibration.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/vpn.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/well-report.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/help/well3d.md +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/helplib.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/housekeeping.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/hydraulics.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/icon.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/interval.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/invoice_check.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/jobs.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/launcher.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/live_ports.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/loadtest.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/modbus.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/model_card.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/month_end.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/notify.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/oidc.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/oidc_mock.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/op_seismicity.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/opcua_port.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/operator_app.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/osdu.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/pad_summary.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/patches.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/pdf_report.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/penetrator.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/permits.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/piwebapi.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/pore_pressure.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/ports.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/ppdm.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/project.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/quakeml.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reader.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reader_app.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reconciler.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/recorder_link.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/WMM2025.COF +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/eia_prices.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/iscwsa_rev4_example.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/iscwsa_rev5_example.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/mahoning_example.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/mud_motor_specs.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/owsg_tool_models.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/penetrator_ratings.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/seismicity_protocols.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_3d.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_surfaces.json.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/reference/volve_well_picks.csv.gz +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/report_history.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/rig_state.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sample_record.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sbom.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seedlink.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/segy.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_array.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_film.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_response.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_track.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/seismic_watch.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/series_cache.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/service.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/service_life.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/shapefile.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/shell.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/shut_in.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/simulation.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/site_map.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sla_report.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/slip.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/soak.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/sra.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/store_forward.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/strata_join.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/structure.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/supervisor.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/survey_view.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/telemetry.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/timestamp.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tls.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tool_library.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/torque_drag.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/transient.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tray.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/tutorial.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/updates.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/vibration.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/vpn.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/web/reader.html +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/well3d.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/well_assembler.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/well_records.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/well_report.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/wellplan.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/wellpos.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/winident.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/wits0.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/witsml.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/workspace.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/workspaces.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/x25519.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea/xlsx_read.py +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea_program.egg-info/SOURCES.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.80.0 → gea_program-0.82.0}/setup.cfg +0 -0
- {gea_program-0.80.0 → gea_program-0.82.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.
|
|
3
|
+
Version: 0.82.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.
|
|
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
|
|
@@ -491,8 +494,11 @@ agent is a policy trained by proximal policy optimization in a physics
|
|
|
491
494
|
twin of the lateral - the layer rolling with dip, undulation and faults,
|
|
492
495
|
the gamma and the deep-resistivity boundary the tools read of it, the
|
|
493
496
|
steering tool, the bit, the hydraulics, the hole - on scenes drawn fresh,
|
|
494
|
-
judged
|
|
495
|
-
|
|
497
|
+
judged on scenes it never saw between a textbook driller (the bar: what a
|
|
498
|
+
careful driller does by the book from the same observation) and an oracle
|
|
499
|
+
told the twin's own layer (the ceiling no policy can beat); `gea-driller
|
|
500
|
+
evaluate` prints the three rows and the agent's standing between them.
|
|
501
|
+
The figures of that judgement are a simulation's and are labelled so. Advisory by
|
|
496
502
|
default; the closed loop ships as a design with a switch, armed by a named
|
|
497
503
|
operator for one section, disarming itself on a stale feed, a crossed
|
|
498
504
|
limit or the section's end, through a downlink that keeps every command and
|
|
@@ -837,7 +843,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
|
|
|
837
843
|
reader made from the workspace knows the site's key fingerprints, so it
|
|
838
844
|
says whether a dossier is the site's; it allows no network request, and it
|
|
839
845
|
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.
|
|
846
|
+
it installed, every release also carries `GEA-Reader-Setup-0.82.0.exe`: GEA
|
|
841
847
|
Reader as a Windows program of its own - its own icon and taskbar button,
|
|
842
848
|
Check with GEA Reader on a dossier's right-click menu, fingerprints the client
|
|
843
849
|
saves kept on that computer, nothing of GEA-Program. `gea help reader`.
|
|
@@ -1602,7 +1608,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1602
1608
|
|
|
1603
1609
|
### The Windows installer
|
|
1604
1610
|
|
|
1605
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1611
|
+
Every release also carries `GEA-Program-Setup-0.82.0.exe` (for 0.82.0): the
|
|
1606
1612
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1607
1613
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1608
1614
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1621,7 +1627,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1621
1627
|
software deployment:
|
|
1622
1628
|
|
|
1623
1629
|
```
|
|
1624
|
-
GEA-Program-Setup-0.
|
|
1630
|
+
GEA-Program-Setup-0.82.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1625
1631
|
```
|
|
1626
1632
|
|
|
1627
1633
|
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.
|
|
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
|
|
@@ -452,8 +455,11 @@ agent is a policy trained by proximal policy optimization in a physics
|
|
|
452
455
|
twin of the lateral - the layer rolling with dip, undulation and faults,
|
|
453
456
|
the gamma and the deep-resistivity boundary the tools read of it, the
|
|
454
457
|
steering tool, the bit, the hydraulics, the hole - on scenes drawn fresh,
|
|
455
|
-
judged
|
|
456
|
-
|
|
458
|
+
judged on scenes it never saw between a textbook driller (the bar: what a
|
|
459
|
+
careful driller does by the book from the same observation) and an oracle
|
|
460
|
+
told the twin's own layer (the ceiling no policy can beat); `gea-driller
|
|
461
|
+
evaluate` prints the three rows and the agent's standing between them.
|
|
462
|
+
The figures of that judgement are a simulation's and are labelled so. Advisory by
|
|
457
463
|
default; the closed loop ships as a design with a switch, armed by a named
|
|
458
464
|
operator for one section, disarming itself on a stale feed, a crossed
|
|
459
465
|
limit or the section's end, through a downlink that keeps every command and
|
|
@@ -798,7 +804,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
|
|
|
798
804
|
reader made from the workspace knows the site's key fingerprints, so it
|
|
799
805
|
says whether a dossier is the site's; it allows no network request, and it
|
|
800
806
|
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.
|
|
807
|
+
it installed, every release also carries `GEA-Reader-Setup-0.82.0.exe`: GEA
|
|
802
808
|
Reader as a Windows program of its own - its own icon and taskbar button,
|
|
803
809
|
Check with GEA Reader on a dossier's right-click menu, fingerprints the client
|
|
804
810
|
saves kept on that computer, nothing of GEA-Program. `gea help reader`.
|
|
@@ -1563,7 +1569,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1563
1569
|
|
|
1564
1570
|
### The Windows installer
|
|
1565
1571
|
|
|
1566
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1572
|
+
Every release also carries `GEA-Program-Setup-0.82.0.exe` (for 0.82.0): the
|
|
1567
1573
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1568
1574
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1569
1575
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1582,7 +1588,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1582
1588
|
software deployment:
|
|
1583
1589
|
|
|
1584
1590
|
```
|
|
1585
|
-
GEA-Program-Setup-0.
|
|
1591
|
+
GEA-Program-Setup-0.82.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1586
1592
|
```
|
|
1587
1593
|
|
|
1588
1594
|
The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
|
|
@@ -16511,7 +16511,7 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16511
16511
|
num = (lp_ - lm_) / (2 * eps)
|
|
16512
16512
|
grads_ok = grads_ok and abs(num - g[k][i]) <= 1e-5 * max(1.0, abs(num))
|
|
16513
16513
|
shipped = P.Policy.load(S.SHIPPED_POLICY)
|
|
16514
|
-
|
|
16514
|
+
three = P.evaluate_all(shipped, range(20)); ev = three["agent"]; tb = three["textbook"]; orc = three["oracle"]
|
|
16515
16515
|
fresh = P.Policy(seed=5); before = P.evaluate(P.policy_act_fn(fresh), range(10, 14), "fresh")
|
|
16516
16516
|
P.train(fresh, seconds=10.0, batch_steps=2048, n_envs=8, scene_seed0=600000)
|
|
16517
16517
|
after = P.evaluate(P.policy_act_fn(fresh), range(10, 14), "trained")
|
|
@@ -16524,7 +16524,10 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16524
16524
|
ex = shipped.explain(T.Lateral(T.Scene(2)).reset())
|
|
16525
16525
|
c2 = {
|
|
16526
16526
|
"gradients": grads_ok,
|
|
16527
|
-
|
|
16527
|
+
# the bar is a strong driller now (0.82.0): the agent is held above it in the hole in the layer by more than a point and within the
|
|
16528
|
+
# reward's own noise of it, and the gate says how far it stands toward the oracle rather than claiming a wide margin
|
|
16529
|
+
"beats_textbook": ev["reward"] > tb["reward"] - 3.0 and ev["in_layer_pct"] > tb["in_layer_pct"] + 1.0 and ev["stuck"] <= tb["stuck"],
|
|
16530
|
+
"under_oracle": orc["in_layer_pct"] > ev["in_layer_pct"] and orc["reward"] > ev["reward"] and 0.0 < three["standing"]["in_layer_pct_of_the_way"] < 100.0,
|
|
16528
16531
|
"learns": after["reward"] > before["reward"],
|
|
16529
16532
|
"file": same and layout_refused and int(shipped.meta.get("trained_steps", 0)) >= 1000000,
|
|
16530
16533
|
"explains": set(ex["choices"]) == set(T.ACTION_NAMES) and all(0 < c["confidence"] <= 1 for c in ex["choices"].values()) and ex["choices"]["wob"]["choice"] in T.WOB_CHOICES,
|
|
@@ -16532,8 +16535,9 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16532
16535
|
failed2 = [k for k, v in c2.items() if not v]
|
|
16533
16536
|
ok(not failed2,
|
|
16534
16537
|
f"DV2 the policy's written-out gradients agree with finite differences; the shipped policy ({int(shipped.meta.get('trained_steps', 0)):,} twin steps) beats the "
|
|
16535
|
-
f"textbook driller on twenty held-out scenes (in the layer {ev['in_layer_pct']:.0f}% against {tb['in_layer_pct']:.0f}%, reward {ev['reward']:.0f} against {tb['reward']:.0f}
|
|
16536
|
-
"
|
|
16538
|
+
f"textbook driller on twenty held-out scenes (in the layer {ev['in_layer_pct']:.0f}% against {tb['in_layer_pct']:.0f}%, reward {ev['reward']:.0f} against {tb['reward']:.0f}) "
|
|
16539
|
+
f"and stands under the oracle told the layer ({orc['in_layer_pct']:.0f}%, {orc['reward']:.0f}: {three['standing']['in_layer_pct_of_the_way']:.0f}% of the way, SIMULATION); "
|
|
16540
|
+
"ten seconds of training raise a fresh policy's return; the file round-trips and another layout is refused; a decision explains itself in "
|
|
16537
16541
|
"operational units with a confidence per choice" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
16538
16542
|
# -- DV3 the service with the twin as the rig ------------------------------------------------------------------------
|
|
16539
16543
|
cfg = json.loads(json.dumps(C.EXAMPLE)); cfg["output"]["dir"] = str(d / "rig"); cfg["status"]["port"] = 0; cfg["status"]["bind"] = "127.0.0.1"
|
|
@@ -16566,6 +16570,7 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16566
16570
|
time.sleep(0.2)
|
|
16567
16571
|
s_ov, _ = call("/api/answer", {"what": "override", "by": "tester", "note": "held", "override": {"build_deg_100ft": 0.0, "wob_klb": 25}})
|
|
16568
16572
|
md = drl.feed.snapshot()["state"]["hole_depth"]
|
|
16573
|
+
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
16574
|
s_long, _ = call("/api/arm", {"by": "tester", "to_md": md + 5000})
|
|
16570
16575
|
s_arm, armed = call("/api/arm", {"by": "tester", "to_md": md + 150})
|
|
16571
16576
|
t_end = time.monotonic() + 30
|
|
@@ -17011,6 +17016,270 @@ def section_dx_third_dimension(tmp: str) -> None:
|
|
|
17011
17016
|
"plan azimuth and cross dip go through" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
17012
17017
|
|
|
17013
17018
|
|
|
17019
|
+
def section_dy_vibration(tmp: str) -> None:
|
|
17020
|
+
"""Section DY - the vibration index from the feed: the index off the surface channels (a steady feed near zero, a
|
|
17021
|
+
torque swinging as the twin's limit swings it reading the limit, a weight swinging reading lateral, the statistics
|
|
17022
|
+
path equal to the samples path, pooled statistics, a window without torque or weight reading nothing); on the twin
|
|
17023
|
+
the derived index tracking the twin's own; the rig side (the twin as the rig publishing the surface channels and
|
|
17024
|
+
no downhole index, the advisor reading the derived one and saying so, the downhole item winning, a feed with
|
|
17025
|
+
neither reading none, the loop disarming on the derived index, the screen, the help); GEA's side (the lateral
|
|
17026
|
+
file from the self-test export with the statistics, the replay reading the stick-slip stretch over the limit
|
|
17027
|
+
and the advisor easing there, a record without the statistics unjudged, the card)."""
|
|
17028
|
+
import http.cookiejar
|
|
17029
|
+
import importlib
|
|
17030
|
+
import math as _m
|
|
17031
|
+
import urllib.error
|
|
17032
|
+
import urllib.request
|
|
17033
|
+
from . import driller_link as DL
|
|
17034
|
+
from . import edr as E
|
|
17035
|
+
from . import helplib as H
|
|
17036
|
+
from .service import Service, Users
|
|
17037
|
+
from .workspace import Workspace
|
|
17038
|
+
pkg = Path(__file__).parent
|
|
17039
|
+
d = Path(tmp, "dy"); d.mkdir()
|
|
17040
|
+
prog = DL.program()
|
|
17041
|
+
if prog is None:
|
|
17042
|
+
ok(True, "DY the driller's program (gea-driller) is not installed beside GEA in this install; nothing to check here")
|
|
17043
|
+
return
|
|
17044
|
+
if prog["env"] and prog["env"] not in sys.path:
|
|
17045
|
+
sys.path.insert(0, prog["env"])
|
|
17046
|
+
T = importlib.import_module("gea_driller.twin"); V = importlib.import_module("gea_driller.vibration"); P = importlib.import_module("gea_driller.policy")
|
|
17047
|
+
A = importlib.import_module("gea_driller.advisor"); C = importlib.import_module("gea_driller.config"); S = importlib.import_module("gea_driller.service")
|
|
17048
|
+
R = importlib.import_module("gea_driller.rig"); SH = importlib.import_module("gea_driller.shadow")
|
|
17049
|
+
np_ = importlib.import_module("numpy")
|
|
17050
|
+
# -- DY1 the index --------------------------------------------------------------------------------------------------------
|
|
17051
|
+
tt = np_.arange(60)
|
|
17052
|
+
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}
|
|
17053
|
+
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}
|
|
17054
|
+
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}
|
|
17055
|
+
v0 = V.index(steady); v1 = V.index(ss); v2 = V.index(lat)
|
|
17056
|
+
v1s = V.index_from_stats(V.stats(ss))
|
|
17057
|
+
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()})]))
|
|
17058
|
+
none = V.index({"rpm": 120 + 0 * tt, "spp": 2800 + 0 * tt})
|
|
17059
|
+
short = V.index({k: v[:5] for k, v in ss.items()})
|
|
17060
|
+
# on the twin: the derived index against the twin's own, step by step over twenty scenes
|
|
17061
|
+
tr, de = [], []
|
|
17062
|
+
for sd in range(20):
|
|
17063
|
+
lt = T.Lateral(T.Scene(sd)); o = lt.reset()
|
|
17064
|
+
while not lt.done:
|
|
17065
|
+
o, _, _, inf = lt.step(T.textbook_action(o))
|
|
17066
|
+
if inf.get("conditioning") != "drill":
|
|
17067
|
+
continue
|
|
17068
|
+
smp = [lt.surface_sample() for _ in range(20)]
|
|
17069
|
+
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]})
|
|
17070
|
+
tr.append(lt.vib); de.append(v["index"])
|
|
17071
|
+
tr_, de_ = np_.array(tr), np_.array(de)
|
|
17072
|
+
corr = float(np_.corrcoef(tr_, de_)[0, 1]); agree = float(((tr_ > T.VIB_LIMIT) == (de_ > T.VIB_LIMIT)).mean())
|
|
17073
|
+
c1 = {
|
|
17074
|
+
"steady": v0 is not None and v0["index"] < 0.1,
|
|
17075
|
+
"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,
|
|
17076
|
+
"lateral": v2 is not None and abs(v2["index"] - 1.2) < 0.1 and v2["kind"] == "lateral" and v2["stick_slip"] < 0.1,
|
|
17077
|
+
"paths": v1s["index"] == v1["index"] and abs(pooled["index"] - v1["index"]) < 0.08,
|
|
17078
|
+
"nothing": none is None and short is None,
|
|
17079
|
+
"twin": len(tr) > 1500 and corr > 0.95 and agree >= 0.95 and float(np_.median(np_.abs(tr_ - de_))) < 0.05,
|
|
17080
|
+
"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),
|
|
17081
|
+
}
|
|
17082
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
17083
|
+
ok(not failed1,
|
|
17084
|
+
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, "
|
|
17085
|
+
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 "
|
|
17086
|
+
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}%, "
|
|
17087
|
+
"SIMULATION - the twin's calibration, not a string's)" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
17088
|
+
# -- DY2 the rig side ---------------------------------------------------------------------------------------------------------
|
|
17089
|
+
shipped = P.Policy.load(S.SHIPPED_POLICY)
|
|
17090
|
+
cfg = json.loads(json.dumps(C.EXAMPLE)); cfg["output"]["dir"] = str(d / "rig"); cfg["status"]["port"] = 0; cfg["status"]["bind"] = "127.0.0.1"
|
|
17091
|
+
cfg["rig"]["transport"] = "sim"; cfg["closed_loop"]["allowed"] = True; cfg["closed_loop"]["stale_s"] = 30
|
|
17092
|
+
cfg = C.check(cfg)
|
|
17093
|
+
try:
|
|
17094
|
+
C.check(json.loads(json.dumps(cfg)) | {"rig": {**cfg["rig"], "vibration_window_s": 2}}); win_refused = False
|
|
17095
|
+
except C.ConfigError:
|
|
17096
|
+
win_refused = True
|
|
17097
|
+
drl = S.Driller(cfg, policy=shipped, twin_seed=11, twin_pace_s=0.6)
|
|
17098
|
+
drl.start()
|
|
17099
|
+
try:
|
|
17100
|
+
t_end = time.monotonic() + 25
|
|
17101
|
+
while time.monotonic() < t_end and len(drl.advisor.history) < 3:
|
|
17102
|
+
time.sleep(0.2)
|
|
17103
|
+
snap = drl.feed.snapshot(); live = drl.live()
|
|
17104
|
+
cur = dict(drl.advisor.history[-1]) if drl.advisor.history else None
|
|
17105
|
+
md = snap["state"].get("hole_depth")
|
|
17106
|
+
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")
|
|
17107
|
+
with urllib.request.urlopen(rq, timeout=5) as r_:
|
|
17108
|
+
armed = json.load(r_)
|
|
17109
|
+
drl.cfg["limits"]["vibration_index"] = 0.01 # the limit lowered under the loop: the derived index crosses it at the next look
|
|
17110
|
+
t_end = time.monotonic() + 8
|
|
17111
|
+
while time.monotonic() < t_end and drl.advisor.armed is not None:
|
|
17112
|
+
time.sleep(0.2)
|
|
17113
|
+
drl.cfg["limits"]["vibration_index"] = 1.2
|
|
17114
|
+
last = drl.advisor.arm_log[-1]
|
|
17115
|
+
with urllib.request.urlopen(drl.url + "/live", timeout=5) as r_:
|
|
17116
|
+
screen = r_.read().decode("utf-8")
|
|
17117
|
+
finally:
|
|
17118
|
+
drl.stop()
|
|
17119
|
+
# the downhole item wins; a feed with neither reads none
|
|
17120
|
+
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
|
|
17121
|
+
for k in range(30):
|
|
17122
|
+
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)
|
|
17123
|
+
v_tool = A.Advisor.vibration_of(feed.snapshot())
|
|
17124
|
+
feed.state["vibration"] = None
|
|
17125
|
+
v_der = A.Advisor.vibration_of(feed.snapshot())
|
|
17126
|
+
feed2 = R.Feed(cfg); feed2.state.update({"hole_depth": 10500.0, "gamma": 60.0}); feed2.last_utc = time.time(); feed2.connected = True
|
|
17127
|
+
v_none = A.Advisor.vibration_of(feed2.snapshot())
|
|
17128
|
+
adv2 = A.Advisor(cfg, shipped, feed2, A.Records(json.loads(json.dumps(cfg)) | {"output": {"dir": str(d / "rig2")}}))
|
|
17129
|
+
rec2 = adv2.decide(feed2.snapshot())
|
|
17130
|
+
decs = [json.loads(l) for l in open(d / "rig" / "decisions.jsonl", encoding="utf-8")]
|
|
17131
|
+
c2 = {
|
|
17132
|
+
"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
|
|
17133
|
+
and snap["vibration"]["index"] > 0 and snap.get("window_n", 0) >= 10 and abs(snap["vibration"]["index"] - drl.feed.lat.vib) < 0.25,
|
|
17134
|
+
"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"])
|
|
17135
|
+
and live["vibration"]["source"] == V.SOURCE and live["vibration"]["parts"]["kind"] in ("stick-slip", "lateral"),
|
|
17136
|
+
"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,
|
|
17137
|
+
"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"]),
|
|
17138
|
+
"disarms": armed.get("ok") and last["event"] == "disarmed" and "vibration" in last["reason"] and "surface data" in last["reason"],
|
|
17139
|
+
"records": any((x.get("context") or {}).get("vibration_source") == V.SOURCE for x in decs),
|
|
17140
|
+
"screen": "from surface data" in screen and "downhole tool" in screen,
|
|
17141
|
+
"refusal": win_refused,
|
|
17142
|
+
"help": not H.check("driller") and "The vibration index from the feed" in (pkg / "help" / "driller.md").read_text(encoding="utf-8")
|
|
17143
|
+
and "surface" in (pkg / "help" / "tutorial" / "29-driller-rig.md").read_text(encoding="utf-8"),
|
|
17144
|
+
}
|
|
17145
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
17146
|
+
ok(not failed2,
|
|
17147
|
+
"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 "
|
|
17148
|
+
"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 "
|
|
17149
|
+
"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"
|
|
17150
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
17151
|
+
# -- DY3 GEA's side: the lateral file with the statistics, the replay over the limit, the card ---------------------------------------
|
|
17152
|
+
ws = Workspace.create(str(d / "ws"), "Pad 3 vibration", actor="tester")
|
|
17153
|
+
exp = E.selftest(str(d), 3000)
|
|
17154
|
+
w = ws.add_well_file(exp["path"], display="Well EDR", actor="tester")
|
|
17155
|
+
lat_csv = str(d / "lat.csv")
|
|
17156
|
+
info = DL.lateral_from_edr(ws, w["id"], lat_csv)
|
|
17157
|
+
head = Path(lat_csv).read_text(encoding="utf-8").splitlines()[0].split(",")
|
|
17158
|
+
rec = DL.shadow(ws, w["id"], actor="tester")
|
|
17159
|
+
sm = rec["summary"]
|
|
17160
|
+
# the twin's lateral with and without the statistics
|
|
17161
|
+
tw_csv = str(d / "tw.csv"); tw_no = str(d / "tw_no.csv")
|
|
17162
|
+
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)
|
|
17163
|
+
r_tw = SH.run(tw_csv, shipped, well="Twin 5"); r_no = SH.run(tw_no, shipped, well="Twin 5")
|
|
17164
|
+
tv = dict(tinfo["true_vibration"]); mds = np_.array(sorted(tv))
|
|
17165
|
+
tvv = np_.array([tv[m_] for m_ in mds])
|
|
17166
|
+
def true_over(md_): # the twin's own index averaged over the 30 ft the replay's window pooled
|
|
17167
|
+
j0, j1 = int(np_.searchsorted(mds, md_ - 30.0)), int(np_.searchsorted(mds, md_, side="right"))
|
|
17168
|
+
return float(tvv[j0:j1].mean()) if j1 > j0 else float("nan")
|
|
17169
|
+
pairs = np_.array([(x["vibration"], true_over(x["md"])) for x in r_tw["decisions"] if x["vibration"] is not None])
|
|
17170
|
+
pairs = pairs[np_.isfinite(pairs[:, 1])]
|
|
17171
|
+
corr_tw = float(np_.corrcoef(pairs[:, 0], pairs[:, 1])[0, 1]) if len(pairs) > 10 else 0.0
|
|
17172
|
+
md_text = Path(ws.reports_dir, rec["report"]["md"]).read_text(encoding="utf-8")
|
|
17173
|
+
app_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
17174
|
+
c3 = {
|
|
17175
|
+
"lateral_file": all(c in head for c in DL.LATERAL_STATS) and info["vibration_rows"] >= 1000,
|
|
17176
|
+
"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
|
|
17177
|
+
and sm["eased_when_over_pct"] is not None and sm["eased_when_over_pct"] >= 50.0,
|
|
17178
|
+
"report": "stood over the limit" in md_text and "| Vib |" in md_text,
|
|
17179
|
+
"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,
|
|
17180
|
+
"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"]),
|
|
17181
|
+
"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 ("",)),
|
|
17182
|
+
"card": "Vibration over limit" in app_src and "eased" in app_src,
|
|
17183
|
+
}
|
|
17184
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
17185
|
+
ok(not failed3,
|
|
17186
|
+
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 "
|
|
17187
|
+
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 "
|
|
17188
|
+
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; "
|
|
17189
|
+
"the card carries the column" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
17190
|
+
|
|
17191
|
+
|
|
17192
|
+
def section_dz_textbook_oracle(tmp: str) -> None:
|
|
17193
|
+
"""Section DZ - the stronger textbook driller and the oracle: the textbook's behaviours from the observation
|
|
17194
|
+
alone (steering back hard when the filter says the bit is out, the weight the bit is rated for in a calm hole
|
|
17195
|
+
and not while the hole fills, the vibration trial - lighter and faster first, heavier and slower when that did
|
|
17196
|
+
not quiet it - circulating at 40%, a new lateral a new memory); the oracle told the twin's layer refusing to run
|
|
17197
|
+
unbound and beating the textbook and the agent; the three rows and the standing; the command line, the self-test
|
|
17198
|
+
and the help."""
|
|
17199
|
+
import importlib
|
|
17200
|
+
import subprocess as _sp
|
|
17201
|
+
from . import driller_link as DL
|
|
17202
|
+
from . import helplib as H
|
|
17203
|
+
pkg = Path(__file__).parent
|
|
17204
|
+
d = Path(tmp, "dz"); d.mkdir()
|
|
17205
|
+
prog = DL.program()
|
|
17206
|
+
if prog is None:
|
|
17207
|
+
ok(True, "DZ the driller's program (gea-driller) is not installed beside GEA in this install; nothing to check here")
|
|
17208
|
+
return
|
|
17209
|
+
if prog["env"] and prog["env"] not in sys.path:
|
|
17210
|
+
sys.path.insert(0, prog["env"])
|
|
17211
|
+
T = importlib.import_module("gea_driller.twin"); P = importlib.import_module("gea_driller.policy"); S = importlib.import_module("gea_driller.service")
|
|
17212
|
+
np_ = importlib.import_module("numpy")
|
|
17213
|
+
# -- DZ1 the textbook and the oracle ---------------------------------------------------------------------------------------
|
|
17214
|
+
lat = T.Lateral(T.Scene(2)); base = lat.reset().copy()
|
|
17215
|
+
i = {n: k for k, n in enumerate(T.OBS_NAMES)}
|
|
17216
|
+
|
|
17217
|
+
def obs(**kw):
|
|
17218
|
+
o = base.copy()
|
|
17219
|
+
o[i["filter_p_in"]], o[i["filter_p_above"]], o[i["filter_p_below"]] = 0.95, 0.03, 0.02
|
|
17220
|
+
o[i["filter_dist_top"]], o[i["filter_dist_base"]] = 20.0 / 30, 20.0 / 30
|
|
17221
|
+
o[i["vibration"]] = 0.5 / 1.5; o[i["cuttings_bed"]] = 0.1; o[i["balling"]] = 0.0; o[i["gamma_trend"]] = 0.0; o[i["deep_res_available"]] = 0.0
|
|
17222
|
+
o[i["inclination_minus_90"]] = 0.0; o[i["progress"]] = 0.5
|
|
17223
|
+
for k, v in kw.items():
|
|
17224
|
+
o[i[k]] = v
|
|
17225
|
+
return o
|
|
17226
|
+
tb = T.TextbookDriller()
|
|
17227
|
+
a_calm = tb(obs())
|
|
17228
|
+
a_above = tb(obs(filter_p_in=0.1, filter_p_above=0.85, filter_p_below=0.05, filter_dist_top=-15.0 / 30))
|
|
17229
|
+
a_below = tb(obs(filter_p_in=0.1, filter_p_above=0.05, filter_p_below=0.85, filter_dist_base=-15.0 / 30))
|
|
17230
|
+
a_fill = tb(obs(cuttings_bed=0.35))
|
|
17231
|
+
a_circ = tb(obs(cuttings_bed=0.45)); a_ream = tb(obs(balling=0.45))
|
|
17232
|
+
tb2 = T.TextbookDriller()
|
|
17233
|
+
v1 = tb2(obs(vibration=1.4 / 1.5)); v2 = tb2(obs(vibration=1.45 / 1.5)); v3 = tb2(obs(vibration=1.5 / 1.5)); v4 = tb2(obs(vibration=0.6 / 1.5)); v5 = tb2(obs(vibration=1.4 / 1.5))
|
|
17234
|
+
tb3 = T.TextbookDriller()
|
|
17235
|
+
tb3(obs(vibration=1.4 / 1.5)); tb3(obs(vibration=1.5 / 1.5)); trial_before = tb3.vib_trial # a trial that did not quiet: the second cure
|
|
17236
|
+
tb3(obs(vibration=1.4 / 1.5, progress=0.0)); trial_after = tb3.vib_trial # a new lateral (the progress fell): a new memory
|
|
17237
|
+
try:
|
|
17238
|
+
T.OracleDriller()(base); unbound = False
|
|
17239
|
+
except RuntimeError:
|
|
17240
|
+
unbound = True
|
|
17241
|
+
three = P.evaluate_all(P.Policy.load(S.SHIPPED_POLICY), range(20))
|
|
17242
|
+
tbr, agr, orr = three["textbook"], three["agent"], three["oracle"]
|
|
17243
|
+
old = T.run_episode(T.Lateral(T.Scene(0)), T.textbook_action); new = T.run_episode(T.Lateral(T.Scene(0)), T.TextbookDriller())
|
|
17244
|
+
c1 = {
|
|
17245
|
+
"calm": a_calm[1] == 2 and a_calm[2] == 1 and a_calm[4] == 0 and a_fill[1] == 1,
|
|
17246
|
+
"out": a_above[0] == 0 and a_below[0] == 4,
|
|
17247
|
+
"hole": a_circ[4] == 1 and a_ream[4] == 2,
|
|
17248
|
+
"trial": (v1[1], v1[2]) == (0, 2) and (v2[1], v2[2]) == (1, 0) and (v3[1], v3[2]) == (1, 0) and v4[1] == 2 and (v5[1], v5[2]) == (0, 2),
|
|
17249
|
+
"memory": trial_before == 2 and trial_after == 1 and abs(old["reward"] - new["reward"]) < 1e-9,
|
|
17250
|
+
"oracle": unbound and orr["in_layer_pct"] > agr["in_layer_pct"] > tbr["in_layer_pct"] and orr["reward"] > agr["reward"] > tbr["reward"] and orr["in_layer_pct"] >= 90.0,
|
|
17251
|
+
"standing": 0.0 < three["standing"]["in_layer_pct_of_the_way"] < 100.0 and three["label"] == "SIMULATION" and three["scenes"] == list(range(20)),
|
|
17252
|
+
}
|
|
17253
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
17254
|
+
ok(not failed1,
|
|
17255
|
+
f"DZ1 the textbook driller from the observation alone: the rated weight in a calm hole in the layer and not while the hole fills, a hard drop when the filter says "
|
|
17256
|
+
f"above and a hard build when below, circulating at 40% and reaming a balled bit, the vibration trial lighter and faster first then heavier and slower, a new "
|
|
17257
|
+
f"lateral a new memory; the oracle refuses to run unbound and, told the layer, holds {orr['in_layer_pct']:.0f}% of the hole in it against the agent's {agr['in_layer_pct']:.0f}% "
|
|
17258
|
+
f"and the textbook's {tbr['in_layer_pct']:.0f}% on twenty held-out scenes (SIMULATION); the standing reads between them" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
17259
|
+
# -- DZ2 the command line, the self-test and the help --------------------------------------------------------------------------
|
|
17260
|
+
env = dict(os.environ)
|
|
17261
|
+
if prog["env"]:
|
|
17262
|
+
env["PYTHONPATH"] = prog["env"] + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
|
|
17263
|
+
r_ev = _sp.run([sys.executable, "-m", "gea_driller", "evaluate", "--scenes", "4", "--json"], capture_output=True, text=True, env=env, cwd=str(d))
|
|
17264
|
+
r_tx = _sp.run([sys.executable, "-m", "gea_driller", "evaluate", "--scenes", "3"], capture_output=True, text=True, env=env, cwd=str(d))
|
|
17265
|
+
try:
|
|
17266
|
+
j = json.loads(r_ev.stdout)
|
|
17267
|
+
except ValueError:
|
|
17268
|
+
j = {}
|
|
17269
|
+
main_src = (Path(prog["path"]) / "__main__.py").read_text(encoding="utf-8")
|
|
17270
|
+
help_text = (pkg / "help" / "driller.md").read_text(encoding="utf-8")
|
|
17271
|
+
c2 = {
|
|
17272
|
+
"json": r_ev.returncode == 0 and set(j) >= {"textbook", "agent", "oracle", "standing"} and j["scenes"] == [0, 1, 2, 3] and "episodes" not in j["agent"],
|
|
17273
|
+
"text": r_tx.returncode == 0 and "oracle" in r_tx.stdout and "textbook" in r_tx.stdout and "of the way from the textbook to the oracle" in r_tx.stdout and "SIMULATION" in r_tx.stdout,
|
|
17274
|
+
"selftest": "evaluate_all" in main_src and "oracle" in main_src,
|
|
17275
|
+
"help": not H.check("driller") and "oracle" in help_text and "the bar" in help_text,
|
|
17276
|
+
}
|
|
17277
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
17278
|
+
ok(not failed2,
|
|
17279
|
+
"DZ2 `gea-driller evaluate` prints the three rows - the textbook, the agent, the oracle - and where the agent stands between them, as text and as JSON; "
|
|
17280
|
+
"the self-test holds the policy to the oracle as well; the help names the bar and the ceiling" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
17281
|
+
|
|
17282
|
+
|
|
17014
17283
|
def main() -> int:
|
|
17015
17284
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
17016
17285
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -17142,6 +17411,8 @@ def main() -> int:
|
|
|
17142
17411
|
section_dv_driller(tmp)
|
|
17143
17412
|
section_dw_shadow(tmp)
|
|
17144
17413
|
section_dx_third_dimension(tmp)
|
|
17414
|
+
section_dy_vibration(tmp)
|
|
17415
|
+
section_dz_textbook_oracle(tmp)
|
|
17145
17416
|
if _FAILS:
|
|
17146
17417
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
17147
17418
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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=
|
|
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
|
|
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', '
|
|
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.
|
|
5
|
+
**The command**: on the rig PC, `GEA-Driller-0.82.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. **The bar and the ceiling** (since 0.82.0): the agent is judged between two drillers on the same held-out scenes. The textbook driller is the bar - what a careful directional driller and geosteerer do by the book from the same observation the agent gets and nothing more: aim at the middle of the layer as the filter places it, steer back hard when the filter says the bit is out, lean away from a boundary the gamma's trend is running at, the rated weight in a calm hole in the layer and not while the hole fills, over the vibration limit lighter and faster first and heavier and slower when that did not quiet it, circulate at 40% of a bed, ream a balled bit, hold the plan line; it has a driller's memory of its own last decisions and none of the twin's secret. The oracle is the ceiling - the same driller told the twin's own layer at the bit and 120 ft ahead of it, which no policy can beat because it sees what no tool measures. `gea-driller evaluate` prints the three rows and how far the agent stands from the bar toward the ceiling; the self-test refuses a policy that does not beat the textbook, and the gate holds it under the oracle. The figures are a simulation's, labelled; a stronger textbook lowers the agent's standing without changing the agent, and that is the point of it. 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
|
-
**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
|
|
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 between the textbook driller and the oracle on sixty held-out twin scenes - the hole in the layer, the sweet spot, the corridor, feet a day, dogleg, stuck pipe, losses, and the agent's standing from the one toward the other - 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`.
|