gea-program 0.78.1__tar.gz → 0.80.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.78.1/gea_program.egg-info → gea_program-0.80.0}/PKG-INFO +13 -6
- {gea_program-0.78.1 → gea_program-0.80.0}/README.md +12 -5
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/__init__.py +1 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/__main__.py +15 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/acceptance_tests.py +284 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/driller_link.py +128 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/IT_SECURITY.md +4 -1
- gea_program-0.80.0/gea/help/driller.md +13 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/install.md +2 -2
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/reader.md +1 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/recorder.md +1 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/01-install.md +2 -2
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/19-dossier-reader.md +1 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/22-updates.md +1 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/25-install-recorder.md +2 -2
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/28-driller-office.md +5 -4
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/29-driller-rig.md +3 -3
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial.md +2 -2
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/service.py +10 -1
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/web/app.html +7 -0
- {gea_program-0.78.1 → gea_program-0.80.0/gea_program.egg-info}/PKG-INFO +13 -6
- {gea_program-0.78.1 → gea_program-0.80.0}/pyproject.toml +1 -1
- gea_program-0.78.1/gea/help/driller.md +0 -13
- {gea_program-0.78.1 → gea_program-0.80.0}/LICENSE +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/alerts.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/backup.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/bench.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/bit_seismic.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/blind_harness.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/casing_design.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog_map.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/catalog_register.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/certificates.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/cli.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/client_reports.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/collision.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/config_versioning.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/conformance.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/control_room.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/correlation.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/dashboard.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/declarations.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/decline.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/deviation.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/dlis.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/dnp3.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/doctor.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/dossier.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/dossier_verify.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/drill_string.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/earth_model.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/economics.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/ed25519.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/edr.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/elevation.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/etp.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/example_register_map.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fat_sat.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/field_pull.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/files.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/follower.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/forward_model.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/frac_hits.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/friction_priors.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/gamma.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/geodesy.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/geomag.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/hartip.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/alarms.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/alerts.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/backup.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/bit-image.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/casing.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/catalog.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/charts.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/collision.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/company-sign-in.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/conformance.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/control-room.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/data-in.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/declare.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/decline.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/dlis.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/doctor.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/dossier.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/drift.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/drillstring.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/economics.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/edr.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/etp.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/files.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/frac-hits.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/historian.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/https.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/hydraulics.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/instruments.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/interval.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/invoice-check.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/map.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/month-end.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/notifications.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/opseis.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/osdu.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/pad-summary.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/patches.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/penetrator.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/plan.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/pore-pressure.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/quality.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/records.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/report-history.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/rig-time.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/rocks.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/seismic.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/setup.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/simulation.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/site.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/sites.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/slip.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/soak.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/sra.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/start.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/structure.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tools.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/torque-drag.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/transients.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/02-sign-in.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/03-site.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/04-add-well.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/05-records.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/06-well-page.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/07-declare.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/08-patches.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/09-alarms.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/10-control-room.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/11-summary-month.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/12-where-the-well-is.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/13-drilling-pages.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/14-production-pages.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/15-seismic.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/16-seismicity.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/17-recorder-office.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/18-reports.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/20-admin.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/21-upkeep.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/23-vpn.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/24-the-box.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/26-monitor.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/tutorial/27-mirror-vpn.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/vibration.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/vpn.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/well-report.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/help/well3d.md +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/helplib.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/housekeeping.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/hydraulics.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/icon.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/interval.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/invoice_check.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/jobs.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/launcher.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/live_ports.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/loadtest.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/modbus.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/model_card.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/month_end.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/notify.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/oidc.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/oidc_mock.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/op_seismicity.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/opcua_port.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/operator_app.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/osdu.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/pad_summary.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/patches.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/pdf_report.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/penetrator.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/permits.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/piwebapi.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/pore_pressure.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/ports.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/ppdm.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/project.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/quakeml.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reader.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reader_app.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reconciler.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/recorder_link.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/WMM2025.COF +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/eia_prices.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/iscwsa_rev4_example.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/iscwsa_rev5_example.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/mahoning_example.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/mud_motor_specs.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/owsg_tool_models.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/penetrator_ratings.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/seismicity_protocols.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_3d.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_surfaces.json.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/reference/volve_well_picks.csv.gz +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/report_history.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/rig_state.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sample_record.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sbom.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seedlink.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/segy.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_array.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_film.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_response.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_track.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/seismic_watch.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/series_cache.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/service_life.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/shapefile.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/shell.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/shut_in.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/simulation.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/site_map.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sla_report.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/slip.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/soak.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/sra.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/store_forward.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/strata_join.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/structure.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/supervisor.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/survey_view.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/telemetry.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/timestamp.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tls.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tool_library.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/torque_drag.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/transient.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tray.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/tutorial.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/updates.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/vibration.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/vpn.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/web/reader.html +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/well3d.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/well_assembler.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/well_records.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/well_report.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/wellplan.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/wellpos.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/winident.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/wits0.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/witsml.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/workspace.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/workspaces.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/x25519.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea/xlsx_read.py +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea_program.egg-info/SOURCES.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.78.1 → gea_program-0.80.0}/setup.cfg +0 -0
- {gea_program-0.78.1 → gea_program-0.80.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.80.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
|
|
@@ -473,10 +473,17 @@ build, drop or hold and by how much (toolface and steering ratio for a
|
|
|
473
473
|
rotary steerable system), the weight on bit, the rotary speed, the flow
|
|
474
474
|
rate, and whether to drill on, circulate, or ream and wash first - with its
|
|
475
475
|
reasons and the confidence of each choice. A position filter (since
|
|
476
|
-
0.78.
|
|
476
|
+
0.78.0) places the bit in the layer the way a geosteerer does, from the
|
|
477
477
|
gamma and the deep-resistivity distance against the model, and the screen
|
|
478
478
|
draws the band it puts the layer in. The driller accepts, rejects or
|
|
479
|
-
records what was done instead, by name
|
|
479
|
+
records what was done instead, by name. The third dimension (since
|
|
480
|
+
0.80.0): the lateral has an azimuth, the agent's sixth choice is where to
|
|
481
|
+
aim it and the recommendation reads as one toolface; the layer is a surface with
|
|
482
|
+
a dip across the plan line as well as along it, the hole is placed by
|
|
483
|
+
minimum curvature through the surveys' azimuths, the corridor the lease
|
|
484
|
+
and the offset wells leave the hole is in the twin and on the screen's
|
|
485
|
+
plan view, and the config's model carries the plan's azimuth, the cross
|
|
486
|
+
dip and the corridor. Every recommendation, answer and
|
|
480
487
|
command is on record with its hash, and GEA pulls the records into the
|
|
481
488
|
well from the **Drill string** tab's card (`gea workspace --path C:\site
|
|
482
489
|
--action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
|
|
@@ -830,7 +837,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
|
|
|
830
837
|
reader made from the workspace knows the site's key fingerprints, so it
|
|
831
838
|
says whether a dossier is the site's; it allows no network request, and it
|
|
832
839
|
leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
|
|
833
|
-
it installed, every release also carries `GEA-Reader-Setup-0.
|
|
840
|
+
it installed, every release also carries `GEA-Reader-Setup-0.80.0.exe`: GEA
|
|
834
841
|
Reader as a Windows program of its own - its own icon and taskbar button,
|
|
835
842
|
Check with GEA Reader on a dossier's right-click menu, fingerprints the client
|
|
836
843
|
saves kept on that computer, nothing of GEA-Program. `gea help reader`.
|
|
@@ -1595,7 +1602,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1595
1602
|
|
|
1596
1603
|
### The Windows installer
|
|
1597
1604
|
|
|
1598
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1605
|
+
Every release also carries `GEA-Program-Setup-0.80.0.exe` (for 0.80.0): the
|
|
1599
1606
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1600
1607
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1601
1608
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1614,7 +1621,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1614
1621
|
software deployment:
|
|
1615
1622
|
|
|
1616
1623
|
```
|
|
1617
|
-
GEA-Program-Setup-0.
|
|
1624
|
+
GEA-Program-Setup-0.80.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1618
1625
|
```
|
|
1619
1626
|
|
|
1620
1627
|
The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
|
|
@@ -434,10 +434,17 @@ build, drop or hold and by how much (toolface and steering ratio for a
|
|
|
434
434
|
rotary steerable system), the weight on bit, the rotary speed, the flow
|
|
435
435
|
rate, and whether to drill on, circulate, or ream and wash first - with its
|
|
436
436
|
reasons and the confidence of each choice. A position filter (since
|
|
437
|
-
0.78.
|
|
437
|
+
0.78.0) places the bit in the layer the way a geosteerer does, from the
|
|
438
438
|
gamma and the deep-resistivity distance against the model, and the screen
|
|
439
439
|
draws the band it puts the layer in. The driller accepts, rejects or
|
|
440
|
-
records what was done instead, by name
|
|
440
|
+
records what was done instead, by name. The third dimension (since
|
|
441
|
+
0.80.0): the lateral has an azimuth, the agent's sixth choice is where to
|
|
442
|
+
aim it and the recommendation reads as one toolface; the layer is a surface with
|
|
443
|
+
a dip across the plan line as well as along it, the hole is placed by
|
|
444
|
+
minimum curvature through the surveys' azimuths, the corridor the lease
|
|
445
|
+
and the offset wells leave the hole is in the twin and on the screen's
|
|
446
|
+
plan view, and the config's model carries the plan's azimuth, the cross
|
|
447
|
+
dip and the corridor. Every recommendation, answer and
|
|
441
448
|
command is on record with its hash, and GEA pulls the records into the
|
|
442
449
|
well from the **Drill string** tab's card (`gea workspace --path C:\site
|
|
443
450
|
--action driller-pull --box http://192.168.1.60:8790 --well SWD-1`). The
|
|
@@ -791,7 +798,7 @@ unsigned, the key hand-overs - and shows the reports as they were signed. A
|
|
|
791
798
|
reader made from the workspace knows the site's key fingerprints, so it
|
|
792
799
|
says whether a dossier is the site's; it allows no network request, and it
|
|
793
800
|
leaves the trusted time-stamp to `verify_dossier.py`. For a client who wants
|
|
794
|
-
it installed, every release also carries `GEA-Reader-Setup-0.
|
|
801
|
+
it installed, every release also carries `GEA-Reader-Setup-0.80.0.exe`: GEA
|
|
795
802
|
Reader as a Windows program of its own - its own icon and taskbar button,
|
|
796
803
|
Check with GEA Reader on a dossier's right-click menu, fingerprints the client
|
|
797
804
|
saves kept on that computer, nothing of GEA-Program. `gea help reader`.
|
|
@@ -1556,7 +1563,7 @@ attaches the zips to the GitHub release of that tag.
|
|
|
1556
1563
|
|
|
1557
1564
|
### The Windows installer
|
|
1558
1565
|
|
|
1559
|
-
Every release also carries `GEA-Program-Setup-0.
|
|
1566
|
+
Every release also carries `GEA-Program-Setup-0.80.0.exe` (for 0.80.0): the
|
|
1560
1567
|
same Windows kit installed like any Windows program, for the signed-in user
|
|
1561
1568
|
alone and with no administrator rights (`%LOCALAPPDATA%\Programs\GEA-Program`).
|
|
1562
1569
|
It asks for the site workspace (an existing one such as `C:\site` is used as
|
|
@@ -1575,7 +1582,7 @@ it, removes the program and leaves the workspace. Silent, for a site's
|
|
|
1575
1582
|
software deployment:
|
|
1576
1583
|
|
|
1577
1584
|
```
|
|
1578
|
-
GEA-Program-Setup-0.
|
|
1585
|
+
GEA-Program-Setup-0.80.0.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /WORKSPACE="C:\site" /SITENAME="Pad 3" /TASKS="desktopicon"
|
|
1579
1586
|
```
|
|
1580
1587
|
|
|
1581
1588
|
The setup is built by Inno Setup 6 from `tools/installer.iss` in the same
|
|
@@ -370,7 +370,7 @@ def main(argv=None) -> int:
|
|
|
370
370
|
p_ws.add_argument("--path", type=str, required=True, help="the workspace folder")
|
|
371
371
|
p_ws.add_argument("--action", type=str, default="list",
|
|
372
372
|
choices=["init", "add-file", "add-catalog", "add-live", "remove", "list", "migrate", "refresh", "audit",
|
|
373
|
-
"add-seismic", "refresh-seismic", "remove-seismic", "sar-film", "bit-image", "field-pull", "driller-pull", "refresh-all", "add-track", "refresh-track", "remove-track",
|
|
373
|
+
"add-seismic", "refresh-seismic", "remove-seismic", "sar-film", "bit-image", "field-pull", "driller-pull", "driller-shadow", "refresh-all", "add-track", "refresh-track", "remove-track",
|
|
374
374
|
"seismic-dataset", "seismic-field", "add-site", "sites", "site-report", "remove-site", "rename",
|
|
375
375
|
"set-well", "sra-define", "sra-report", "associate", "osdu-export", "quakeml-export", "well-identity", "vibration-report",
|
|
376
376
|
"add-live-station", "live-fold", "live-run", "month-end", "add-layer", "layers", "remove-layer", "structure", "interval",
|
|
@@ -3563,6 +3563,20 @@ def main(argv=None) -> int:
|
|
|
3563
3563
|
if not a.track:
|
|
3564
3564
|
raise SystemExit("remove-track needs --track TRACK_ID")
|
|
3565
3565
|
ws.remove_track(a.track, actor=a.actor); print("removed (folder kept):", a.track); return 0
|
|
3566
|
+
elif a.action == "driller-shadow":
|
|
3567
|
+
from . import driller_link as DL
|
|
3568
|
+
if not a.well:
|
|
3569
|
+
raise SystemExit("driller-shadow needs --well Well-30636033 (a well with a drilling-recorder export)")
|
|
3570
|
+
try:
|
|
3571
|
+
r = DL.shadow(ws, a.well, actor=a.actor)
|
|
3572
|
+
except (ValueError, RuntimeError) as e:
|
|
3573
|
+
raise SystemExit(f"driller-shadow: {e}")
|
|
3574
|
+
sm = r['summary']
|
|
3575
|
+
print(f"{r['label']} - {r['display']}: {sm['decisions']} decisions over {sm['lateral_ft']:,.0f} ft of lateral; the steer agrees {sm['steer_agree_pct']:.0f}%, opposes {sm['steer_oppose_pct']:.0f}%; "
|
|
3576
|
+
f"WOB {sm['wob_agree_pct']:.0f}%, rpm {sm['rpm_agree_pct']:.0f}%, flow {sm['flow_agree_pct']:.0f}%; out by the gamma {sm['out_by_gamma_pct']:.0f}% in {sm['exits']} stretch(es), "
|
|
3577
|
+
f"the advisor called the way back at the first reading {sm['exits_called_at_first_reading']} time(s); the model {'read off the lateral in hindsight' if r['model_derived'] else 'as given'}; "
|
|
3578
|
+
f"the report: {r['report']['html']}")
|
|
3579
|
+
return 0
|
|
3566
3580
|
elif a.action == "driller-pull":
|
|
3567
3581
|
from . import driller_link as DL
|
|
3568
3582
|
if not a.box or not a.well:
|
|
@@ -16698,7 +16698,7 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16698
16698
|
e_ = inf["estimate"]; truth = inf["lithology"]
|
|
16699
16699
|
guess = max(("above", e_["p_above"]), ("in", e_["p_in"]), ("below", e_["p_below"]), key=lambda x: x[1])[0]
|
|
16700
16700
|
conf[truth][guess] += 1; n_steps += 1
|
|
16701
|
-
errs.append(abs(e_["d_top"] - (lt.tvd - sc.layer_top(lt.vs))))
|
|
16701
|
+
errs.append(abs(e_["d_top"] - (lt.tvd - sc.layer_top(lt.vs, getattr(lt, "y", 0.0)))))
|
|
16702
16702
|
right = sum(conf[k][k] for k in conf); total = sum(sum(v.values()) for v in conf.values())
|
|
16703
16703
|
# a filter told nothing but the gamma of a flat layer sits where the model says; told a boundary, it moves
|
|
16704
16704
|
f1 = PF.PositionFilter(9000.0, 0.0, 40.0, 60.0, 130.0, 115.0, seed=3)
|
|
@@ -16730,6 +16730,287 @@ def section_dv_driller(tmp: str) -> None:
|
|
|
16730
16730
|
"card, the workspace command, the VPN kind, the kit and the workflow, and the help page carry it" + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
|
|
16731
16731
|
|
|
16732
16732
|
|
|
16733
|
+
def section_dw_shadow(tmp: str) -> None:
|
|
16734
|
+
"""Section DW - shadow mode: a drilled lateral replayed through the advisor against the record. A lateral drilled
|
|
16735
|
+
in the twin by the agent itself, written as the driller's lateral file: the heel found below a vertical
|
|
16736
|
+
approach, the model read off the gamma in hindsight close to the twin's own layer, one decision per 30 ft, the
|
|
16737
|
+
agent agreeing with its own record more often than not, the exits the gamma marks called at the first reading,
|
|
16738
|
+
the report in three files labelled SHADOW MODE; in GEA, a drilling-recorder well shadowed as a job from the
|
|
16739
|
+
card, the lateral file written from the export beside the well, the report under the well's reports, the
|
|
16740
|
+
audit line, the refusals and the help."""
|
|
16741
|
+
import http.cookiejar
|
|
16742
|
+
import importlib
|
|
16743
|
+
import urllib.error
|
|
16744
|
+
import urllib.request
|
|
16745
|
+
from . import driller_link as DL
|
|
16746
|
+
from . import edr as E
|
|
16747
|
+
from . import helplib as H
|
|
16748
|
+
from .service import Service, Users
|
|
16749
|
+
from .workspace import Workspace
|
|
16750
|
+
pkg = Path(__file__).parent
|
|
16751
|
+
d = Path(tmp, "dw"); d.mkdir()
|
|
16752
|
+
prog = DL.program()
|
|
16753
|
+
if prog is None:
|
|
16754
|
+
ok(True, "DW the driller's program (gea-driller) is not installed beside GEA in this install; nothing to shadow here")
|
|
16755
|
+
return
|
|
16756
|
+
if prog["env"] and prog["env"] not in sys.path:
|
|
16757
|
+
sys.path.insert(0, prog["env"])
|
|
16758
|
+
SH = importlib.import_module("gea_driller.shadow"); P = importlib.import_module("gea_driller.policy"); S = importlib.import_module("gea_driller.service")
|
|
16759
|
+
np_ = importlib.import_module("numpy")
|
|
16760
|
+
pol = P.Policy.load(S.SHIPPED_POLICY)
|
|
16761
|
+
# -- DW1 the replay on a lateral whose layer is known ------------------------------------------------------------------
|
|
16762
|
+
lat_csv = str(d / "lat.csv")
|
|
16763
|
+
info = SH.twin_lateral(lat_csv, seed=7, act_fn=P.policy_act_fn(pol))
|
|
16764
|
+
lat = SH.read_lateral(lat_csv)
|
|
16765
|
+
heel = SH.find_heel(lat["md_ft"], lat["tvd_ft"])
|
|
16766
|
+
res = SH.run(lat_csv, pol, out_dir=str(d / "out"), well="Twin 7", site="Pad 3 shadow")
|
|
16767
|
+
sc = info["scene"]; m = res["model"]; sm = res["summary"]
|
|
16768
|
+
bad_cols = str(d / "bad.csv")
|
|
16769
|
+
Path(bad_cols).write_text("md_ft,tvd_ft\n1,2\n", encoding="utf-8")
|
|
16770
|
+
try:
|
|
16771
|
+
SH.read_lateral(bad_cols); cols_refused = False
|
|
16772
|
+
except ValueError:
|
|
16773
|
+
cols_refused = True
|
|
16774
|
+
given = SH.run(lat_csv, pol, model={"layer_top_tvd_ft": sc["layer_top_heel_ft"], "thickness_ft": sc["thickness_ft"], "dip_deg": sc["dip_deg"], "gamma_in": sc["gamma_in_above_below"][0],
|
|
16775
|
+
"gamma_above": sc["gamma_in_above_below"][1], "gamma_below": sc["gamma_in_above_below"][2], "heel_md_ft": info["heel_md"]}, well="Twin 7")
|
|
16776
|
+
md_text = Path(res["paths"]["md"]).read_text(encoding="utf-8"); html_text = Path(res["paths"]["html"]).read_text(encoding="utf-8")
|
|
16777
|
+
c1 = {
|
|
16778
|
+
"heel": -150.0 <= lat["md_ft"][heel] - info["heel_md"] <= 30.0, # found in the last of the build, never past the heel
|
|
16779
|
+
"model": abs(m["layer_top_tvd_ft"] - sc["layer_top_heel_ft"]) <= 40.0 and 0.5 <= m["thickness_ft"] / sc["thickness_ft"] <= 1.6 and abs(m["dip_deg"] - sc["dip_deg"]) <= 1.0 and res["model_derived"],
|
|
16780
|
+
"decisions": abs(sm["decisions"] - sm["lateral_ft"] / 30.0) <= 4 and sm["decisions"] >= 100,
|
|
16781
|
+
"self_agreement": sm["steer_agree_pct"] >= 35.0 and sm["steer_oppose_pct"] <= 30.0 and sm["steer_agree_pct"] > sm["steer_oppose_pct"],
|
|
16782
|
+
"exits": sm["exits"] >= 1 and sm["exits_called_at_first_reading"] >= 1,
|
|
16783
|
+
"given_model": not given["model_derived"] and given["model"]["thickness_ft"] == sc["thickness_ft"] and given["summary"]["model_fit"] == "given" and sm["model_fit"] in ("good", "fair"),
|
|
16784
|
+
"report": all(Path(res["paths"][k]).is_file() for k in ("json", "md", "html")) and "SHADOW MODE" in md_text and "SHADOW MODE" in html_text and "<svg" in html_text
|
|
16785
|
+
and "Not the pre-drill model" in md_text and "nothing here touched the well" in md_text.lower(),
|
|
16786
|
+
"refusal": cols_refused,
|
|
16787
|
+
}
|
|
16788
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
16789
|
+
ok(not failed1,
|
|
16790
|
+
f"DW1 a lateral drilled in the twin by the agent, replayed: the heel found below the vertical approach, the model read off the gamma in hindsight within "
|
|
16791
|
+
f"40 ft, a factor and a degree of the twin's own layer, one decision per 30 ft ({sm['decisions']}), the agent agreeing with its own record "
|
|
16792
|
+
f"{sm['steer_agree_pct']:.0f}% and opposing it {sm['steer_oppose_pct']:.0f}%, the gamma's exits called at the first reading, a given model taken as given, "
|
|
16793
|
+
"the report in three files labelled SHADOW MODE with the drawing, a lateral file without the columns refused" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
16794
|
+
# -- DW2 GEA: a drilling-recorder well shadowed from the card -----------------------------------------------------------
|
|
16795
|
+
ws = Workspace.create(str(d / "ws"), "Pad 3 shadow", actor="tester")
|
|
16796
|
+
exp = E.selftest(str(d), 3000)
|
|
16797
|
+
w = ws.add_well_file(exp["path"], display="Well EDR", actor="tester")
|
|
16798
|
+
w2 = ws.add_well_records("Paper well", actor="tester")
|
|
16799
|
+
rec = DL.shadow(ws, w["id"], actor="tester")
|
|
16800
|
+
try:
|
|
16801
|
+
DL.shadow(ws, w2["id"], actor="tester"); no_edr_refused = False
|
|
16802
|
+
except ValueError:
|
|
16803
|
+
no_edr_refused = True
|
|
16804
|
+
Users(str(Path(ws.path, "users.json"))).add("op", "op-pass-123", "operator")
|
|
16805
|
+
svc = Service(ws.path, port=0, scheduler=False).start()
|
|
16806
|
+
base = svc.url.rstrip("/")
|
|
16807
|
+
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
16808
|
+
|
|
16809
|
+
def gcall(method, path, body=None):
|
|
16810
|
+
rq = urllib.request.Request(base + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
16811
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
|
|
16812
|
+
try:
|
|
16813
|
+
with opener.open(rq, timeout=60) as rr_:
|
|
16814
|
+
return rr_.status, json.loads(rr_.read())
|
|
16815
|
+
except urllib.error.HTTPError as e:
|
|
16816
|
+
return e.code, json.loads(e.read() or b"{}")
|
|
16817
|
+
try:
|
|
16818
|
+
gcall("POST", "/api/login", {"name": "op", "password": "op-pass-123"})
|
|
16819
|
+
s_d, dd = gcall("GET", "/api/driller")
|
|
16820
|
+
s_bad, _ = gcall("POST", "/api/driller/shadow", {"well": w2["id"]})
|
|
16821
|
+
s_job, job = gcall("POST", "/api/driller/shadow", {"well": w["id"]})
|
|
16822
|
+
finally:
|
|
16823
|
+
svc.stop()
|
|
16824
|
+
app_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
16825
|
+
main_src = (pkg / "__main__.py").read_text(encoding="utf-8")
|
|
16826
|
+
c2 = {
|
|
16827
|
+
"lateral_file": Path(ws.path, "wells", w["id"], "driller", "lateral.csv").is_file() and rec["lateral"]["rows"] >= 1000 and rec["lateral"]["gamma_rows"] > 0,
|
|
16828
|
+
"report": all(Path(ws.reports_dir, rec["report"][k]).is_file() for k in ("html", "md", "json")) and rec["label"] == "SHADOW MODE" and rec["summary"]["decisions"] >= 20 and rec["model_derived"],
|
|
16829
|
+
"record": DL.last_shadow(ws, w["id"]) is not None and [x["well"] for x in DL.shadow_wells(ws)] == [w["id"]],
|
|
16830
|
+
"refusal": no_edr_refused,
|
|
16831
|
+
"audit": any(a["action"] == "driller.shadow" and a["detail"]["label"] == "SHADOW MODE" for a in ws.audit_log()),
|
|
16832
|
+
"routes": s_d == 200 and [x["well"] for x in dd["shadow"]] == [w["id"]] and dd["shadow"][0]["shadow"]["summary"]["decisions"] >= 20 and s_bad == 400 and s_job == 200 and "id" in job,
|
|
16833
|
+
"card": all(t_ in app_src for t_ in ("Shadow a drilled well", "/api/driller/shadow", "Shadow mode")),
|
|
16834
|
+
"cli": '"driller-shadow"' in main_src and "DL.shadow" in main_src,
|
|
16835
|
+
"help": not H.check("driller") and "SHADOW MODE" in (pkg / "help" / "driller.md").read_text(encoding="utf-8"),
|
|
16836
|
+
}
|
|
16837
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
16838
|
+
ok(not failed2,
|
|
16839
|
+
"DW2 in GEA a drilling-recorder well is shadowed: the lateral file written from the export beside the well, the driller's program run on it, the report "
|
|
16840
|
+
"under the well's reports labelled SHADOW MODE, the run recorded and audited; a well without an export is refused; the route runs it as a job and "
|
|
16841
|
+
"refuses the wrong well; the card, the workspace command and the help page carry it" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
16842
|
+
|
|
16843
|
+
|
|
16844
|
+
def section_dx_third_dimension(tmp: str) -> None:
|
|
16845
|
+
"""Section DX - the third dimension of GEA Driller: the directional arithmetic (minimum curvature, the dogleg of a
|
|
16846
|
+
build and a turn, the toolface), the twin in the plan's frame (the turn, the layer as a surface, the corridor,
|
|
16847
|
+
an older five-choice action), the filter's cross dip; the rig side (the bit placed from surveys with azimuths,
|
|
16848
|
+
the twin as the rig publishing the azimuth, a decision with the turn and the toolface, an override with a turn,
|
|
16849
|
+
the limit on both together, the config's refusals, the screen, the help); the policy with six heads holding the
|
|
16850
|
+
corridor on the held-out scenes, and shadow mode judging the turn with the record's azimuth and not without.
|
|
16851
|
+
The sixth choice is where to aim the azimuth (left of the plan, along it, right of it); the tool turns toward it
|
|
16852
|
+
at its own rate, as a directional driller holds the azimuth he is given."""
|
|
16853
|
+
import importlib
|
|
16854
|
+
import math as _m
|
|
16855
|
+
from . import driller_link as DL
|
|
16856
|
+
from . import helplib as H
|
|
16857
|
+
pkg = Path(__file__).parent
|
|
16858
|
+
d = Path(tmp, "dx"); d.mkdir()
|
|
16859
|
+
prog = DL.program()
|
|
16860
|
+
if prog is None:
|
|
16861
|
+
ok(True, "DX the driller's program (gea-driller) is not installed beside GEA in this install; nothing to check here")
|
|
16862
|
+
return
|
|
16863
|
+
if prog["env"] and prog["env"] not in sys.path:
|
|
16864
|
+
sys.path.insert(0, prog["env"])
|
|
16865
|
+
T = importlib.import_module("gea_driller.twin"); G = importlib.import_module("gea_driller.geometry"); PF = importlib.import_module("gea_driller.position")
|
|
16866
|
+
P = importlib.import_module("gea_driller.policy"); A = importlib.import_module("gea_driller.advisor"); C = importlib.import_module("gea_driller.config")
|
|
16867
|
+
S = importlib.import_module("gea_driller.service"); R = importlib.import_module("gea_driller.rig"); SH = importlib.import_module("gea_driller.shadow")
|
|
16868
|
+
np_ = importlib.import_module("numpy")
|
|
16869
|
+
# -- DX1 the arithmetic, the twin, the filter -----------------------------------------------------------------------------
|
|
16870
|
+
dn, de, dv, dl = G.min_curvature(90.0, 30.0, 90.0, 30.0, 1000.0)
|
|
16871
|
+
_, _, dv_b, dl_b = G.min_curvature(90.0, 0.0, 91.5, 0.0, 100.0)
|
|
16872
|
+
_, _, _, dl_t = G.min_curvature(90.0, 0.0, 90.0, 2.0, 100.0)
|
|
16873
|
+
_, _, _, dl_t60 = G.min_curvature(60.0, 0.0, 60.0, 2.0, 100.0)
|
|
16874
|
+
lh = T.Lateral(T.Scene(3)); lh.reset(); lt = T.Lateral(T.Scene(3)); lt.reset(); l5 = T.Lateral(T.Scene(3)); l5.reset()
|
|
16875
|
+
for _ in range(8):
|
|
16876
|
+
lh.step(T.HOLD_ACTION); lt.step((2, 1, 1, 1, 0, 2)); l5.step((2, 1, 1, 1, 0))
|
|
16877
|
+
sc = T.Scene(3)
|
|
16878
|
+
cross = (sc.layer_top(500.0, 100.0) - sc.layer_top(500.0, 0.0)) - 100.0 * _m.tan(_m.radians(sc.cross_dip_deg))
|
|
16879
|
+
# a hole aimed right of the plan and never brought back leaves the corridor and is lost
|
|
16880
|
+
lw = T.Lateral(T.Scene(9)); lw.scene.corridor_ft = 50.0; lw.reset()
|
|
16881
|
+
while not lw.done and lw.steps < 400:
|
|
16882
|
+
lw.step((2, 1, 1, 1, 0, 2))
|
|
16883
|
+
try:
|
|
16884
|
+
T.full_action((1, 2, 3)); short_refused = False
|
|
16885
|
+
except ValueError:
|
|
16886
|
+
short_refused = True
|
|
16887
|
+
# the filter: with a cross dip in the model, the top moves with the offset; the cross dip is read only across the plan line
|
|
16888
|
+
f_along = PF.PositionFilter(9000.0, 0.0, 40.0, 60.0, 130.0, 115.0, seed=3, model_cross_dip_deg=2.0)
|
|
16889
|
+
f_across = PF.PositionFilter(9000.0, 0.0, 40.0, 60.0, 130.0, 115.0, seed=3, model_cross_dip_deg=2.0)
|
|
16890
|
+
for k in range(40):
|
|
16891
|
+
f_along.predict(30.0, 0.0); f_along.update(9020.0, 60.0) # along the plan: the gamma in the layer, nothing learnt of the cross dip
|
|
16892
|
+
f_across.predict(0.0, 10.0); f_across.update(9020.0 + 10.0 * (k + 1) * _m.tan(_m.radians(1.0)), 62.0, 4.0) # across: the top tracks a real cross dip of 1 degree, the tool says so
|
|
16893
|
+
e_along = f_along.estimate(9020.0); e_across = f_across.estimate(9020.0 + 400.0 * _m.tan(_m.radians(1.0)))
|
|
16894
|
+
top_shift = float(f_along.model_top(0.0, 100.0) - f_along.model_top(0.0, 0.0))
|
|
16895
|
+
c1 = {
|
|
16896
|
+
"straight": abs(dn - 1000.0 * _m.cos(_m.radians(30.0))) < 1e-6 and abs(de - 500.0) < 1e-6 and abs(dv) < 1e-6 and abs(dl) < 1e-9,
|
|
16897
|
+
"dogleg": abs(dl_b - 1.5) < 1e-9 and abs(dl_t - 2.0) < 1e-6 and abs(dl_t60 - 2.0 * _m.sin(_m.radians(60.0))) < 0.02 and abs(dv_b + 100.0 * _m.sin(_m.radians(0.75))) < 0.05,
|
|
16898
|
+
"toolface": abs(G.toolface_of(1.5, 0.0, 90.0)) < 1e-9 and abs(G.toolface_of(0.0, 2.0, 90.0) - 90.0) < 1e-9 and abs(G.toolface_of(-1.5, 0.0, 90.0) - 180.0) < 1e-9
|
|
16899
|
+
and abs(G.toolface_of(0.0, -2.0, 90.0) - 270.0) < 1e-9 and abs(G.dls_of(3.0, 4.0, 90.0) - 5.0) < 1e-9,
|
|
16900
|
+
"turns": lt.az > lh.az + 1.5 and lt.y > lh.y + 5.0 and 2.5 < lt.az - lh.az < 6.0 and abs(T.turn_toward(4.0, 0.0) - 2.0) < 1e-9 and abs(T.turn_toward(0.0, 0.5) + 0.75) < 1e-9,
|
|
16901
|
+
"surface": abs(cross) < 1.0 + sc.und_amp and T.Scene(1).cross_dip_deg != T.Scene(2).cross_dip_deg and "cross_dip_deg" in sc.describe() and "corridor_ft" in sc.describe(),
|
|
16902
|
+
"lost": lw.done and lw.ended == "outside the corridor" and lw.summary()["lost"] and lw.max_offset > lw.scene.corridor_ft + T.CORRIDOR_END_FT and any("outside the corridor" in e for e in lw.events),
|
|
16903
|
+
"five_choices": abs(l5.az - lh.az) < 1e-9 and abs(l5.y - lh.y) < 1e-9 and short_refused and len(T.ACTION_SIZES) == 6 and T.ACTION_NAMES[-1] == "aim",
|
|
16904
|
+
"obs": len(T.OBS_NAMES) == T.OBS_SIZE == 34 == lt.observe().shape[0] and all(np_.isfinite(lt.observe())) and "offset_right_of_plan" in T.OBS_NAMES,
|
|
16905
|
+
"filter": abs(top_shift - 100.0 * _m.tan(_m.radians(2.0))) < 1e-9 and abs(e_along["cross_dip_deg"] - 2.0) < 0.3 and e_along["cross_dip_sigma"] > 0.3
|
|
16906
|
+
and abs(e_across["cross_dip_deg"] - 1.0) < 0.6 and e_across["cross_dip_sigma"] < e_along["cross_dip_sigma"],
|
|
16907
|
+
}
|
|
16908
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
16909
|
+
ok(not failed1,
|
|
16910
|
+
"DX1 minimum curvature lands a straight hole 30° off the plan where the sine says, a build's dogleg is the build and a turn's counts by the inclination's sine, "
|
|
16911
|
+
"the toolface of a build is up and of a turn is right; in the twin an aim right of the plan turns the hole toward it at the tool's rate and swings it to the "
|
|
16912
|
+
"right, the layer's top moves across the plan line by the cross dip, a hole aimed out of the corridor is lost and says so, a five-choice action is taken aimed "
|
|
16913
|
+
"along the plan and a shorter one refused, "
|
|
16914
|
+
"the observation is 34 named and finite; the filter moves the model's top by its cross dip and reads the cross dip only across the plan line"
|
|
16915
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
16916
|
+
# -- DX2 the rig side --------------------------------------------------------------------------------------------------------
|
|
16917
|
+
shipped = P.Policy.load(S.SHIPPED_POLICY)
|
|
16918
|
+
cfg = json.loads(json.dumps(C.EXAMPLE)); cfg["output"]["dir"] = str(d / "rig"); cfg["status"]["port"] = 0; cfg["status"]["bind"] = "127.0.0.1"
|
|
16919
|
+
cfg["rig"]["transport"] = "sim"; cfg["model"]["plan_azimuth_deg"] = 40.0; cfg["model"]["corridor_ft"] = 120.0; cfg["model"]["cross_dip_deg"] = 1.0
|
|
16920
|
+
cfg = C.check(cfg)
|
|
16921
|
+
heel_tvd0 = float(cfg["model"]["heel_tvd_ft"]) # the twin as the rig rewrites the model block in place below
|
|
16922
|
+
try:
|
|
16923
|
+
C.check(json.loads(json.dumps(cfg)) | {"model": {**cfg["model"], "cross_dip_deg": 20.0}}); cross_refused = False
|
|
16924
|
+
except C.ConfigError:
|
|
16925
|
+
cross_refused = True
|
|
16926
|
+
try:
|
|
16927
|
+
C.check(json.loads(json.dumps(cfg)) | {"model": {**cfg["model"], "corridor_ft": 2.0}}); corridor_refused = False
|
|
16928
|
+
except C.ConfigError:
|
|
16929
|
+
corridor_refused = True
|
|
16930
|
+
# the bit placed from surveys: a feed that holds 90 degrees at the plan's azimuth plus 30 for 600 ft
|
|
16931
|
+
feed = R.Feed(cfg); feed.state.update({"hole_depth": 10800.0, "gamma": 60.0, "continuous_inc": 90.0, "continuous_azi": 70.0}); feed.last_utc = time.time(); feed.connected = True
|
|
16932
|
+
for md_ in (10200.0, 10290.0, 10380.0, 10470.0, 10560.0, 10650.0):
|
|
16933
|
+
feed.add_survey(md_, 90.0, 70.0, "test")
|
|
16934
|
+
adv = A.Advisor(cfg, shipped, feed, A.Records(cfg))
|
|
16935
|
+
obs_, ctx = adv.observation(feed.snapshot())
|
|
16936
|
+
rec = adv.decide(feed.snapshot())
|
|
16937
|
+
words_turn = adv._words(1.5, 25.0, 120.0, 500.0, "drill", {"inc": 90.0, "bed": 0.1, "balling": 0.0, "plan_az": 40.0}, {}, 2.0)
|
|
16938
|
+
words_aim = adv._words(1.5, 25.0, 120.0, 500.0, "drill", {"inc": 90.0, "bed": 0.1, "balling": 0.0, "plan_az": 40.0}, {}, 2.0, 4.0)
|
|
16939
|
+
words_hold = adv._words(0.0, 25.0, 120.0, 500.0, "drill", {"inc": 90.0, "bed": 0.1, "balling": 0.0, "plan_az": 40.0}, {}, 0.0, 0.0)
|
|
16940
|
+
ov = adv._action_of({"turn_deg_100ft": -2.0, "build_deg_100ft": 1.5}, [2, 1, 1, 1, 0])
|
|
16941
|
+
# the limit holds the build and the turn together: a 4 deg/100 ft limit on a 3 build with a 2 turn clips both
|
|
16942
|
+
cfg_l = json.loads(json.dumps(cfg)); cfg_l["limits"]["max_dls_deg_100ft"] = 3.0
|
|
16943
|
+
adv_l = A.Advisor(C.check(cfg_l), shipped, feed, A.Records(cfg_l))
|
|
16944
|
+
rl = adv_l.decide(feed.snapshot())
|
|
16945
|
+
# the twin as the rig publishes the azimuth and the plan view has what it needs
|
|
16946
|
+
drl = S.Driller(cfg, policy=shipped, twin_seed=11, twin_pace_s=0.5)
|
|
16947
|
+
drl.start()
|
|
16948
|
+
try:
|
|
16949
|
+
t_end = time.monotonic() + 20
|
|
16950
|
+
while time.monotonic() < t_end and len(drl.advisor.history) < 2:
|
|
16951
|
+
time.sleep(0.2)
|
|
16952
|
+
live = drl.live(); snap = drl.feed.snapshot()
|
|
16953
|
+
import urllib.request
|
|
16954
|
+
with urllib.request.urlopen(drl.url + "/live", timeout=5) as r_:
|
|
16955
|
+
screen = r_.read().decode("utf-8")
|
|
16956
|
+
cur = dict(drl.advisor.history[-1]) if drl.advisor.history else None
|
|
16957
|
+
finally:
|
|
16958
|
+
drl.stop()
|
|
16959
|
+
sv_text = Path(cfg["output"]["dir"], "surveys.csv").read_text(encoding="utf-8")
|
|
16960
|
+
c2 = {
|
|
16961
|
+
"placed": abs(ctx["vs"] - 600.0 * _m.cos(_m.radians(30.0))) < 0.5 and abs(ctx["y"] - 600.0 * _m.sin(_m.radians(30.0))) < 0.5 and abs(ctx["az"] - 30.0) < 1e-9
|
|
16962
|
+
and abs(ctx["tvd"] - heel_tvd0) < 0.5 and ctx["corridor"] == 120.0 and obs_.shape[0] == T.OBS_SIZE and abs(obs_[29] * 50.0 - ctx["y"]) < 1e-6,
|
|
16963
|
+
"decision": rec is not None and rec["recommend"].get("aim_deg") in T.AIM_CHOICES and abs(rec["recommend"]["turn_deg_100ft"]) <= T.TURN_RATE + 1e-9
|
|
16964
|
+
and abs(rec["recommend"]["turn_deg_100ft"] - T.turn_toward(rec["recommend"]["aim_deg"], 30.0)) < 1e-6 and rec["recommend"]["steer_az"] in ("hold", "turn right", "turn left")
|
|
16965
|
+
and abs(rec["recommend"]["aim_azimuth_deg"] - (40.0 + rec["recommend"]["aim_deg"])) < 1e-9
|
|
16966
|
+
and 0.0 <= rec["recommend"]["toolface_deg"] < 360.0 and any("plan line" in r_ for r_ in rec["reasons"]) and "aim" in " ".join(rec["reasons"]) and len(rec["action"]) == 6,
|
|
16967
|
+
"words": "turn right 2.0°/100 ft" in words_turn and "toolface 53°" in words_turn and "Build +1.5" in words_turn and words_hold.startswith("Hold angle and azimuth")
|
|
16968
|
+
and "aim 4° right of the plan (azimuth 44.0°), turning right 2.0°/100 ft" in words_aim,
|
|
16969
|
+
"override": ov == (3, 1, 1, 1, 0, 0),
|
|
16970
|
+
"limit": rl is not None and G.dls_of(rl["recommend"]["build_deg_100ft"], rl["recommend"]["turn_deg_100ft"], 90.0) <= 3.0 + 1e-9,
|
|
16971
|
+
"refusals": cross_refused and corridor_refused,
|
|
16972
|
+
"twin_rig": snap["state"].get("continuous_azi") is not None and live["plan_azimuth_deg"] is not None and live["model"]["corridor_ft"] > 0 and live["path"] and "y" in live["path"][-1]
|
|
16973
|
+
and live["advisor"]["position"] is not None and "true_y" in live["twin"] and cur is not None and "turn_deg_100ft" in cur["recommend"]
|
|
16974
|
+
and all(s_.get("azi") is not None for s_ in snap["surveys"]),
|
|
16975
|
+
"screen": "The plan view" in screen and "drawPlan" in screen and "turn_deg_100ft" in screen and "off the plan line" in screen and 'placeholder="aim' in screen,
|
|
16976
|
+
"surveys_file": "azimuth_deg" in sv_text.splitlines()[0] and len(sv_text.splitlines()) >= 2 and sv_text.splitlines()[1].split(",")[2] not in ("", "0.00"),
|
|
16977
|
+
"help": not H.check("driller") and "The third dimension" in (pkg / "help" / "driller.md").read_text(encoding="utf-8") and "plan view" in (pkg / "help" / "tutorial" / "28-driller-office.md").read_text(encoding="utf-8"),
|
|
16978
|
+
}
|
|
16979
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
16980
|
+
ok(not failed2,
|
|
16981
|
+
"DX2 the advisor places the bit from surveys 30° off the plan where the arithmetic says (along, right, depth), a decision carries the aim, the turn it asks "
|
|
16982
|
+
"from where the hole points and the toolface, with the azimuth and the corridor among its reasons, the words name a build and an aim as one toolface, an "
|
|
16983
|
+
"override takes the aim or the turn made, the DLS limit "
|
|
16984
|
+
"holds the build and the turn together, a cross dip and a corridor out of range are refused, the twin as the rig publishes the azimuth and surveys with it, "
|
|
16985
|
+
"the screen carries the plan view, and the help and the tutorial say so" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
16986
|
+
# -- DX3 the policy and shadow mode -------------------------------------------------------------------------------------------
|
|
16987
|
+
ev = P.evaluate(P.policy_act_fn(shipped), range(20), "agent"); tb = P.evaluate(T.textbook_action, range(20), "textbook")
|
|
16988
|
+
lat_az = str(d / "lat_az.csv"); lat_no = str(d / "lat_no.csv")
|
|
16989
|
+
info = SH.twin_lateral(lat_az, seed=5, act_fn=P.policy_act_fn(shipped)); SH.twin_lateral(lat_no, seed=5, act_fn=P.policy_act_fn(shipped), with_azimuth=False)
|
|
16990
|
+
sc5 = info["scene"]
|
|
16991
|
+
model5 = {"layer_top_tvd_ft": sc5["layer_top_heel_ft"], "thickness_ft": sc5["thickness_ft"], "dip_deg": sc5["dip_deg"], "cross_dip_deg": sc5["cross_dip_deg"],
|
|
16992
|
+
"gamma_in": sc5["gamma_in_above_below"][0], "gamma_above": sc5["gamma_in_above_below"][1], "gamma_below": sc5["gamma_in_above_below"][2],
|
|
16993
|
+
"heel_md_ft": info["heel_md"], "plan_azimuth_deg": sc5["plan_azimuth_deg"], "corridor_ft": sc5["corridor_ft"]}
|
|
16994
|
+
r_az = SH.run(lat_az, shipped, model=model5, out_dir=str(d / "sh_az"), well="Twin 5"); r_no = SH.run(lat_no, shipped, model=model5, well="Twin 5")
|
|
16995
|
+
md_az = Path(r_az["paths"]["md"]).read_text(encoding="utf-8")
|
|
16996
|
+
c3 = {
|
|
16997
|
+
"heads": list(shipped.to_json()["action_sizes"]) == list(T.ACTION_SIZES) and shipped.to_json()["obs_size"] == 34 and int(shipped.meta.get("trained_steps", 0)) >= 1000000,
|
|
16998
|
+
"corridor": ev["corridor_pct"] >= 90.0 and ev["lost"] == 0 and ev["max_offset_ft"] < 200.0,
|
|
16999
|
+
"textbook_corridor": tb["corridor_pct"] >= 95.0 and tb["lost"] == 0,
|
|
17000
|
+
"layer": ev["in_layer_pct"] > tb["in_layer_pct"] and ev["reward"] > tb["reward"],
|
|
17001
|
+
"shadow_turn": r_az["summary"]["azimuth_in_record"] and r_az["summary"]["turn_agree_pct"] is not None and r_az["summary"]["turn_agree_pct"] >= 30.0
|
|
17002
|
+
and (r_az["summary"]["turn_oppose_pct"] or 0.0) <= 30.0 and "The turn (right, hold or left" in md_az,
|
|
17003
|
+
"shadow_without": not r_no["summary"]["azimuth_in_record"] and r_no["summary"]["turn_agree_pct"] is None and all(x["actual"]["turn"] is None for x in r_no["decisions"]),
|
|
17004
|
+
"model_through": r_az["model"]["plan_azimuth_deg"] == sc5["plan_azimuth_deg"] and r_az["model"]["cross_dip_deg"] == sc5["cross_dip_deg"],
|
|
17005
|
+
}
|
|
17006
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
17007
|
+
ok(not failed3,
|
|
17008
|
+
f"DX3 the shipped policy has six heads over 34 observations; on twenty held-out scenes it keeps {ev['corridor_pct']:.0f}% of the hole in the corridor "
|
|
17009
|
+
f"(none lost, {ev['in_layer_pct']:.0f}% in the layer against the textbook's {tb['in_layer_pct']:.0f}%, SIMULATION) and the textbook holds the corridor; shadow mode "
|
|
17010
|
+
f"judges the turn from a record with the azimuth ({r_az['summary']['turn_agree_pct'] or 0:.0f}% agreeing) and leaves it unjudged without one, and a given model's "
|
|
17011
|
+
"plan azimuth and cross dip go through" + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
17012
|
+
|
|
17013
|
+
|
|
16733
17014
|
def main() -> int:
|
|
16734
17015
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
16735
17016
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -16859,6 +17140,8 @@ def main() -> int:
|
|
|
16859
17140
|
section_dt_vpn(tmp)
|
|
16860
17141
|
section_du_tutorial(tmp)
|
|
16861
17142
|
section_dv_driller(tmp)
|
|
17143
|
+
section_dw_shadow(tmp)
|
|
17144
|
+
section_dx_third_dimension(tmp)
|
|
16862
17145
|
if _FAILS:
|
|
16863
17146
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
16864
17147
|
for f in _FAILS:
|
|
@@ -276,3 +276,131 @@ def wells_with_records(ws) -> List[dict]:
|
|
|
276
276
|
if lp:
|
|
277
277
|
out.append({'well': w['id'], 'display': w.get('display', w['id']), 'pulled_utc': lp['pulled_utc'], 'source': lp['source'], 'summary': lp['summary'], 'rig_well': lp.get('rig_well')})
|
|
278
278
|
return out
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# -- shadow mode: a drilled well of this workspace replayed through the advisor ---------------------------------------------
|
|
282
|
+
|
|
283
|
+
LATERAL_COLUMNS = ('md_ft', 'tvd_ft', 'gamma_api', 'wob_klb', 'rpm', 'flow_gpm', 'rop_ft_hr', 'spp_psi', 'hours')
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def lateral_from_edr(ws, well_id: str, out_csv: str) -> dict:
|
|
287
|
+
"""The driller's lateral file from a well's drilling-recorder export: one row per foot of hole made while on
|
|
288
|
+
bottom - the first second the hole reached that foot - with the gamma as the median of the seconds since the
|
|
289
|
+
foot before, and the rig's parameters at that second. Written beside the well; the export is read, not copied."""
|
|
290
|
+
import csv as _csv
|
|
291
|
+
from . import edr as E
|
|
292
|
+
well = next((w for w in ws.wells() if w['id'] == well_id), None)
|
|
293
|
+
if well is None:
|
|
294
|
+
raise ValueError(f'no well {well_id}')
|
|
295
|
+
src = next((os.path.join(ws.path, 'wells', well_id, 'source', f) for f in well.get('files', []) if f.lower().endswith('.csv')), None)
|
|
296
|
+
if not src or not E.is_edr(src):
|
|
297
|
+
raise ValueError(f"{well_id} has no drilling-recorder export (an EDR CSV) under its sources")
|
|
298
|
+
st = E.read(src)
|
|
299
|
+
ch = {k: E._ch(st, k) for k in ('hole', 'tvd', 'gamma', 'wob', 'rpm', 'flow', 'rop', 'spp', 'onb')}
|
|
300
|
+
hole = ch['hole']
|
|
301
|
+
if hole is None or ch['tvd'] is None:
|
|
302
|
+
raise ValueError('the export carries no hole depth or no interpolated TVD; the lateral cannot be placed')
|
|
303
|
+
# the depth channel read for what it can be trusted for, as the drilling record reads it: a section that opens on
|
|
304
|
+
# another well's depth, a re-reference, a sidetrack's abandoned hole are left out
|
|
305
|
+
de = E.depth_events(st)
|
|
306
|
+
keep_h, _ = E._keep_masks(st, de)
|
|
307
|
+
secs = st.index
|
|
308
|
+
n = len(hole)
|
|
309
|
+
rows = []
|
|
310
|
+
seen = set(); g_acc = []
|
|
311
|
+
for i in range(n):
|
|
312
|
+
h = hole[i]
|
|
313
|
+
if h is None or (isinstance(h, float) and (h != h)) or not keep_h[i]:
|
|
314
|
+
continue
|
|
315
|
+
if ch['gamma'] is not None and not (ch['gamma'][i] != ch['gamma'][i]):
|
|
316
|
+
g_acc.append(float(ch['gamma'][i]))
|
|
317
|
+
foot = int(h)
|
|
318
|
+
if foot in seen:
|
|
319
|
+
continue
|
|
320
|
+
seen.add(foot)
|
|
321
|
+
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 = []
|
|
327
|
+
if len(rows) < 100:
|
|
328
|
+
raise ValueError(f'the export yields only {len(rows)} feet of new hole; a lateral is thousands')
|
|
329
|
+
rows.sort(key=lambda r: r['md_ft'])
|
|
330
|
+
os.makedirs(os.path.dirname(out_csv), exist_ok=True)
|
|
331
|
+
with open(out_csv, 'w', encoding='utf-8', newline='') as f:
|
|
332
|
+
w = _csv.DictWriter(f, fieldnames=list(LATERAL_COLUMNS)); w.writeheader()
|
|
333
|
+
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})
|
|
335
|
+
rows.sort(key=lambda r: r['md_ft'])
|
|
336
|
+
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']),
|
|
337
|
+
'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
|
+
|
|
339
|
+
|
|
340
|
+
def _v(arr, i):
|
|
341
|
+
if arr is None:
|
|
342
|
+
return float('nan')
|
|
343
|
+
x = arr[i]
|
|
344
|
+
return float(x) if not (x != x) else float('nan')
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def shadow(ws, well_id: str, actor: str = 'system', model: Optional[dict] = None, timeout_s: float = 1800.0) -> dict:
|
|
348
|
+
"""SHADOW MODE on a well of this workspace: the lateral file from its export, the driller's own program run
|
|
349
|
+
on it as a process of its own, the report kept under the well's reports and the summary in the driller folder."""
|
|
350
|
+
from . import __version__
|
|
351
|
+
prog = program()
|
|
352
|
+
if prog is None:
|
|
353
|
+
raise ValueError("the driller's program (gea-driller) is not installed beside GEA: the kit and the setup carry it")
|
|
354
|
+
well = next((w for w in ws.wells() if w['id'] == well_id), None)
|
|
355
|
+
if well is None:
|
|
356
|
+
raise ValueError(f'no well {well_id}')
|
|
357
|
+
d = ws.dir('wells', well_id, 'driller')
|
|
358
|
+
lat_csv = os.path.join(d, 'lateral.csv')
|
|
359
|
+
lat = lateral_from_edr(ws, well_id, lat_csv)
|
|
360
|
+
if model is None and os.path.isfile(os.path.join(d, 'model.json')): # the site's pre-drill model, kept beside the well
|
|
361
|
+
with open(os.path.join(d, 'model.json'), encoding='utf-8') as f:
|
|
362
|
+
model = json.load(f)
|
|
363
|
+
model = model.get('model', model)
|
|
364
|
+
out = ws.dir('reports', 'wells', well_id, 'driller_shadow')
|
|
365
|
+
cmd = [sys.executable, '-m', 'gea_driller', 'shadow', '--lateral', lat_csv, '--out', out, '--well', str(well.get('display', well_id)), '--site', str(ws.manifest.get('name') or 'site'), '--json']
|
|
366
|
+
if model:
|
|
367
|
+
mp = os.path.join(d, 'model.json')
|
|
368
|
+
if not os.path.isfile(mp):
|
|
369
|
+
with open(mp, 'w', encoding='utf-8') as f:
|
|
370
|
+
json.dump({'model': model}, f, indent=1)
|
|
371
|
+
cmd += ['--model', mp]
|
|
372
|
+
env = dict(os.environ)
|
|
373
|
+
if prog['env']:
|
|
374
|
+
env['PYTHONPATH'] = prog['env'] + (os.pathsep + env['PYTHONPATH'] if env.get('PYTHONPATH') else '')
|
|
375
|
+
r = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=timeout_s)
|
|
376
|
+
if r.returncode != 0:
|
|
377
|
+
raise RuntimeError(f"the driller's shadow run failed: {(r.stderr or r.stdout).strip()[-600:]}")
|
|
378
|
+
res = json.loads(r.stdout)
|
|
379
|
+
rec = {'well': well_id, 'display': well.get('display', well_id), 'run_utc': res['run_utc'], 'by': actor, 'label': res['label'], 'driller_version': res['version'],
|
|
380
|
+
'lateral': lat, 'model': res['model'], 'model_derived': res['model_derived'], 'summary': res['summary'], 'exits': res['exits'][:50],
|
|
381
|
+
'report': {k: os.path.relpath(v, ws.reports_dir) for k, v in res['paths'].items()}, 'gea_version': __version__}
|
|
382
|
+
with open(os.path.join(d, 'shadow.json'), 'w', encoding='utf-8') as f:
|
|
383
|
+
json.dump(rec, f, indent=1)
|
|
384
|
+
ws.audit(actor, 'driller.shadow', {'well': well_id, 'decisions': res['summary']['decisions'], 'steer_agree_pct': round(res['summary']['steer_agree_pct'], 1),
|
|
385
|
+
'model_derived': res['model_derived'], 'label': res['label']}, inputs=[lat['source']])
|
|
386
|
+
return rec
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def last_shadow(ws, well_id: str) -> Optional[dict]:
|
|
390
|
+
p = os.path.join(ws.path, 'wells', well_id, 'driller', 'shadow.json')
|
|
391
|
+
try:
|
|
392
|
+
with open(p, encoding='utf-8') as f:
|
|
393
|
+
return json.load(f)
|
|
394
|
+
except (OSError, ValueError):
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def shadow_wells(ws) -> List[dict]:
|
|
399
|
+
"""The wells a shadow run can take (a drilling-recorder export among their sources), with the last run if any."""
|
|
400
|
+
from . import edr as E
|
|
401
|
+
out = []
|
|
402
|
+
for w in ws.wells():
|
|
403
|
+
srcs = [os.path.join(ws.path, 'wells', w['id'], 'source', f) for f in w.get('files', []) if f.lower().endswith('.csv')]
|
|
404
|
+
if any(os.path.isfile(p) and E.is_edr(p) for p in srcs):
|
|
405
|
+
out.append({'well': w['id'], 'display': w.get('display', w['id']), 'shadow': last_shadow(ws, w['id'])})
|
|
406
|
+
return out
|
|
@@ -180,7 +180,10 @@ declared extras.
|
|
|
180
180
|
feed, a crossed limit or the section's end; this version's only downlink
|
|
181
181
|
keeps every command on record and sends none. The records carry no
|
|
182
182
|
secret; GEA pulls them checked against their hashes. The twin as the rig
|
|
183
|
-
on the office PC binds to 127.0.0.1 only.
|
|
183
|
+
on the office PC binds to 127.0.0.1 only. Since 0.80.0 the records carry
|
|
184
|
+
the hole's azimuth and its offset from the plan line, as the surveys
|
|
185
|
+
give them - a position, not a coordinate: the plan's azimuth and the
|
|
186
|
+
heel are in the rig PC's config, no surface location is.
|
|
184
187
|
|
|
185
188
|
## What it records
|
|
186
189
|
|