gea-program 0.32.0__tar.gz → 0.34.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.32.0/gea_program.egg-info → gea_program-0.34.0}/PKG-INFO +35 -2
- {gea_program-0.32.0 → gea_program-0.34.0}/README.md +34 -1
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/__init__.py +1 -1
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/acceptance_tests.py +280 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/backup.py +1 -1
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/dashboard.py +11 -3
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/edr.py +33 -8
- gea_program-0.34.0/gea/help/charts.md +11 -0
- gea_program-0.34.0/gea/help/map.md +11 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/helplib.py +3 -1
- gea_program-0.34.0/gea/reference/us_outline.json +1 -0
- gea_program-0.34.0/gea/reference/us_outline.provenance.json +22 -0
- gea_program-0.34.0/gea/series_cache.py +299 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/service.py +117 -0
- gea_program-0.34.0/gea/site_map.py +295 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/web/app.html +320 -9
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/workspace.py +1 -1
- {gea_program-0.32.0 → gea_program-0.34.0/gea_program.egg-info}/PKG-INFO +35 -2
- {gea_program-0.32.0 → gea_program-0.34.0}/gea_program.egg-info/SOURCES.txt +6 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/pyproject.toml +1 -1
- {gea_program-0.32.0 → gea_program-0.34.0}/LICENSE +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/__main__.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/bench.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/blind_harness.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog_map.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/catalog_register.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/certificates.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/cli.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/client_reports.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/config_versioning.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/conformance.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/correlation.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/deviation.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/dlis.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/dnp3.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/doctor.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/earth_model.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/elevation.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/etp.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/example_register_map.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/fat_sat.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/files.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/follower.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/forward_model.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/friction_priors.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/gamma.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/geodesy.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/hartip.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/alarms.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/backup.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/catalog.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/conformance.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/data-in.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/dlis.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/doctor.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/drift.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/edr.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/etp.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/files.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/historian.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/instruments.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/interval.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/month-end.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/notifications.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/osdu.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/patches.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/quality.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/seismic.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/setup.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/site.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/sites.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/slip.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/soak.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/sra.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/start.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/structure.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/tools.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/transients.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/vibration.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/housekeeping.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/interval.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/jobs.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/live_ports.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/loadtest.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/modbus.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/model_card.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/month_end.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/notify.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/opcua_port.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/operator_app.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/osdu.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/patches.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/permits.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/piwebapi.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/ports.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/ppdm.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/project.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/quakeml.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reconciler.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sample_record.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sbom.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seedlink.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/segy.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_array.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_film.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_response.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_track.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/service_life.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/shapefile.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/shell.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/shut_in.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sla_report.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/slip.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/soak.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/sra.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/store_forward.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/strata_join.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/structure.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/supervisor.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/survey_view.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/telemetry.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/tool_library.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/transient.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/vibration.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/well_assembler.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/wits0.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea/witsml.py +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.32.0 → gea_program-0.34.0}/setup.cfg +0 -0
- {gea_program-0.32.0 → gea_program-0.34.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.34.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 (389 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,39 @@ 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
|
+
### The site map
|
|
652
|
+
|
|
653
|
+
The Map tab puts everything in the workspace that has a position in one
|
|
654
|
+
WGS84 frame: the wells at their declared surface positions (a NAD27
|
|
655
|
+
declaration moved by its datum shift, the shift shown), the structure layers
|
|
656
|
+
- faults and folds, formation contours, areas, points - each drawn at the
|
|
657
|
+
detail the view needs without a vertex moved, the World Stress Map's SHmax
|
|
658
|
+
directions, the seismic stations and the Seismicity Response Areas, over the
|
|
659
|
+
outline of the US states and counties. The outline ships with the program
|
|
660
|
+
(US Census Bureau 2017 cartographic boundaries by way of us-atlas, with its
|
|
661
|
+
provenance), so the map needs no network. A well without a declared position
|
|
662
|
+
is listed as not placed and is never drawn. Drag, the wheel or the keys pan
|
|
663
|
+
and zoom; click anywhere for what every layer says about that spot and the
|
|
664
|
+
distance to every placed well; rings draw distance circles around the wells.
|
|
665
|
+
`gea help map`.
|
|
666
|
+
|
|
667
|
+
### The charts
|
|
668
|
+
|
|
669
|
+
A well's page carries the Charts card: up to four channels stacked on one
|
|
670
|
+
horizontal axis, a cursor that reads them all at the same moment, cut from
|
|
671
|
+
every sample of the well's file. Drag across a stretch to zoom into it, the
|
|
672
|
+
wheel zooms where you point, double-click or Reset shows everything; the
|
|
673
|
+
keyboard does the same (arrows, + and -, Page Up and Page Down, Home). A
|
|
674
|
+
month-wide view keeps a one-second spike - each bucket is the minimum, the
|
|
675
|
+
maximum and the mean of its samples - and a stretch with no samples is drawn
|
|
676
|
+
empty, never bridged. On a drilling recorder's export the axis switches
|
|
677
|
+
between time and depth (the drilling samples by bit depth, kept off hole a
|
|
678
|
+
later sidetrack abandoned), the depth events are marked where they
|
|
679
|
+
happened, and each section of the recording is a button. The Wells page
|
|
680
|
+
carries the drilling progress of every drilling-recorder well: hole depth
|
|
681
|
+
against days, one colour per well. The refresh writes a chart cache per well
|
|
682
|
+
from the read it already makes; `gea help charts`.
|
|
683
|
+
|
|
651
684
|
### The setup checklist
|
|
652
685
|
|
|
653
686
|
The Setup tab (`#/setup`, `gea checklist --workspace C:\site`) says what a
|
|
@@ -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 (389 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,39 @@ 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
|
+
### The site map
|
|
613
|
+
|
|
614
|
+
The Map tab puts everything in the workspace that has a position in one
|
|
615
|
+
WGS84 frame: the wells at their declared surface positions (a NAD27
|
|
616
|
+
declaration moved by its datum shift, the shift shown), the structure layers
|
|
617
|
+
- faults and folds, formation contours, areas, points - each drawn at the
|
|
618
|
+
detail the view needs without a vertex moved, the World Stress Map's SHmax
|
|
619
|
+
directions, the seismic stations and the Seismicity Response Areas, over the
|
|
620
|
+
outline of the US states and counties. The outline ships with the program
|
|
621
|
+
(US Census Bureau 2017 cartographic boundaries by way of us-atlas, with its
|
|
622
|
+
provenance), so the map needs no network. A well without a declared position
|
|
623
|
+
is listed as not placed and is never drawn. Drag, the wheel or the keys pan
|
|
624
|
+
and zoom; click anywhere for what every layer says about that spot and the
|
|
625
|
+
distance to every placed well; rings draw distance circles around the wells.
|
|
626
|
+
`gea help map`.
|
|
627
|
+
|
|
628
|
+
### The charts
|
|
629
|
+
|
|
630
|
+
A well's page carries the Charts card: up to four channels stacked on one
|
|
631
|
+
horizontal axis, a cursor that reads them all at the same moment, cut from
|
|
632
|
+
every sample of the well's file. Drag across a stretch to zoom into it, the
|
|
633
|
+
wheel zooms where you point, double-click or Reset shows everything; the
|
|
634
|
+
keyboard does the same (arrows, + and -, Page Up and Page Down, Home). A
|
|
635
|
+
month-wide view keeps a one-second spike - each bucket is the minimum, the
|
|
636
|
+
maximum and the mean of its samples - and a stretch with no samples is drawn
|
|
637
|
+
empty, never bridged. On a drilling recorder's export the axis switches
|
|
638
|
+
between time and depth (the drilling samples by bit depth, kept off hole a
|
|
639
|
+
later sidetrack abandoned), the depth events are marked where they
|
|
640
|
+
happened, and each section of the recording is a button. The Wells page
|
|
641
|
+
carries the drilling progress of every drilling-recorder well: hole depth
|
|
642
|
+
against days, one colour per well. The refresh writes a chart cache per well
|
|
643
|
+
from the read it already makes; `gea help charts`.
|
|
644
|
+
|
|
612
645
|
### The setup checklist
|
|
613
646
|
|
|
614
647
|
The Setup tab (`#/setup`, `gea checklist --workspace C:\site`) says what a
|
|
@@ -8170,6 +8170,284 @@ def section_ca_setup_checklist(tmp: str) -> None:
|
|
|
8170
8170
|
"request; the help page and its view mapping"
|
|
8171
8171
|
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
8172
8172
|
|
|
8173
|
+
|
|
8174
|
+
def section_cb_charts(tmp: str) -> None:
|
|
8175
|
+
"""Section CB - the interactive charts: a window cut from every sample through the series cache, an envelope that
|
|
8176
|
+
keeps a one-second spike in a month-wide view and never bridges a gap, the depth axis for a drilling recorder from
|
|
8177
|
+
the same samples as the gamma log, the drilling progress of every well, the page's zoom, pan, cursor and keys."""
|
|
8178
|
+
import http.cookiejar
|
|
8179
|
+
import os as _os
|
|
8180
|
+
import urllib.request
|
|
8181
|
+
import urllib.error
|
|
8182
|
+
import numpy as _np
|
|
8183
|
+
from . import edr as E
|
|
8184
|
+
from . import series_cache as SCH
|
|
8185
|
+
from . import backup as BK
|
|
8186
|
+
from . import helplib as H
|
|
8187
|
+
from .workspace import Workspace
|
|
8188
|
+
from .service import Service, Users
|
|
8189
|
+
pkg = Path(__file__).parent
|
|
8190
|
+
d = Path(tmp, "cb"); d.mkdir()
|
|
8191
|
+
|
|
8192
|
+
ev = E.selftest_events(str(d))
|
|
8193
|
+
st = E.read(ev["path"])
|
|
8194
|
+
meta = SCH.build(st, str(d / "c"), extras=E.chart_masks(st))
|
|
8195
|
+
c = SCH.load(str(d / "c"), ev["path"])
|
|
8196
|
+
idx = _np.asarray(c.index); rop = _np.asarray(c.channel("Rate Of Penetration"), dtype=float)
|
|
8197
|
+
w = SCH.window(c, ["Rate Of Penetration", "Hole Depth"], points=300)
|
|
8198
|
+
edges = _np.linspace(idx[0], idx[-1], 301); b = _np.clip(_np.searchsorted(edges, idx, "right") - 1, 0, 299)
|
|
8199
|
+
brute_ok = True
|
|
8200
|
+
for k in range(300):
|
|
8201
|
+
m = (b == k) & ~_np.isnan(rop)
|
|
8202
|
+
got = w["channels"]["Rate Of Penetration"]
|
|
8203
|
+
if m.any():
|
|
8204
|
+
if got["max"][k] is None or abs(got["max"][k] - rop[m].max()) > 1e-3 or abs(got["min"][k] - rop[m].min()) > 1e-3 or abs(got["mean"][k] - rop[m].mean()) > 1e-2 or got["n"][k] != int(m.sum()):
|
|
8205
|
+
brute_ok = False; break
|
|
8206
|
+
elif got["max"][k] is not None:
|
|
8207
|
+
brute_ok = False; break
|
|
8208
|
+
gaps = sum(1 for x in w["channels"]["Rate Of Penetration"]["mean"] if x is None)
|
|
8209
|
+
spike = st.channels["Rate Of Penetration"].values.copy()
|
|
8210
|
+
w_small = SCH.window(c, ["Rate Of Penetration"], x0=float(idx[1300]), x1=float(idx[1300]) + 300)
|
|
8211
|
+
dw = SCH.depth_window(c, ["Gamma"], points=200)
|
|
8212
|
+
pr = SCH.progress(c)
|
|
8213
|
+
cons = SCH.connections(c, float(idx[0]), float(idx[-1]))
|
|
8214
|
+
stale_size = _os.path.getsize(ev["path"])
|
|
8215
|
+
with open(ev["path"], "a", encoding="utf-8") as fh:
|
|
8216
|
+
fh.write("")
|
|
8217
|
+
_os.utime(ev["path"], (1, 1))
|
|
8218
|
+
stale = SCH.load(str(d / "c"), ev["path"])
|
|
8219
|
+
c1 = {
|
|
8220
|
+
"cache": meta["n"] == 34720 and {"drilling", "keep_b", "keep_h", "excluded", "bottom", "flag_idle"} <= set(meta["extras"])
|
|
8221
|
+
and len(meta["sections"]) == 2 and _os.path.isfile(str(d / "c" / "index.npy")),
|
|
8222
|
+
"envelope": w["mode"] == "envelope" and len(w["x"]) == 300 and w["samples"] == 34720 and brute_ok and gaps > 200,
|
|
8223
|
+
"samples": w_small["mode"] == "samples" and len(w_small["x"]) == 301 and w_small["channels"]["Rate Of Penetration"]["value"][0] is not None,
|
|
8224
|
+
"depth": dw["axis"] == "Bit Depth" and dw["extent"] == [4800.0, 5750.0] and dw["samples"] == 27420
|
|
8225
|
+
and all(v is None or abs(v - 110.0) < 1e-6 for v in dw["channels"]["Gamma"]["mean"]) and "abandoned" in dw["how"],
|
|
8226
|
+
"progress": pr is not None and pr["first_utc"] == "2026-07-01T00:00:00" and max(v for v in pr["bottom_max"] if v is not None) == 5750.0
|
|
8227
|
+
and abs(pr["days"][-1] - 2.4) < 0.01,
|
|
8228
|
+
"connections": len(cons) == 3,
|
|
8229
|
+
"stale": stale is None and stale_size == _os.path.getsize(ev["path"]),
|
|
8230
|
+
}
|
|
8231
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
8232
|
+
ok(not failed1,
|
|
8233
|
+
"CB1 the series cache: every sample of a drilling recorder export with the depth pass's masks and the running bottom; a window of equal time "
|
|
8234
|
+
"buckets whose minimum, maximum, mean and count equal the samples' own, a bucket with none left empty (a gap, never bridged), the samples "
|
|
8235
|
+
"themselves when they fit; the depth axis the drilling samples by bit depth kept off the abandoned hole (4,800 to 5,750 ft, the gamma log's "
|
|
8236
|
+
"range); the drilling progress the running bottom against days; a cache whose source changed is not used"
|
|
8237
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
8238
|
+
|
|
8239
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
8240
|
+
w1 = ws.add_well_file(ev["path"], display="Well B", actor="tester")
|
|
8241
|
+
w2 = ws.add_well_catalog("volve_f12_f14_production_excerpt", "15/9-F-12", 10000.0, actor="tester")
|
|
8242
|
+
ws.refresh_dashboard(actor="tester")
|
|
8243
|
+
built = _os.path.isfile(_os.path.join(wsp, "cache", "series", w1["id"], "x_drilling.npy"))
|
|
8244
|
+
Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer")
|
|
8245
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
8246
|
+
base_url = svc.url.rstrip("/")
|
|
8247
|
+
o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
8248
|
+
|
|
8249
|
+
def call(method, path, body=None):
|
|
8250
|
+
req = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
8251
|
+
req.add_header("Content-Type", "application/json"); req.add_header("X-GEA-Action", "1")
|
|
8252
|
+
try:
|
|
8253
|
+
with o.open(req, timeout=120) as rr_:
|
|
8254
|
+
return rr_.status, json.loads(rr_.read())
|
|
8255
|
+
except urllib.error.HTTPError as e:
|
|
8256
|
+
return e.code, json.loads(e.read())
|
|
8257
|
+
q = lambda s_: urllib.parse.quote(s_)
|
|
8258
|
+
try:
|
|
8259
|
+
call("POST", "/api/login", {"name": "v", "password": "viewer-pass-1"})
|
|
8260
|
+
st_m, m1 = call("GET", f"/api/wells/{w1['id']}/chart/meta")
|
|
8261
|
+
st_w, wt = call("GET", f"/api/wells/{w1['id']}/chart/window?ch={q('Rate Of Penetration')}&ch={q('Hole Depth')}&points=400")
|
|
8262
|
+
st_z, wz = call("GET", f"/api/wells/{w1['id']}/chart/window?ch={q('Rate Of Penetration')}&x0=172800&x1=180000&points=400")
|
|
8263
|
+
st_d, wd = call("GET", f"/api/wells/{w1['id']}/chart/window?ch=Gamma&axis=depth&points=200")
|
|
8264
|
+
st_p, pp = call("GET", "/api/pad/progress")
|
|
8265
|
+
st_g, mg = call("GET", f"/api/wells/{w2['id']}/chart/meta")
|
|
8266
|
+
st_bad, bad = call("GET", f"/api/wells/{w1['id']}/chart/window?ch=Nothing")
|
|
8267
|
+
st_none, none_ = call("GET", f"/api/wells/{w1['id']}/chart/window")
|
|
8268
|
+
st_x, _ = call("GET", "/api/wells/no-such-well/chart/meta")
|
|
8269
|
+
finally:
|
|
8270
|
+
svc.stop()
|
|
8271
|
+
c2 = {
|
|
8272
|
+
"refresh_builds": built and not any(f.startswith("cache/") for f in BK.site_files(wsp)),
|
|
8273
|
+
"meta": st_m == 200 and m1["axes"] == ["time", "depth"] and m1["n"] == 34720 and len(m1["events"]) == 4 and m1["events"][2]["type"] == "SIDETRACK"
|
|
8274
|
+
and m1["events"][0]["x"] > 0 and len(m1["sections"]) == 2 and m1["default"] == ["Rate Of Penetration"],
|
|
8275
|
+
"window": st_w == 200 and wt["mode"] == "envelope" and set(wt["channels"]) == {"Rate Of Penetration", "Hole Depth"} and st_z == 200
|
|
8276
|
+
and wz["mode"] == "envelope" and "connections" in wz and wz["x0"] == 172800.0,
|
|
8277
|
+
"depth": st_d == 200 and wd["extent"] == [4800.0, 5750.0],
|
|
8278
|
+
"progress": st_p == 200 and [x["well_id"] for x in pp["wells"]] == [w1["id"]] and pp["wells"][0]["display"] == "Well B",
|
|
8279
|
+
"gauge_well": st_g == 200 and mg["axes"] == ["time_s"] and mg["n"] > 0 and mg["events"] == [],
|
|
8280
|
+
"errors": st_bad == 400 and "no channel 'Nothing'" in bad.get("error", "") and st_none == 400 and "name one or more channels" in none_.get("error", "") and st_x == 404,
|
|
8281
|
+
}
|
|
8282
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
8283
|
+
ok(not failed2,
|
|
8284
|
+
"CB2 in a site: the refresh writes each file well's chart cache from the read it already makes, and backups leave it out; the API gives a "
|
|
8285
|
+
"signed-in viewer the channels, the axes, the depth events at their times, the sections, a time window with the connections when zoomed in, "
|
|
8286
|
+
"the depth window and every drilling-recorder well's progress; a gauge well's cache is built on its first view; a channel the well does not "
|
|
8287
|
+
"have, no channel at all and an unknown well are named"
|
|
8288
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
8289
|
+
|
|
8290
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
8291
|
+
help_md = (pkg / "help" / "charts.md").read_text(encoding="utf-8")
|
|
8292
|
+
c3 = {
|
|
8293
|
+
"page": all(x in page_src for x in ("async function chartPanel", "async function padProgress", "/chart/meta", "/chart/window", "/api/pad/progress",
|
|
8294
|
+
'data-axis="depth"', "data-sec=", "PageUp", "'Home' || ev.key === 'Escape'", "ArrowLeft", "dblclick", "'wheel'",
|
|
8295
|
+
"setPointerCapture", "ResizeObserver", "cp-tbl", 'aria-live="polite"', "role=\"application\"", "Drilling progress",
|
|
8296
|
+
"#/help/charts", "cp-loading")),
|
|
8297
|
+
"palette": page_src.count("--s1:") == 3 and page_src.count("--s3:") == 3,
|
|
8298
|
+
"help": any(t["topic"] == "charts" for t in H.topics()) and not H.check("charts") and "never bridged" in help_md.split("will not call a measurement")[1],
|
|
8299
|
+
}
|
|
8300
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
8301
|
+
ok(not failed3,
|
|
8302
|
+
"CB3 the page: up to four tracks on one axis, a cursor that reads every track at the same moment, drag to zoom, the wheel, double-click and "
|
|
8303
|
+
"Reset, pan, the keys (arrows, + and -, Page Up and Page Down, Home and Esc), time or depth, the section buttons, the table view, the frame "
|
|
8304
|
+
"kept while a window loads, the drilling progress chart with one colour per well in a fixed order in both themes; the help page"
|
|
8305
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
8306
|
+
|
|
8307
|
+
|
|
8308
|
+
def section_cc_site_map(tmp: str) -> None:
|
|
8309
|
+
"""Section CC - the site map: the shipped state and county outline with its provenance, every positioned thing in one
|
|
8310
|
+
WGS84 frame (a NAD27 well moved by its datum shift and saying so, a well without a position never drawn), a layer
|
|
8311
|
+
thinned to the view's pixel without a vertex moved, what every layer says about a spot, the page."""
|
|
8312
|
+
import hashlib as _hl
|
|
8313
|
+
import http.cookiejar
|
|
8314
|
+
import math as _m
|
|
8315
|
+
import urllib.request
|
|
8316
|
+
import urllib.error
|
|
8317
|
+
from . import edr as E
|
|
8318
|
+
from . import helplib as H
|
|
8319
|
+
from . import shapefile as SF
|
|
8320
|
+
from . import site_map as SM
|
|
8321
|
+
from .workspace import Workspace
|
|
8322
|
+
from .service import Service, Users
|
|
8323
|
+
pkg = Path(__file__).parent
|
|
8324
|
+
d = Path(tmp, "cc"); d.mkdir()
|
|
8325
|
+
|
|
8326
|
+
ol = SM.outline_data()
|
|
8327
|
+
prov = json.loads((pkg / "reference" / "us_outline.provenance.json").read_text(encoding="utf-8"))
|
|
8328
|
+
cul = [c for c in ol["counties"] if c["name"] == "Culberson"]
|
|
8329
|
+
wide = SM.outline_view([-110.0, 25.0, -90.0, 37.0], 0.02)
|
|
8330
|
+
near = SM.outline_view([-105.2, 31.0, -104.0, 32.0], 0.002)
|
|
8331
|
+
c1 = {
|
|
8332
|
+
"outline": len(ol["counties"]) == 3231 and ol["states"].get("48") == "Texas" and cul and cul[0]["fips"] == "48109"
|
|
8333
|
+
and abs(cul[0]["label"][0] + 104.65) < 0.2 and abs(cul[0]["label"][1] - 31.47) < 0.2,
|
|
8334
|
+
"provenance": prov["sha256"] == _hl.sha256((pkg / "reference" / "us_outline.json").read_bytes()).hexdigest() and prov["package_license"] == "ISC"
|
|
8335
|
+
and "Copyright 2013-2019 Michael Bostock" in prov["package_license_text"] and "public domain" in prov["original_source"]
|
|
8336
|
+
and prov["counts"]["counties"] == 3231,
|
|
8337
|
+
"detail": all(a["s"] == 1 for a in wide["arcs"]) and not wide["labels"] and any(a["s"] == 0 for a in near["arcs"])
|
|
8338
|
+
and "Culberson" in [x["name"] for x in near["labels"]],
|
|
8339
|
+
}
|
|
8340
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
8341
|
+
ok(not failed1,
|
|
8342
|
+
"CC1 the outline ships with the program: the US Census Bureau's 2017 cartographic counties by way of us-atlas 3.0.1, 3,231 counties, the "
|
|
8343
|
+
"provenance with its hash, the package's ISC notice and the public-domain source; state lines only in a wide view, county lines and names "
|
|
8344
|
+
"once the view is close (Culberson, FIPS 48109)"
|
|
8345
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
8346
|
+
|
|
8347
|
+
lat1, lon1 = 31.42, -104.10
|
|
8348
|
+
kmlon = 1.0 / (111.195 * _m.cos(_m.radians(lat1)))
|
|
8349
|
+
faults = [([[(lon1 - 0.2 + 0.01 * i, lat1 - 0.3 + 0.0002 * j) for j in range(3001)]], {"TYPE": "normal fault", "NAME": f"F{i}"}) for i in range(0, 40, 8)]
|
|
8350
|
+
SF.write(str(d / "Faults"), "PolyLine", faults, [("TYPE", "C", 20, 0), ("NAME", "C", 10, 0)], SF.NAD83_GEOGCS)
|
|
8351
|
+
ctr = [([[(lon1 + (i - 1.5) * 4 * kmlon + 0.001 * k, lat1 - 0.3 + 0.006 * k) for k in range(100)]], {"ElevTop_ft": -8500.0 + 500.0 * i}) for i in range(4)]
|
|
8352
|
+
SF.write(str(d / "Top_A"), "PolyLine", ctr, [("ElevTop_ft", "F", 10, 1)], SF.NAD83_GEOGCS)
|
|
8353
|
+
SF.write(str(d / "Picks"), "Point", [([[(lon1 + 0.0001 * i, lat1 + 0.00005 * i)]], {"NAME": f"P{i}"}) for i in range(6000)], [("NAME", "C", 10, 0)], SF.NAD83_GEOGCS)
|
|
8354
|
+
with open(d / "wsm.csv", "w", encoding="utf-8") as f:
|
|
8355
|
+
f.write("ID,LAT,LON,AZI,TYPE,DEPTH,QUALITY,REGIME,LOCALITY\n")
|
|
8356
|
+
for i in range(40):
|
|
8357
|
+
f.write(f"W{i},{lat1 - 0.1 + 0.005 * i:.4f},{lon1 - 0.05:.4f},{60 + i},BO,2.5,{'DCBA'[i % 4]},NF,test\n")
|
|
8358
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
8359
|
+
empty_view = SM.overview(ws)["view"]
|
|
8360
|
+
ws.add_layer(str(d / "Faults.shp"), "Basement faults", actor="tester", citation="test")
|
|
8361
|
+
ws.add_layer(str(d / "Top_A.shp"), "Wolfcamp top", actor="tester", formation="Wolfcamp", role="top", citation="test")
|
|
8362
|
+
ws.add_layer(str(d / "Picks.shp"), "Picks", actor="tester", citation="test")
|
|
8363
|
+
ws.add_stress_map(str(d / "wsm.csv"), actor="tester", citation="test WSM")
|
|
8364
|
+
layer_view0 = SM.overview(ws)["view"]
|
|
8365
|
+
a = E.selftest(str(d)); b = E.selftest_events(str(d))
|
|
8366
|
+
wa = ws.add_well_file(a["path"], display="Well A", actor="tester"); wb = ws.add_well_file(b["path"], display="Well B", actor="tester")
|
|
8367
|
+
wc = ws.add_well_file(a["path"], display="Well C", actor="tester")
|
|
8368
|
+
ws.set_well(wa["id"], surface={"lat": 31.41, "lon": -104.12, "datum": "NAD27"}, actor="tester")
|
|
8369
|
+
ws.set_well(wb["id"], surface={"lat": 31.43, "lon": -104.08, "datum": "NAD83"}, actor="tester")
|
|
8370
|
+
o = SM.overview(ws)
|
|
8371
|
+
wl = {w["id"]: w for w in o["wells"]}
|
|
8372
|
+
view = o["view"]["bbox"]
|
|
8373
|
+
fine = SM.layer_view(ws, "Basement-faults", [-105, 30, -103, 32], 0.0)
|
|
8374
|
+
coarse = SM.layer_view(ws, "Basement-faults", [-105, 30, -103, 32], 0.01)
|
|
8375
|
+
raw = SM._layer(ws, "Basement-faults")
|
|
8376
|
+
src_pts = {(round(float(x), 5), round(float(y), 5)) for f in raw["feats"] for pp in f["parts"] for x, y in pp}
|
|
8377
|
+
moved = [p for f in coarse["features"] for pp in f["parts"] for p in pp if (p[0], p[1]) not in src_pts]
|
|
8378
|
+
ends_kept = all(f["parts"][0][0] == fine["features"][k]["parts"][0][0] and f["parts"][0][-1] == fine["features"][k]["parts"][0][-1] for k, f in enumerate(coarse["features"]))
|
|
8379
|
+
pts = SM.layer_view(ws, "Picks", [-105, 30, -103, 32], 0.0, max_points=1000)
|
|
8380
|
+
wh = SM.what_here(ws, 31.42, -104.10)
|
|
8381
|
+
sv = SM.stress_view(ws, [-104.3, 31.2, -103.9, 31.6])
|
|
8382
|
+
c2 = {
|
|
8383
|
+
"frame": "WGS84" in o["frame"] and o["view"]["why"] == "the placed wells" and empty_view["why"].startswith("nothing in the workspace")
|
|
8384
|
+
and layer_view0["why"].startswith("the area most of the layers cover (the median extent of 3 of the 3)"),
|
|
8385
|
+
"wells": wl[wa["id"]]["placed"] and 30.0 < wl[wa["id"]]["shift_m"] < 90.0 and wl[wa["id"]]["declared"]["datum"] == "NAD27"
|
|
8386
|
+
and wl[wb["id"]]["placed"] and wl[wb["id"]]["shift_m"] == 0.0 and not wl[wc["id"]]["placed"] and "lat" not in wl[wc["id"]]
|
|
8387
|
+
and view[0] < -104.12 < view[2] and view[1] < 31.43 < view[3],
|
|
8388
|
+
"layers": [(l["id"], l["kind"]) for l in o["layers"]] == [("Basement-faults", "structure"), ("Wolfcamp-top", "contours"), ("Picks", "points")]
|
|
8389
|
+
and o["layers"][0]["classes"] == ["fault"] and o["layers"][0]["n_points"] == 5 * 3001 and o["stress_map"]["n_records"] == 40,
|
|
8390
|
+
"thinning": fine["vertices"] == 5 * 3001 and coarse["vertices"] < fine["vertices"] / 10 and not moved and ends_kept
|
|
8391
|
+
and all(f.get("cls") == "fault" for f in coarse["features"]),
|
|
8392
|
+
"points": pts["in_view"] == 6000 and pts["shown"] == 1000 and pts["kind"] == "points",
|
|
8393
|
+
"what_here": wh["answered"] >= 2 and any("Nearest mapped fault" in ln for l_ in wh["layers"] for ln in (l_["lines"] or []))
|
|
8394
|
+
and any("contours" in ln for l_ in wh["layers"] for ln in (l_["lines"] or []))
|
|
8395
|
+
and [w["id"] for w in wh["wells"]] == sorted([wa["id"], wb["id"]], key=lambda i: next(x["distance_km"] for x in wh["wells"] if x["id"] == i))
|
|
8396
|
+
and len(wh["wells"]) == 2,
|
|
8397
|
+
"stress": sv["n_in_view"] == 40 and sv["records"][0]["quality"] == "A" and sv["records"][-1]["quality"] == "D" and sv["citation"] == "test WSM",
|
|
8398
|
+
}
|
|
8399
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
8400
|
+
ok(not failed2,
|
|
8401
|
+
"CC2 one frame: a well declared on NAD27 moved to WGS84 by its datum shift and the shift kept with it, a well declared on NAD83 not moved, a "
|
|
8402
|
+
"well with no position never placed; the map opens on the placed wells (else the area most layers cover, else Texas, said so); a layer "
|
|
8403
|
+
"thinned to the view's pixel keeps its ends and moves no vertex, points sampled evenly past the limit; each layer's own statement for a spot "
|
|
8404
|
+
"and the distance to every placed well; the stress records in view, best quality first"
|
|
8405
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
8406
|
+
|
|
8407
|
+
Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer")
|
|
8408
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
8409
|
+
base_url = svc.url.rstrip("/")
|
|
8410
|
+
op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
8411
|
+
|
|
8412
|
+
def call(path):
|
|
8413
|
+
req = urllib.request.Request(base_url + path, method="GET")
|
|
8414
|
+
try:
|
|
8415
|
+
with op.open(req, timeout=120) as rr_:
|
|
8416
|
+
return rr_.status, json.loads(rr_.read())
|
|
8417
|
+
except urllib.error.HTTPError as e:
|
|
8418
|
+
return e.code, json.loads(e.read())
|
|
8419
|
+
try:
|
|
8420
|
+
lreq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": "v", "password": "viewer-pass-1"}).encode())
|
|
8421
|
+
lreq.add_header("Content-Type", "application/json"); lreq.add_header("X-GEA-Action", "1"); op.open(lreq, timeout=30)
|
|
8422
|
+
bb = ",".join(f"{x:.5f}" for x in view)
|
|
8423
|
+
st_o, ov = call("/api/map")
|
|
8424
|
+
st_l, lv = call(f"/api/map/layer/Wolfcamp-top?bbox={bb}&tol=0.001")
|
|
8425
|
+
st_ol, olv = call(f"/api/map/outline?bbox={bb}&tol=0.001")
|
|
8426
|
+
st_s, svv = call(f"/api/map/stress?bbox={bb}")
|
|
8427
|
+
st_a, at = call("/api/map/at?lat=31.42&lon=-104.10")
|
|
8428
|
+
st_bad, _ = call("/api/map/layer/Wolfcamp-top?bbox=1,2,3")
|
|
8429
|
+
st_nol, _ = call(f"/api/map/layer/no-such-layer?bbox={bb}")
|
|
8430
|
+
st_noll, _ = call("/api/map/at?lat=x")
|
|
8431
|
+
finally:
|
|
8432
|
+
svc.stop()
|
|
8433
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
8434
|
+
help_md = (pkg / "help" / "map.md").read_text(encoding="utf-8")
|
|
8435
|
+
c3 = {
|
|
8436
|
+
"api": st_o == 200 and len(ov["wells"]) == 3 and st_l == 200 and lv["kind"] == "contours" and all("value" in f for f in lv["features"])
|
|
8437
|
+
and st_ol == 200 and st_s == 200 and st_a == 200 and len(at["wells"]) == 2 and st_bad == 400 and st_nol == 404 and st_noll == 400,
|
|
8438
|
+
"page": all(x in page_src for x in ("VIEWS.map", "['#/map', 'Map']", "/api/map/layer/", "/api/map/outline", "/api/map/stress", "/api/map/at",
|
|
8439
|
+
"Not placed", "declare it", "data-fit", "mpRings", "ArrowUp", "'Home' || k === 'Escape'", "scale bar", "'wheel'",
|
|
8440
|
+
"What is at", "setPointerCapture")),
|
|
8441
|
+
"help": any(t["topic"] == "map" for t in H.topics()) and not H.check("map") and H.VIEW_TOPIC.get("map") == "map"
|
|
8442
|
+
and "never moved" in help_md.split("will not call a measurement")[1],
|
|
8443
|
+
}
|
|
8444
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
8445
|
+
ok(not failed3,
|
|
8446
|
+
"CC3 the API (the contents, a layer with its contour values, the outline, the stress records, what is at a spot; a malformed box, an unknown "
|
|
8447
|
+
"layer and a missing position named) and the Map tab: pan and zoom by pointer, wheel and keys, layer toggles and fit, distance rings, a scale "
|
|
8448
|
+
"bar, the not-placed wells with the way to place them, what is at a click; the help page"
|
|
8449
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
8450
|
+
|
|
8173
8451
|
def main() -> int:
|
|
8174
8452
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
8175
8453
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -8252,6 +8530,8 @@ def main() -> int:
|
|
|
8252
8530
|
section_by_edr(tmp)
|
|
8253
8531
|
section_bz_tool_library(tmp)
|
|
8254
8532
|
section_ca_setup_checklist(tmp)
|
|
8533
|
+
section_cb_charts(tmp)
|
|
8534
|
+
section_cc_site_map(tmp)
|
|
8255
8535
|
if _FAILS:
|
|
8256
8536
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
8257
8537
|
for f in _FAILS:
|
|
@@ -28,7 +28,7 @@ from datetime import datetime, timezone
|
|
|
28
28
|
from typing import Dict, List, Optional
|
|
29
29
|
|
|
30
30
|
STALE_AFTER_H = 26.0 # a daily backup that is more than a day and change old
|
|
31
|
-
EXCLUDE_TOP = ('jobs',)
|
|
31
|
+
EXCLUDE_TOP = ('jobs', 'cache') # jobs taken selectively (schedule.json only); cache is rebuilt from the sources
|
|
32
32
|
EXCLUDE_NAMES = ('_uploads', '__pycache__')
|
|
33
33
|
LOG_NAME = 'backups.jsonl' # records/backups.jsonl: one line per backup taken from this workspace
|
|
34
34
|
|
|
@@ -347,8 +347,9 @@ def render(data: dict, out_dir: str, site_name: str = 'site', program_version: s
|
|
|
347
347
|
def orchestrate(out_dir: str, catalog_wells: List[dict], file_wells: List[dict], td_ft: float = 10500.0,
|
|
348
348
|
gauge_spec=None, outages: Optional[List[str]] = None, month: Optional[str] = None,
|
|
349
349
|
site_name: str = 'site', criteria_path: Optional[str] = None, monitor_root: Optional[str] = None,
|
|
350
|
-
run_sat: bool = False) -> dict:
|
|
351
|
-
"""catalog_wells: [{'entry', 'well', 'md_ft'}]; file_wells: [{'path', 'name'}].
|
|
350
|
+
run_sat: bool = False, series_cache_root: Optional[str] = None) -> dict:
|
|
351
|
+
"""catalog_wells: [{'entry', 'well', 'md_ft'}]; file_wells: [{'path', 'name'}]. With `series_cache_root`, each file
|
|
352
|
+
well's stream is also cached for the charts, from the same read."""
|
|
352
353
|
from . import (production_live_stream, ingest, Reconciler, SimulatorConfig, CATALOG, __version__ as _v)
|
|
353
354
|
from .sample_record import TagCatalogue, records_from_stream
|
|
354
355
|
from .client_reports import (gauge_drift_report, well_test_report, alarm_event_report, data_resilience_report,
|
|
@@ -401,16 +402,23 @@ def orchestrate(out_dir: str, catalog_wells: List[dict], file_wells: List[dict],
|
|
|
401
402
|
continue
|
|
402
403
|
with open(os.path.join(d, 'well.json'), 'w', encoding='utf-8') as f:
|
|
403
404
|
json.dump({'display': name, 'source': fw['path'], 'index_kind': stream.index_kind, 'source_format': stream.source_format}, f)
|
|
405
|
+
cache_dir = os.path.join(series_cache_root, name) if series_cache_root else None
|
|
404
406
|
if stream.source_format == 'edr': # a drilling recorder's export: the drilling record, not the gauge pipeline
|
|
405
407
|
from .edr import write_record
|
|
406
408
|
try:
|
|
407
|
-
write_record(stream, d, _v)
|
|
409
|
+
write_record(stream, d, _v, cache_dir=cache_dir)
|
|
408
410
|
made.setdefault(name, []).append('drilling_record')
|
|
409
411
|
except Exception as ex:
|
|
410
412
|
with open(os.path.join(d, 'drilling_record_not_written.json'), 'w', encoding='utf-8') as f:
|
|
411
413
|
json.dump({'well': name, 'reason': f'{type(ex).__name__}: {ex}'}, f, indent=1)
|
|
412
414
|
made.setdefault(name, []).append('drilling_record_not_written')
|
|
413
415
|
continue
|
|
416
|
+
if cache_dir:
|
|
417
|
+
try:
|
|
418
|
+
from . import series_cache as _SCH
|
|
419
|
+
_SCH.build(stream, cache_dir)
|
|
420
|
+
except Exception:
|
|
421
|
+
pass # the cache is a convenience; the page builds it on first view
|
|
414
422
|
if stream.index_kind != 'time_s': # a depth log is a survey input: run the strata survey, not the gauge pipeline
|
|
415
423
|
try:
|
|
416
424
|
from .survey_cmd import run_survey
|
|
@@ -322,6 +322,32 @@ def _idle_flag(drilling: np.ndarray, hole: Optional[np.ndarray], rop: Optional[n
|
|
|
322
322
|
return idle
|
|
323
323
|
|
|
324
324
|
|
|
325
|
+
def drilling_mask(stream: LiveStream, de: dict) -> Tuple[np.ndarray, np.ndarray]:
|
|
326
|
+
"""The samples that are drilling - the on-bottom flag set at the bottom of the hole, not excluded, not the flag
|
|
327
|
+
left on with nothing drilled - and, separately, the flag-left-on samples. One definition for the record and the charts."""
|
|
328
|
+
hole, rop, onb = _ch(stream, 'hole'), _ch(stream, 'rop'), _ch(stream, 'onb')
|
|
329
|
+
n = len(stream.index)
|
|
330
|
+
on_flag = (onb == 1.0) if onb is not None else np.zeros(n, dtype=bool)
|
|
331
|
+
excl = de['excluded']; M = de['running_bottom']
|
|
332
|
+
if hole is not None and M is not None:
|
|
333
|
+
drilling = on_flag & ~excl & ~np.isnan(hole) & (hole >= np.nan_to_num(M, nan=np.inf) - 10.0)
|
|
334
|
+
else:
|
|
335
|
+
drilling = on_flag & ~excl
|
|
336
|
+
idle = _idle_flag(drilling, hole, rop)
|
|
337
|
+
return drilling & ~idle, idle
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def chart_masks(stream: LiveStream, de: Optional[dict] = None) -> dict:
|
|
341
|
+
"""What the charts need from the depth pass, as arrays the length of the stream: drilling, the samples a depth
|
|
342
|
+
table may use (by hole depth and by bit depth), the excluded samples, and the running bottom of the hole."""
|
|
343
|
+
de = de if de is not None else depth_events(stream)
|
|
344
|
+
drilling, idle = drilling_mask(stream, de)
|
|
345
|
+
keep_h, keep_b = _keep_masks(stream, de)
|
|
346
|
+
n = len(stream.index)
|
|
347
|
+
bottom = de['running_bottom'] if de['running_bottom'] is not None else np.full(n, np.nan)
|
|
348
|
+
return {'drilling': drilling, 'flag_idle': idle, 'keep_h': keep_h, 'keep_b': keep_b, 'excluded': de['excluded'], 'bottom': bottom}
|
|
349
|
+
|
|
350
|
+
|
|
325
351
|
def _keep_masks(stream: LiveStream, de: dict) -> Tuple[np.ndarray, np.ndarray]:
|
|
326
352
|
"""Samples a depth table may use: not excluded, and not in a borehole abandoned by a later sidetrack
|
|
327
353
|
(by hole depth for the TVD table, by bit depth for the gamma log)."""
|
|
@@ -358,12 +384,7 @@ def record(stream: LiveStream, de: Optional[dict] = None) -> dict:
|
|
|
358
384
|
out['notes'].append('channels this record needs are not in the file: ' + ', '.join(missing))
|
|
359
385
|
on_flag = (onb == 1.0) if onb is not None else np.zeros(n, dtype=bool)
|
|
360
386
|
excl = de['excluded']; M = de['running_bottom']; inc = de['increments']
|
|
361
|
-
|
|
362
|
-
drilling = on_flag & ~excl & ~np.isnan(hole) & (hole >= np.nan_to_num(M, nan=np.inf) - 10.0)
|
|
363
|
-
else:
|
|
364
|
-
drilling = on_flag & ~excl
|
|
365
|
-
idle = _idle_flag(drilling, hole, rop)
|
|
366
|
-
drilling = drilling & ~idle
|
|
387
|
+
drilling, idle = drilling_mask(stream, de)
|
|
367
388
|
rot = drilling & (rpm > 0) if rpm is not None else drilling
|
|
368
389
|
prev_end = None
|
|
369
390
|
for si, (a, b) in enumerate(sections, 1):
|
|
@@ -679,10 +700,14 @@ def document(rec: dict, program_version: str):
|
|
|
679
700
|
data={k: v for k, v in rec.items() if k != 'lines'} | {'_records': [], '_catalogue_obj': None})
|
|
680
701
|
|
|
681
702
|
|
|
682
|
-
def write_record(stream: LiveStream, out_dir: str, program_version: str) -> dict:
|
|
683
|
-
"""The record beside the well's other reports: drilling_record.json / .md / .html, and the MD-TVD table as CSV
|
|
703
|
+
def write_record(stream: LiveStream, out_dir: str, program_version: str, cache_dir: Optional[str] = None) -> dict:
|
|
704
|
+
"""The record beside the well's other reports: drilling_record.json / .md / .html, and the MD-TVD table as CSV;
|
|
705
|
+
with `cache_dir`, the charts' series cache from the same read and the same depth pass."""
|
|
684
706
|
from .client_reports import write
|
|
685
707
|
de = depth_events(stream)
|
|
708
|
+
if cache_dir:
|
|
709
|
+
from . import series_cache as SCH
|
|
710
|
+
SCH.build(stream, cache_dir, extras=chart_masks(stream, de))
|
|
686
711
|
rec = record(stream, de=de)
|
|
687
712
|
os.makedirs(out_dir, exist_ok=True)
|
|
688
713
|
paths = write(document(rec, program_version), out_dir, basename='drilling_record')
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# The charts
|
|
2
|
+
|
|
3
|
+
> A well's channels, stacked on one horizontal axis with a cursor that reads them all at the same moment, cut from every sample of the well's file - not from a thinned copy. Drag across a stretch to zoom into it, wheel to zoom where you point, double-click to see everything again; on a drilling recorder's export the axis switches between time and depth, the depth events are marked where they happened, the recording's sections are a click each, and the Wells page carries the drilling progress of every well on one chart.
|
|
4
|
+
|
|
5
|
+
**The command**: the Charts card on a well's page. Choose up to four channels (one per track); point at the chart for the values at that moment - each channel's mean in the bucket under the cursor, with its minimum and maximum and how many samples it holds, or the sample itself when the window is close enough to show every one. Drag across a stretch to zoom into it; the wheel zooms where you point; + and − zoom, ◀ and ▶ pan by half a window, Reset (or double-click) shows everything. The keyboard does the same once the chart has focus: ← → move the cursor (Shift for ten steps), + and − zoom, Page Up and Page Down pan, Home or Esc resets. Time or Depth switches the axis on a drilling recorder; the section buttons zoom to one stretch of recording. Table shows the window as rows. On the Wells page, Drilling progress plots each drilling-recorder well's hole depth against days since its first sample; point at it for every well's depth on that day.
|
|
6
|
+
|
|
7
|
+
**What it writes**: a chart cache per well under `cache\series\` in the workspace, written by the refresh from the same read that writes the reports - the index, each channel, which samples were flagged, and for a drilling recorder the drilling samples, the samples a depth table may use, the excluded samples and the running bottom of the hole. It is a copy: it carries the source file's size and time and is rebuilt when they no longer match, the first view of a well with no cache builds it, and backups leave it out.
|
|
8
|
+
|
|
9
|
+
**The number to check**: the sample count under the chart against the file's rows (`gea edr --file`); a bucket's minimum and maximum against the raw rows for a short stretch (zoom until the chart says every sample is shown); the depth axis's range against the gamma log's.
|
|
10
|
+
|
|
11
|
+
**What this page will not call a measurement**: a bucket's mean - it is arithmetic on the samples in the bucket, and the band around it is their range; a line across a gap - a stretch with no samples is drawn empty, never bridged; the depth axis as the hole - it is the drilling samples by bit depth, kept off hole a later sidetrack abandoned, the same samples the gamma log uses; the drilling progress as a plan - it is the running bottom the depth pass read from the recorder, stale and re-referenced depths left out.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# The site map
|
|
2
|
+
|
|
3
|
+
> Everything in the workspace that has a position, in one frame: the wells where their surface positions were declared, the structure layers the site brought (faults and folds, formation contours, areas, points), the World Stress Map's SHmax directions, the seismic stations, the Seismicity Response Areas, and the outline of the US states and counties underneath. A well without a declared position is listed as not placed and is never drawn anywhere. Click the map for what every layer says about that spot.
|
|
4
|
+
|
|
5
|
+
**The command**: the Map tab. Drag to pan, the wheel or + − to zoom, Home to return to where the map opened (the placed wells, else the response area, else the area most of the layers cover). Tick a layer to draw it, "fit" to zoom to it; Rings draws distance circles around every placed well. Point at the map for the position (WGS84) and the nearest placed well; click it - or press Enter for the centre - for each layer's own statement there: the nearest fault and its distance and bearing, the contours it lies between, the area it falls in, the nearest points, and the distance and bearing to every placed well. The keyboard does the same once the map has focus: arrows pan, + and − zoom, Home returns. A well's marker opens its page; "declare it" beside a not-placed well opens the setup checklist.
|
|
6
|
+
|
|
7
|
+
**What it writes**: nothing. The map reads the workspace: each well's declared surface position, each layer's shapefile (read once per run of the program and again when it changes), the stress map, the stations and the response areas. The outline is shipped with the program (`reference/us_outline.json`, from the US Census Bureau's 2017 cartographic boundary files by way of the us-atlas package, with its provenance beside it), so the map needs no network.
|
|
8
|
+
|
|
9
|
+
**The number to check**: a placed well against its survey plat - its marker is drawn at the declared latitude and longitude moved from the declared datum to WGS84, and the move is printed beside it (about fifty metres for NAD27 in West Texas); a layer's line against the map it came from, at the scale that map was made.
|
|
10
|
+
|
|
11
|
+
**What this page will not call a measurement**: a well's position - it is the operator's declaration, drawn where it was declared; a line drawn at this zoom as the line in the file - a vertex that would fall in the same screen cell as the one before it is left out of the drawing (never moved), and the full line is what "what is here" measures against; the outline as a survey - it is the Census Bureau's cartographic generalisation, good to a few hundred metres; a distance to a mapped fault as a hazard - it is a fact of the map.
|
|
@@ -43,6 +43,8 @@ INDEX: List[tuple] = [
|
|
|
43
43
|
('edr', 'The drilling recorder', 'the rig\'s one-second EDR export read as delivered - sections, depths, hours on bottom, the rate of penetration, the recorder\'s MD-TVD table - and what the record will not say'),
|
|
44
44
|
('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'),
|
|
45
45
|
('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'),
|
|
46
|
+
('map', 'The site map', 'everything with a position in one frame: the placed wells, the structure layers, the stress directions, the stations and response areas over the state and county outline; what every layer says about any spot'),
|
|
47
|
+
('charts', 'The charts', 'a well\'s channels stacked on one axis with a linked cursor, zoom and pan from every sample, time or depth for a drilling recorder, the depth events marked, and the drilling progress of every well'),
|
|
46
48
|
('setup', 'The setup checklist', 'what this workspace still needs before its reports can be handed over - each well\'s location, elevation and number, the client site, the backup, the reports - read from the workspace as it stands, each with its form or button'),
|
|
47
49
|
('tools', 'Tools and ports', 'every class of downhole tool in use across the industry with a hover description and a pop-open tutorial, your own fleet with its datasheets, the gauges this program reads with their citations and ratings, the formats and protocols that bring readings in, and the rating check on a tool string'),
|
|
48
50
|
('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'),
|
|
@@ -69,7 +71,7 @@ REQUIRED_LINES = ('**The command**', '**What it writes**', '**The number to chec
|
|
|
69
71
|
VIEW_TOPIC: Dict[str, str] = {
|
|
70
72
|
'home': 'start', 'wells': 'data-in', 'well': 'drift', 'live': 'patches', 'patch': 'patches', 'files': 'files', 'alarms': 'alarms',
|
|
71
73
|
'approvals': 'well-tests', 'config': 'site', 'reports': 'drift', 'verify': 'start', 'survey': 'data-in', 'jobs': 'site',
|
|
72
|
-
'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'setup': 'setup', 'audit': 'audit-update', 'tools': 'tools', 'catalog': 'catalog',
|
|
74
|
+
'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'setup': 'setup', 'map': 'map', 'audit': 'audit-update', 'tools': 'tools', 'catalog': 'catalog',
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
|