gea-program 0.26.0__tar.gz → 0.28.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.26.0/gea_program.egg-info → gea_program-0.28.0}/PKG-INFO +26 -2
- {gea_program-0.26.0 → gea_program-0.28.0}/README.md +25 -1
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/__init__.py +1 -1
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/__main__.py +72 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/acceptance_tests.py +157 -0
- gea_program-0.28.0/gea/fixtures/README.md +10 -0
- gea_program-0.28.0/gea/fixtures/comcat_delaware_basin_2026-09.txt +29 -0
- gea_program-0.28.0/gea/fixtures/comcat_youngstown_2011-2012.txt +10 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/sra.md +1 -1
- gea_program-0.28.0/gea/help/tools.md +11 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/helplib.py +2 -1
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/service.py +19 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sra.py +43 -0
- gea_program-0.28.0/gea/tool_catalog.py +190 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/web/app.html +56 -1
- {gea_program-0.26.0 → gea_program-0.28.0/gea_program.egg-info}/PKG-INFO +26 -2
- {gea_program-0.26.0 → gea_program-0.28.0}/gea_program.egg-info/SOURCES.txt +5 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/pyproject.toml +2 -2
- {gea_program-0.26.0 → gea_program-0.28.0}/LICENSE +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/backup.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/bench.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/blind_harness.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/catalog_register.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/certificates.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/cli.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/client_reports.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/config_versioning.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/conformance.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/correlation.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/dashboard.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/deviation.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/dlis.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/dnp3.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/doctor.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/earth_model.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/elevation.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/etp.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/example_register_map.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/fat_sat.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/files.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/follower.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/forward_model.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/friction_priors.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/gamma.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/geodesy.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/hartip.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/alarms.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/backup.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/catalog.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/conformance.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/data-in.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/dlis.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/doctor.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/drift.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/etp.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/files.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/historian.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/instruments.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/interval.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/month-end.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/notifications.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/osdu.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/patches.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/quality.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/seismic.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/site.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/sites.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/slip.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/soak.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/start.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/structure.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/transients.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/vibration.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/housekeeping.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/interval.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/jobs.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/live_ports.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/loadtest.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/modbus.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/model_card.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/month_end.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/notify.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/opcua_port.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/operator_app.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/osdu.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/patches.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/permits.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/piwebapi.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/ports.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/ppdm.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/project.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/quakeml.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reconciler.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sample_record.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sbom.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seedlink.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/segy.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_array.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_film.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_response.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_track.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/service_life.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/shapefile.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/shell.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/shut_in.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/sla_report.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/slip.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/soak.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/store_forward.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/strata_join.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/structure.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/supervisor.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/survey_view.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/telemetry.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/tool_library.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/transient.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/vibration.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/well_assembler.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/wits0.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/witsml.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea/workspace.py +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.26.0 → gea_program-0.28.0}/setup.cfg +0 -0
- {gea_program-0.26.0 → gea_program-0.28.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.28.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 (368 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]")
|
|
@@ -648,6 +648,30 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
648
648
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
649
649
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
650
650
|
|
|
651
|
+
### Tools and ports
|
|
652
|
+
|
|
653
|
+
The Tools & ports tab (`#/tools`, `gea tools`) is the program's two
|
|
654
|
+
registers in one place: the tool library - every downhole and surface tool
|
|
655
|
+
with its source citation, ratings, what it measures, the telemetry interface
|
|
656
|
+
it declares and its datasheet aging rate where the vendor published one -
|
|
657
|
+
and the ports, the file formats read and the eleven live protocols spoken,
|
|
658
|
+
each with what it speaks to, what the site must supply and what to rehearse
|
|
659
|
+
against. Tools whose declared interface no port in this build speaks are
|
|
660
|
+
listed by name. The rating check hangs a tool string in a well and reports
|
|
661
|
+
each station's tool against the conditions there, with the basis stated:
|
|
662
|
+
`gea tools --rating --station 16000:quartz_pt_geoq177_16k` exits 1 when a
|
|
663
|
+
station is over a rating. `gea help tools`.
|
|
664
|
+
|
|
665
|
+
### ComCat
|
|
666
|
+
|
|
667
|
+
The seismicity response plan reads a TexNet export; it reads the FDSN text
|
|
668
|
+
export of USGS ComCat - or any FDSN event service - the same way, with the
|
|
669
|
+
contributor and magnitude type on every event. `gea comcat --lat --lon
|
|
670
|
+
--radius-km --start --end` prints the query to open; `gea comcat --file`
|
|
671
|
+
reads the answer; `sra-report --catalog` takes it. Proven on two verbatim
|
|
672
|
+
public-domain extracts (the Delaware Basin, September 2026; the 2011
|
|
673
|
+
Youngstown sequence with its M 4.0), kept as fixtures with their provenance.
|
|
674
|
+
|
|
651
675
|
### Slip tendency on the mapped faults
|
|
652
676
|
|
|
653
677
|
The stress state the site declares - the three gradients and the ambient
|
|
@@ -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 (368 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]")
|
|
@@ -609,6 +609,30 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
609
609
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
610
610
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
611
611
|
|
|
612
|
+
### Tools and ports
|
|
613
|
+
|
|
614
|
+
The Tools & ports tab (`#/tools`, `gea tools`) is the program's two
|
|
615
|
+
registers in one place: the tool library - every downhole and surface tool
|
|
616
|
+
with its source citation, ratings, what it measures, the telemetry interface
|
|
617
|
+
it declares and its datasheet aging rate where the vendor published one -
|
|
618
|
+
and the ports, the file formats read and the eleven live protocols spoken,
|
|
619
|
+
each with what it speaks to, what the site must supply and what to rehearse
|
|
620
|
+
against. Tools whose declared interface no port in this build speaks are
|
|
621
|
+
listed by name. The rating check hangs a tool string in a well and reports
|
|
622
|
+
each station's tool against the conditions there, with the basis stated:
|
|
623
|
+
`gea tools --rating --station 16000:quartz_pt_geoq177_16k` exits 1 when a
|
|
624
|
+
station is over a rating. `gea help tools`.
|
|
625
|
+
|
|
626
|
+
### ComCat
|
|
627
|
+
|
|
628
|
+
The seismicity response plan reads a TexNet export; it reads the FDSN text
|
|
629
|
+
export of USGS ComCat - or any FDSN event service - the same way, with the
|
|
630
|
+
contributor and magnitude type on every event. `gea comcat --lat --lon
|
|
631
|
+
--radius-km --start --end` prints the query to open; `gea comcat --file`
|
|
632
|
+
reads the answer; `sra-report --catalog` takes it. Proven on two verbatim
|
|
633
|
+
public-domain extracts (the Delaware Basin, September 2026; the 2011
|
|
634
|
+
Youngstown sequence with its M 4.0), kept as fixtures with their provenance.
|
|
635
|
+
|
|
612
636
|
### Slip tendency on the mapped faults
|
|
613
637
|
|
|
614
638
|
The stress state the site declares - the three gradients and the ambient
|
|
@@ -278,6 +278,18 @@ def main(argv=None) -> int:
|
|
|
278
278
|
p_lp.add_argument("--stream-csv", type=str, default=None, help="also write a historian-style CSV the other commands ingest")
|
|
279
279
|
p_lp.add_argument("--selftest", action="store_true", help="etp: the codec round-trip and a session against the simulated store on the loopback")
|
|
280
280
|
|
|
281
|
+
p_tl = sub.add_parser("tools", help="the tool library and the port registry: every tool with its citation, ratings and the interface it declares; every file format and live protocol; --rating checks a tool string")
|
|
282
|
+
p_tl.add_argument("--json", action="store_true")
|
|
283
|
+
p_tl.add_argument("--list", action="store_true", help="just the tool names")
|
|
284
|
+
p_tl.add_argument("--rating", action="store_true", help="check a tool string: --station <md_ft>:<tool> (repeatable)")
|
|
285
|
+
p_tl.add_argument("--station", type=str, action="append", default=None, help="a station as <measured depth in feet>:<tool name>")
|
|
286
|
+
p_tl.add_argument("--surface-temp-f", type=float, default=75.0); p_tl.add_argument("--temp-gradient-f-ft", type=float, default=0.018)
|
|
287
|
+
p_tl.add_argument("--surface-pressure-psi", type=float, default=14.7); p_tl.add_argument("--pressure-gradient-psi-ft", type=float, default=0.465)
|
|
288
|
+
p_cc = sub.add_parser("comcat", help="USGS ComCat / any FDSN event service: --lat --lon --radius-km --start --end prints the text-format query to open; --file reads the export it returns")
|
|
289
|
+
p_cc.add_argument("--lat", type=float, default=None); p_cc.add_argument("--lon", type=float, default=None); p_cc.add_argument("--radius-km", type=float, default=25.0)
|
|
290
|
+
p_cc.add_argument("--start", type=str, default=None); p_cc.add_argument("--end", type=str, default=None); p_cc.add_argument("--min-mag", type=float, default=1.0)
|
|
291
|
+
p_cc.add_argument("--file", type=str, default=None, help="an FDSN text export to read and summarise")
|
|
292
|
+
p_cc.add_argument("--json", action="store_true")
|
|
281
293
|
p_sl = sub.add_parser("slip", help="slip tendency on the mapped faults of a layer at a position, from declared gradients: --layer --lat --lon --depth-ft --sv --shmin --shmax (--shmax-azimuth or --wsm)")
|
|
282
294
|
p_sl.add_argument("--layer", type=str, required=True); p_sl.add_argument("--member", type=str, default=None); p_sl.add_argument("--feature-kind", type=str, choices=["fault", "fold"], default=None)
|
|
283
295
|
p_sl.add_argument("--lat", type=float, required=True); p_sl.add_argument("--lon", type=float, required=True); p_sl.add_argument("--radius-km", type=float, default=25.0)
|
|
@@ -2351,6 +2363,66 @@ def main(argv=None) -> int:
|
|
|
2351
2363
|
stop.set()
|
|
2352
2364
|
print("etp-sim: stopped")
|
|
2353
2365
|
return 0
|
|
2366
|
+
elif a.cmd == "tools":
|
|
2367
|
+
import json as _json
|
|
2368
|
+
from . import tool_catalog as _TC
|
|
2369
|
+
if a.rating or a.station:
|
|
2370
|
+
stations = []
|
|
2371
|
+
for spec in (a.station or []):
|
|
2372
|
+
if ":" not in spec:
|
|
2373
|
+
raise SystemExit(f"--station takes <measured depth in feet>:<tool name>, got {spec!r}")
|
|
2374
|
+
md, _, nm = spec.partition(":")
|
|
2375
|
+
try:
|
|
2376
|
+
stations.append((float(md), nm.strip()))
|
|
2377
|
+
except ValueError:
|
|
2378
|
+
raise SystemExit(f"--station depth is not a number: {md!r}")
|
|
2379
|
+
try:
|
|
2380
|
+
r = _TC.check_string(stations, surface_temp_F=a.surface_temp_f, temp_gradient_F_per_ft=a.temp_gradient_f_ft,
|
|
2381
|
+
surface_pressure_psi=a.surface_pressure_psi, pressure_gradient_psi_per_ft=a.pressure_gradient_psi_ft)
|
|
2382
|
+
except ValueError as e:
|
|
2383
|
+
raise SystemExit(f"tools: {e}")
|
|
2384
|
+
if a.json:
|
|
2385
|
+
print(_json.dumps(r, indent=1)); return 0 if not r["n_over_rating"] else 1
|
|
2386
|
+
for line in r["lines"]:
|
|
2387
|
+
print(line)
|
|
2388
|
+
return 0 if not r["n_over_rating"] else 1
|
|
2389
|
+
if a.list:
|
|
2390
|
+
for t in _TC.tools():
|
|
2391
|
+
print(t["name"])
|
|
2392
|
+
return 0
|
|
2393
|
+
if a.json:
|
|
2394
|
+
print(_json.dumps(_TC.catalog(), indent=1)); return 0
|
|
2395
|
+
print(_TC.text())
|
|
2396
|
+
return 0
|
|
2397
|
+
elif a.cmd == "comcat":
|
|
2398
|
+
import json as _json
|
|
2399
|
+
from . import sra as _SR
|
|
2400
|
+
from . import geodesy as _GD
|
|
2401
|
+
if a.file:
|
|
2402
|
+
c = _SR.read_catalog(a.file)
|
|
2403
|
+
if c.get("format") != "fdsn-text":
|
|
2404
|
+
print(f"comcat: {a.file} is not an FDSN text export (it read as a {c.get('basis', '')[:60]}...)"); return 1
|
|
2405
|
+
ev = c["events"]
|
|
2406
|
+
if a.lat is not None and a.lon is not None:
|
|
2407
|
+
for e in ev:
|
|
2408
|
+
dm = _GD.geodesic_m(a.lat, a.lon, e["lat"], e["lon"])["distance_m"]
|
|
2409
|
+
e["distance_km"] = round(dm / 1000.0, 2) if dm is not None else None
|
|
2410
|
+
if a.json:
|
|
2411
|
+
print(_json.dumps(c, indent=1, default=str)); return 0
|
|
2412
|
+
big = max(ev, key=lambda e: e["magnitude"]) if ev else None
|
|
2413
|
+
ts = sorted(e["time"] for e in ev)
|
|
2414
|
+
print(f"comcat: {c['n_events']} event(s) ({c['n_skipped']} skipped) from {ts[0][:10] if ts else '-'} to {ts[-1][:10] if ts else '-'}; "
|
|
2415
|
+
f"contributors {', '.join(c['contributors'])}; magnitude types {', '.join(c['magnitude_types'])}")
|
|
2416
|
+
if big:
|
|
2417
|
+
print(f" largest: M {big['magnitude']:.1f} {big['mag_type']} {big['time']} at {big['lat']:.4f}, {big['lon']:.4f}, {big['depth_km']} km - {big['place']} ({big['event_id']})")
|
|
2418
|
+
for e in sorted(ev, key=lambda x: x["time"])[:40]:
|
|
2419
|
+
print(f" {e['time'][:19]} M {e['magnitude']:>4.1f} {e['mag_type']:<6s} {e['lat']:9.4f} {e['lon']:10.4f} {str(e['depth_km']):>7s} km " + (f"{e['distance_km']:7.2f} km " if e.get("distance_km") is not None else "") + f"{e['place']}")
|
|
2420
|
+
return 0
|
|
2421
|
+
if a.lat is None or a.lon is None or not a.start or not a.end:
|
|
2422
|
+
raise SystemExit("comcat needs --lat --lon --start --end (--radius-km, --min-mag), or --file <export>")
|
|
2423
|
+
print(_SR.comcat_url(a.lat, a.lon, a.radius_km, a.start, a.end, a.min_mag))
|
|
2424
|
+
print(" open it in a browser (this machine may not reach the service) and save the text it returns; `gea comcat --file <saved>` reads it, and sra-report --catalog takes it.")
|
|
2425
|
+
return 0
|
|
2354
2426
|
elif a.cmd == "slip":
|
|
2355
2427
|
import json as _json
|
|
2356
2428
|
from . import shapefile as _SF, slip as _SL, friction_priors as _FP
|
|
@@ -7274,6 +7274,161 @@ def section_bt_slip(tmp: str) -> None:
|
|
|
7274
7274
|
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
7275
7275
|
|
|
7276
7276
|
|
|
7277
|
+
def section_bu_comcat(tmp: str) -> None:
|
|
7278
|
+
"""Section BU - the USGS ComCat / FDSN text export read as a catalogue, proven on two verbatim public-domain
|
|
7279
|
+
extracts kept as fixtures (the Delaware Basin, September 2026; the Youngstown 2011 sequence); the SRA seismicity
|
|
7280
|
+
on the real Youngstown sequence; the query builder; the CLI."""
|
|
7281
|
+
import subprocess as _sp
|
|
7282
|
+
from . import sra as SR
|
|
7283
|
+
from . import geodesy as GD
|
|
7284
|
+
pkg = Path(__file__).parent
|
|
7285
|
+
d = Path(tmp, "bu"); d.mkdir()
|
|
7286
|
+
fx = pkg / "fixtures"
|
|
7287
|
+
de = SR.read_catalog(str(fx / "comcat_delaware_basin_2026-09.txt"))
|
|
7288
|
+
yo = SR.read_catalog(str(fx / "comcat_youngstown_2011-2012.txt"))
|
|
7289
|
+
big = max(yo["events"], key=lambda e: e["magnitude"])
|
|
7290
|
+
url = SR.comcat_url(41.1, -80.68, 25.0, "2011-03-01", "2012-03-01", 1.5)
|
|
7291
|
+
# the Youngstown sequence against an SRA-shaped area around the Northstar 1 site: 10 km, M 2.0 threshold, plan date 2011-12-01
|
|
7292
|
+
sra = SR.define("Youngstown", 41.12, -80.69, 10.0, "2011-12-01", threshold_m=2.0, formation_boundary="base of the Knox")
|
|
7293
|
+
from datetime import datetime as _dt, timezone as _tz
|
|
7294
|
+
se = SR.seismicity(sra, yo, as_of=_dt(2012, 2, 1, tzinfo=_tz.utc))
|
|
7295
|
+
far = next(e for e in yo["events"] if e["event_id"] == "ld60004308")
|
|
7296
|
+
dist_far = GD.geodesic_m(41.12, -80.69, far["lat"], far["lon"])["distance_m"] / 1000.0
|
|
7297
|
+
r_file = _sp.run([sys.executable, "-m", "gea", "comcat", "--file", str(fx / "comcat_youngstown_2011-2012.txt"), "--lat", "41.1", "--lon", "-80.68"], capture_output=True, text=True)
|
|
7298
|
+
r_url = _sp.run([sys.executable, "-m", "gea", "comcat", "--lat", "31.42", "--lon", "-103.5", "--radius-km", "30", "--start", "2026-09-01", "--end", "2026-10-01", "--min-mag", "2.5"], capture_output=True, text=True)
|
|
7299
|
+
r_bad = _sp.run([sys.executable, "-m", "gea", "comcat", "--file", str(pkg / "catalog" / "collingwood_1_28_ks_complete.las")], capture_output=True, text=True)
|
|
7300
|
+
help_md = (pkg / "help" / "sra.md").read_text(encoding="utf-8")
|
|
7301
|
+
c1 = {
|
|
7302
|
+
"delaware": de["format"] == "fdsn-text" and de["n_events"] == 28 and de["n_skipped"] == 0 and de["contributors"] == ["tx", "us"] and de["magnitude_types"] == ["mb_lg", "ml"]
|
|
7303
|
+
and max(e["magnitude"] for e in de["events"]) == 3.4 and de["events"][0]["event_id"] == "tx2026tgiogl" and de["events"][0]["time"] == "2026-09-30T13:35:58Z"
|
|
7304
|
+
and de["events"][0]["depth_km"] == 6.2024 and "mixes scales" in de["basis"] and sum(1 for e in de["events"] if e["contributor"] == "us") == 4,
|
|
7305
|
+
"youngstown": yo["n_events"] == 9 and big["event_id"] == "ld60029101" and big["magnitude"] == 4.0 and big["time"] == "2011-12-31T20:05:01Z" and big["lat"] == 41.1215 and big["lon"] == -80.6843333
|
|
7306
|
+
and big["place"] == "3 km NW of Youngstown, Ohio" and yo["contributors"] == ["ld"],
|
|
7307
|
+
"seismicity": se["n_inside"] == 9 and se["largest"]["event_id"] == "ld60029101" and se["largest"]["magnitude"] == 4.0 and se["n_at_or_above"] == 6 and dist_far < 10.0
|
|
7308
|
+
and se["trigger"]["status"] == "TRIGGERED" and se["trigger"]["respond_by"] == "2012-01-02T20:05:01Z" and se["goal"]["clock_started"] == "2011-12-31",
|
|
7309
|
+
"url": url == "https://earthquake.usgs.gov/fdsnws/event/1/query?format=text&starttime=2011-03-01&endtime=2012-03-01&latitude=41.1000&longitude=-80.6800&maxradiuskm=25&minmagnitude=1.5&orderby=time-asc",
|
|
7310
|
+
"cli": r_file.returncode == 0 and "largest: M 4.0 ml 2011-12-31T20:05:01Z at 41.1215, -80.6843" in r_file.stdout and "1.68 km" in r_file.stdout
|
|
7311
|
+
and r_url.returncode == 0 and "maxradiuskm=30&minmagnitude=2.5" in r_url.stdout and r_bad.returncode == 1 and "not an FDSN text export" in r_bad.stdout,
|
|
7312
|
+
"help_and_fixtures": "gea comcat" in help_md and (fx / "README.md").read_text(encoding="utf-8").count("earthquake.usgs.gov/fdsnws/event/1/query") == 2,
|
|
7313
|
+
}
|
|
7314
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
7315
|
+
ok(not failed1,
|
|
7316
|
+
"BU1 the FDSN text export read as a catalogue with contributors and magnitude types: the Delaware Basin window of September 2026 (28 events, TexNet "
|
|
7317
|
+
"and NEIC, ML and mb_Lg, largest M 3.4) and the Youngstown 2011 sequence (9 events, the M 4.0 of 2011-12-31 3 km NW of Youngstown); the SRA seismicity "
|
|
7318
|
+
"on the real sequence inside a 10 km area (six at or above M 2.0, the M 4.0 TRIGGERED, the goal clock from 2011-12-31); the query builder; `gea comcat --file` with distances and `--lat --lon --start --end` printing the query; "
|
|
7319
|
+
"a LAS refused; the help and the fixtures' provenance"
|
|
7320
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
7321
|
+
|
|
7322
|
+
|
|
7323
|
+
def section_bv_tools(tmp: str) -> None:
|
|
7324
|
+
"""Section BV - the tool library and the port registry as one register: every tool with its citation, ratings,
|
|
7325
|
+
declared interface and published aging rate (or the reason there is none); every file format and live protocol
|
|
7326
|
+
with what the site must supply; the tools no port speaks named; the rating check; the API, the page, the CLI, the help."""
|
|
7327
|
+
import http.cookiejar
|
|
7328
|
+
import subprocess as _sp
|
|
7329
|
+
import urllib.request
|
|
7330
|
+
import urllib.error
|
|
7331
|
+
from . import tool_catalog as TC
|
|
7332
|
+
from . import helplib as H
|
|
7333
|
+
from .ports import PORT_REGISTRY
|
|
7334
|
+
from .tool_library import PARAMETERS_USER_SUPPLIED, TOOL_LIBRARY
|
|
7335
|
+
from .telemetry import TelemetryRecorder, TelemetryConfig
|
|
7336
|
+
from .downhole_engine import DownholeEngine, SimulatorConfig
|
|
7337
|
+
from .workspace import Workspace
|
|
7338
|
+
from .service import Service, Users
|
|
7339
|
+
pkg = Path(__file__).parent
|
|
7340
|
+
d = Path(tmp, "bv"); d.mkdir()
|
|
7341
|
+
|
|
7342
|
+
c = TC.catalog()
|
|
7343
|
+
by = {t["name"]: t for t in c["tools"]}
|
|
7344
|
+
q30, piezo, g6 = by["quartz_pt_geoq177_30k"], by["piezoresistive_pt_class"], by["surface_interface_g6"]
|
|
7345
|
+
rate = TC.check_string([(500.0, "quartz_pt_geoq177_30k"), (16000.0, "quartz_pt_geoq177_16k")])
|
|
7346
|
+
deep = rate["stations"][1]
|
|
7347
|
+
ok_all = TC.check_string([(500.0, "quartz_pt_geoq177_30k")])
|
|
7348
|
+
bad_tool = empty = None
|
|
7349
|
+
try:
|
|
7350
|
+
TC.check_string([(100.0, "no_such_tool")])
|
|
7351
|
+
except ValueError as e:
|
|
7352
|
+
bad_tool = str(e)
|
|
7353
|
+
try:
|
|
7354
|
+
TC.check_string([])
|
|
7355
|
+
except ValueError as e:
|
|
7356
|
+
empty = str(e)
|
|
7357
|
+
c1 = {
|
|
7358
|
+
"tools": c["counts"]["tools"] == len(TOOL_LIBRARY) and c["counts"]["fully_specified"] + c["counts"]["user_supplied"] == len(TOOL_LIBRARY)
|
|
7359
|
+
and all(t["source"] for t in c["tools"]) and q30["aging_rate_pct_fs_yr"] is not None and q30["aging_note"].startswith("the datasheet")
|
|
7360
|
+
and q30["temp_rating_C"] == 177.0 and q30["pressure_rating_psi"] == 30000.0 and q30["gauge_spec"]["full_scale_psi"] == 30000.0,
|
|
7361
|
+
"user_supplied_named": piezo["spec_status"] == PARAMETERS_USER_SUPPLIED and piezo["aging_rate_pct_fs_yr"] is None
|
|
7362
|
+
and "does not invent vendor numbers" in piezo["aging_note"] and g6["measures"] == [],
|
|
7363
|
+
"ports": c["counts"]["file_ports"] == len(PORT_REGISTRY) and {p["name"] for p in c["ports"]["live"]} >= {"wits0", "witsml", "etp", "opcua", "mqtt", "modbus_g6", "modbus_rtu", "dnp3", "hartip", "piwebapi", "seedlink"}
|
|
7364
|
+
and all(p["needs"] and p["speaks"] and p["rehearse"] for p in c["ports"]["live"]) and any(p["status"] == "IMPLEMENTED" for p in c["ports"]["files"])
|
|
7365
|
+
and any(p["name"] == "dlis" for p in c["ports"]["files"]),
|
|
7366
|
+
"interfaces": "modbus_rtu" in q30["ports"] and not piezo["ports"] and {u["tool"] for u in c["unmatched"]} == {t["name"] for t in c["tools"] if not t["ports"]}
|
|
7367
|
+
and "piezoresistive_pt_class" in {u["tool"] for u in c["unmatched"]},
|
|
7368
|
+
"rating": rate["n_over_rating"] == 1 and deep["over_temp_rating"] and not deep["over_pressure_rating"] and abs(deep["station_temp_C"] - 183.9) < 0.2
|
|
7369
|
+
and "OVER its 177 C rating" in rate["lines"][2] and "declared gradients" in rate["basis"] and "no survey given" in rate["deviation"]
|
|
7370
|
+
and ok_all["n_over_rating"] == 0 and bad_tool and "not in the tool library" in bad_tool and empty and "at least one station" in empty,
|
|
7371
|
+
}
|
|
7372
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
7373
|
+
ok(not failed1,
|
|
7374
|
+
f"BV1 the register: all {len(TOOL_LIBRARY)} tools with their citations, the quartz gauge's datasheet aging rate and ratings, the piezoresistive "
|
|
7375
|
+
"class carrying no rate and saying why, the interface card measuring nothing; every file port of the registry and all eleven live protocols with "
|
|
7376
|
+
"what each needs from the site and what to rehearse against; the tools no port in this build speaks named; the rating check flagging a 177 C gauge "
|
|
7377
|
+
"at 16,000 ft and clearing a shallow one, an unknown tool and an empty string refused"
|
|
7378
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
7379
|
+
|
|
7380
|
+
hist = str(d / "hist.csv")
|
|
7381
|
+
TelemetryRecorder(engine=DownholeEngine(SimulatorConfig()), config=TelemetryConfig(duration_hours=0.5, seed=3)).run().export_csv(hist)
|
|
7382
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
7383
|
+
ws.add_well_file(hist, display="SWD 1", actor="tester")
|
|
7384
|
+
users = Users(str(Path(wsp, "users.json"))); users.add("v", "viewer-pass-1", "viewer")
|
|
7385
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
7386
|
+
base_url = svc.url.rstrip("/")
|
|
7387
|
+
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
7388
|
+
|
|
7389
|
+
def call(method, path, body=None):
|
|
7390
|
+
req = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
7391
|
+
req.add_header("Content-Type", "application/json"); req.add_header("X-GEA-Action", "1")
|
|
7392
|
+
try:
|
|
7393
|
+
with opener.open(req, timeout=120) as rr_:
|
|
7394
|
+
return rr_.status, json.loads(rr_.read())
|
|
7395
|
+
except urllib.error.HTTPError as e:
|
|
7396
|
+
return e.code, json.loads(e.read())
|
|
7397
|
+
try:
|
|
7398
|
+
st_anon = call("GET", "/api/tools")[0]
|
|
7399
|
+
call("POST", "/api/login", {"name": "v", "password": "viewer-pass-1"})
|
|
7400
|
+
st_g, got = call("GET", "/api/tools")
|
|
7401
|
+
st_r, rr = call("POST", "/api/tools/rating", {"stations": [{"md_ft": 500, "tool": "quartz_pt_geoq177_30k"}, {"md_ft": 16000, "tool": "quartz_pt_geoq177_16k"}]})
|
|
7402
|
+
st_bad = call("POST", "/api/tools/rating", {"stations": [{"md_ft": 100, "tool": "nope"}]})[0]
|
|
7403
|
+
st_bad2 = call("POST", "/api/tools/rating", {"stations": [{"tool": "quartz_pt_geoq177_30k"}]})[0]
|
|
7404
|
+
finally:
|
|
7405
|
+
svc.stop()
|
|
7406
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
7407
|
+
help_md = (pkg / "help" / "tools.md").read_text(encoding="utf-8")
|
|
7408
|
+
r_txt = _sp.run([sys.executable, "-m", "gea", "tools"], capture_output=True, text=True)
|
|
7409
|
+
r_list = _sp.run([sys.executable, "-m", "gea", "tools", "--list"], capture_output=True, text=True)
|
|
7410
|
+
r_json = _sp.run([sys.executable, "-m", "gea", "tools", "--json"], capture_output=True, text=True)
|
|
7411
|
+
r_rate = _sp.run([sys.executable, "-m", "gea", "tools", "--rating", "--station", "500:quartz_pt_geoq177_30k", "--station", "16000:quartz_pt_geoq177_16k"], capture_output=True, text=True)
|
|
7412
|
+
r_badst = _sp.run([sys.executable, "-m", "gea", "tools", "--rating", "--station", "500"], capture_output=True, text=True)
|
|
7413
|
+
c2 = {
|
|
7414
|
+
"api": st_anon == 401 and st_g == 200 and got["counts"]["tools"] == len(TOOL_LIBRARY) and st_r == 200 and rr["n_over_rating"] == 1
|
|
7415
|
+
and rr["stations"][1]["over_temp_rating"] and st_bad == 400 and st_bad2 == 400,
|
|
7416
|
+
"page": "VIEWS.tools" in page_src and "'#/tools', 'Tools & ports'" in page_src and "/api/tools/rating" in page_src
|
|
7417
|
+
and "Tools no live port in this build speaks" in page_src and "Rating check" in page_src,
|
|
7418
|
+
"cli": r_txt.returncode == 0 and "file ports:" in r_txt.stdout and "live ports:" in r_txt.stdout and "does not invent vendor numbers" in r_txt.stdout
|
|
7419
|
+
and r_list.returncode == 0 and r_list.stdout.split() == sorted(TOOL_LIBRARY) and r_json.returncode == 0 and json.loads(r_json.stdout)["counts"]["live_ports"] == 11
|
|
7420
|
+
and r_rate.returncode == 1 and "OVER its 177 C rating" in r_rate.stdout and r_badst.returncode != 0 and "<measured depth in feet>:<tool name>" in (r_badst.stderr + r_badst.stdout),
|
|
7421
|
+
"help": any(t["topic"] == "tools" for t in H.topics()) and not H.check("tools") and H.VIEW_TOPIC.get("tools") == "tools"
|
|
7422
|
+
and "not a promise the tool survives" in help_md.split("will not call a measurement")[1],
|
|
7423
|
+
}
|
|
7424
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
7425
|
+
ok(not failed2,
|
|
7426
|
+
"BV2 the Tools & ports tab: the API refuses an anonymous caller and answers a viewer, runs the rating check and refuses an unknown tool and a "
|
|
7427
|
+
"station with no depth; the page carries the tab, the unmatched-tools table and the rating-check form; `gea tools`, `--list`, `--json` and "
|
|
7428
|
+
"`--rating --station` (exit 1 when a station is over a rating, and a malformed station named); the help page and its view mapping"
|
|
7429
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
7430
|
+
|
|
7431
|
+
|
|
7277
7432
|
def main() -> int:
|
|
7278
7433
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
7279
7434
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -7349,6 +7504,8 @@ def main() -> int:
|
|
|
7349
7504
|
section_br_logs_historian(tmp)
|
|
7350
7505
|
section_bs_catalog(tmp)
|
|
7351
7506
|
section_bt_slip(tmp)
|
|
7507
|
+
section_bu_comcat(tmp)
|
|
7508
|
+
section_bv_tools(tmp)
|
|
7352
7509
|
if _FAILS:
|
|
7353
7510
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
7354
7511
|
for f in _FAILS:
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# fixtures
|
|
2
|
+
|
|
3
|
+
Small, verbatim, public-domain extracts kept so the gate can prove a reader on real records without a network.
|
|
4
|
+
|
|
5
|
+
- `comcat_delaware_basin_2026-09.txt` - USGS ComCat, FDSN event web service text output, fetched 2026-10-12:
|
|
6
|
+
`https://earthquake.usgs.gov/fdsnws/event/1/query?format=text&starttime=2026-09-01&endtime=2026-10-01&minlatitude=30.5&maxlatitude=32.5&minlongitude=-104.5&maxlongitude=-102.0&minmagnitude=2.5&orderby=time`
|
|
7
|
+
(28 events M >= 2.5, Delaware and Midland basins; contributors tx = TexNet, us = NEIC). US Government work, public domain.
|
|
8
|
+
- `comcat_youngstown_2011-2012.txt` - the same service, fetched 2026-10-12:
|
|
9
|
+
`https://earthquake.usgs.gov/fdsnws/event/1/query?format=text&starttime=2011-03-01&endtime=2012-03-01&latitude=41.1&longitude=-80.68&maxradiuskm=25&minmagnitude=1.5&orderby=time-asc`
|
|
10
|
+
(9 events within 25 km of Youngstown, Ohio: the 2011 sequence that ended with the M 4.0 of 2011-12-31; contributor ld = Lamont-Doherty). Public domain.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#EventID|Time|Latitude|Longitude|Depth/km|Author|Catalog|Contributor|ContributorID|MagType|Magnitude|MagAuthor|EventLocationName
|
|
2
|
+
tx2026tgiogl|2026-09-30T13:35:58.370|31.618|-104.363|6.2024|tx|tx|tx|tx2026tgiogl|ml|2.9|tx|61 km S of Whites City, New Mexico
|
|
3
|
+
tx2026tfzcgy|2026-09-30T08:50:13.448|31.624|-104.364|6.9714|tx|tx|tx|tx2026tfzcgy|ml|3.3|tx|61 km S of Whites City, New Mexico
|
|
4
|
+
tx2026tbppja|2026-09-27T23:45:52.397|31.617|-104.312|8.4583|tx|tx|tx|tx2026tbppja|ml|2.5|tx|59 km NW of Toyah, Texas
|
|
5
|
+
tx2026sxmsve|2026-09-25T18:01:21.042|31.379|-103.705|6.228|tx|tx|tx|tx2026sxmsve|ml|2.6|tx|11 km NE of Toyah, Texas
|
|
6
|
+
tx2026svkhwu|2026-09-24T14:39:26.649|30.831|-103.394|3.3569|tx|tx|tx|tx2026svkhwu|ml|2.9|tx|37 km ESE of Balmorhea, Texas
|
|
7
|
+
tx2026ssvrgl|2026-09-23T05:08:42.441|32.401|-102.046|7.1533|tx|tx|tx|tx2026ssvrgl|ml|3|tx|34 km WSW of Ackerly, Texas
|
|
8
|
+
tx2026sspzfy|2026-09-23T02:16:59.235|32.436|-102.098|6.958|tx|tx|tx|tx2026sspzfy|ml|2.8|tx|35 km SSW of Los Ybanez, Texas
|
|
9
|
+
tx2026srxfgq|2026-09-22T16:50:40.191|31.668|-104.402|6.0999|tx|tx|tx|tx2026srxfgq|ml|2.6|tx|56 km S of Whites City, New Mexico
|
|
10
|
+
tx2026srvtwi|2026-09-22T16:07:21.955|31.605|-103.933|7.7533|tx|tx|tx|tx2026srvtwi|ml|2.5|tx|33 km WSW of Mentone, Texas
|
|
11
|
+
tx2026srfrih|2026-09-22T08:04:38.331|31.666|-104.25|6.0999|tx|tx|tx|tx2026srfrih|ml|3.1|tx|57 km SSE of Whites City, New Mexico
|
|
12
|
+
us7000tisq|2026-09-20T19:23:14.330|32.2823|-103.7703|7.6|us|us|us|us7000tisq|mb_lg|2.9|us|29 km ENE of Malaga, New Mexico
|
|
13
|
+
tx2026sngzur|2026-09-20T04:23:40.180|31.668|-104.362|7.1765|tx|tx|tx|tx2026sngzur|ml|3.2|tx|56 km S of Whites City, New Mexico
|
|
14
|
+
tx2026sipbbo|2026-09-17T15:04:16.188|32.074|-103.679|7.7533|tx|tx|tx|tx2026sipbbo|ml|2.7|tx|40 km ESE of Malaga, New Mexico
|
|
15
|
+
tx2026siects|2026-09-17T09:34:33.358|31.665|-104.453|6.0999|tx|tx|tx|tx2026siects|ml|2.5|tx|57 km S of Whites City, New Mexico
|
|
16
|
+
tx2026sfaiyw|2026-09-15T16:27:44.534|31.615|-104.113|6.0999|tx|tx|tx|tx2026sfaiyw|ml|2.6|tx|45 km NW of Toyah, Texas
|
|
17
|
+
tx2026selaoc|2026-09-15T08:48:29.775|31.657|-104.135|6.1127|tx|tx|tx|tx2026selaoc|ml|3.3|tx|49 km NW of Toyah, Texas
|
|
18
|
+
tx2026sawssd|2026-09-13T10:20:00.004|31.661|-104.432|6.0999|tx|tx|tx|tx2026sawssd|ml|3.4|tx|57 km S of Whites City, New Mexico
|
|
19
|
+
tx2026sapxnl|2026-09-13T06:54:23.103|31.661|-104.432|6.0999|tx|tx|tx|tx2026sapxnl|ml|2.9|tx|57 km S of Whites City, New Mexico
|
|
20
|
+
tx2026saectr|2026-09-13T00:58:24.306|31.751|-104.336|7.074|tx|tx|tx|tx2026saectr|ml|2.9|tx|47 km S of Whites City, New Mexico
|
|
21
|
+
us7000tgvj|2026-09-12T00:22:12.507|32.2629|-103.2847|7.91|us|us|us|us7000tgvj|mb_lg|2.6|us|18 km NNW of Jal, New Mexico
|
|
22
|
+
tx2026rupmzs|2026-09-10T00:15:33.655|31.64|-104.408|6.3306|tx|tx|tx|tx2026rupmzs|ml|3|tx|59 km S of Whites City, New Mexico
|
|
23
|
+
us7000tg2k|2026-09-09T16:00:21.180|32.3229|-104.4961|3.897|us|us|us|us7000tg2k|ml|2.5|us|19 km NW of Whites City, New Mexico
|
|
24
|
+
tx2026rqcbab|2026-09-07T13:11:15.952|32.005|-103.24|6.0999|tx|tx|tx|tx2026rqcbab|ml|2.7|tx|12 km SSW of Jal, New Mexico
|
|
25
|
+
tx2026roctny|2026-09-06T11:24:04.550|31.542|-104.128|8.8428|tx|tx|tx|tx2026roctny|ml|2.5|tx|40 km NW of Toyah, Texas
|
|
26
|
+
us7000tegw|2026-09-05T03:41:56.500|32.3519|-104.4998|5|us|us|us|us7000tegw|ml|2.7|us|22 km NNW of Whites City, New Mexico
|
|
27
|
+
tx2026rliwah|2026-09-04T23:14:17.831|31.667|-104.37|6.9202|tx|tx|tx|tx2026rliwah|ml|2.5|tx|56 km S of Whites City, New Mexico
|
|
28
|
+
tx2026rjxsxm|2026-09-04T04:35:25.328|31.542|-104.129|8.5095|tx|tx|tx|tx2026rjxsxm|ml|3.1|tx|40 km NW of Toyah, Texas
|
|
29
|
+
tx2026rjmsif|2026-09-03T23:02:00.297|31.656|-104.387|6.0999|tx|tx|tx|tx2026rjmsif|ml|2.5|tx|57 km S of Whites City, New Mexico
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#EventID|Time|Latitude|Longitude|Depth/km|Author|Catalog|Contributor|ContributorID|MagType|Magnitude|MagAuthor|EventLocationName
|
|
2
|
+
ld60004308|2011-03-17T10:53:11.670|41.126|-80.6056667|3.54|ld|ld|ld|ld60004308|ml|2.1|ld|2 km WSW of Maplewood Park, Ohio
|
|
3
|
+
ld60007303|2011-08-22T08:00:32.640|41.1303333|-80.7081667|5|ld|ld|ld|ld60007303|ml|1.87|ld|2 km SSW of Girard, Ohio
|
|
4
|
+
ld60009603|2011-09-26T01:06:10.840|41.115|-80.6823333|5|ld|ld|ld|ld60009603|ml|2.12|ld|3 km WNW of Youngstown, Ohio
|
|
5
|
+
ld60009803|2011-09-30T00:52:38.710|41.1346667|-80.6845|5|ld|ld|ld|ld60009803|ml|2.44|ld|2 km SSE of Girard, Ohio
|
|
6
|
+
ld60010908|2011-10-20T22:41:10.820|41.1253333|-80.704|6.39|ld|ld|ld|ld60010908|ml|2.04|ld|3 km S of Girard, Ohio
|
|
7
|
+
ld60012603|2011-11-25T06:47:28.250|41.124|-80.6771667|5|ld|ld|ld|ld60012603|ml|1.79|ld|3 km NW of Youngstown, Ohio
|
|
8
|
+
ld60013703|2011-12-24T06:24:58.810|41.1225|-80.7046667|5|ld|ld|ld|ld60013703|ml|2.37|ld|3 km S of Girard, Ohio
|
|
9
|
+
ld60029101|2011-12-31T20:05:01.060|41.1215|-80.6843333|5|ld|ld|ld|ld60029101|ml|4|ld|3 km NW of Youngstown, Ohio
|
|
10
|
+
ld60014118|2012-01-13T22:29:35.120|41.1245|-80.6923333|5.79|ld|ld|ld|ld60014118|ml|1.74|ld|3 km SSE of Girard, Ohio
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**The number to check**: `Response:` in section "Seismicity against the plan" - TRIGGERED names the event, its magnitude and the deadline for the response group's meeting; NOT TRIGGERED names why. `Goal:` gives the days without a threshold event and the date the plan's goal falls on. The packet's front says COMPLETE or INCOMPLETE with the count of gaps.
|
|
10
10
|
|
|
11
|
-
**What this page will not call a measurement**: which earthquakes are aftershocks - the operator declares them with `--aftershocks` and they are shown as exempt, never decided here. A volume read off a pressure gauge - a well with no rate channel has no volume and no maximum rate, and the packet says NOT RECORDED. A depth tier from depth alone - the tier is stratigraphic, above or below the named formation base, and is declared. The TexNet reporting tool's own upload template - the export carries the Notice's parameter names and the mapping is the operator's step. A catalogue nobody handed in - the catalogue is a file the operator exports from TexNet, and its export date is on the packet.
|
|
11
|
+
**What this page will not call a measurement**: which earthquakes are aftershocks - the operator declares them with `--aftershocks` and they are shown as exempt, never decided here. A volume read off a pressure gauge - a well with no rate channel has no volume and no maximum rate, and the packet says NOT RECORDED. A depth tier from depth alone - the tier is stratigraphic, above or below the named formation base, and is declared. The TexNet reporting tool's own upload template - the export carries the Notice's parameter names and the mapping is the operator's step. A catalogue nobody handed in - the catalogue is a file the operator exports from TexNet, or the FDSN text export of USGS ComCat (`gea comcat --lat --lon --radius-km --start --end` prints the query; the file it returns reads directly, with its contributors and magnitude types on the packet), and its export date is on the packet.
|
|
12
12
|
|
|
13
13
|
The shape is the Commission's: the operator-led response plans on file (Gardendale, Northern Culberson-Reeves, Stanton) - a circle of about 9 km, a plan written against M 3.5, an 18-month goal, a response group meeting within 48 hours of a threshold event, quarterly checkpoints with Commission staff, and disposal wells in two tiers by the base of the Wolfcamp - and the December 2023 Notice to Operators on disposal-well monitoring and reporting in the Permian Basin, which names the four daily parameters and the three bottomhole-pressure methods. A downhole gauge this program monitors is the Notice's permanent probe.
|
|
14
14
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Tools and ports
|
|
2
|
+
|
|
3
|
+
> What this program knows how to measure with, and what it knows how to speak. The tool library is the downhole and surface tools - each with the citation its numbers came from, the conditions it is rated for, and the telemetry interface it declares; the port registry is the file formats and live protocols that bring a tool's readings in. The page draws the line between them: a tool declares an interface, a port speaks one, and a tool whose interface no port in this build speaks is named rather than hidden.
|
|
4
|
+
|
|
5
|
+
**The command**: the page is Tools & ports on the dashboard; `gea tools` prints the same register at the command line (`--json` for the machine record, `--rating --station <ft>:<tool> ...` for the rating check). A tool whose vendor published no numbers is listed as PARAMETERS_USER_SUPPLIED: `gea config` takes your own datasheet (`load_gauge_spec_json`) and the tool is then simulated and aged from it. The live protocols each name what the site must supply before they run and what to rehearse against - `gea wits0-sim`, `gea etp-sim`, `gea seedlink-sim`, or the stand-in slave, outstation, device and historian the field ports ship with.
|
|
6
|
+
|
|
7
|
+
**What it writes**: nothing to the workspace - this page is a register, not a record. It states, per tool: the class, what it measures, the temperature and pressure ratings, the published aging rate in %FS/yr where the datasheet gives one (and the reason there is none where it does not), the interface it declares, the ports that can carry it, and its source. Per port: the transport, the status (IMPLEMENTED, or DECLARED_SITE_DETAILS_REQUIRED with what is missing), and what it speaks to. The rating check returns, per station, the temperature and pressure at that depth, the tool's ratings and whether the station is within them, with the basis of the conditions printed beside the answer.
|
|
8
|
+
|
|
9
|
+
**The number to check**: the aging rate against your own datasheet before you trust a drift report built on it, and the rating check's per-station temperature against the tool's rating - the check that catches a 177 °C gauge hung in a 233 °C zone before the well does.
|
|
10
|
+
|
|
11
|
+
**What this page will not call a measurement**: a vendor number nobody published - a tool with no datasheet rate carries none and raises rather than inventing one, and the page says PARAMETERS_USER_SUPPLIED. A rating as a prediction - a station within its ratings is arithmetic on the vendor's number and the declared conditions, not a promise the tool survives. The conditions themselves - without a well profile they are the gradients declared on the page, and the answer prints which basis it used. A port as a connection - a port listed here speaks a protocol; whether the site's own device answers is what the Patch panel shows.
|
|
@@ -42,6 +42,7 @@ INDEX: List[tuple] = [
|
|
|
42
42
|
('catalog', 'The catalogue', 'every shipped public dataset, what in this program reads it or that nothing does; the measured friction envelope; the core check; any log through the survey'),
|
|
43
43
|
('dlis', 'The DLIS log', 'a well log as it is delivered (API RP66 V1), read as the standard lays it out: the frames, the channels, what was skipped; into the strata survey'),
|
|
44
44
|
('historian', 'The historian pull', 'an operator\'s gauge history out of the PI System through PI Web API, read-only, every value with its archive time and flags'),
|
|
45
|
+
('tools', 'Tools and ports', 'the downhole and surface tools this program knows, each with its citation and ratings, the formats and protocols that bring their readings in, and the rating check on a tool string'),
|
|
45
46
|
('field-ports', 'The field ports', 'Modbus RTU on the serial line, DNP3 from the pad RTU, HART-IP from the transmitter itself - read-only, polled, with the stand-ins to rehearse against'),
|
|
46
47
|
('slip', 'Slip tendency on the mapped faults', 'the declared stress state resolved on each mapped fault around a well: the slip tendency, the pressure to slip, the World Stress Map as the SHmax source, the published Hennings values beside'),
|
|
47
48
|
('interval', 'The interval against the mapped tops', 'the declared disposal interval, subsea, beside each formation-top bracket; the depth tier against the mapped base; the catalogue events against the mapped faults'),
|
|
@@ -66,7 +67,7 @@ REQUIRED_LINES = ('**The command**', '**What it writes**', '**The number to chec
|
|
|
66
67
|
VIEW_TOPIC: Dict[str, str] = {
|
|
67
68
|
'home': 'start', 'wells': 'data-in', 'well': 'drift', 'live': 'patches', 'patch': 'patches', 'files': 'files', 'alarms': 'alarms',
|
|
68
69
|
'approvals': 'well-tests', 'config': 'site', 'reports': 'drift', 'verify': 'start', 'survey': 'data-in', 'jobs': 'site',
|
|
69
|
-
'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'audit': 'audit-update',
|
|
70
|
+
'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'audit': 'audit-update', 'tools': 'tools',
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
|
|
@@ -1637,6 +1637,9 @@ def make_handler(app: App):
|
|
|
1637
1637
|
raise ApiError(404, str(e))
|
|
1638
1638
|
if path == '/api/stress':
|
|
1639
1639
|
return self._json(200, {'stress': app.ws.stress(), 'stress_map': app.ws.stress_map()})
|
|
1640
|
+
if path == '/api/tools':
|
|
1641
|
+
from . import tool_catalog as _TC
|
|
1642
|
+
return self._json(200, _TC.catalog())
|
|
1640
1643
|
if path == '/api/stress/wsm':
|
|
1641
1644
|
try:
|
|
1642
1645
|
lat, lon = float(qs['lat'][0]), float(qs['lon'][0]); rad = float(qs.get('radius_km', ['100'])[0])
|
|
@@ -1839,6 +1842,22 @@ def make_handler(app: App):
|
|
|
1839
1842
|
depth_ft=(float(b['depth_ft']) if b.get('depth_ft') is not None else None), actor=user['name']))
|
|
1840
1843
|
except WorkspaceError as e:
|
|
1841
1844
|
raise ApiError(404, str(e))
|
|
1845
|
+
if path == '/api/tools/rating':
|
|
1846
|
+
from . import tool_catalog as _TC
|
|
1847
|
+
b = body or {}
|
|
1848
|
+
try:
|
|
1849
|
+
stations = [(float(x['md_ft']), str(x['tool'])) for x in (b.get('stations') or [])]
|
|
1850
|
+
except (KeyError, TypeError, ValueError):
|
|
1851
|
+
raise ApiError(400, 'each station needs md_ft and tool')
|
|
1852
|
+
try: # the conditions are the declared gradients, and the answer says so
|
|
1853
|
+
return self._json(200, _TC.check_string(stations, profile=None, deviation=None,
|
|
1854
|
+
surface_temp_F=float(b.get('surface_temp_F', 75.0)),
|
|
1855
|
+
temp_gradient_F_per_ft=float(b.get('temp_gradient_F_per_ft', 0.018)),
|
|
1856
|
+
surface_pressure_psi=float(b.get('surface_pressure_psi', 14.7)),
|
|
1857
|
+
pressure_gradient_psi_per_ft=float(b.get('pressure_gradient_psi_per_ft', 0.465)),
|
|
1858
|
+
name=str(b.get('name', 'toolstring'))))
|
|
1859
|
+
except (ValueError, KeyError) as e:
|
|
1860
|
+
raise ApiError(400, str(e))
|
|
1842
1861
|
if path == '/api/stress':
|
|
1843
1862
|
App.require(user, 'operator')
|
|
1844
1863
|
try:
|
|
@@ -340,6 +340,10 @@ def read_catalog(path: str, mapping: Optional[Dict[str, str]] = None) -> dict:
|
|
|
340
340
|
"""A TexNet earthquake-catalogue export (CSV). The columns are found by name; a mapping wins. Every event
|
|
341
341
|
keeps its own id so a claim in the packet can be traced to the catalogue line it came from."""
|
|
342
342
|
from .permits import read_table, _float
|
|
343
|
+
with open(path, encoding='utf-8-sig', errors='replace') as f:
|
|
344
|
+
first = f.readline()
|
|
345
|
+
if first.startswith('#EventID|') or first.startswith('EventID|Time|'):
|
|
346
|
+
return read_fdsn_text(path)
|
|
343
347
|
header, rows = read_table(path)
|
|
344
348
|
cols = _detect(header, mapping)
|
|
345
349
|
events, skipped = [], 0
|
|
@@ -364,6 +368,45 @@ def read_catalog(path: str, mapping: Optional[Dict[str, str]] = None) -> dict:
|
|
|
364
368
|
'datum': 'WGS84', 'basis': 'the TexNet earthquake catalogue as exported by the operator; positions WGS84, magnitudes ML'}
|
|
365
369
|
|
|
366
370
|
|
|
371
|
+
def read_fdsn_text(path: str) -> dict:
|
|
372
|
+
"""The FDSN event web service's text format - USGS ComCat (earthquake.usgs.gov/fdsnws/event/1/query?format=text), and every
|
|
373
|
+
FDSN-compliant catalogue service: `#EventID|Time|Latitude|Longitude|Depth/km|Author|Catalog|Contributor|ContributorID|MagType|
|
|
374
|
+
Magnitude|MagAuthor|EventLocationName`. The contributor (tx = TexNet, us = NEIC, ld = Lamont-Doherty) and the magnitude type ride
|
|
375
|
+
on each event, since a ComCat window mixes networks and magnitude scales."""
|
|
376
|
+
from .permits import _float
|
|
377
|
+
events, skipped, n_rows = [], 0, 0
|
|
378
|
+
with open(path, encoding='utf-8-sig', errors='replace') as f:
|
|
379
|
+
header = [h.strip().lstrip('#') for h in f.readline().rstrip('\n').split('|')]
|
|
380
|
+
idx = {h.lower(): i for i, h in enumerate(header)}
|
|
381
|
+
for line in f:
|
|
382
|
+
if not line.strip() or line.startswith('#'):
|
|
383
|
+
continue
|
|
384
|
+
n_rows += 1
|
|
385
|
+
parts = line.rstrip('\n').split('|')
|
|
386
|
+
def g(name):
|
|
387
|
+
i = idx.get(name)
|
|
388
|
+
return parts[i].strip() if i is not None and i < len(parts) else ''
|
|
389
|
+
t = _parse_dt(g('time').replace('T', ' ').split('.')[0]) if g('time') else None
|
|
390
|
+
m, la, lo = _float(g('magnitude')), _float(g('latitude')), _float(g('longitude'))
|
|
391
|
+
if t is None or m is None or la is None or lo is None:
|
|
392
|
+
skipped += 1; continue
|
|
393
|
+
events.append({'event_id': g('eventid') or f'row{n_rows}', 'time': _utc(t), 'magnitude': m, 'lat': la, 'lon': lo, 'depth_km': _float(g('depth/km')),
|
|
394
|
+
'mag_type': g('magtype'), 'contributor': g('contributor'), 'catalog': g('catalog'), 'place': g('eventlocationname')})
|
|
395
|
+
contribs = sorted({e['contributor'] for e in events if e['contributor']})
|
|
396
|
+
mtypes = sorted({e['mag_type'] for e in events if e['mag_type']})
|
|
397
|
+
return {'path': os.path.abspath(path), 'export_mtime_utc': _utc(datetime.fromtimestamp(os.path.getmtime(path), timezone.utc)),
|
|
398
|
+
'columns': {h.lower(): h for h in header}, 'n_rows': n_rows, 'n_events': len(events), 'n_skipped': skipped, 'events': events, 'datum': 'WGS84',
|
|
399
|
+
'format': 'fdsn-text', 'contributors': contribs, 'magnitude_types': mtypes,
|
|
400
|
+
'basis': f"an FDSN event-service text export (USGS ComCat or another FDSN catalogue); positions WGS84; contributors {', '.join(contribs) or '?'}; "
|
|
401
|
+
f"magnitude types {', '.join(mtypes) or '?'} - a window across networks mixes scales, and the plan's threshold is read as the catalogue's reported magnitude"}
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def comcat_url(lat: float, lon: float, radius_km: float, start: str, end: str, min_magnitude: float = 1.0, fmt: str = 'text') -> str:
|
|
405
|
+
"""The ComCat query for a circle and a window - the URL to open in a browser or hand to a machine that can reach the service."""
|
|
406
|
+
return ('https://earthquake.usgs.gov/fdsnws/event/1/query?format=' + fmt + f'&starttime={start}&endtime={end}&latitude={lat:.4f}&longitude={lon:.4f}'
|
|
407
|
+
f'&maxradiuskm={radius_km:g}&minmagnitude={min_magnitude:g}&orderby=time-asc')
|
|
408
|
+
|
|
409
|
+
|
|
367
410
|
def _detect(header: Sequence[str], mapping: Optional[Dict[str, str]]) -> Dict[str, Optional[str]]:
|
|
368
411
|
from .permits import _norm
|
|
369
412
|
norm = {_norm(h): h for h in header}
|