gea-program 0.13.0__tar.gz → 0.15.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.13.0 → gea_program-0.15.0}/PKG-INFO +40 -2
- {gea_program-0.13.0 → gea_program-0.15.0}/README.md +39 -1
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/__init__.py +1 -1
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/__main__.py +115 -3
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/acceptance_tests.py +248 -1
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/certificates.py +31 -2
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/client_reports.py +80 -4
- gea_program-0.15.0/gea/conformance.py +230 -0
- gea_program-0.15.0/gea/help/conformance.md +11 -0
- gea_program-0.15.0/gea/help/vibration.md +11 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/helplib.py +2 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic.py +16 -4
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/service.py +8 -2
- gea_program-0.15.0/gea/vibration.py +463 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/web/app.html +3 -3
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/workspace.py +31 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/PKG-INFO +40 -2
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/SOURCES.txt +4 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/pyproject.toml +1 -1
- {gea_program-0.13.0 → gea_program-0.15.0}/LICENSE +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/bench.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/blind_harness.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/cli.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/config_versioning.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/correlation.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/dashboard.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/deviation.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/doctor.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/earth_model.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/example_register_map.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/fat_sat.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/files.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/follower.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/forward_model.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/gamma.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/geodesy.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/alarms.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/data-in.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/doctor.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/drift.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/files.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/instruments.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/notifications.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/osdu.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/patches.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/quality.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/seismic.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/site.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/sites.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/sra.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/start.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/transients.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/housekeeping.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/jobs.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/live_ports.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/loadtest.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/modbus.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/model_card.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/notify.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/opcua_port.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/operator_app.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/osdu.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/patches.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/permits.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/ports.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/ppdm.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/project.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/quakeml.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reconciler.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sample_record.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sbom.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/segy.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_array.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_film.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_response.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_track.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/service_life.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/shell.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/shut_in.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sla_report.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/sra.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/store_forward.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/strata_join.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/supervisor.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/survey_view.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/telemetry.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/tool_library.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/transient.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/well_assembler.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/wits0.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea/witsml.py +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.13.0 → gea_program-0.15.0}/setup.cfg +0 -0
- {gea_program-0.13.0 → gea_program-0.15.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.15.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 (333 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]")
|
|
@@ -602,6 +602,44 @@ It will not assume a sidetrack, invent an injection interval or a
|
|
|
602
602
|
completion, or name a county. `gea ppdm --action parse --number ...` takes a
|
|
603
603
|
number apart from the command line; `gea help ppdm`.
|
|
604
604
|
|
|
605
|
+
### Machine vibration
|
|
606
|
+
|
|
607
|
+
The pump's record read the way an operations engineer expects. `gea
|
|
608
|
+
workspace --action vibration-report --well <id> --record pump.csv --vib-unit
|
|
609
|
+
g --rpm 1780 --group 2 --support rigid --bearing 9,7.94,39.04` writes the
|
|
610
|
+
broadband r.m.s. vibration velocity over 10-1000 Hz (2-1000 Hz below 600
|
|
611
|
+
r/min), the quantity ISO 20816-1 defines, and the ISO 20816-3 zone for the
|
|
612
|
+
declared machine group and support class with the boundaries printed; then
|
|
613
|
+
the envelope spectrum of the most impulsive band (chosen by kurtosis, or
|
|
614
|
+
declared) against the bearing's defect frequencies - BPFO, BPFI, BSF, FTF
|
|
615
|
+
from its geometry and the shaft speed - each MATCHED at its fundamental or
|
|
616
|
+
NOT MATCHED, the inner race with its sidebands. A record in counts needs a
|
|
617
|
+
sensitivity; a rate that cannot carry 1000 Hz is PARTIAL BAND, never
|
|
618
|
+
promoted; the group and the support are declarations; a matched frequency
|
|
619
|
+
is not a fault size. CSV or miniSEED/SAC; `gea vibration` runs the labelled
|
|
620
|
+
pump; `gea help vibration`.
|
|
621
|
+
|
|
622
|
+
### Conformity, in the standards' words
|
|
623
|
+
|
|
624
|
+
The drift report's "bias inside the instrument's class" is a statement of
|
|
625
|
+
conformity, and ISO/IEC 17025:2017 7.8.6 says what one carries: the result it
|
|
626
|
+
applies to, the specification, and the decision rule - which has to take
|
|
627
|
+
the uncertainty into account. The report now states it that way: the tag's
|
|
628
|
+
bias over the window with its sample count, the certificate's accuracy
|
|
629
|
+
class as the tolerance limit, the bias's expanded uncertainty (k = 2) as the
|
|
630
|
+
guard band, and the ILAC-G8:09/2019 non-binary rule - PASS, CONDITIONAL
|
|
631
|
+
PASS, CONDITIONAL FAIL or FAIL, with the acceptance limit printed; without
|
|
632
|
+
an uncertainty it falls back to simple acceptance and says so. The
|
|
633
|
+
certificate register takes what 7.8.4 asks the paper to carry (the expanded
|
|
634
|
+
uncertainty with k and probability, the traceability statement as worded,
|
|
635
|
+
the conditions, the calibration date, the method, who authorised it) and
|
|
636
|
+
`gea certificates --action conformance` prints each certificate against
|
|
637
|
+
the fourteen items of 7.8.2.1 and 7.8.4.1 - CARRIED, NOT CARRIED, NOT
|
|
638
|
+
RECORDED - with COMPLETE or INCOMPLETE and the missing clauses named. The
|
|
639
|
+
well page's filing form takes the items and its table shows U (k) and the
|
|
640
|
+
standing. `gea conformance --action decide` states one decision. `gea help
|
|
641
|
+
conformance`.
|
|
642
|
+
|
|
605
643
|
### Audit / Update
|
|
606
644
|
|
|
607
645
|
The Audit / Update tab holds three things. The whole audit log
|
|
@@ -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 (333 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]")
|
|
@@ -563,6 +563,44 @@ It will not assume a sidetrack, invent an injection interval or a
|
|
|
563
563
|
completion, or name a county. `gea ppdm --action parse --number ...` takes a
|
|
564
564
|
number apart from the command line; `gea help ppdm`.
|
|
565
565
|
|
|
566
|
+
### Machine vibration
|
|
567
|
+
|
|
568
|
+
The pump's record read the way an operations engineer expects. `gea
|
|
569
|
+
workspace --action vibration-report --well <id> --record pump.csv --vib-unit
|
|
570
|
+
g --rpm 1780 --group 2 --support rigid --bearing 9,7.94,39.04` writes the
|
|
571
|
+
broadband r.m.s. vibration velocity over 10-1000 Hz (2-1000 Hz below 600
|
|
572
|
+
r/min), the quantity ISO 20816-1 defines, and the ISO 20816-3 zone for the
|
|
573
|
+
declared machine group and support class with the boundaries printed; then
|
|
574
|
+
the envelope spectrum of the most impulsive band (chosen by kurtosis, or
|
|
575
|
+
declared) against the bearing's defect frequencies - BPFO, BPFI, BSF, FTF
|
|
576
|
+
from its geometry and the shaft speed - each MATCHED at its fundamental or
|
|
577
|
+
NOT MATCHED, the inner race with its sidebands. A record in counts needs a
|
|
578
|
+
sensitivity; a rate that cannot carry 1000 Hz is PARTIAL BAND, never
|
|
579
|
+
promoted; the group and the support are declarations; a matched frequency
|
|
580
|
+
is not a fault size. CSV or miniSEED/SAC; `gea vibration` runs the labelled
|
|
581
|
+
pump; `gea help vibration`.
|
|
582
|
+
|
|
583
|
+
### Conformity, in the standards' words
|
|
584
|
+
|
|
585
|
+
The drift report's "bias inside the instrument's class" is a statement of
|
|
586
|
+
conformity, and ISO/IEC 17025:2017 7.8.6 says what one carries: the result it
|
|
587
|
+
applies to, the specification, and the decision rule - which has to take
|
|
588
|
+
the uncertainty into account. The report now states it that way: the tag's
|
|
589
|
+
bias over the window with its sample count, the certificate's accuracy
|
|
590
|
+
class as the tolerance limit, the bias's expanded uncertainty (k = 2) as the
|
|
591
|
+
guard band, and the ILAC-G8:09/2019 non-binary rule - PASS, CONDITIONAL
|
|
592
|
+
PASS, CONDITIONAL FAIL or FAIL, with the acceptance limit printed; without
|
|
593
|
+
an uncertainty it falls back to simple acceptance and says so. The
|
|
594
|
+
certificate register takes what 7.8.4 asks the paper to carry (the expanded
|
|
595
|
+
uncertainty with k and probability, the traceability statement as worded,
|
|
596
|
+
the conditions, the calibration date, the method, who authorised it) and
|
|
597
|
+
`gea certificates --action conformance` prints each certificate against
|
|
598
|
+
the fourteen items of 7.8.2.1 and 7.8.4.1 - CARRIED, NOT CARRIED, NOT
|
|
599
|
+
RECORDED - with COMPLETE or INCOMPLETE and the missing clauses named. The
|
|
600
|
+
well page's filing form takes the items and its table shows U (k) and the
|
|
601
|
+
standing. `gea conformance --action decide` states one decision. `gea help
|
|
602
|
+
conformance`.
|
|
603
|
+
|
|
566
604
|
### Audit / Update
|
|
567
605
|
|
|
568
606
|
The Audit / Update tab holds three things. The whole audit log
|
|
@@ -282,7 +282,7 @@ def main(argv=None) -> int:
|
|
|
282
282
|
choices=["init", "add-file", "add-catalog", "add-live", "remove", "list", "migrate", "refresh", "audit",
|
|
283
283
|
"add-seismic", "refresh-seismic", "remove-seismic", "sar-film", "refresh-all", "add-track", "refresh-track", "remove-track",
|
|
284
284
|
"seismic-dataset", "seismic-field", "add-site", "sites", "site-report", "remove-site", "rename",
|
|
285
|
-
"set-well", "sra-define", "sra-report", "associate", "osdu-export", "quakeml-export", "well-identity"])
|
|
285
|
+
"set-well", "sra-define", "sra-report", "associate", "osdu-export", "quakeml-export", "well-identity", "vibration-report"])
|
|
286
286
|
p_ws.add_argument("--stations", type=str, nargs="+", default=None, help="add-track: two or more array station ids of this workspace")
|
|
287
287
|
p_ws.add_argument("--site", type=str, default=None, help="site-report/remove-site: the site id")
|
|
288
288
|
p_ws.add_argument("--api", type=str, default=None, help="set-well: the API number")
|
|
@@ -317,6 +317,15 @@ def main(argv=None) -> int:
|
|
|
317
317
|
p_ws.add_argument("--operator-org", type=str, default="", help="osdu-export: the operator's Organisation record id on the platform")
|
|
318
318
|
p_ws.add_argument("--out", type=str, default=None, help="osdu-export: the folder to write the manifest and files into; quakeml-export: the file to write")
|
|
319
319
|
p_ws.add_argument("--agency", type=str, default="", help="quakeml-export: the agencyID written in creationInfo (default: the site's name)")
|
|
320
|
+
p_ws.add_argument("--record", type=str, default=None, help="vibration-report: the machine record (CSV with a timestamp or elapsed-seconds column, or miniSEED/SAC)")
|
|
321
|
+
p_ws.add_argument("--channel", type=str, default=None, help="vibration-report: the channel to assess (default: the first)")
|
|
322
|
+
p_ws.add_argument("--vib-unit", type=str, default="g", help="vibration-report: the channel's unit - g, m/s2, mm/s, in/s, or counts with --sensitivity")
|
|
323
|
+
p_ws.add_argument("--sensitivity", type=float, default=None, help="vibration-report: units per count, when the record is in counts")
|
|
324
|
+
p_ws.add_argument("--rpm", type=float, default=None, help="vibration-report: the shaft speed, r/min (declared)")
|
|
325
|
+
p_ws.add_argument("--group", type=int, choices=[1, 2], default=None, help="vibration-report: ISO 20816-3 machine group - 1 above 300 kW, 2 from 15 to 300 kW (declared)")
|
|
326
|
+
p_ws.add_argument("--support", type=str, choices=["rigid", "flexible"], default=None, help="vibration-report: the support class (declared)")
|
|
327
|
+
p_ws.add_argument("--bearing", type=str, default=None, help="vibration-report: elements,ball_mm,pitch_mm[,contact_deg] - the bearing geometry (declared)")
|
|
328
|
+
p_ws.add_argument("--demod-band", type=float, nargs=2, default=None, help="vibration-report: the demodulation band in Hz (default: chosen by kurtosis)")
|
|
320
329
|
p_ws.add_argument("--depth-km", type=float, default=6.0, help="associate: the hypocentral depth the location is made under, km (declared)")
|
|
321
330
|
p_ws.add_argument("--rms-tol", type=float, default=0.15, help="associate: the RMS residual an event must fit within, s")
|
|
322
331
|
p_ws.add_argument("--wells", type=str, nargs="+", default=None, help="add-site: well ids of this workspace")
|
|
@@ -400,6 +409,26 @@ def main(argv=None) -> int:
|
|
|
400
409
|
|
|
401
410
|
p_osdu = sub.add_parser("osdu", help="the OSDU-shaped export: the self-test on a labelled site")
|
|
402
411
|
p_osdu.add_argument("--action", choices=["selftest"], default="selftest")
|
|
412
|
+
p_cf = sub.add_parser("conformance", help="ISO/IEC 17025 7.8 certificate items and the ILAC-G8 decision rules: the self-test, or one decision")
|
|
413
|
+
p_cf.add_argument("--action", choices=["selftest", "decide"], default="selftest")
|
|
414
|
+
p_cf.add_argument("--value", type=float, default=None, help="decide: the measured value (a deviation; the tolerance is symmetric)")
|
|
415
|
+
p_cf.add_argument("--tolerance", type=float, default=None, help="decide: the tolerance limit TL")
|
|
416
|
+
p_cf.add_argument("--uncertainty", type=float, default=None, help="decide: the expanded uncertainty U of the value (omit: simple acceptance)")
|
|
417
|
+
p_cf.add_argument("--k", type=float, default=2.0)
|
|
418
|
+
p_cf.add_argument("--rule", choices=["simple-acceptance", "binary-guard-band", "non-binary-guard-band"], default="non-binary-guard-band")
|
|
419
|
+
p_cf.add_argument("--unit", type=str, default="")
|
|
420
|
+
p_vib = sub.add_parser("vibration", help="machine vibration: ISO 20816-3 zone and bearing envelope analysis on a record, or the self-test")
|
|
421
|
+
p_vib.add_argument("--action", choices=["selftest", "assess"], default="selftest")
|
|
422
|
+
p_vib.add_argument("--record", type=str, default=None, help="assess: the record (CSV with a time column, or miniSEED/SAC)")
|
|
423
|
+
p_vib.add_argument("--channel", type=str, default=None)
|
|
424
|
+
p_vib.add_argument("--unit", type=str, default="g", help="g, m/s2, mm/s, in/s, or counts with --sensitivity")
|
|
425
|
+
p_vib.add_argument("--sensitivity", type=float, default=None)
|
|
426
|
+
p_vib.add_argument("--rpm", type=float, default=None)
|
|
427
|
+
p_vib.add_argument("--group", type=int, choices=[1, 2], default=None)
|
|
428
|
+
p_vib.add_argument("--support", type=str, choices=["rigid", "flexible"], default=None)
|
|
429
|
+
p_vib.add_argument("--bearing", type=str, default=None, help="elements,ball_mm,pitch_mm[,contact_deg]")
|
|
430
|
+
p_vib.add_argument("--demod-band", type=float, nargs=2, default=None)
|
|
431
|
+
p_vib.add_argument("--json", action="store_true")
|
|
403
432
|
p_ppdm = sub.add_parser("ppdm", help="the well named as the US Well Number and PPDM name it: take a number apart, or run the self-test")
|
|
404
433
|
p_ppdm.add_argument("--action", choices=["selftest", "parse"], default="selftest")
|
|
405
434
|
p_ppdm.add_argument("--number", type=str, default=None, help="parse: a US Well Number (10, 12 or 14 digits, dashes optional)")
|
|
@@ -501,7 +530,7 @@ def main(argv=None) -> int:
|
|
|
501
530
|
|
|
502
531
|
p_ce = sub.add_parser("certificates", help="calibration certificates per instrument: list, file one, status against today")
|
|
503
532
|
p_ce.add_argument("--register", type=str, required=True, help="the well's certificates.jsonl")
|
|
504
|
-
p_ce.add_argument("--action", choices=["list", "add", "status"], default="list")
|
|
533
|
+
p_ce.add_argument("--action", choices=["list", "add", "status", "conformance"], default="list")
|
|
505
534
|
p_ce.add_argument("--tag", type=str, default=None)
|
|
506
535
|
p_ce.add_argument("--tags", type=str, default=None, help="comma-separated tags for --action status")
|
|
507
536
|
p_ce.add_argument("--serial", type=str, default="")
|
|
@@ -515,6 +544,17 @@ def main(argv=None) -> int:
|
|
|
515
544
|
p_ce.add_argument("--doc", type=str, default=None, help="the certificate file (hashed, not copied)")
|
|
516
545
|
p_ce.add_argument("--note", type=str, default="")
|
|
517
546
|
p_ce.add_argument("--actor", type=str, default="cli")
|
|
547
|
+
p_ce.add_argument("--calibrated", type=str, default="", help="ISO/IEC 17025 7.8.2.1 i: the date the calibration was performed")
|
|
548
|
+
p_ce.add_argument("--method", type=str, default="", help="7.8.2.1 f: the method used")
|
|
549
|
+
p_ce.add_argument("--authorised-by", type=str, default="", help="7.8.2.1 o: who authorised the certificate")
|
|
550
|
+
p_ce.add_argument("--uncertainty", type=float, default=None, help="7.8.4.1 a: the expanded uncertainty U, in --uncertainty-unit (default the result's unit)")
|
|
551
|
+
p_ce.add_argument("--uncertainty-unit", type=str, default="")
|
|
552
|
+
p_ce.add_argument("--k", type=float, default=None, help="7.8.4.1 a: the coverage factor U is stated at")
|
|
553
|
+
p_ce.add_argument("--probability", type=float, default=None, help="7.8.4.1 a: the coverage probability as a fraction (0.95)")
|
|
554
|
+
p_ce.add_argument("--conditions", type=str, default="", help="7.8.4.1 b: the conditions the calibration was made under")
|
|
555
|
+
p_ce.add_argument("--traceability", type=str, default="", help="7.8.4.1 c: the statement of metrological traceability, as the certificate words it")
|
|
556
|
+
p_ce.add_argument("--adjustment", type=str, default="", help="7.8.4.1 d: results before and after adjustment, if the certificate carries them")
|
|
557
|
+
p_ce.add_argument("--decision-rule", type=str, default="", help="7.8.6: the decision rule the certificate's conformity statement names, if any")
|
|
518
558
|
|
|
519
559
|
p_tr = sub.add_parser("transient", help="shut-in detection and build-up analysis (Horner + Bourdet derivative with a bootstrap band)")
|
|
520
560
|
p_tr.add_argument("--file", type=str, required=True, help="historian file")
|
|
@@ -752,7 +792,10 @@ def main(argv=None) -> int:
|
|
|
752
792
|
if a.action == "add":
|
|
753
793
|
try:
|
|
754
794
|
print(_json.dumps(reg.add(a.tag or "", a.serial, a.certificate, a.issued or "", a.valid_until or "", a.actor, a.lab,
|
|
755
|
-
a.accuracy_pct_fs, a.full_scale, a.unit, a.doc, a.note
|
|
795
|
+
a.accuracy_pct_fs, a.full_scale, a.unit, a.doc, a.note,
|
|
796
|
+
calibrated_utc=a.calibrated, method=a.method, authorised_by=a.authorised_by, uncertainty=a.uncertainty,
|
|
797
|
+
uncertainty_unit=a.uncertainty_unit, uncertainty_k=a.k, uncertainty_probability=a.probability,
|
|
798
|
+
conditions=a.conditions, traceability=a.traceability, adjustment=a.adjustment, decision_rule=a.decision_rule), indent=1))
|
|
756
799
|
except (ValueError, TypeError) as e:
|
|
757
800
|
raise SystemExit(f"certificates: {e}")
|
|
758
801
|
return 0
|
|
@@ -763,6 +806,13 @@ def main(argv=None) -> int:
|
|
|
763
806
|
print(f"{r['tag_id']:24s} {r['status']:9s} {r.get('certificate_id') or '-':16s} until {r.get('valid_until_utc') or '-'} {('' if r['days_left'] is None else str(r['days_left']) + ' d')}")
|
|
764
807
|
print(_json.dumps(CertificateRegister.summary(rows)))
|
|
765
808
|
return 0 if CertificateRegister.summary(rows)['all_valid'] else 1
|
|
809
|
+
if a.action == "conformance":
|
|
810
|
+
from .conformance import report_lines
|
|
811
|
+
c = reg.conformance()
|
|
812
|
+
for r in c["rows"]:
|
|
813
|
+
print("\n".join(report_lines(r)))
|
|
814
|
+
print(f"certificates: {c['n']} filed, {c['complete']} COMPLETE against ISO/IEC 17025:2017 7.8" + (f"; incomplete: {', '.join(c['incomplete'])}" if c['incomplete'] else ''))
|
|
815
|
+
return 0 if not c["incomplete"] else 1
|
|
766
816
|
for e in reg.list():
|
|
767
817
|
print(f"{e['tag_id']:24s} {e['serial']:12s} {e['certificate_id']:16s} {e['issued_utc'][:10]} to {e['valid_until_utc'][:10]} ±{e.get('accuracy_pct_fs') or '-'} % FS {e.get('lab', '')}")
|
|
768
818
|
print(f"certificates: {len(reg.list())} filed")
|
|
@@ -1503,6 +1553,52 @@ def main(argv=None) -> int:
|
|
|
1503
1553
|
return 0
|
|
1504
1554
|
print(f"notifications: {'configured' if n.cfg else 'not configured'}" + (f" - {len(n.cfg['channels'])} channel(s), {len(n.cfg['rules'])} rule(s), quiet {n.cfg['quiet_s']} s" if n.cfg else " (gea notify --example)"))
|
|
1505
1555
|
return 0
|
|
1556
|
+
elif a.cmd == "conformance":
|
|
1557
|
+
from . import conformance as _C
|
|
1558
|
+
if a.action == "decide":
|
|
1559
|
+
if a.value is None or a.tolerance is None:
|
|
1560
|
+
raise SystemExit("conformance --action decide needs --value and --tolerance")
|
|
1561
|
+
d = _C.decide(a.value, a.tolerance, a.uncertainty, rule=a.rule, k=a.k if a.uncertainty is not None else None,
|
|
1562
|
+
probability=(0.95 if abs(a.k - 2.0) < 1e-9 else None) if a.uncertainty is not None else None, unit=a.unit)
|
|
1563
|
+
print(d["statement"]); print(f" {d['rule_text']}")
|
|
1564
|
+
return 0 if d["outcome"] in ("PASS", "CONDITIONAL PASS") else 1
|
|
1565
|
+
r = _C.selftest()
|
|
1566
|
+
print(f"conformance selftest [{r['label']}]: {r['status']}")
|
|
1567
|
+
for k, v in r["checks"].items():
|
|
1568
|
+
print(f" {'ok ' if v else 'BAD'} {k}")
|
|
1569
|
+
print("\n".join(_C.report_lines(r["full"])))
|
|
1570
|
+
for d in r["decisions"]:
|
|
1571
|
+
print(" " + d["statement"])
|
|
1572
|
+
return 0 if r["status"] == "OK" else 1
|
|
1573
|
+
elif a.cmd == "vibration":
|
|
1574
|
+
from . import vibration as _V
|
|
1575
|
+
if a.action == "assess":
|
|
1576
|
+
if not a.record:
|
|
1577
|
+
raise SystemExit("vibration --action assess needs --record")
|
|
1578
|
+
brg = None
|
|
1579
|
+
if a.bearing:
|
|
1580
|
+
parts = [float(x) for x in a.bearing.split(",")]
|
|
1581
|
+
if len(parts) not in (3, 4):
|
|
1582
|
+
raise SystemExit("--bearing is elements,ball_mm,pitch_mm[,contact_deg]")
|
|
1583
|
+
brg = {"n_elements": int(parts[0]), "d_mm": parts[1], "D_mm": parts[2], "contact_deg": parts[3] if len(parts) == 4 else 0.0}
|
|
1584
|
+
try:
|
|
1585
|
+
rec = _V.read_record(a.record, a.channel)
|
|
1586
|
+
except ValueError as e:
|
|
1587
|
+
raise SystemExit(f"vibration: {e}")
|
|
1588
|
+
r = _V.assess(rec["x"], rec["fs"], a.unit, a.rpm, group=a.group, support=a.support, bearing=brg,
|
|
1589
|
+
band_hz=tuple(a.demod_band) if a.demod_band else None, label=f"{rec['name']}:{rec['channel']}", sensitivity=a.sensitivity)
|
|
1590
|
+
r["gaps"] = list(r["gaps"]) + list(rec["notes"])
|
|
1591
|
+
if a.json:
|
|
1592
|
+
print(json.dumps({k: v for k, v in r.items()}, indent=1, default=str))
|
|
1593
|
+
else:
|
|
1594
|
+
print(_V.report_text(r))
|
|
1595
|
+
return 0 if r["status"] == "ASSESSED" else 1
|
|
1596
|
+
r = _V.selftest()
|
|
1597
|
+
print(f"vibration selftest [{r['label']}]: {r['status']}")
|
|
1598
|
+
for k, v in r["checks"].items():
|
|
1599
|
+
print(f" {'ok ' if v else 'BAD'} {k}")
|
|
1600
|
+
print(_V.report_text(r["assessment"]))
|
|
1601
|
+
return 0 if r["status"] == "OK" else 1
|
|
1506
1602
|
elif a.cmd == "ppdm":
|
|
1507
1603
|
from . import ppdm as _P
|
|
1508
1604
|
if a.action == "parse":
|
|
@@ -1790,6 +1886,22 @@ def main(argv=None) -> int:
|
|
|
1790
1886
|
countries=a.country, operator_org_id=a.operator_org, out_dir=a.out, actor=a.actor)
|
|
1791
1887
|
print(_osdu_text(r)); v = r["validate"]
|
|
1792
1888
|
print(f" structure: {'ok' if v['ok'] else 'PROBLEMS'} ({v['records']} record(s))" + ('' if v['ok'] else '; ' + '; '.join(v['problems'][:5]))); return 0
|
|
1889
|
+
elif a.action == "vibration-report":
|
|
1890
|
+
from .vibration import report_text as _vib_text
|
|
1891
|
+
if not a.well or not a.record:
|
|
1892
|
+
raise SystemExit("vibration-report needs --well <id> and --record <file>")
|
|
1893
|
+
brg = None
|
|
1894
|
+
if a.bearing:
|
|
1895
|
+
parts = [float(x) for x in a.bearing.split(",")]
|
|
1896
|
+
if len(parts) not in (3, 4):
|
|
1897
|
+
raise SystemExit("--bearing is elements,ball_mm,pitch_mm[,contact_deg]")
|
|
1898
|
+
brg = {"n_elements": int(parts[0]), "d_mm": parts[1], "D_mm": parts[2], "contact_deg": parts[3] if len(parts) == 4 else 0.0}
|
|
1899
|
+
try:
|
|
1900
|
+
r = ws.vibration_report(a.well, a.record, channel=a.channel, unit=a.vib_unit, rpm=a.rpm, group=a.group, support=a.support, bearing=brg,
|
|
1901
|
+
band_hz=a.demod_band, sensitivity=a.sensitivity, actor=a.actor)
|
|
1902
|
+
except ValueError as e:
|
|
1903
|
+
raise SystemExit(f"vibration-report: {e}")
|
|
1904
|
+
print(_vib_text(r)); print(" written:", r["paths"].get("md") or r["paths"]); return 0
|
|
1793
1905
|
elif a.action == "well-identity":
|
|
1794
1906
|
from .ppdm import report_text as _ppdm_text
|
|
1795
1907
|
if not a.well:
|
|
@@ -2420,7 +2420,7 @@ def section_ah_band2(tmp: str) -> None:
|
|
|
2420
2420
|
and Path(wsp, "wells", w1["id"], "records", "certificates", "CERT-1_cert1.txt").exists()
|
|
2421
2421
|
and st2["P_raw_psi_S2"] == 48 and st2["P_raw_psi_S1"] == 240 and gd["instruments"]["swap_notes"][0]["samples_excluded"] == 192
|
|
2422
2422
|
and [c["status"] for c in inst["certificate_status"]] == ["VALID", "VALID"] and not [c for c in inst["candidates"] if c["tag_id"] == "P_raw_psi_S2"]
|
|
2423
|
-
and "Instruments: sensor swaps" in drift_html and "CERT-77" in drift_html and "
|
|
2423
|
+
and "Instruments: sensor swaps" in drift_html and "CERT-77" in drift_html and "Conformity" in drift_html and "ISO/IEC 17025 7.8" in drift_html
|
|
2424
2424
|
and ptr and ptr["analyses"][0]["status"] == "OK" and abs(ptr["analyses"][0]["derived"]["k_md"] - k) / k < 0.05
|
|
2425
2425
|
and ov["wells"][0]["instruments"]["swaps"] == 1 and ov["wells"][0]["transient"]["analysed"] == 1 and ov["site"]["certificates"]["counts"]["VALID"] == 2
|
|
2426
2426
|
and "swap.add" in audit and "certificate.add" in audit and "transient.params" in audit,
|
|
@@ -5208,6 +5208,251 @@ def section_bg_ppdm(tmp: str) -> None:
|
|
|
5208
5208
|
"a number from the command line with the exit code saying whether it is valid, and runs the self-test; the help page names the sidetrack "
|
|
5209
5209
|
"it will not assume")
|
|
5210
5210
|
|
|
5211
|
+
|
|
5212
|
+
def section_bh_vibration(tmp: str) -> None:
|
|
5213
|
+
"""Section BH - machine vibration: the ISO 20816-3 zone of the declared machine from the broadband r.m.s.
|
|
5214
|
+
velocity, and the bearing's defect frequencies found or not found in the envelope spectrum of the most
|
|
5215
|
+
impulsive band; the declarations named as declarations, the band's limits named, no fault size claimed."""
|
|
5216
|
+
import csv as _csv
|
|
5217
|
+
import subprocess as _sp
|
|
5218
|
+
import numpy as _np
|
|
5219
|
+
from . import vibration as V
|
|
5220
|
+
from . import seismic as S
|
|
5221
|
+
from . import helplib as H
|
|
5222
|
+
from .client_reports import forbidden_terms
|
|
5223
|
+
from .workspace import Workspace
|
|
5224
|
+
pkg = Path(__file__).parent
|
|
5225
|
+
d = Path(tmp, "bh"); d.mkdir()
|
|
5226
|
+
|
|
5227
|
+
# -- the self-test on the labelled pump ----------------------------------------------------------
|
|
5228
|
+
r = V.selftest()
|
|
5229
|
+
a = r["assessment"]
|
|
5230
|
+
ok(r["status"] == "OK" and all(r["checks"].values()) and r["label"] == "SIMULATION_SELF_TEST"
|
|
5231
|
+
and a["zone"]["zone"] == "C" and abs(a["broadband"]["rms_mm_s"] - r["truth"]["unbalance_rms_mm_s"] * (1 + 0.09) ** 0.5) < 0.3
|
|
5232
|
+
and a["envelope"]["match"]["matched"] == ["BPFO"] and len(a["envelope"]["match"]["rows"]["BPFO"]["harmonics_found"]) == 3
|
|
5233
|
+
and r["inner"]["envelope"]["match"]["matched"] == ["BPFI"] and len(r["inner"]["envelope"]["match"]["rows"]["BPFI"]["sidebands"]["found"]) == 2
|
|
5234
|
+
and V.ZONE_BOUNDARIES == {(1, "rigid"): (2.3, 4.5, 7.1), (1, "flexible"): (3.5, 7.1, 11.0), (2, "rigid"): (1.4, 2.8, 4.5), (2, "flexible"): (2.3, 4.5, 7.1)}
|
|
5235
|
+
and V.BAND_HZ == (10.0, 1000.0) and V.BAND_LOW_SPEED_HZ == (2.0, 1000.0) and V.LOW_SPEED_RPM == 600.0
|
|
5236
|
+
and abs(V.bearing_frequencies(1780, 9, 7.94, 39.04)["BPFI"] - 0.5 * 9 * (1780 / 60) * (1 + 7.94 / 39.04)) < 1e-3
|
|
5237
|
+
and abs(V.bearing_frequencies(1780, 9, 7.94, 39.04)["BSF"] - (39.04 / (2 * 7.94)) * (1780 / 60) * (1 - (7.94 / 39.04) ** 2)) < 1e-3
|
|
5238
|
+
and abs(V.bearing_frequencies(1780, 9, 7.94, 39.04)["FTF"] - 0.5 * (1780 / 60) * (1 - 7.94 / 39.04)) < 1e-3
|
|
5239
|
+
and abs(V.bearing_frequencies(1780, 9, 7.94, 39.04, 30.0)["BPFO"] - 0.5 * 9 * (1780 / 60) * (1 - 7.94 / 39.04 * _np.cos(_np.radians(30)))) < 1e-3,
|
|
5240
|
+
"BH1 the self-test on a labelled pump at 1780 r/min: the broadband r.m.s. velocity recovers the unbalance line put into the record to within "
|
|
5241
|
+
"8% and places a Group 2 rigid machine in zone C as the truth says; the most impulsive band is chosen and the outer-race fault is matched at "
|
|
5242
|
+
"its fundamental and two harmonics with the inner race, the ball and the cage not matched; an inner-race scene is matched at BPFI with both "
|
|
5243
|
+
"sidebands at the shaft speed and the outer race not matched; the zone boundaries are ISO 20816-3's for both groups and both supports, the "
|
|
5244
|
+
"band is ISO 20816-1's, and the four defect frequencies are the kinematic formulas including the contact angle")
|
|
5245
|
+
|
|
5246
|
+
# -- what it will not call a measurement ----------------------------------------------------------
|
|
5247
|
+
sc = V.synthetic_scene(seconds=2.0)
|
|
5248
|
+
slow = V.assess(sc["acc_m_s2"][::10], sc["fs"] / 10.0, "m/s2", sc["rpm"], group=2, support="rigid", bearing=sc["bearing"])
|
|
5249
|
+
short = V.assess(sc["acc_m_s2"][:int(0.5 * sc["fs"])], sc["fs"], "m/s2", sc["rpm"], group=2, support="rigid", bearing=sc["bearing"])
|
|
5250
|
+
nod = V.assess(sc["acc_m_s2"], sc["fs"], "m/s2", None)
|
|
5251
|
+
cnt = V.assess(_np.round(sc["acc_m_s2"] / 9.80665 / 1e-4), sc["fs"], "counts", sc["rpm"], group=2, support="rigid", bearing=sc["bearing"])
|
|
5252
|
+
sens = V.assess(_np.round(sc["acc_m_s2"] / 9.80665 / 1e-4), sc["fs"], "g", sc["rpm"], group=2, support="rigid", bearing=sc["bearing"], sensitivity=1e-4)
|
|
5253
|
+
low = V.assess(sc["acc_m_s2"], sc["fs"], "m/s2", 450.0, group=1, support="flexible")
|
|
5254
|
+
declared_band = V.assess(sc["acc_m_s2"], sc["fs"], "m/s2", sc["rpm"], group=2, support="rigid", bearing=sc["bearing"], band_hz=(2000.0, 4000.0))
|
|
5255
|
+
ok(slow["broadband"]["band_partial"] and slow["broadband"]["band_hz"][1] < 1000 and slow["zone"]["zone_qualified"] == "PARTIAL BAND"
|
|
5256
|
+
and any("PARTIAL BAND" in g for g in slow["gaps"])
|
|
5257
|
+
and any("shorter than one second" in g for g in short["gaps"])
|
|
5258
|
+
and nod["zone"] is None and nod["status"] == "PARTIAL" and any("no shaft speed" in g for g in nod["gaps"]) and any("group" in g for g in nod["gaps"])
|
|
5259
|
+
and any("bearing" in g for g in nod["gaps"]) and nod["envelope"]["match"] is None and len(nod["envelope"]["peaks"]) > 0
|
|
5260
|
+
and cnt["status"] == "NOT ASSESSED" and cnt["broadband"]["status"] == "NOT EVALUATED" and cnt["envelope"]["match"]["matched"] == ["BPFO"]
|
|
5261
|
+
and sens["status"] == "ASSESSED" and abs(sens["broadband"]["rms_mm_s"] - a["broadband"]["rms_mm_s"]) < 0.3 and sens["declared"]["sensitivity"] == 1e-4
|
|
5262
|
+
and low["broadband"]["band_hz"][0] == 2.0 and low["zone"]["boundaries_mm_s"] == {"A/B": 3.5, "B/C": 7.1, "C/D": 11.0}
|
|
5263
|
+
and declared_band["envelope"]["band"]["status"] == "DECLARED" and declared_band["envelope"]["band"]["band_hz"] == [2000.0, 4000.0]
|
|
5264
|
+
and declared_band["envelope"]["match"]["matched"] == ["BPFO"]
|
|
5265
|
+
and "fault size" in " ".join(a["not_a_measurement"]) and "declared" in " ".join(a["not_a_measurement"]),
|
|
5266
|
+
"BH2 a record whose rate cannot carry 1000 Hz is evaluated to its own Nyquist frequency and marked PARTIAL BAND, never promoted; a record "
|
|
5267
|
+
"under a second is named; without a shaft speed, a group or a bearing the broadband value is stated, the zone is not, the envelope peaks "
|
|
5268
|
+
"are listed and nothing is matched; a record in counts gets no mm/s and no zone but its envelope is still read, and with a declared "
|
|
5269
|
+
"sensitivity it agrees with the same record in g; below 600 r/min the band starts at 2 Hz and Group 1 flexible has its own boundaries; a "
|
|
5270
|
+
"declared demodulation band is used as declared; the assessment says it is not a fault size and that the machine is a declaration")
|
|
5271
|
+
|
|
5272
|
+
# -- through the workspace and the command line, from a CSV and from a miniSEED record ------------
|
|
5273
|
+
csvp = d / "pump.csv"
|
|
5274
|
+
with open(csvp, "w", newline="") as f:
|
|
5275
|
+
w = _csv.writer(f); w.writerow(["elapsed_s", "acc_g", "temp_C"])
|
|
5276
|
+
for i, x in enumerate(sc["acc_m_s2"]):
|
|
5277
|
+
w.writerow([f"{i / sc['fs']:.6f}", f"{x / 9.80665:.6f}", "41.0"])
|
|
5278
|
+
counts = _np.round(sc["acc_m_s2"] / 9.80665 / 1e-4).astype(_np.int32)
|
|
5279
|
+
S.write_mseed([S.Trace("XX", "PUMP", "", "ACC", 1700000000.1234567, sc["fs"], counts, "synthetic", "INT32")], str(d / "pump.mseed"))
|
|
5280
|
+
back = S.read_any(str(d / "pump.mseed"))
|
|
5281
|
+
hist = d / "swd.csv"
|
|
5282
|
+
with open(hist, "w", newline="") as f:
|
|
5283
|
+
w = _csv.writer(f); w.writerow(["timestamp", "P_surf_psi"])
|
|
5284
|
+
for h in range(24):
|
|
5285
|
+
w.writerow([f"2026-03-01T{h:02d}:00:00Z", "1500"])
|
|
5286
|
+
ws = Workspace.create(str(d / "ws"), "Pad 3", actor="tester")
|
|
5287
|
+
w1 = ws.add_well_file(str(hist), display="SWD 1", actor="tester", station_md_ft=9800.0)
|
|
5288
|
+
run = lambda *a: _sp.run([sys.executable, "-m", "gea", "workspace", "--path", ws.path, "--actor", "tester", *a], capture_output=True, text=True)
|
|
5289
|
+
r1 = run("--action", "vibration-report", "--well", w1["id"], "--record", str(csvp), "--channel", "acc_g", "--vib-unit", "g", "--rpm", "1780",
|
|
5290
|
+
"--group", "2", "--support", "rigid", "--bearing", "9,7.94,39.04")
|
|
5291
|
+
r0 = run("--action", "vibration-report", "--well", w1["id"], "--record", str(csvp), "--channel", "nope")
|
|
5292
|
+
out = Path(ws.path, "reports", "wells", w1["id"])
|
|
5293
|
+
md = (out / "vibration_report.md").read_text(encoding="utf-8"); html = (out / "vibration_report.html").read_text(encoding="utf-8")
|
|
5294
|
+
js = json.loads((out / "vibration_report.json").read_text(encoding="utf-8"))
|
|
5295
|
+
audit = Path(ws.path, "records", "audit.jsonl").read_text(encoding="utf-8")
|
|
5296
|
+
r2 = _sp.run([sys.executable, "-m", "gea", "vibration", "--action", "assess", "--record", str(d / "pump.mseed"), "--unit", "g", "--sensitivity", "1e-4",
|
|
5297
|
+
"--rpm", "1780", "--group", "2", "--support", "rigid", "--bearing", "9,7.94,39.04"], capture_output=True, text=True)
|
|
5298
|
+
r3 = _sp.run([sys.executable, "-m", "gea", "vibration", "--action", "assess", "--record", str(d / "pump.mseed"), "--unit", "counts", "--rpm", "1780",
|
|
5299
|
+
"--group", "2", "--support", "rigid"], capture_output=True, text=True)
|
|
5300
|
+
r4 = _sp.run([sys.executable, "-m", "gea", "vibration"], capture_output=True, text=True)
|
|
5301
|
+
help_md = (pkg / "help" / "vibration.md").read_text(encoding="utf-8")
|
|
5302
|
+
ok(len(back) == 1 and back[0].npts == counts.size and not back[0].gaps and abs(back[0].starttime - 1700000000.1234567) < 2e-6
|
|
5303
|
+
and r1.returncode == 0 and "ISO 20816-3 zone C" in r1.stdout and "BPFO 106.3486 Hz: MATCHED" in r1.stdout and "written:" in r1.stdout
|
|
5304
|
+
and r0.returncode != 0 and "no channel" in (r0.stderr + r0.stdout)
|
|
5305
|
+
and Path(ws.path, "wells", w1["id"], "machine", "pump.csv").is_file()
|
|
5306
|
+
and "| **Result** | ZONE C |" in md and "Bearing defect frequencies" in md and "Group 2 (15 kW to 300 kW)" in md and "fault size" in md
|
|
5307
|
+
and not forbidden_terms(md) and not forbidden_terms(html)
|
|
5308
|
+
and js["assessment"]["record"]["sha256"] and js["assessment"]["zone"]["zone"] == "C" and js["assessment"]["declared"]["bearing"]["n_elements"] == 9
|
|
5309
|
+
and "well.vibration" in audit and '"zone": "C"' in audit
|
|
5310
|
+
and r2.returncode == 0 and "from acceleration (g), 2.0 s at 20000 Hz" in r2.stdout and "zone C" in r2.stdout and "MATCHED" in r2.stdout
|
|
5311
|
+
and r3.returncode == 1 and "NOT ASSESSED" in r3.stdout and "without a sensitivity" in r3.stdout
|
|
5312
|
+
and r4.returncode == 0 and "vibration selftest [SIMULATION_SELF_TEST]: OK" in r4.stdout
|
|
5313
|
+
and any(t["topic"] == "vibration" for t in H.topics()) and not H.check("vibration")
|
|
5314
|
+
and "fault size" in help_md.split("will not call a measurement")[1] and "2.3 / 4.5 / 7.1" in help_md,
|
|
5315
|
+
"BH3 a 20 kHz record round-trips through this program's own miniSEED writer as one trace with no gap (the header's 0.1 ms time field "
|
|
5316
|
+
"is coarser than a sample above 5 kHz and every record read back as a gap until blockette 1001 carried the microseconds); "
|
|
5317
|
+
"`--action vibration-report` copies the record beside the well, writes the report in three forms with the zone as its result, the "
|
|
5318
|
+
"declarations in their own table and the defect frequencies each matched or not, audits it with the zone and the declarations, and names "
|
|
5319
|
+
"a channel that is not there; `gea vibration --action assess` reads a miniSEED record in counts with a declared sensitivity and says "
|
|
5320
|
+
"NOT ASSESSED without one; the self-test runs from the command line; the help page carries the boundaries and names the fault size it will not claim")
|
|
5321
|
+
|
|
5322
|
+
|
|
5323
|
+
def section_bi_conformance(tmp: str) -> None:
|
|
5324
|
+
"""Section BI - conformity in the standards' words: each certificate against the items ISO/IEC 17025:2017
|
|
5325
|
+
7.8.2.1 and 7.8.4.1 ask it to carry, and the drift report's bias-against-class line as a statement of
|
|
5326
|
+
conformity with its ILAC-G8 decision rule named, the uncertainty as the guard band, nothing assumed."""
|
|
5327
|
+
import csv
|
|
5328
|
+
import datetime as D
|
|
5329
|
+
import http.cookiejar
|
|
5330
|
+
import subprocess as _sp
|
|
5331
|
+
import urllib.request
|
|
5332
|
+
import urllib.error
|
|
5333
|
+
import numpy as _np
|
|
5334
|
+
from . import conformance as C
|
|
5335
|
+
from . import helplib as H
|
|
5336
|
+
from .certificates import CertificateRegister
|
|
5337
|
+
from .workspace import Workspace
|
|
5338
|
+
from .service import Service, Users
|
|
5339
|
+
pkg = Path(__file__).parent
|
|
5340
|
+
d = Path(tmp, "bi"); d.mkdir()
|
|
5341
|
+
|
|
5342
|
+
# -- the self-test and the rules --------------------------------------------------------------------
|
|
5343
|
+
r = C.selftest()
|
|
5344
|
+
ok(r["status"] == "OK" and all(r["checks"].values())
|
|
5345
|
+
and [x["outcome"] for x in r["decisions"]] == ["PASS", "CONDITIONAL PASS", "CONDITIONAL FAIL", "FAIL", "PASS"]
|
|
5346
|
+
and r["decisions"][4]["rule"] == "simple-acceptance"
|
|
5347
|
+
and C.decide(8.0, 10.0, 2.0)["outcome"] == "PASS" and C.decide(8.0001, 10.0, 2.0)["outcome"] == "CONDITIONAL PASS"
|
|
5348
|
+
and C.decide(10.0, 10.0, 2.0)["outcome"] == "CONDITIONAL PASS" and C.decide(10.0001, 10.0, 2.0)["outcome"] == "CONDITIONAL FAIL"
|
|
5349
|
+
and C.decide(12.0, 10.0, 2.0)["outcome"] == "CONDITIONAL FAIL" and C.decide(12.0001, 10.0, 2.0)["outcome"] == "FAIL"
|
|
5350
|
+
and C.decide(10.0, 10.0, 2.0, rule="simple-acceptance")["outcome"] == "PASS" and C.decide(8.5, 10.0, 2.0, rule="binary-guard-band")["outcome"] == "FAIL"
|
|
5351
|
+
and len(C.CERTIFICATE_CLAUSES) == 14 and {c[0].split(" ")[0] for c in C.CERTIFICATE_CLAUSES} == {"7.8.2.1", "7.8.4.1"}
|
|
5352
|
+
and all(k in " ".join(x[1] for x in C.CERTIFICATE_CLAUSES) for k in ("uncertainty", "traceability", "conditions", "adjustment", "decision_rule", "authorised_by", "method", "calibrated_utc")),
|
|
5353
|
+
"BI1 the ILAC-G8:09/2019 rules give the four outcomes at their boundaries (PASS to TL - U, CONDITIONAL PASS to TL, CONDITIONAL FAIL to TL + U, "
|
|
5354
|
+
"FAIL above), simple acceptance ignores U and says so, the binary rule fails inside the guard band; the certificate items are the fourteen of "
|
|
5355
|
+
"ISO/IEC 17025:2017 7.8.2.1 and 7.8.4.1 - identification, laboratory, item, dates, result, method, authorisation, uncertainty with its "
|
|
5356
|
+
"coverage factor, conditions, traceability, adjustment, decision rule - and a full certificate is COMPLETE, a thin one INCOMPLETE with the "
|
|
5357
|
+
"missing clauses named, an entry filed before the fields existed NOT RECORDED rather than NOT CARRIED")
|
|
5358
|
+
|
|
5359
|
+
# -- the register: the fields recorded from the paper, nothing invented ------------------------------
|
|
5360
|
+
reg = CertificateRegister(str(d / "certs.jsonl"))
|
|
5361
|
+
e1 = reg.add("P1", "S1", "C-1", "2026-01-10", "2027-01-10", "tester", "Acme Cal", 0.1, 10000.0, "psi",
|
|
5362
|
+
uncertainty=2.5, uncertainty_k=2.0, uncertainty_probability=0.95, traceability="NIST via DWT 1234", conditions="23 ± 1 °C",
|
|
5363
|
+
calibrated_utc="2026-01-09", method="comparison", authorised_by="J. Doe", adjustment="as found / as left", decision_rule="simple acceptance")
|
|
5364
|
+
e2 = reg.add("P2", "S2", "C-2", "2026-01-10", "2027-01-10", "tester", "Acme Cal", 0.1, 10000.0, "psi")
|
|
5365
|
+
bad = []
|
|
5366
|
+
for kw in ({"uncertainty_k": 0}, {"uncertainty_probability": 1.5}, {"uncertainty": -1}, {"nonsense": "x"}):
|
|
5367
|
+
try:
|
|
5368
|
+
reg.add("P3", "S3", "C-3", "2026-01-10", "2027-01-10", "tester", **kw); bad.append(False)
|
|
5369
|
+
except ValueError:
|
|
5370
|
+
bad.append(True)
|
|
5371
|
+
st = {x["tag_id"]: x for x in reg.status(["P1", "P2"], now=D.datetime(2026, 6, 1, tzinfo=D.timezone.utc))}
|
|
5372
|
+
conf = reg.conformance()
|
|
5373
|
+
r1 = _sp.run([sys.executable, "-m", "gea", "certificates", "--register", str(d / "certs.jsonl"), "--action", "conformance"], capture_output=True, text=True)
|
|
5374
|
+
r2 = _sp.run([sys.executable, "-m", "gea", "certificates", "--register", str(d / "cli.jsonl"), "--action", "add", "--tag", "P9", "--serial", "S9", "--certificate", "C-9",
|
|
5375
|
+
"--issued", "2026-01-10", "--valid-until", "2027-01-10", "--lab", "Cal Lab GmbH", "--accuracy-pct-fs", "0.05", "--full-scale", "5000", "--unit", "psi", "--uncertainty", "1.2",
|
|
5376
|
+
"--k", "2", "--probability", "0.95", "--traceability", "PTB via transfer standard 7", "--conditions", "21 °C", "--calibrated", "2026-01-08",
|
|
5377
|
+
"--method", "comparison", "--authorised-by", "A. B."], capture_output=True, text=True)
|
|
5378
|
+
r3 = _sp.run([sys.executable, "-m", "gea", "certificates", "--register", str(d / "cli.jsonl"), "--action", "conformance"], capture_output=True, text=True)
|
|
5379
|
+
r4 = _sp.run([sys.executable, "-m", "gea", "conformance", "--action", "decide", "--value", "11", "--tolerance", "10", "--uncertainty", "2", "--unit", "psi"], capture_output=True, text=True)
|
|
5380
|
+
r5 = _sp.run([sys.executable, "-m", "gea", "conformance"], capture_output=True, text=True)
|
|
5381
|
+
ok(e1["uncertainty"] == 2.5 and e1["uncertainty_k"] == 2.0 and e1["traceability"] == "NIST via DWT 1234" and e2["uncertainty"] is None and e2["traceability"] == ""
|
|
5382
|
+
and all(bad) and st["P1"]["iso17025"]["status"] == "COMPLETE" and st["P1"]["iso17025"]["carried"] == 14
|
|
5383
|
+
and st["P2"]["iso17025"]["status"] == "INCOMPLETE" and any("7.8.4.1 c" in m for m in st["P2"]["iso17025"]["missing"]) and st["P2"]["uncertainty"] is None
|
|
5384
|
+
and conf["n"] == 2 and conf["complete"] == 1 and conf["incomplete"] == ["C-2"]
|
|
5385
|
+
and r1.returncode == 1 and "C-1 (serial S1, tag P1): COMPLETE - 14 of 14" in r1.stdout and "NOT CARRIED a statement identifying how the measurements are metrologically traceable" in r1.stdout
|
|
5386
|
+
and r2.returncode == 0 and r3.returncode == 0 and "1 COMPLETE" in r3.stdout
|
|
5387
|
+
and r4.returncode == 1 and "CONDITIONAL FAIL" in r4.stdout and "acceptance limit 8 psi" in r4.stdout
|
|
5388
|
+
and r5.returncode == 0 and "conformance selftest [SELF_TEST]: OK" in r5.stdout,
|
|
5389
|
+
"BI2 the register takes what 7.8.4 asks the paper to carry - the expanded uncertainty with its coverage factor and probability, the "
|
|
5390
|
+
"traceability statement as worded, the conditions, the calibration date, the method, who authorised it, the adjustment results, the "
|
|
5391
|
+
"decision rule - rejects a k of zero, a probability above one, a negative uncertainty and a field it does not know, leaves empty what was "
|
|
5392
|
+
"not filed, and every status row carries the certificate's 7.8 standing; `gea certificates --action conformance` prints it item by item "
|
|
5393
|
+
"and exits 1 while any certificate is incomplete; `gea conformance --action decide` states one decision from the command line")
|
|
5394
|
+
|
|
5395
|
+
# -- the drift report: the statement of conformity with its rule named ----------------------------------
|
|
5396
|
+
rng = _np.random.default_rng(5)
|
|
5397
|
+
n = 240
|
|
5398
|
+
t0 = D.datetime(2026, 3, 1, tzinfo=D.timezone.utc)
|
|
5399
|
+
hist = d / "hist.csv"
|
|
5400
|
+
base = 3000.0 + 0.2 * _np.sin(_np.arange(n) / 24.0)
|
|
5401
|
+
with open(hist, "w", newline="") as f:
|
|
5402
|
+
w = csv.writer(f); w.writerow(["timestamp_utc", "P_raw_psi_S1", "P_raw_psi_S2", "T_raw_F_S1"])
|
|
5403
|
+
for i in range(n):
|
|
5404
|
+
w.writerow([(t0 + D.timedelta(hours=i)).strftime("%Y-%m-%dT%H:%M:%SZ"), round(base[i] + rng.normal(0, 0.8), 2), round(base[i] + 1.5 + rng.normal(0, 0.8), 2), round(80 + 0.1 * rng.normal(), 2)])
|
|
5405
|
+
wsp = str(d / "ws")
|
|
5406
|
+
ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
5407
|
+
w1 = ws.add_well_file(str(hist), display="Well BI", actor="tester")
|
|
5408
|
+
users = Users(str(Path(wsp, "users.json"))); users.add("op1", "operator-pass-1", "operator")
|
|
5409
|
+
svc = Service(wsp, host="127.0.0.1", port=0, scheduler=False).start()
|
|
5410
|
+
base_url = svc.url.rstrip("/")
|
|
5411
|
+
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
5412
|
+
|
|
5413
|
+
def call(method, path, body=None):
|
|
5414
|
+
req = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
5415
|
+
req.add_header("Content-Type", "application/json")
|
|
5416
|
+
if method == "POST":
|
|
5417
|
+
req.add_header("X-GEA-Action", "1")
|
|
5418
|
+
try:
|
|
5419
|
+
with opener.open(req, timeout=600) as rr:
|
|
5420
|
+
return rr.status, json.loads(rr.read())
|
|
5421
|
+
except urllib.error.HTTPError as ex:
|
|
5422
|
+
return ex.code, json.loads(ex.read())
|
|
5423
|
+
try:
|
|
5424
|
+
call("POST", "/api/login", {"name": "op1", "password": "operator-pass-1"})
|
|
5425
|
+
s_c1, _ = call("POST", f"/api/wells/{w1['id']}/certificates", {"tag_id": "P_raw_psi_S1", "serial": "SN-1", "certificate_id": "CERT-A", "issued_utc": "2026-01-01",
|
|
5426
|
+
"valid_until_utc": "2027-01-01", "lab": "LabX", "accuracy_pct_fs": 0.02, "full_scale": 10000, "unit": "psi",
|
|
5427
|
+
"uncertainty": "0.5", "uncertainty_k": "2", "uncertainty_probability": "0.95", "traceability": "NIST via DWT",
|
|
5428
|
+
"conditions": "23 °C", "calibrated_utc": "2025-12-30", "method": "comparison", "authorised_by": "Q. A."})
|
|
5429
|
+
s_c2, _ = call("POST", f"/api/wells/{w1['id']}/certificates", {"tag_id": "P_raw_psi_S2", "serial": "SN-2", "certificate_id": "CERT-B", "issued_utc": "2026-01-01",
|
|
5430
|
+
"valid_until_utc": "2027-01-01", "lab": "LabX", "accuracy_pct_fs": 0.02, "full_scale": 10000, "unit": "psi"})
|
|
5431
|
+
call("POST", "/api/refresh", {})
|
|
5432
|
+
svc.app.runner.wait(svc.app.runner.list(1)[0]["id"], 600)
|
|
5433
|
+
inst = call("GET", f"/api/wells/{w1['id']}/instruments")[1]
|
|
5434
|
+
drift_md = Path(wsp, "reports", "wells", w1["id"], "gauge_drift_report.md").read_text(encoding="utf-8")
|
|
5435
|
+
drift_html = Path(wsp, "reports", "wells", w1["id"], "gauge_drift_report.html").read_text(encoding="utf-8")
|
|
5436
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
5437
|
+
by = inst["iso17025"]["by_certificate"]
|
|
5438
|
+
ok(s_c1 == 200 and s_c2 == 200 and inst["iso17025"]["n"] == 2 and inst["iso17025"]["complete"] == 1 and inst["iso17025"]["incomplete"] == ["CERT-B"]
|
|
5439
|
+
and by["CERT-A"]["status"] == "COMPLETE" and by["CERT-B"]["status"] == "INCOMPLETE"
|
|
5440
|
+
and "Conformity" in drift_md and "ISO/IEC 17025 7.8" in drift_md and "decision rule: non-binary-guard-band (ILAC-G8:09/2019)" in drift_md
|
|
5441
|
+
and "bias of P_raw_psi_S1 over the evaluation window" in drift_md and "with expanded uncertainty U = " in drift_md and "(k = 2, 95%)" in drift_md
|
|
5442
|
+
and "tolerance limit 2 psi" in drift_md and "acceptance limit" in drift_md and "COMPLETE (12/14)" in drift_md and "INCOMPLETE (5/14)" in drift_md and by["CERT-A"]["carried"] == 12
|
|
5443
|
+
and ("CONDITIONAL" in drift_md or "PASS" in drift_md or "FAIL" in drift_md) and "ISO/IEC 17025:2017 7.8.6" in drift_html
|
|
5444
|
+
and "ctUnc" in page_src and "ctTrace" in page_src and "uncertainty_k" in page_src and "ISO/IEC 17025 7.8" in page_src
|
|
5445
|
+
and any(t["topic"] == "conformance" for t in H.topics()) and not H.check("conformance")
|
|
5446
|
+
and "simple acceptance" in (pkg / "help" / "conformance.md").read_text(encoding="utf-8").split("will not call a measurement")[1],
|
|
5447
|
+
"BI3 through the API: a certificate filed with its uncertainty, coverage factor and traceability is COMPLETE and one filed without them is "
|
|
5448
|
+
"INCOMPLETE; the instruments answer carries every certificate's 7.8 standing; the drift report's bias line is a statement of conformity "
|
|
5449
|
+
"in 7.8.6's words - the result it applies to with its sample count, the certificate's class as the tolerance limit, the bias's expanded "
|
|
5450
|
+
"uncertainty at k = 2, the ILAC-G8 non-binary guard-band rule and the acceptance limit - beside the certificate's own 7.8 standing; the "
|
|
5451
|
+
"page's filing form takes the 7.8.4 items and its table shows U (k) and the standing; the help page names simple acceptance as the "
|
|
5452
|
+
"fallback it will not dress up")
|
|
5453
|
+
finally:
|
|
5454
|
+
svc.stop()
|
|
5455
|
+
|
|
5211
5456
|
def main() -> int:
|
|
5212
5457
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
5213
5458
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -5270,6 +5515,8 @@ def main() -> int:
|
|
|
5270
5515
|
section_be_osdu(tmp)
|
|
5271
5516
|
section_bf_quakeml(tmp)
|
|
5272
5517
|
section_bg_ppdm(tmp)
|
|
5518
|
+
section_bh_vibration(tmp)
|
|
5519
|
+
section_bi_conformance(tmp)
|
|
5273
5520
|
if _FAILS:
|
|
5274
5521
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
5275
5522
|
for f in _FAILS:
|