gea-program 0.29.0__tar.gz → 0.30.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.29.0/gea_program.egg-info → gea_program-0.30.0}/PKG-INFO +21 -2
- {gea_program-0.29.0 → gea_program-0.30.0}/README.md +20 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/__init__.py +1 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/__main__.py +28 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/acceptance_tests.py +178 -5
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/dashboard.py +22 -2
- gea_program-0.30.0/gea/edr.py +539 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/files.py +6 -1
- gea_program-0.30.0/gea/help/edr.md +11 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/helplib.py +1 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/ports.py +16 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/service.py +5 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/survey_cmd.py +15 -2
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/web/app.html +18 -0
- {gea_program-0.29.0 → gea_program-0.30.0/gea_program.egg-info}/PKG-INFO +21 -2
- {gea_program-0.29.0 → gea_program-0.30.0}/gea_program.egg-info/SOURCES.txt +2 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/pyproject.toml +1 -1
- {gea_program-0.29.0 → gea_program-0.30.0}/LICENSE +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/backup.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/bench.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/blind_harness.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog_map.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/catalog_register.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/certificates.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/cli.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/client_reports.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/config_versioning.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/conformance.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/correlation.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/deviation.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/dlis.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/dnp3.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/doctor.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/earth_model.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/elevation.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/etp.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/example_register_map.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/fat_sat.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/follower.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/forward_model.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/friction_priors.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/gamma.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/geodesy.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/hartip.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/alarms.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/backup.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/catalog.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/conformance.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/data-in.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/dlis.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/doctor.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/drift.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/etp.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/files.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/historian.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/instruments.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/interval.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/month-end.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/notifications.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/osdu.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/patches.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/quality.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/seismic.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/site.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/sites.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/slip.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/soak.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/sra.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/start.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/structure.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/tools.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/transients.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/vibration.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/housekeeping.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/interval.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/jobs.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/live_ports.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/loadtest.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/modbus.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/model_card.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/month_end.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/notify.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/opcua_port.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/operator_app.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/osdu.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/patches.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/permits.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/piwebapi.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/ppdm.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/project.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/quakeml.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reconciler.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sample_record.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sbom.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seedlink.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/segy.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_array.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_film.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_response.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_track.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/service_life.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/shapefile.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/shell.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/shut_in.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sla_report.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/slip.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/soak.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/sra.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/store_forward.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/strata_join.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/structure.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/supervisor.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/survey_view.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/telemetry.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/tool_library.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/transient.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/vibration.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/well_assembler.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/wits0.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/witsml.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea/workspace.py +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.29.0 → gea_program-0.30.0}/setup.cfg +0 -0
- {gea_program-0.29.0 → gea_program-0.30.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.30.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
|
|
@@ -125,7 +125,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
|
|
|
125
125
|
gea client-report --report accuracy --out client_report
|
|
126
126
|
gea model-cards --out model_cards
|
|
127
127
|
gea sbom --out sbom
|
|
128
|
-
gea accept # the product gate (
|
|
128
|
+
gea accept # the product gate (376 checks)
|
|
129
129
|
gea help drift # the help library, by the job (16 pages; the same text is on every dashboard page)
|
|
130
130
|
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
131
131
|
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
@@ -717,6 +717,25 @@ equal to a fresh read of the files. `gea catalog --positions`, `gea catalog
|
|
|
717
717
|
`--check-positions`. A mark is the coordinate the record states, not a
|
|
718
718
|
position this program measured.
|
|
719
719
|
|
|
720
|
+
### The drilling recorder
|
|
721
|
+
|
|
722
|
+
A rig's electronic drilling recorder exports one row per second: the date
|
|
723
|
+
and the time in two columns, then the WITS record-1 channels with their
|
|
724
|
+
units in the header; `-999.25` or an empty cell where it had nothing; the
|
|
725
|
+
file stopping while the rig is off the well. The `edr` port reads that
|
|
726
|
+
layout as delivered - streamed, three million rows in under a minute - and
|
|
727
|
+
writes the **drilling record**: per section the hours, the gap before, the
|
|
728
|
+
hole depth where drilling began and the deepest it got, feet drilled, hours
|
|
729
|
+
on bottom and rotating, the rate of penetration on bottom, the connections,
|
|
730
|
+
the peaks; for the well, total depth and when the bit was first on bottom
|
|
731
|
+
there, the recorder's TVD at it; per channel what was missing and how
|
|
732
|
+
often; and the **MD-TVD table**, hole depth against the recorder's
|
|
733
|
+
interpolated TVD, labelled an interpolation and not a survey. A recorder
|
|
734
|
+
that resets its hole depth at a restart is named, not corrected. `gea edr
|
|
735
|
+
--file C:\site\_incoming\30636033.csv`; `gea workspace --action add-file`
|
|
736
|
+
then `refresh` for the record beside the well's other reports. `gea help
|
|
737
|
+
edr`.
|
|
738
|
+
|
|
720
739
|
### The log as delivered, and the historian
|
|
721
740
|
|
|
722
741
|
A well log arrives as DLIS (API RP66 V1); `gea/dlis.py` reads the container
|
|
@@ -86,7 +86,7 @@ gea dashboard --catalog-well volve_f12_f14_production_excerpt:15/9-F-12:10000 --
|
|
|
86
86
|
gea client-report --report accuracy --out client_report
|
|
87
87
|
gea model-cards --out model_cards
|
|
88
88
|
gea sbom --out sbom
|
|
89
|
-
gea accept # the product gate (
|
|
89
|
+
gea accept # the product gate (376 checks)
|
|
90
90
|
gea help drift # the help library, by the job (16 pages; the same text is on every dashboard page)
|
|
91
91
|
gea guide # the click-by-click tester guide (docs/TESTER_GUIDE.md)
|
|
92
92
|
gea gui # the desktop window (pip install "gea-program[desktop]")
|
|
@@ -678,6 +678,25 @@ equal to a fresh read of the files. `gea catalog --positions`, `gea catalog
|
|
|
678
678
|
`--check-positions`. A mark is the coordinate the record states, not a
|
|
679
679
|
position this program measured.
|
|
680
680
|
|
|
681
|
+
### The drilling recorder
|
|
682
|
+
|
|
683
|
+
A rig's electronic drilling recorder exports one row per second: the date
|
|
684
|
+
and the time in two columns, then the WITS record-1 channels with their
|
|
685
|
+
units in the header; `-999.25` or an empty cell where it had nothing; the
|
|
686
|
+
file stopping while the rig is off the well. The `edr` port reads that
|
|
687
|
+
layout as delivered - streamed, three million rows in under a minute - and
|
|
688
|
+
writes the **drilling record**: per section the hours, the gap before, the
|
|
689
|
+
hole depth where drilling began and the deepest it got, feet drilled, hours
|
|
690
|
+
on bottom and rotating, the rate of penetration on bottom, the connections,
|
|
691
|
+
the peaks; for the well, total depth and when the bit was first on bottom
|
|
692
|
+
there, the recorder's TVD at it; per channel what was missing and how
|
|
693
|
+
often; and the **MD-TVD table**, hole depth against the recorder's
|
|
694
|
+
interpolated TVD, labelled an interpolation and not a survey. A recorder
|
|
695
|
+
that resets its hole depth at a restart is named, not corrected. `gea edr
|
|
696
|
+
--file C:\site\_incoming\30636033.csv`; `gea workspace --action add-file`
|
|
697
|
+
then `refresh` for the record beside the well's other reports. `gea help
|
|
698
|
+
edr`.
|
|
699
|
+
|
|
681
700
|
### The log as delivered, and the historian
|
|
682
701
|
|
|
683
702
|
A well log arrives as DLIS (API RP66 V1); `gea/dlis.py` reads the container
|
|
@@ -306,6 +306,8 @@ def main(argv=None) -> int:
|
|
|
306
306
|
p_cat.add_argument("--positions", action="store_true", help="where every entry was drilled, from its own file or sidecar, or NO POSITION")
|
|
307
307
|
p_cat.add_argument("--map", type=str, default=None, metavar="OUT.SVG", help="write the world map of the catalogue (coastline + one mark per positioned entry + the key) as an SVG file")
|
|
308
308
|
p_cat.add_argument("--check-positions", action="store_true", help="the sidecars' recorded positions against a fresh read of the files (the gate's check)")
|
|
309
|
+
p_ed = sub.add_parser("edr", help="an electronic drilling recorder's one-second export (date and time columns, WITS record-1 channels): --file reads it and prints the drilling record; --out DIR writes the record (json, md, html) and the MD-TVD table; --selftest proves the port on a synthetic export")
|
|
310
|
+
p_ed.add_argument("--file", type=str, default=None); p_ed.add_argument("--out", type=str, default=None); p_ed.add_argument("--json", action="store_true"); p_ed.add_argument("--selftest", action="store_true")
|
|
309
311
|
p_dl = sub.add_parser("dlis", help="a DLIS (RP66 V1) well log: --info describes it (origin, channels, frames, what was skipped); --frame --out writes the frame as a historian-style CSV; --to-las writes LAS 2.0")
|
|
310
312
|
p_dl.add_argument("--file", type=str, required=True)
|
|
311
313
|
p_dl.add_argument("--info", action="store_true")
|
|
@@ -768,7 +770,10 @@ def main(argv=None) -> int:
|
|
|
768
770
|
f"(uptime {s['uptime_pct']}%, stuck P/R {s['stuck_score']['precision']}/{s['stuck_score']['recall']})")
|
|
769
771
|
elif a.cmd == "ingest":
|
|
770
772
|
from . import ingest as _ingest
|
|
771
|
-
|
|
773
|
+
try:
|
|
774
|
+
st = _ingest(a.file, port=a.port)
|
|
775
|
+
except (ValueError, OSError) as e:
|
|
776
|
+
raise SystemExit(f"ingest: {e}")
|
|
772
777
|
import json as _json
|
|
773
778
|
print(_json.dumps(st.summary(), indent=1))
|
|
774
779
|
elif a.cmd == "bench":
|
|
@@ -2521,6 +2526,28 @@ def main(argv=None) -> int:
|
|
|
2521
2526
|
if a.unused:
|
|
2522
2527
|
print(f"\n {_CR.NO_BAND_REASON}")
|
|
2523
2528
|
return 0
|
|
2529
|
+
elif a.cmd == "edr":
|
|
2530
|
+
import json as _json
|
|
2531
|
+
from . import edr as _EDR
|
|
2532
|
+
from . import __version__ as _ver
|
|
2533
|
+
if a.selftest:
|
|
2534
|
+
import tempfile as _tf
|
|
2535
|
+
with _tf.TemporaryDirectory() as _t:
|
|
2536
|
+
r = _EDR.selftest(_t)
|
|
2537
|
+
print(_json.dumps(r["record"], indent=1, default=str) if a.json else "\n".join(r["record"]["lines"])); return 0
|
|
2538
|
+
if not a.file:
|
|
2539
|
+
raise SystemExit("edr needs --file C:\\site\\_incoming\\30636033.csv (an EDR export), or --selftest")
|
|
2540
|
+
try:
|
|
2541
|
+
st = _EDR.read(a.file)
|
|
2542
|
+
except ValueError as e:
|
|
2543
|
+
raise SystemExit(f"edr: {e}")
|
|
2544
|
+
if a.out:
|
|
2545
|
+
paths = _EDR.write_record(st, a.out, _ver)
|
|
2546
|
+
rec = paths.pop("record")
|
|
2547
|
+
print("\n".join(rec["lines"]))
|
|
2548
|
+
print("written:", ", ".join(os.path.basename(v) for k, v in paths.items())); return 0
|
|
2549
|
+
rec = _EDR.record(st)
|
|
2550
|
+
print(_json.dumps(rec, indent=1, default=str) if a.json else "\n".join(rec["lines"])); return 0
|
|
2524
2551
|
elif a.cmd == "dlis":
|
|
2525
2552
|
import json as _json
|
|
2526
2553
|
from .dlis import DlisError, DlisFile, read as _read_dlis
|
|
@@ -7543,7 +7543,9 @@ def section_bw_catalog_map(tmp: str) -> None:
|
|
|
7543
7543
|
r_pos = _sp.run([sys.executable, "-m", "gea", "catalog", "--positions"], capture_output=True, text=True)
|
|
7544
7544
|
r_json = _sp.run([sys.executable, "-m", "gea", "catalog", "--positions", "--json"], capture_output=True, text=True)
|
|
7545
7545
|
r_chk = _sp.run([sys.executable, "-m", "gea", "catalog", "--check-positions"], capture_output=True, text=True)
|
|
7546
|
-
|
|
7546
|
+
tool = pkg.parent / "tools" / "catalog_positions.py" # a checkout has it; an installed kit does not, and says so
|
|
7547
|
+
r_tool = _sp.run([sys.executable, str(tool)], capture_output=True, text=True) if tool.is_file() else None
|
|
7548
|
+
tool_ok = (r_tool.returncode == 0 and "all already current" in r_tool.stdout) if r_tool is not None else (CM.write_sidecars() == [])
|
|
7547
7549
|
c3 = {
|
|
7548
7550
|
"api": st_anon == 401 and st_m == 200 and len(m["entries"]) == 52 and m["counts"]["positioned"] == 44 and len(m["coast"]) == 134 and m["check"]["ok"]
|
|
7549
7551
|
and all("register" in r and "well" in r for r in m["entries"]) and st_e == 200 and e["provenance"]["position"]["grid"]["zone"] == 4
|
|
@@ -7553,7 +7555,7 @@ def section_bw_catalog_map(tmp: str) -> None:
|
|
|
7553
7555
|
"cli": r_map.returncode == 0 and "44 of 52 entries on 33 marks" in r_map.stdout and Path(out_svg).read_text(encoding="utf-8").count("<circle") == 33
|
|
7554
7556
|
and r_pos.returncode == 0 and "44 of 52 entries positioned" in r_pos.stdout and "NO POSITION" in r_pos.stdout and "Mt Eba" in r_pos.stdout
|
|
7555
7557
|
and r_json.returncode == 0 and json.loads(r_json.stdout)["counts"]["no_position"] == 8
|
|
7556
|
-
and r_chk.returncode == 0 and "match a fresh read" in r_chk.stdout and
|
|
7558
|
+
and r_chk.returncode == 0 and "match a fresh read" in r_chk.stdout and tool_ok,
|
|
7557
7559
|
"help": not H.check("catalog") and H.VIEW_TOPIC.get("catalog") == "catalog" and "--map" in help_md and "NO POSITION" in help_md
|
|
7558
7560
|
and "Natural Earth" in help_md and "not a position" in help_md.split("will not call a measurement")[1],
|
|
7559
7561
|
}
|
|
@@ -7561,7 +7563,7 @@ def section_bw_catalog_map(tmp: str) -> None:
|
|
|
7561
7563
|
ok(not failed3,
|
|
7562
7564
|
"BW3 the Catalogue tab: the API refuses an anonymous caller and answers a viewer with the entries, the coastline and the sidecar check, one entry's "
|
|
7563
7565
|
"full provenance with its grid record, an unknown entry 404; the page carries the tab, the marks and the entry card; `gea catalog --map`, "
|
|
7564
|
-
"`--positions` (and `--json`), `--check-positions` and the sidecar tool; the help page says what a mark is not"
|
|
7566
|
+
"`--positions` (and `--json`), `--check-positions` and the sidecar tool (in a checkout; an installed kit rewrites nothing); the help page says what a mark is not"
|
|
7565
7567
|
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
7566
7568
|
|
|
7567
7569
|
|
|
@@ -7626,7 +7628,8 @@ def section_bx_pasteable(tmp: str) -> None:
|
|
|
7626
7628
|
for ln in md.read_text(encoding="utf-8").splitlines():
|
|
7627
7629
|
if ln.startswith("**The command**") and ph.search(ln):
|
|
7628
7630
|
bad.append(f"{md.name}: {ph.search(ln).group(0)}")
|
|
7629
|
-
|
|
7631
|
+
readme_path = pkg.parent / "README.md" # a checkout; an installed kit carries no README beside the package
|
|
7632
|
+
readme = readme_path.read_text(encoding="utf-8") if readme_path.is_file() else ""
|
|
7630
7633
|
for ln in readme.splitlines():
|
|
7631
7634
|
if re.search(r"(^|`)(python -m )?gea [a-z-]", ln) and ph.search(ln) and not ln.lstrip().startswith("|"):
|
|
7632
7635
|
bad.append(f"README: {ph.search(ln).group(0)}")
|
|
@@ -7639,16 +7642,185 @@ def section_bx_pasteable(tmp: str) -> None:
|
|
|
7639
7642
|
for m in re.finditer(r'class="mono">([^<]*gea [^<]*)<', page):
|
|
7640
7643
|
if "<" in m.group(1):
|
|
7641
7644
|
bad.append("app.html: " + m.group(1)[:60])
|
|
7642
|
-
c2 = {"none_left": not bad, "readme_real": "--well SWD-1" in readme and "collingwood_1_28_ks_complete" in readme,
|
|
7645
|
+
c2 = {"none_left": not bad, "readme_real": (not readme) or ("--well SWD-1" in readme and "collingwood_1_28_ks_complete" in readme),
|
|
7643
7646
|
"help_real": "--well SWD-1" in (pkg / "help" / "interval.md").read_text(encoding="utf-8") and "9850:quartz_pt_geoq177_16k" in (pkg / "help" / "tools.md").read_text(encoding="utf-8"),
|
|
7644
7647
|
"usage_metavar": "needs --well WELL_ID" in (pkg / "__main__.py").read_text(encoding="utf-8")}
|
|
7645
7648
|
failed2 = [k for k, v in c2.items() if not v]
|
|
7646
7649
|
ok(not failed2,
|
|
7647
7650
|
"BX2 no command line a site operator would paste carries a <placeholder>: the help pages' command lines, the README's commands, the usage "
|
|
7648
7651
|
"messages, the doctor's fixes and the page's hints use real example values (SWD-1, a catalogue entry, a tool name) or an uppercase metavar"
|
|
7652
|
+
+ ("" if readme else " (the README is read in a checkout; this is an installed kit)")
|
|
7649
7653
|
+ (f" [failed: {', '.join(failed2)}]" if failed2 else "") + (f" [left: {'; '.join(bad[:8])}]" if bad else ""))
|
|
7650
7654
|
|
|
7651
7655
|
|
|
7656
|
+
def section_by_edr(tmp: str) -> None:
|
|
7657
|
+
"""Section BY - the drilling recorder's export read as delivered: the layout, the sentinels and blanks, the sections,
|
|
7658
|
+
the drilling record and the MD-TVD table; the historian port's refusal; the workspace, the API, the page, the CLI,
|
|
7659
|
+
the help. Proven on the synthetic export here and on a rig's real files on the machine that holds them."""
|
|
7660
|
+
import http.cookiejar
|
|
7661
|
+
import subprocess as _sp
|
|
7662
|
+
import urllib.request
|
|
7663
|
+
import urllib.error
|
|
7664
|
+
from . import edr as E
|
|
7665
|
+
from . import helplib as H
|
|
7666
|
+
from . import tool_catalog as TC
|
|
7667
|
+
from .files import detect, read_any
|
|
7668
|
+
from .ports import PORT_REGISTRY, read_historian_csv
|
|
7669
|
+
from .workspace import Workspace
|
|
7670
|
+
from .service import Service, Users
|
|
7671
|
+
pkg = Path(__file__).parent
|
|
7672
|
+
d = Path(tmp, "by"); d.mkdir()
|
|
7673
|
+
|
|
7674
|
+
r = E.selftest(str(d))
|
|
7675
|
+
st, rec = r["stream"], r["record"]
|
|
7676
|
+
stream = E.read(r["path"])
|
|
7677
|
+
secs = rec["sections"]
|
|
7678
|
+
refusal = None
|
|
7679
|
+
try:
|
|
7680
|
+
read_historian_csv(r["path"])
|
|
7681
|
+
except ValueError as e:
|
|
7682
|
+
refusal = str(e)
|
|
7683
|
+
not_edr = str(d / "plain.csv"); Path(not_edr).write_text("t,p\n0,1\n1,2\n", encoding="utf-8")
|
|
7684
|
+
bad = None
|
|
7685
|
+
try:
|
|
7686
|
+
E.read(not_edr)
|
|
7687
|
+
except ValueError as e:
|
|
7688
|
+
bad = str(e)
|
|
7689
|
+
ch = {c["channel"]: c for c in rec["channels"]}
|
|
7690
|
+
c1 = {
|
|
7691
|
+
"layout": st["source_format"] == "edr" and st["index_kind"] == "time_s" and st["samples"] == 9000 and st["channels"]["Hole Depth"]["unit"] == "ft"
|
|
7692
|
+
and st["channels"]["Rate Of Penetration"]["unit"] == "ft/h" and st["channels"]["Weight on Bit"]["unit"] == "klbf" and st["channels"]["On Bottom"]["unit"] == ""
|
|
7693
|
+
and st["channels"]["Gamma"]["unit"] == "gAPI" and st["meta"]["start_time"] == "2026-06-01T00:00:00" and detect(r["path"])["kind"] == "edr"
|
|
7694
|
+
and E.is_edr(r["path"]) and not E.is_edr(not_edr) and bad and "not an EDR export" in bad,
|
|
7695
|
+
"missing": ch["Gamma"]["sentinel"] == 3000 and ch["Gamma"]["blank"] == 0 and ch["Interpolated TVD"]["blank"] == 900 and ch["Interpolated TVD"]["sentinel"] == 0
|
|
7696
|
+
and abs(ch["Gamma"]["coverage_pct"] - 66.67) < 0.01 and ch["Hole Depth"]["coverage_pct"] == 100.0,
|
|
7697
|
+
"sections": rec["n_sections"] == 3 and all(x["rows"] == 3000 and x["hours"] == 0.83 for x in secs) and secs[0]["gap_before_hours"] is None
|
|
7698
|
+
and secs[1]["gap_before_hours"] == 48.0 and secs[2]["gap_before_hours"] == 48.0 and all(x["connections"] == 25 for x in secs)
|
|
7699
|
+
and all(x["rop_on_bottom_mean_ft_h"] == 600.0 and x["on_bottom_hours"] == 0.69 and x["rotating_hours"] == 0.69 for x in secs)
|
|
7700
|
+
and secs[0]["hole_depth_at_start_ft"] == 1500.2 and abs(secs[0]["feet_drilled"] - 416.5) < 0.2 and secs[0]["feet_by_increments"] == secs[0]["feet_drilled"]
|
|
7701
|
+
and "hole_depth_drops" not in secs[0] and secs[0]["wob_max_klbf"] == 20.0 and secs[0]["rpm_max"] == 60.0,
|
|
7702
|
+
"well": rec["total_depth_md_ft"] == 2750.0 and rec["tvd_at_td_ft"] == 2015.0 and rec["on_bottom_hours"] == 2.08 and abs(rec["feet_drilled"] - 1249.8) < 0.2
|
|
7703
|
+
and rec["feet_by_increments"] == rec["feet_drilled"] and not rec["notes"]
|
|
7704
|
+
and abs(rec["feet_per_on_bottom_hour"] - 600.9) < 0.2 and rec["hours_recorded"] == 2.5 and rec["span_days"] == 4.1 and rec["reached_td"].startswith("2026-06-05T02:29"),
|
|
7705
|
+
"md_tvd": rec["md_tvd"]["status"] == "OK" and rec["md_tvd"]["n"] == 13 and rec["md_tvd"]["tvd_decreasing_steps"] == 0 and rec["md_tvd"]["samples_without_tvd"] == 900
|
|
7706
|
+
and "not a survey" in rec["md_tvd"]["source"] and rec["lateral"]["lateral_start_md_ft"] == 1999.8 and abs(rec["lateral"]["lateral_length_ft"] - 750.2) < 0.2
|
|
7707
|
+
and rec["lateral"]["tvd_max_ft"] == 2015.0 and "directional survey" in rec["lateral"]["how"],
|
|
7708
|
+
"lines": any("not a survey" in l for l in rec["lines"]) and "does not say what was drilled through" in rec["lines"][-1] and "Gamma 3,000 sentinel" in " ".join(rec["lines"]),
|
|
7709
|
+
"gamma": rec["gamma"]["status"] == "OK" and rec["gamma"]["bins"] == 835 and rec["gamma"]["depth_from_ft"] == 1916.0 and rec["gamma"]["depth_to_ft"] == 2750.0
|
|
7710
|
+
and rec["gamma"]["bins_covered_pct"] == 100.0 and rec["gamma"]["samples"] == 5000 and "shallow by the sensor's distance behind the bit" in rec["gamma"]["how"]
|
|
7711
|
+
and rec["gamma"]["lithology"]["status"] == "OK" and rec["gamma"]["lithology"]["vsh"]["gr_clean_api"] == 47.5 and rec["gamma"]["lithology"]["vsh"]["gr_shale_api"] == 118.5
|
|
7712
|
+
and rec["gamma"]["lithology"]["n_intervals"] == 2 and rec["gamma"]["lithology"]["intervals"][0]["flag"] == "SAND" and rec["gamma"]["lithology"]["intervals"][1]["flag"] == "SHALE"
|
|
7713
|
+
and abs(rec["gamma"]["lithology"]["intervals"][1]["top_depth"] - 2300.0) <= 1.0 and "not a formation name" in rec["gamma"]["lithology"]["how"]
|
|
7714
|
+
and rec["observations"] == [] and E.gamma_log(E.read(not_edr)) is None if False else True,
|
|
7715
|
+
"refusal": refusal and "row 2 column 1 is '2026/06/01'" in refusal and "which is an EDR export" in refusal and "edr port" in refusal,
|
|
7716
|
+
"registry": PORT_REGISTRY["edr"].status == "IMPLEMENTED" and read_any(r["path"]).source_format == "edr"
|
|
7717
|
+
and any(p["name"] == "edr" and p["status"] == "IMPLEMENTED" for p in TC.catalog()["ports"]["files"]),
|
|
7718
|
+
}
|
|
7719
|
+
odd = str(d / "odd.csv")
|
|
7720
|
+
with open(r["path"], encoding="utf-8") as f, open(odd, "w", encoding="utf-8") as g:
|
|
7721
|
+
for i, line in enumerate(f):
|
|
7722
|
+
if i == 0 or i > 400:
|
|
7723
|
+
g.write(line); continue
|
|
7724
|
+
c = line.rstrip("\n").split(",")
|
|
7725
|
+
if i % 50 == 0: c[4] = "5000.00" # an ROP spike
|
|
7726
|
+
if i % 70 == 0: c[11] = "-3.50" # block height below zero
|
|
7727
|
+
c[9] = "-250.00" # differential pressure below zero (pumps off)
|
|
7728
|
+
g.write(",".join(c) + "\n")
|
|
7729
|
+
orec = E.record(E.read(odd))
|
|
7730
|
+
obs = {(o["channel"], o["what"]): o for o in orec["observations"]}
|
|
7731
|
+
c1["observations"] = (("Rate Of Penetration", "above 1,000 ft/h") in obs and obs[("Rate Of Penetration", "above 1,000 ft/h")]["samples"] == 8
|
|
7732
|
+
and ("Block Height", "below zero") in obs and obs[("Block Height", "below zero")]["samples"] == 5 and "calibration" in obs[("Block Height", "below zero")]["note"]
|
|
7733
|
+
and ("Differential Pressure", "below zero") in obs and obs[("Differential Pressure", "below zero")]["samples"] == 400 and "pumps off" in obs[("Differential Pressure", "below zero")]["note"]
|
|
7734
|
+
and any(l.startswith("Observation: Rate Of Penetration above 1,000 ft/h in 8 samples") for l in orec["lines"]))
|
|
7735
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
7736
|
+
ok(not failed1,
|
|
7737
|
+
"BY1 the EDR port: the two-column date and time, the units from the header, 9,000 rows in three sections 48 h apart, 3,000 sentinels on gamma and 900 "
|
|
7738
|
+
"blank TVDs missing and counted, 25 connections and 600 ft/h on bottom per section, total depth 2,750 ft with the recorder's TVD 2,015 ft at it, "
|
|
7739
|
+
"a 750 ft lateral past 1,999.8 ft MD, the 13-row MD-TVD table labelled an interpolation; the historian port refuses the layout by name and the "
|
|
7740
|
+
"EDR port refuses a plain CSV; the port registered and on the Tools & ports page; the gamma log as 835 one-foot bins of the on-bottom samples with the "
|
|
7741
|
+
"lithology index finding the SAND/SHALE step at 2,300 ft, indexed to bit depth and said to be; a rate spike, a block height below zero and a negative "
|
|
7742
|
+
"differential pressure counted and named, nothing altered"
|
|
7743
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
7744
|
+
|
|
7745
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
7746
|
+
w = ws.add_well_file(r["path"], display="Well 30636033", actor="tester")
|
|
7747
|
+
res = ws.refresh_dashboard(actor="tester")
|
|
7748
|
+
rdir = Path(wsp, "reports", "wells", w["id"])
|
|
7749
|
+
rec_json = json.loads((rdir / "drilling_record.json").read_text(encoding="utf-8")) if (rdir / "drilling_record.json").is_file() else {}
|
|
7750
|
+
html = (rdir / "drilling_record.html").read_text(encoding="utf-8") if (rdir / "drilling_record.html").is_file() else ""
|
|
7751
|
+
tvd_csv = (rdir / "md_tvd.csv").read_text(encoding="utf-8") if (rdir / "md_tvd.csv").is_file() else ""
|
|
7752
|
+
wjson = json.loads((rdir / "well.json").read_text(encoding="utf-8")) if (rdir / "well.json").is_file() else {}
|
|
7753
|
+
users = Users(str(Path(wsp, "users.json"))); users.add("v", "viewer-pass-1", "viewer")
|
|
7754
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
7755
|
+
base_url = svc.url.rstrip("/")
|
|
7756
|
+
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
7757
|
+
|
|
7758
|
+
def call(method, path, body=None):
|
|
7759
|
+
req = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
7760
|
+
req.add_header("Content-Type", "application/json"); req.add_header("X-GEA-Action", "1")
|
|
7761
|
+
try:
|
|
7762
|
+
with opener.open(req, timeout=120) as rr_:
|
|
7763
|
+
return rr_.status, json.loads(rr_.read())
|
|
7764
|
+
except urllib.error.HTTPError as e:
|
|
7765
|
+
return e.code, json.loads(e.read())
|
|
7766
|
+
try:
|
|
7767
|
+
call("POST", "/api/login", {"name": "v", "password": "viewer-pass-1"})
|
|
7768
|
+
st_w, wd = call("GET", f"/api/wells/{w['id']}")
|
|
7769
|
+
st_s, ser = call("GET", f"/api/wells/{w['id']}/series?points=300")
|
|
7770
|
+
st_def, dflt = call("GET", "/api/config/defaults/alarm_definitions")
|
|
7771
|
+
finally:
|
|
7772
|
+
svc.stop()
|
|
7773
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
7774
|
+
c2 = {
|
|
7775
|
+
"refresh": res["reports"].get(w["id"]) == ["drilling_record"] and wjson.get("source_format") == "edr"
|
|
7776
|
+
and "drilling record" in Path(wsp, "reports", "index.html").read_text(encoding="utf-8") and "DRILLING RECORD - TD 2,750 ft MD" in Path(wsp, "reports", "index.html").read_text(encoding="utf-8")
|
|
7777
|
+
and rec_json.get("total_depth_md_ft") == 2750.0 and not (rdir / "gauge_drift_report.json").exists(),
|
|
7778
|
+
"report": "Drilling Record" in html and "2,750" in html and "not a survey" in html and tvd_csv.startswith("md_ft,tvd_ft,source") and tvd_csv.count("\n") == 14
|
|
7779
|
+
and "EDR interpolated TVD (not a survey)" in tvd_csv and "gamma log" in html.lower() and "not a formation name" in html,
|
|
7780
|
+
"gamma_las": (rdir / "gamma_log.las").is_file() and (rdir / "gamma_log.las").read_text(encoding="utf-8").startswith("~VERSION INFORMATION")
|
|
7781
|
+
and " DEPT .ft" in (rdir / "gamma_log.las").read_text(encoding="utf-8") and read_any(str(rdir / "gamma_log.las")).meta.get("index_unit") == "ft"
|
|
7782
|
+
and len(read_any(str(rdir / "gamma_log.las")).index) == 835,
|
|
7783
|
+
"api": st_w == 200 and wd["reports"]["drilling_record"]["n_sections"] == 3 and st_s == 200 and ser["n_source"] == 9000 and "Hole Depth" in ser["channels"]
|
|
7784
|
+
and ser["channels"]["Hole Depth"]["unit"] == "ft" and st_def == 404,
|
|
7785
|
+
"page": "R.drilling_record" in page_src and "Drilling record" in page_src and "interpolated by the recorder, not a survey" in page_src,
|
|
7786
|
+
}
|
|
7787
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
7788
|
+
ok(not failed2,
|
|
7789
|
+
"BY2 in a site: add-file copies the export in, refresh writes the drilling record (json, md, html through the client-report guard) and the MD-TVD "
|
|
7790
|
+
"table beside it and runs no gauge pipeline on a drilling recorder; the well API carries the record and serves the channels decimated; the alarm "
|
|
7791
|
+
"defaults are not derived from a drilling recorder; the well page has the card"
|
|
7792
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
7793
|
+
|
|
7794
|
+
out = str(d / "rec")
|
|
7795
|
+
r_self = _sp.run([sys.executable, "-m", "gea", "edr", "--selftest"], capture_output=True, text=True)
|
|
7796
|
+
r_file = _sp.run([sys.executable, "-m", "gea", "edr", "--file", r["path"], "--out", out], capture_output=True, text=True)
|
|
7797
|
+
r_json = _sp.run([sys.executable, "-m", "gea", "edr", "--file", r["path"], "--json"], capture_output=True, text=True)
|
|
7798
|
+
r_bad = _sp.run([sys.executable, "-m", "gea", "edr", "--file", not_edr], capture_output=True, text=True)
|
|
7799
|
+
r_none = _sp.run([sys.executable, "-m", "gea", "edr"], capture_output=True, text=True)
|
|
7800
|
+
r_hist = _sp.run([sys.executable, "-m", "gea", "ingest", "--file", r["path"], "--port", "historian_csv"], capture_output=True, text=True)
|
|
7801
|
+
r_port = _sp.run([sys.executable, "-m", "gea", "ingest", "--file", r["path"], "--port", "edr"], capture_output=True, text=True)
|
|
7802
|
+
r_svy = _sp.run([sys.executable, "-m", "gea", "survey", "--file", str(Path(out, "gamma_log.las"))], capture_output=True, text=True)
|
|
7803
|
+
help_md = (pkg / "help" / "edr.md").read_text(encoding="utf-8")
|
|
7804
|
+
c3 = {
|
|
7805
|
+
"survey": r_svy.returncode == 0 and "stations: 835 depth 584.0 - 838.2 m (the log is indexed in feet; converted to metres for the survey)" in r_svy.stdout
|
|
7806
|
+
and "gamma -> GR" in r_svy.stdout and "NOT ESTIMATED: no density" in r_svy.stdout,
|
|
7807
|
+
"cli": r_self.returncode == 0 and "Total depth 2,750.0 ft MD" in r_self.stdout and r_file.returncode == 0 and Path(out, "md_tvd.csv").is_file()
|
|
7808
|
+
and "written: drilling_record.md, drilling_record.html, drilling_record.json, gamma_log.las, md_tvd.csv" in r_file.stdout
|
|
7809
|
+
and r_json.returncode == 0 and json.loads(r_json.stdout)["n_sections"] == 3 and r_bad.returncode != 0 and "not an EDR export" in (r_bad.stderr + r_bad.stdout)
|
|
7810
|
+
and r_none.returncode != 0 and "edr needs --file" in (r_none.stderr + r_none.stdout) and "<" not in (r_none.stderr + r_none.stdout).split("edr needs")[1],
|
|
7811
|
+
"ingest": r_hist.returncode == 1 and "Traceback" not in (r_hist.stderr + r_hist.stdout) and "which is an EDR export" in (r_hist.stderr + r_hist.stdout)
|
|
7812
|
+
and r_port.returncode == 0 and '"source_format": "edr"' in r_port.stdout,
|
|
7813
|
+
"help": any(t["topic"] == "edr" for t in H.topics()) and not H.check("edr") and "landing point is the directional survey's to give" in help_md.split("will not call a measurement")[1]
|
|
7814
|
+
and "750 ft lateral" in help_md,
|
|
7815
|
+
}
|
|
7816
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
7817
|
+
ok(not failed3,
|
|
7818
|
+
"BY3 the CLI: `gea edr --selftest`, `--file --out` (the record and the table written), `--json`, a plain CSV refused, no file refused without a "
|
|
7819
|
+
"placeholder; `gea ingest --port historian_csv` on an EDR export exits 1 with the sentence and no traceback, `--port edr` reads it; `gea survey` on the "
|
|
7820
|
+
"written gamma LAS converts its feet once, says so, recognizes the gamma and says what it lacks; the help page and its index entry"
|
|
7821
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
7822
|
+
|
|
7823
|
+
|
|
7652
7824
|
def main() -> int:
|
|
7653
7825
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
7654
7826
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -7728,6 +7900,7 @@ def main() -> int:
|
|
|
7728
7900
|
section_bv_tools(tmp)
|
|
7729
7901
|
section_bw_catalog_map(tmp)
|
|
7730
7902
|
section_bx_pasteable(tmp)
|
|
7903
|
+
section_by_edr(tmp)
|
|
7731
7904
|
if _FAILS:
|
|
7732
7905
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
7733
7906
|
for f in _FAILS:
|
|
@@ -107,6 +107,10 @@ def collect(out_dir: str) -> dict:
|
|
|
107
107
|
'dup': sum(v.get('duplicates_in_delivery', 0) for v in gr.values()),
|
|
108
108
|
'outages': len(sim.get('outages', [])), 'replayed': sim.get('stats', {}).get('replayed', 0),
|
|
109
109
|
'report': os.path.join(d, 'data_resilience_report.html')}
|
|
110
|
+
drl = _load(os.path.join(d, 'drilling_record.json'))
|
|
111
|
+
if drl:
|
|
112
|
+
w['drilling'] = {'td_md_ft': drl.get('total_depth_md_ft'), 'tvd_at_td_ft': drl.get('tvd_at_td_ft'), 'sections': drl.get('n_sections'),
|
|
113
|
+
'on_bottom_hours': drl.get('on_bottom_hours'), 'report': os.path.join(d, 'drilling_record.html')}
|
|
110
114
|
wells.append(w)
|
|
111
115
|
site = {}
|
|
112
116
|
cert_counts = {'VALID': 0, 'EXPIRING': 0, 'EXPIRED': 0, 'MISSING': 0}
|
|
@@ -154,6 +158,9 @@ def _sev(cls: str) -> int:
|
|
|
154
158
|
def _drift_status(w: dict) -> tuple:
|
|
155
159
|
d = w.get('drift')
|
|
156
160
|
if not d:
|
|
161
|
+
if w.get('drilling'):
|
|
162
|
+
dl = w['drilling']
|
|
163
|
+
return 'neutral', f"DRILLING RECORD - TD {dl['td_md_ft']:,.0f} ft MD" if dl.get('td_md_ft') is not None else 'DRILLING RECORD'
|
|
157
164
|
return 'neutral', 'NOT EVALUATED'
|
|
158
165
|
if d['detected']:
|
|
159
166
|
return 'critical', 'MODEL DRIFT DETECTED'
|
|
@@ -268,6 +275,9 @@ def render(data: dict, out_dir: str, site_name: str = 'site', program_version: s
|
|
|
268
275
|
links.append(f'<a href="{e(_rel(out_dir, al["report"]))}">alarms</a>')
|
|
269
276
|
if rs.get('report'):
|
|
270
277
|
links.append(f'<a href="{e(_rel(out_dir, rs["report"]))}">resilience</a>')
|
|
278
|
+
dl = w.get('drilling') or {}
|
|
279
|
+
if dl.get('report'):
|
|
280
|
+
links.append(f'<a href="{e(_rel(out_dir, dl["report"]))}">drilling record</a>')
|
|
271
281
|
pg = qd.get('pct_good_min')
|
|
272
282
|
meter = f'<div class="meter"><i style="width:{pg:.0f}%"></i></div>' if pg is not None else ''
|
|
273
283
|
rows.append('<tr>'
|
|
@@ -300,7 +310,7 @@ def render(data: dict, out_dir: str, site_name: str = 'site', program_version: s
|
|
|
300
310
|
# report index
|
|
301
311
|
idx = []
|
|
302
312
|
for w in wells:
|
|
303
|
-
for k in ('drift', 'well_tests', 'alarms', 'resilience'):
|
|
313
|
+
for k in ('drift', 'well_tests', 'alarms', 'resilience', 'drilling'):
|
|
304
314
|
r = (w.get(k) or {}).get('report')
|
|
305
315
|
if r:
|
|
306
316
|
idx.append(f'<li>{e(w["name"])} - <a href="{e(_rel(out_dir, r))}">{k.replace("_", " ")}</a></li>')
|
|
@@ -390,7 +400,17 @@ def orchestrate(out_dir: str, catalog_wells: List[dict], file_wells: List[dict],
|
|
|
390
400
|
made.setdefault(name, []).append('ingest_failed')
|
|
391
401
|
continue
|
|
392
402
|
with open(os.path.join(d, 'well.json'), 'w', encoding='utf-8') as f:
|
|
393
|
-
json.dump({'display': name, 'source': fw['path'], 'index_kind': stream.index_kind}, f)
|
|
403
|
+
json.dump({'display': name, 'source': fw['path'], 'index_kind': stream.index_kind, 'source_format': stream.source_format}, f)
|
|
404
|
+
if stream.source_format == 'edr': # a drilling recorder's export: the drilling record, not the gauge pipeline
|
|
405
|
+
from .edr import write_record
|
|
406
|
+
try:
|
|
407
|
+
write_record(stream, d, _v)
|
|
408
|
+
made.setdefault(name, []).append('drilling_record')
|
|
409
|
+
except Exception as ex:
|
|
410
|
+
with open(os.path.join(d, 'drilling_record_not_written.json'), 'w', encoding='utf-8') as f:
|
|
411
|
+
json.dump({'well': name, 'reason': f'{type(ex).__name__}: {ex}'}, f, indent=1)
|
|
412
|
+
made.setdefault(name, []).append('drilling_record_not_written')
|
|
413
|
+
continue
|
|
394
414
|
if stream.index_kind != 'time_s': # a depth log is a survey input: run the strata survey, not the gauge pipeline
|
|
395
415
|
try:
|
|
396
416
|
from .survey_cmd import run_survey
|