gea-program 0.49.0__tar.gz → 0.50.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.49.0 → gea_program-0.50.0}/PKG-INFO +16 -1
- {gea_program-0.49.0 → gea_program-0.50.0}/README.md +15 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/__init__.py +1 -1
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/__main__.py +61 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/acceptance_tests.py +252 -2
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/collision.py +59 -11
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/dossier.py +22 -3
- gea_program-0.50.0/gea/help/collision.md +19 -0
- gea_program-0.50.0/gea/help/plan.md +19 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/helplib.py +3 -2
- gea_program-0.50.0/gea/reference/iscwsa_rev5_example.json +2015 -0
- gea_program-0.50.0/gea/reference/owsg_tool_models.json +4611 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/service.py +28 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/web/app.html +108 -3
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/well3d.py +50 -18
- gea_program-0.50.0/gea/wellplan.py +388 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/wellpos.py +169 -5
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/PKG-INFO +16 -1
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/SOURCES.txt +4 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/pyproject.toml +1 -1
- gea_program-0.49.0/gea/help/collision.md +0 -19
- {gea_program-0.49.0 → gea_program-0.50.0}/LICENSE +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/alerts.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/backup.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/bench.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/blind_harness.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog_map.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/catalog_register.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/certificates.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/cli.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/client_reports.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/config_versioning.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/conformance.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/control_room.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/correlation.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/dashboard.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/declarations.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/deviation.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/dlis.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/dnp3.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/doctor.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/dossier_verify.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/drill_string.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/earth_model.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/economics.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/ed25519.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/edr.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/elevation.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/etp.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/example_register_map.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fat_sat.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/files.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/follower.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/forward_model.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/friction_priors.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/gamma.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/geodesy.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/geomag.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/hartip.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/alarms.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/alerts.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/backup.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/catalog.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/charts.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/conformance.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/control-room.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/data-in.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/declare.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/dlis.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/doctor.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/dossier.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/drift.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/drillstring.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/economics.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/edr.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/etp.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/files.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/historian.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/instruments.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/interval.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/invoice-check.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/map.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/month-end.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/notifications.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/opseis.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/osdu.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/pad-summary.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/patches.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/penetrator.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/quality.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/report-history.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/rig-time.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/seismic.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/setup.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/simulation.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/site.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/sites.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/slip.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/soak.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/sra.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/start.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/structure.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/tools.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/transients.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/vibration.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/well-report.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/help/well3d.md +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/housekeeping.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/interval.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/invoice_check.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/jobs.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/live_ports.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/loadtest.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/modbus.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/model_card.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/month_end.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/notify.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/op_seismicity.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/opcua_port.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/operator_app.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/osdu.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/pad_summary.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/patches.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/pdf_report.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/penetrator.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/permits.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/piwebapi.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/ports.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/ppdm.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/project.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/quakeml.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reconciler.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/WMM2025.COF +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/eia_prices.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/iscwsa_rev4_example.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/mahoning_example.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/mud_motor_specs.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/penetrator_ratings.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/seismicity_protocols.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_3d.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_surfaces.json.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/reference/volve_well_picks.csv.gz +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/report_history.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/rig_state.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sample_record.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sbom.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seedlink.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/segy.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_array.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_film.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_response.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_track.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/seismic_watch.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/series_cache.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/service_life.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/shapefile.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/shell.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/shut_in.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/simulation.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/site_map.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sla_report.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/slip.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/soak.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/sra.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/store_forward.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/strata_join.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/structure.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/supervisor.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/survey_view.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/telemetry.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/tool_library.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/transient.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/vibration.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/well_assembler.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/well_report.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/wits0.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/witsml.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/workspace.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea/xlsx_read.py +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.49.0 → gea_program-0.50.0}/setup.cfg +0 -0
- {gea_program-0.49.0 → gea_program-0.50.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.50.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
|
|
@@ -648,6 +648,21 @@ 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
|
+
### Plan vs actual and the survey tools
|
|
652
|
+
|
|
653
|
+
Each well against its directional plan: at every survey station, how far
|
|
654
|
+
it is from the plan - high or low, right or left, in the plan's own frame -
|
|
655
|
+
against the survey's own uncertainty in that direction; the bit projected
|
|
656
|
+
below the last survey; the one arc back to the plan, with its dogleg
|
|
657
|
+
severity and toolface. Each well's survey program names the tool that
|
|
658
|
+
surveyed each run, weighed by the ISCWSA MWD Rev 5.11 model (checked
|
|
659
|
+
against all 144 rows of the ISCWSA's own Rev 5 example) or one of 21 OWSG
|
|
660
|
+
tool-code models on its weighting functions - MWD and EMS with the standard,
|
|
661
|
+
high- or low-resolution geomagnetic model or in-field referencing. Wells not
|
|
662
|
+
yet drilled are checked for collision along their plans, a well being
|
|
663
|
+
drilled along its survey and then its plan, and the Collision tab draws the
|
|
664
|
+
travelling cylinder. The **Plan vs actual** tab, `gea plan`, `gea help plan`.
|
|
665
|
+
|
|
651
666
|
### Well collision checks
|
|
652
667
|
|
|
653
668
|
Every well scanned against every other: at each point of one well, the
|
|
@@ -609,6 +609,21 @@ 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
|
+
### Plan vs actual and the survey tools
|
|
613
|
+
|
|
614
|
+
Each well against its directional plan: at every survey station, how far
|
|
615
|
+
it is from the plan - high or low, right or left, in the plan's own frame -
|
|
616
|
+
against the survey's own uncertainty in that direction; the bit projected
|
|
617
|
+
below the last survey; the one arc back to the plan, with its dogleg
|
|
618
|
+
severity and toolface. Each well's survey program names the tool that
|
|
619
|
+
surveyed each run, weighed by the ISCWSA MWD Rev 5.11 model (checked
|
|
620
|
+
against all 144 rows of the ISCWSA's own Rev 5 example) or one of 21 OWSG
|
|
621
|
+
tool-code models on its weighting functions - MWD and EMS with the standard,
|
|
622
|
+
high- or low-resolution geomagnetic model or in-field referencing. Wells not
|
|
623
|
+
yet drilled are checked for collision along their plans, a well being
|
|
624
|
+
drilled along its survey and then its plan, and the Collision tab draws the
|
|
625
|
+
travelling cylinder. The **Plan vs actual** tab, `gea plan`, `gea help plan`.
|
|
626
|
+
|
|
612
627
|
### Well collision checks
|
|
613
628
|
|
|
614
629
|
Every well scanned against every other: at each point of one well, the
|
|
@@ -604,6 +604,24 @@ def main(argv=None) -> int:
|
|
|
604
604
|
p_co.add_argument("--actor", type=str, default="cli")
|
|
605
605
|
p_co.add_argument("--json", action="store_true")
|
|
606
606
|
|
|
607
|
+
p_pl = sub.add_parser("plan", help="a well against its plan: the distance high/low and right/left at each survey, the bit projected, the arc back to the plan; the survey program's tool models")
|
|
608
|
+
p_pl.add_argument("--workspace", type=str, default=None)
|
|
609
|
+
p_pl.add_argument("--well", type=str, default=None)
|
|
610
|
+
p_pl.add_argument("--attach", type=str, default=None, help="attach FILE as the well's plan (CSV, Excel or WITSML)")
|
|
611
|
+
p_pl.add_argument("--azimuth-reference", type=str, default=None, help="with --attach: true, grid or magnetic")
|
|
612
|
+
p_pl.add_argument("--md-unit", type=str, default="ft", help="with --attach: ft or m")
|
|
613
|
+
p_pl.add_argument("--grid", type=str, default=None, help="with a grid azimuth reference: the grid (e.g. UTM14N)")
|
|
614
|
+
p_pl.add_argument("--declination", type=str, default=None, help="with a magnetic azimuth reference: the declination used")
|
|
615
|
+
p_pl.add_argument("--remove", action="store_true", help="take the well's plan off it")
|
|
616
|
+
p_pl.add_argument("--program", type=str, default=None, help="the survey program: 'MWD+SRGM' or '0-1500:MWD+SRGM, 1500-:MWD+IFR1' (metres)")
|
|
617
|
+
p_pl.add_argument("--bit-offset", type=str, default=None, help="survey sensor to bit, m")
|
|
618
|
+
p_pl.add_argument("--lookahead", type=str, default=None, help="how far ahead the arc back rejoins the plan, m")
|
|
619
|
+
p_pl.add_argument("--source", type=str, default="", help="where the plan or the program came from")
|
|
620
|
+
p_pl.add_argument("--models", action="store_true", help="list the tool models")
|
|
621
|
+
p_pl.add_argument("--write", action="store_true", help="write the well's report")
|
|
622
|
+
p_pl.add_argument("--actor", type=str, default="cli")
|
|
623
|
+
p_pl.add_argument("--json", action="store_true")
|
|
624
|
+
|
|
607
625
|
p_rt = sub.add_parser("rig-time", help="what the rig did each second of the drilling record - drilling, connections, trips, the slips - and the time lost against the pad's own best")
|
|
608
626
|
p_rt.add_argument("--workspace", type=str, required=True)
|
|
609
627
|
p_rt.add_argument("--well", type=str, default=None, help="with --write: one well's report (without it, the pad's)")
|
|
@@ -2422,6 +2440,49 @@ def main(argv=None) -> int:
|
|
|
2422
2440
|
raise SystemExit(f"collision: {e.args[0] if e.args else e}")
|
|
2423
2441
|
print(_json.dumps({k: v for k, v in r.items()}, default=str) if a.json else _CO.text(r))
|
|
2424
2442
|
return 0
|
|
2443
|
+
elif a.cmd == "plan":
|
|
2444
|
+
import json as _json
|
|
2445
|
+
from . import wellplan as _PL
|
|
2446
|
+
from . import wellpos as _WP
|
|
2447
|
+
from .cli import _safe_stdout
|
|
2448
|
+
from .workspace import Workspace, WorkspaceError
|
|
2449
|
+
_safe_stdout()
|
|
2450
|
+
try:
|
|
2451
|
+
if a.models:
|
|
2452
|
+
for m_ in _WP.model_list():
|
|
2453
|
+
print(f"{m_['name']:<18} {m_['id']:<14} {m_['terms']:>2} terms {m_['family']:<10} {m_['long_name']}" + (" (default)" if m_['default'] else ""))
|
|
2454
|
+
return 0
|
|
2455
|
+
if not a.workspace:
|
|
2456
|
+
raise ValueError("--workspace is needed")
|
|
2457
|
+
ws = Workspace(a.workspace)
|
|
2458
|
+
if (a.attach or a.remove or a.program or a.bit_offset is not None or a.lookahead is not None or a.write) and not a.well:
|
|
2459
|
+
raise ValueError("--well is needed")
|
|
2460
|
+
if a.attach:
|
|
2461
|
+
with open(a.attach, "rb") as f_:
|
|
2462
|
+
r_ = _PL.attach(ws, a.well, os.path.basename(a.attach), f_.read(), a.actor, a.azimuth_reference or "", a.md_unit, a.grid,
|
|
2463
|
+
float(a.declination) if a.declination else None, a.source)
|
|
2464
|
+
print(f"plan attached to {a.well}: {r_['stations']} stations, {r_['md_range_m'][0]:,.1f} to {r_['md_range_m'][1]:,.1f} m MD ({r_['azimuth_reference']} north)")
|
|
2465
|
+
return 0
|
|
2466
|
+
if a.remove:
|
|
2467
|
+
_PL.remove(ws, a.well, a.actor)
|
|
2468
|
+
print(f"plan removed from {a.well}")
|
|
2469
|
+
return 0
|
|
2470
|
+
if a.program or a.bit_offset is not None or a.lookahead is not None:
|
|
2471
|
+
s_ = _PL.set_well(ws, a.actor, a.well, _PL.parse_program(a.program) if a.program else None, a.bit_offset, a.lookahead, a.source)
|
|
2472
|
+
print(f"{a.well}: " + ", ".join(f"{p_['model']} to {p_['to_md_m']:,.0f} m" if p_['to_md_m'] is not None else f"{p_['model']} to TD" for p_ in s_['program'])
|
|
2473
|
+
+ f"; the bit {s_['bit_offset_m']:g} m below the survey sensor; back to the plan {s_['lookahead_m']:g} m ahead")
|
|
2474
|
+
return 0
|
|
2475
|
+
if a.write:
|
|
2476
|
+
r_ = _PL.write_report(ws, __version__, a.well, a.actor)
|
|
2477
|
+
print(f"wrote {r_['report_id']}: {r_['paths']['html']}")
|
|
2478
|
+
if r_['paths'].get('pdf'):
|
|
2479
|
+
print(f" printable: {r_['paths']['pdf']}")
|
|
2480
|
+
return 0
|
|
2481
|
+
r = _PL.page(ws, a.well)
|
|
2482
|
+
except (KeyError, ValueError, OSError, WorkspaceError) as e:
|
|
2483
|
+
raise SystemExit(f"plan: {e.args[0] if e.args else e}")
|
|
2484
|
+
print(_json.dumps(r, default=str) if a.json else _PL.text(r))
|
|
2485
|
+
return 0
|
|
2425
2486
|
elif a.cmd == "rig-time":
|
|
2426
2487
|
import json as _json
|
|
2427
2488
|
from . import rig_state as _RS
|
|
@@ -11165,7 +11165,8 @@ def section_cr_collision(tmp: str) -> None:
|
|
|
11165
11165
|
fld = {"declination_deg": 6.0, "dip_deg": 60.0, "total_nT": 48000.0}
|
|
11166
11166
|
md = [0.0, 500.0, 1000.0, 2000.0]
|
|
11167
11167
|
mk = lambda i, x, inc=(0, 0, 0, 0), az=(0, 0, 0, 0), y=0.0: {"id": i, "display": i, "md": md, "inc": list(inc), "az": list(az), "x0": x, "y0": y,
|
|
11168
|
-
"ref_elev_m": 0.0, "field": fld, "hole_in": 8.5
|
|
11168
|
+
"ref_elev_m": 0.0, "field": fld, "hole_in": 8.5,
|
|
11169
|
+
"program": [{"to_md_m": None, "model": WP.REV4}]}
|
|
11169
11170
|
rule = {**CO.DEFAULTS}
|
|
11170
11171
|
A, B = CO.prepare(mk("A", 0.0)), CO.prepare(mk("B", 10.0))
|
|
11171
11172
|
sAB, sBA = CO.scan(A, B, rule), CO.scan(B, A, rule)
|
|
@@ -11207,7 +11208,7 @@ def section_cr_collision(tmp: str) -> None:
|
|
|
11207
11208
|
c3 = {
|
|
11208
11209
|
"wells": len(v["wells"]) == 3 and len(v["pairs"]) == 6 and abs(wl["15/9-F-10"]["td_md_m"] - 5300.1) < 0.1
|
|
11209
11210
|
and all(abs(x["field"]["declination_deg"] - 1.12) < 0.05 for x in v["wells"]) and all("grid convergence" in x["azimuth_note"] for x in v["wells"]),
|
|
11210
|
-
"worst": w_["level"] == "BELOW 1.0" and abs(w_["min_sf"] - 0.
|
|
11211
|
+
"worst": w_["level"] == "BELOW 1.0" and abs(w_["min_sf"] - 0.062) < 0.01 and {w_["reference_name"], w_["offset_name"]} == {"15/9-F-5", "15/9-F-10"}
|
|
11211
11212
|
and abs(w_["at_md_m"] - 250) < 15 and abs(w_["distance_m"] - 1.20) < 0.05,
|
|
11212
11213
|
"order": [p["min_sf"] for p in v["pairs"]] == sorted(p["min_sf"] for p in v["pairs"]) and all(len(p["profile"]["md_m"]) == len(p["profile"]["sf"]) for p in v["pairs"]),
|
|
11213
11214
|
"ellipses": wl["15/9-F-10"]["td_ellipse_1sigma"]["major_m"] > wl["15/9-F-5"]["td_ellipse_1sigma"]["major_m"] > wl["NO 15/9-F-4"]["td_ellipse_1sigma"]["major_m"] > 1.0,
|
|
@@ -11296,6 +11297,254 @@ def section_cr_collision(tmp: str) -> None:
|
|
|
11296
11297
|
+ (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
|
|
11297
11298
|
|
|
11298
11299
|
|
|
11300
|
+
def section_cs_plan_and_tools(tmp: str) -> None:
|
|
11301
|
+
"""Section CS - plan against actual, the survey tools and the travelling cylinder: the ISCWSA MWD Rev 5.11 model
|
|
11302
|
+
checked against all 144 rows of the ISCWSA's own Rev 5 example, with the OWSG tool-code models on its weighting
|
|
11303
|
+
functions; survey programs weighing each run by its tool; a well against its plan - high or low, right or left,
|
|
11304
|
+
against the survey's own uncertainty - the bit projected and the arc back, each checked by construction; planned
|
|
11305
|
+
wells in the collision check and the travelling cylinder's directions; the API, the CLI, the report, the dossier,
|
|
11306
|
+
the tabs and the help."""
|
|
11307
|
+
import base64 as _b64
|
|
11308
|
+
import http.cookiejar
|
|
11309
|
+
import math as _m
|
|
11310
|
+
import subprocess as _sp
|
|
11311
|
+
import urllib.request
|
|
11312
|
+
import urllib.error
|
|
11313
|
+
import zipfile as _zf
|
|
11314
|
+
import numpy as _np
|
|
11315
|
+
from . import collision as CO
|
|
11316
|
+
from . import dossier as DZ
|
|
11317
|
+
from . import edr as E
|
|
11318
|
+
from . import helplib as H
|
|
11319
|
+
from . import well3d as W
|
|
11320
|
+
from . import wellplan as WPL
|
|
11321
|
+
from . import wellpos as WP
|
|
11322
|
+
from . import xlsx_read as XR
|
|
11323
|
+
from .workspace import Workspace
|
|
11324
|
+
from .service import Service, Users
|
|
11325
|
+
pkg = Path(__file__).parent
|
|
11326
|
+
d = Path(tmp, "planvs"); d.mkdir()
|
|
11327
|
+
|
|
11328
|
+
# -- CS1 the Rev 5.11 model against the ISCWSA's example; the OWSG models ---------------------------------------------
|
|
11329
|
+
ex5 = WP.check_example_rev5()
|
|
11330
|
+
ex4 = WP.check_example()
|
|
11331
|
+
t8 = ex5["totals"]["8000"]
|
|
11332
|
+
ms = WP.models()
|
|
11333
|
+
ml = WP.model_list()
|
|
11334
|
+
sv = json.loads((pkg / "reference" / "iscwsa_rev5_example.json").read_text(encoding="utf-8"))["survey"]
|
|
11335
|
+
md_, inc_, az_ = (_np.array(sv[k], float) for k in ("md", "inc", "azi"))
|
|
11336
|
+
tvd_ = WP.min_curve_tvd(md_, inc_, az_)
|
|
11337
|
+
at = lambda name: WP.program_uncertainty(md_, inc_, az_, tvd_, -4.0, 72.0, 50000.0, [{"to_md_m": None, "model": name}])["cov"][-1]
|
|
11338
|
+
c_s, c_i, c_h = at("MWD+SRGM"), at("MWD+IFR1"), at("MWD+HRGM")
|
|
11339
|
+
owsg = json.loads((pkg / "reference" / "owsg_tool_models.json").read_text(encoding="utf-8"))
|
|
11340
|
+
c1 = {
|
|
11341
|
+
"example": ex5["rows"] == 144 and ex5["sources"] == 35 and not ex5["disagree"] and ex5["worst_relative"] < 5e-5 and ex5["depths_m"] == [1200, 2100, 5100, 8000],
|
|
11342
|
+
"totals": abs(t8[0] - 8518.67) < 0.01 and abs(t8[1] - 711.20) < 0.01 and abs(t8[2] - 513.29) < 0.01 and abs(t8[3] + 2244.33) < 0.01,
|
|
11343
|
+
"rev4_kept": ex4["rows"] == 112 and not ex4["disagree"],
|
|
11344
|
+
"models": len(ms) == 22 and WP.DEFAULT_MODEL == "MWD+SRGM" and sum(1 for m in ml if m["default"]) == 1 and WP.REV4 in ms
|
|
11345
|
+
and all(len(m["terms"]) >= 27 for m in ms.values()) and {"MWD+IFR1", "MWD+IFR2+SAG", "MWD+HRGM", "EMS+SRGM", "MWD+LRGM+SAG"} <= set(ms),
|
|
11346
|
+
"magnitudes": ms["MWD+SRGM"]["terms"]["DEC-OS"][1] == 0.24 * _m.pi / 180 and ms["MWD+SRGM"]["terms"]["DEC-OS"][2] == "global"
|
|
11347
|
+
and ms["MWD+IFR1"]["terms"]["DEC-CI"][2] == "global" and ms["MWD+SRGM"]["terms"]["DEC-U"][2] == "well",
|
|
11348
|
+
"grades": c_i[0, 0] + c_i[1, 1] < c_h[0, 0] + c_h[1, 1] < c_s[0, 0] + c_s[1, 1],
|
|
11349
|
+
"attribution": "ISCWSA" in ex5["source"] and "Apache" in ex5["license"] and "OWSG" in owsg["source"] and "Apache" in owsg["license"] and len(owsg["models"]) == 21,
|
|
11350
|
+
}
|
|
11351
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
11352
|
+
ok(not failed1,
|
|
11353
|
+
"CS1 the ISCWSA MWD Rev 5.11 model - the surface tie-on, the course-length terms, the enhanced sag and misalignments, the "
|
|
11354
|
+
"declination split well-wide and field-wide - recomputing all 144 rows of the ISCWSA's own Rev 5 example (35 sources and the "
|
|
11355
|
+
"total at four depths) to five significant figures; the Rev 4 example still whole; 21 OWSG tool-code models on the same "
|
|
11356
|
+
"weighting functions with their magnitudes and propagation as published, in-field referencing tighter than the high-resolution "
|
|
11357
|
+
"model and that tighter than the standard; the source and licence of both carried"
|
|
11358
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
11359
|
+
|
|
11360
|
+
# -- CS2 survey programs ------------------------------------------------------------------------------------------------
|
|
11361
|
+
one = WP.program_terms(md_, inc_, az_, tvd_, -4.0, 72.0, 50000.0, [{"to_md_m": None, "model": "MWD+SRGM"}])
|
|
11362
|
+
two = WP.program_terms(md_, inc_, az_, tvd_, -4.0, 72.0, 50000.0, [{"to_md_m": 2100.0, "model": "MWD+SRGM"}, {"to_md_m": None, "model": "MWD+SRGM"}])
|
|
11363
|
+
mix = WP.program_uncertainty(md_, inc_, az_, tvd_, -4.0, 72.0, 50000.0, [{"to_md_m": 2100.0, "model": "MWD+SRGM"}, {"to_md_m": None, "model": "MWD+IFR1"}])
|
|
11364
|
+
p1, P1, _ = WP.covariances(one)
|
|
11365
|
+
p2, P2, _ = WP.covariances(two)
|
|
11366
|
+
k21 = int(_np.flatnonzero(md_ == 2100)[0])
|
|
11367
|
+
refused = 0
|
|
11368
|
+
for bad in ([{"to_md_m": None, "model": "NOPE"}], [{"to_md_m": 900, "model": "MWD+SRGM"}, {"to_md_m": 800, "model": "MWD+SRGM"}],
|
|
11369
|
+
[{"to_md_m": None, "model": "MWD+SRGM"}, {"to_md_m": None, "model": "MWD+IFR1"}], []):
|
|
11370
|
+
try:
|
|
11371
|
+
WPL.check_program([dict(x) for x in bad])
|
|
11372
|
+
except ValueError:
|
|
11373
|
+
refused += 1
|
|
11374
|
+
c2 = {
|
|
11375
|
+
"same_above": _np.allclose(P1[: k21 + 1], P2[: k21 + 1], rtol=1e-12, atol=1e-12),
|
|
11376
|
+
"keys": "DEC-OS" in two and "DEC-U" in two and "ABZ@1" in two and "ABZ@2" in two and "ABZ" not in two and two["DEC-OS"]["shared"] and not two["DEC-U"]["shared"],
|
|
11377
|
+
"runs_independent": not _np.allclose(P1[-1], P2[-1]),
|
|
11378
|
+
"ifr_below": mix["cov"][-1][0, 0] + mix["cov"][-1][1, 1] < P1[-1][0, 0] + P1[-1][1, 1] and mix["model"] == "MWD+SRGM then MWD+IFR1",
|
|
11379
|
+
"parse": WPL.parse_program("0-1500:MWD+SRGM, 1500-:MWD+IFR1") == [{"to_md_m": 1500.0, "model": "MWD+SRGM"}, {"to_md_m": None, "model": "MWD+IFR1"}]
|
|
11380
|
+
and WPL.parse_program("MWD+HRGM") == [{"to_md_m": None, "model": "MWD+HRGM"}],
|
|
11381
|
+
"refused": refused == 4,
|
|
11382
|
+
}
|
|
11383
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
11384
|
+
ok(not failed2,
|
|
11385
|
+
"CS2 survey programs: each station weighed by the run that surveyed it - above the change, two runs of one tool read as one; "
|
|
11386
|
+
"below it a run's own errors start again while the well's and the field's run through; in-field referencing below the "
|
|
11387
|
+
"change tightens the well at TD; a program with an unknown tool, depths out of order or an open run before the last refused"
|
|
11388
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
11389
|
+
|
|
11390
|
+
# -- CS3 a well against its plan, by construction -----------------------------------------------------------------------
|
|
11391
|
+
fld = {"declination_deg": 6.0, "dip_deg": 60.0, "total_nT": 48000.0}
|
|
11392
|
+
prog = [{"to_md_m": None, "model": "MWD+SRGM"}]
|
|
11393
|
+
mds = [float(x) for x in range(0, 1501, 30)]
|
|
11394
|
+
inc30 = [0.0 if m_ < 300 else min(30.0, (m_ - 300) * 0.1) for m_ in mds] # builds 3 deg/30 m from 300 m, holds 30 from 600 m
|
|
11395
|
+
az90 = [90.0] * len(mds)
|
|
11396
|
+
plan = {"md": mds, "incl": inc30, "azi": az90, "slot": [0.0, 0.0], "ref_elev_m": 0.0}
|
|
11397
|
+
act = {"md": mds[:41], "incl": inc30[:41], "azi": az90[:41], "slot": [0.0, 0.0], "ref_elev_m": 0.0} # drilled to 1,200 m of a 1,500 m plan
|
|
11398
|
+
left = WPL.compare({**act, "slot": [0.0, 5.0]}, plan, fld, prog, 15.0, 30.0) # the well 5 m north of a plan heading east
|
|
11399
|
+
up = WPL.compare({**act, "ref_elev_m": 3.0}, plan, fld, prog, 15.0, 30.0) # the well 3 m above the plan
|
|
11400
|
+
same = WPL.compare(act, plan, fld, prog, 15.0, 30.0)
|
|
11401
|
+
done = WPL.compare(plan, plan, fld, prog, 15.0, 30.0)
|
|
11402
|
+
bld = WPL.compare({"md": mds[:15], "incl": inc30[:15], "azi": az90[:15], "slot": [0.0, 0.0], "ref_elev_m": 0.0}, plan, fld, prog, 15.0, 30.0)
|
|
11403
|
+
la, lu = left["last"], up["last"]
|
|
11404
|
+
phi = _m.atan2(5.0, 30.0)
|
|
11405
|
+
dls_hand = _m.degrees(2 * phi) / (_m.hypot(30.0, 5.0) * phi / _m.sin(phi)) * 30.0
|
|
11406
|
+
c3 = {
|
|
11407
|
+
"left": abs(la["right_m"] + 5.0) < 0.01 and abs(la["high_m"]) < 0.01 and abs(la["distance_m"] - 5.0) < 0.01 and abs(la["d_inc_deg"]) < 0.01,
|
|
11408
|
+
"high": abs(lu["high_m"] - 1.5) < 0.01 and abs(lu["right_m"]) < 0.01,
|
|
11409
|
+
"sigma": la["sigma_right_m"] > 0 and abs(la["n_sigma"] - 5.0 / la["sigma_right_m"]) < 0.02 and same["worst"]["distance_m"] < 0.01,
|
|
11410
|
+
"bit": abs(bld["bit"]["inc_deg"] - (inc30[14] + 1.5)) < 1e-6 and abs(bld["bit"]["build_deg_30m"] - 3.0) < 1e-6 and bld["bit"]["md_m"] == mds[14] + 15.0
|
|
11411
|
+
and bld["bit"]["distance_m"] < 0.05,
|
|
11412
|
+
"steer": abs(left["steer"]["toolface_deg"] - 90.0) < 0.5 and abs(left["steer"]["dls_deg_30m"] - dls_hand) < 0.05 and same["steer"]["dls_deg_30m"] < 0.05
|
|
11413
|
+
and done["steer"]["dls_deg_30m"] is None and "past the plan" in done["steer"]["note"] and done["bit"]["past_plan_td"],
|
|
11414
|
+
"views": len(left["views"]["actual"]["n"]) == 41 and abs(left["views"]["actual"]["n"][0] - 5.0) < 1e-6,
|
|
11415
|
+
}
|
|
11416
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
11417
|
+
ok(not failed3,
|
|
11418
|
+
"CS3 a well against its plan, each figure by construction (drilled to 1,200 m of a 1,500 m plan): a well 5 m north of a plan heading east is 5 m left; 3 m above a "
|
|
11419
|
+
"30-degree hold is 1.5 m high; each set against the survey's standard deviation in its direction; the bit projected 15 m "
|
|
11420
|
+
"holding a 3 deg/30 m build lands on the plan that builds the same; the arc back from 5 m left to the plan 30 m ahead turns "
|
|
11421
|
+
"right (toolface 90) at the severity computed by hand, a well on its plan needs none, and a well at the plan's TD has no plan ahead to steer to"
|
|
11422
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
11423
|
+
|
|
11424
|
+
# -- CS4 planned wells in the collision check; the travelling cylinder --------------------------------------------------
|
|
11425
|
+
mk = lambda i, x, inc, az, prog_=None: {"id": i, "display": i, "md": [0.0, 500.0, 1000.0, 2000.0], "inc": list(inc), "az": list(az), "x0": x, "y0": 0.0,
|
|
11426
|
+
"ref_elev_m": 0.0, "field": fld, "hole_in": 8.5, **({"program": prog_} if prog_ else {})}
|
|
11427
|
+
R1, O1 = CO.prepare(mk("R", 0.0, (0, 0, 0, 0), (0, 0, 0, 0))), CO.prepare(mk("O", 10.0, (0, 0, 0, 0), (0, 0, 0, 0)))
|
|
11428
|
+
R2, O2 = CO.prepare(mk("R", 0.0, (45, 45, 45, 45), (0, 0, 0, 0))), CO.prepare(mk("O", 10.0, (45, 45, 45, 45), (0, 0, 0, 0), [{"to_md_m": None, "model": WP.REV4}]))
|
|
11429
|
+
s1, s2 = CO.scan(R1, O1, CO.DEFAULTS), CO.scan(R2, O2, CO.DEFAULTS)
|
|
11430
|
+
ev = E.selftest_events(str(d))
|
|
11431
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
|
|
11432
|
+
ids = []
|
|
11433
|
+
for i, n in enumerate(("Well A", "Well B", "Well C")):
|
|
11434
|
+
w = ws.add_well_file(ev["path"], display=n, actor="tester"); ids.append(w["id"])
|
|
11435
|
+
ws.set_well(w["id"], surface={"lat": 31.42, "lon": -104.10 + 0.00008 * i, "datum": "NAD83", "elevation": {"ft": 3000.0, "datum": "KB", "source": "test plat"}}, actor="tester")
|
|
11436
|
+
tab = lambda pts: "MD (ft),Inc (deg),Azi (deg)\n" + "\n".join(f"{a},{b},{c}" for a, b, c in pts) + "\n"
|
|
11437
|
+
sur_a = [(m_, 0.0 if m_ < 1500 else min(40.0, (m_ - 1500) * 0.02), 95.0) for m_ in range(0, 4001, 100)]
|
|
11438
|
+
plan_a = [(m_, 0.0 if m_ < 1500 else min(45.0, (m_ - 1500) * 0.02), 95.0) for m_ in range(0, 7001, 250)]
|
|
11439
|
+
W.attach_trajectory(ws, ids[0], "a.csv", tab(sur_a).encode(), "tester", "true", "ft", None, None, None, "MWD report (test)")
|
|
11440
|
+
W.attach_trajectory(ws, ids[1], "b.csv", tab([(m_, 0.0 if m_ < 1200 else min(50.0, (m_ - 1200) * 0.025), 265.0) for m_ in range(0, 5001, 100)]).encode(),
|
|
11441
|
+
"tester", "true", "ft", None, None, None, "MWD report (test)")
|
|
11442
|
+
XR.write_simple(str(d / "planC.xlsx"), [["MD (ft)", "Inc (deg)", "Azi (deg)"]] + [[m_, 0.0 if m_ < 800 else min(40.0, (m_ - 800) * 0.02), 5.0] for m_ in range(0, 6001, 500)])
|
|
11443
|
+
WPL.attach(ws, ids[0], "planA.csv", tab(plan_a).encode(), "tester", "true", "ft", None, None, "well plan rev 1 (test)")
|
|
11444
|
+
WPL.attach(ws, ids[2], "planC.xlsx", (d / "planC.xlsx").read_bytes(), "tester", "true", "ft", None, None, "well plan rev 0 (test)")
|
|
11445
|
+
pg = CO.page(ws)
|
|
11446
|
+
wl = {w_["id"]: w_ for w_ in pg["wells"]}
|
|
11447
|
+
sc3 = W.workspace_scene(ws)
|
|
11448
|
+
c4 = {
|
|
11449
|
+
"vertical_north": all(a_ == 90.0 for a_ in s1["profile"]["tc_deg"]) and all(s1["profile"]["tc_north"]),
|
|
11450
|
+
"high_side": all(abs(a_ - 90.0) < 0.5 for a_, nn in zip(s2["profile"]["tc_deg"], s2["profile"]["tc_north"]) if not nn) and not s2["profile"]["tc_north"][-1]
|
|
11451
|
+
and s2["min_sf"] > 0 and abs(s2["distance_m"] - 10.0) < 1e-6,
|
|
11452
|
+
"planned": len(pg["wells"]) == 3 and wl[ids[2]]["basis"] == "plan" and wl[ids[2]]["display"].endswith("(plan)") and "30 m" in wl[ids[2]]["basis_note"]
|
|
11453
|
+
and wl[ids[0]]["basis"] == "survey + plan" and abs(wl[ids[0]]["td_md_m"] - 7000 * 0.3048) < 0.5 and len(pg["pairs"]) == 6 and not pg["left_out"],
|
|
11454
|
+
"scene": [p_["id"] for p_ in sc3["planned"]] == [ids[0], ids[2]] and [w_["id"] for w_ in sc3["wells"]] == ids[:2]
|
|
11455
|
+
and any(x["id"] == ids[2] and "a plan" in x["why"] for x in sc3["not_placed"]),
|
|
11456
|
+
"models": all(w_["model"] == "MWD+SRGM" for w_ in pg["wells"]),
|
|
11457
|
+
}
|
|
11458
|
+
failed4 = [k for k, v in c4.items() if not v]
|
|
11459
|
+
ok(not failed4,
|
|
11460
|
+
"CS4 the travelling cylinder's directions - a neighbour due east of a vertical well at 90 from north, of a well heading north "
|
|
11461
|
+
"at 45 degrees at 90 from its high side (with one well on the Rev 4 model and one on Rev 5.11, their shared errors those both "
|
|
11462
|
+
"carry); a well not yet drilled checked along its plan (an Excel plan), weighed as surveyed every 30 m; a well being drilled "
|
|
11463
|
+
"along its survey and then its plan to TD; the 3D scene carrying the plans"
|
|
11464
|
+
+ (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
|
|
11465
|
+
|
|
11466
|
+
# -- CS5 the API, the CLI, the report, the dossier, the tabs and the help ----------------------------------------------
|
|
11467
|
+
Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
|
|
11468
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
11469
|
+
base_url = svc.url.rstrip("/")
|
|
11470
|
+
|
|
11471
|
+
def opener(name, pw_):
|
|
11472
|
+
o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
11473
|
+
rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
|
|
11474
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
|
|
11475
|
+
return o
|
|
11476
|
+
|
|
11477
|
+
def call(o, method, path, body=None):
|
|
11478
|
+
rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
11479
|
+
if method == "POST":
|
|
11480
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
|
|
11481
|
+
try:
|
|
11482
|
+
with o.open(rq, timeout=120) as rr_:
|
|
11483
|
+
return rr_.status, json.loads(rr_.read())
|
|
11484
|
+
except urllib.error.HTTPError as e:
|
|
11485
|
+
return e.code, json.loads(e.read())
|
|
11486
|
+
plan_b = _b64.b64encode(tab([(m_, 0.0 if m_ < 1200 else min(55.0, (m_ - 1200) * 0.025), 262.0) for m_ in range(0, 6001, 300)]).encode()).decode()
|
|
11487
|
+
try:
|
|
11488
|
+
V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
|
|
11489
|
+
s_vp, vp = call(V, "GET", "/api/plan?well=" + ids[0])
|
|
11490
|
+
s_tm, tm = call(V, "GET", "/api/tool-models")
|
|
11491
|
+
s_va, _ = call(V, "POST", "/api/plan/attach", {"well_id": ids[1], "filename": "b.csv", "content_b64": plan_b, "azimuth_reference": "true", "source": "x"})
|
|
11492
|
+
s_ns, _ = call(O, "POST", "/api/plan/attach", {"well_id": ids[1], "filename": "b.csv", "content_b64": plan_b, "azimuth_reference": "true", "source": ""})
|
|
11493
|
+
s_nr, _ = call(O, "POST", "/api/plan/attach", {"well_id": ids[1], "filename": "b.csv", "content_b64": plan_b, "azimuth_reference": "", "source": "plan"})
|
|
11494
|
+
s_oa, oa = call(O, "POST", "/api/plan/attach", {"well_id": ids[1], "filename": "b.csv", "content_b64": plan_b, "azimuth_reference": "true", "md_unit": "ft", "source": "plan rev 1 (test)"})
|
|
11495
|
+
s_bp, _ = call(O, "POST", "/api/plan/settings", {"well_id": ids[1], "program": "0-500:NOPE", "source": "p"})
|
|
11496
|
+
s_op, op_ = call(O, "POST", "/api/plan/settings", {"well_id": ids[1], "program": "0-500:MWD+SRGM, 500-:MWD+IFR1", "bit_offset_m": "18", "source": "survey program rev 1 (test)"})
|
|
11497
|
+
s_bo, _ = call(O, "POST", "/api/plan/settings", {"well_id": ids[1], "bit_offset_m": 500})
|
|
11498
|
+
s_pb, pb = call(V, "GET", "/api/plan?well=" + ids[1])
|
|
11499
|
+
s_vw, _ = call(V, "POST", "/api/plan/write", {"well_id": ids[1]})
|
|
11500
|
+
s_ow, ow = call(O, "POST", "/api/plan/write", {"well_id": ids[1]})
|
|
11501
|
+
s_rm, _ = call(O, "POST", "/api/plan/remove", {"well_id": ids[1]})
|
|
11502
|
+
s_r2, _ = call(O, "POST", "/api/plan/remove", {"well_id": ids[1]})
|
|
11503
|
+
s_co, co = call(V, "GET", "/api/collision")
|
|
11504
|
+
finally:
|
|
11505
|
+
svc.stop()
|
|
11506
|
+
cli_m = _sp.run([sys.executable, "-m", "gea", "plan", "--models"], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
11507
|
+
cli_p = _sp.run([sys.executable, "-m", "gea", "plan", "--workspace", wsp, "--well", ids[0], "--program", "MWD+HRGM", "--source", "program (test)"], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
11508
|
+
cli_t = _sp.run([sys.executable, "-m", "gea", "plan", "--workspace", wsp, "--well", ids[0]], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
11509
|
+
cli_w = _sp.run([sys.executable, "-m", "gea", "plan", "--workspace", wsp, "--well", ids[0], "--write"], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
11510
|
+
from . import __version__ as _ver
|
|
11511
|
+
dz = DZ.build(ws, "tester", _ver, None)
|
|
11512
|
+
names = _zf.ZipFile(Path(ws.reports_dir, dz["path"])).namelist()
|
|
11513
|
+
audit = Path(ws.audit_path).read_text(encoding="utf-8")
|
|
11514
|
+
pdf = Path(ws.reports_dir, "wells", ids[0], "plan_vs_actual.pdf")
|
|
11515
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
11516
|
+
c5 = {
|
|
11517
|
+
"api": s_vp == 200 and vp["comparison"] is not None and s_tm == 200 and len(tm["models"]) == 22 and tm["default"] == "MWD+SRGM"
|
|
11518
|
+
and s_va == 403 and s_ns == 400 and s_nr == 400 and s_oa == 200 and oa["stations"] == 21 and s_bp == 400 and s_op == 200
|
|
11519
|
+
and op_["program"][1]["model"] == "MWD+IFR1" and op_["bit_offset_m"] == 18.0 and s_bo == 400 and s_pb == 200 and pb["comparison"]["bit"]["offset_m"] == 18.0
|
|
11520
|
+
and pb["comparison"]["model"] == "MWD+SRGM then MWD+IFR1" and s_vw == 403 and s_ow == 200 and ow["report_id"].startswith("PVA-")
|
|
11521
|
+
and s_rm == 200 and s_r2 == 404 and s_co == 200 and any(w_["model"] == "MWD+SRGM then MWD+IFR1" for w_ in co["wells"]),
|
|
11522
|
+
"cli": cli_m.returncode == 0 and "MWD+SRGM" in cli_m.stdout and "(default)" in cli_m.stdout and "ISCWSA MWD Rev4" in cli_m.stdout
|
|
11523
|
+
and cli_p.returncode == 0 and "MWD+HRGM to TD" in cli_p.stdout and cli_t.returncode == 0 and "the bit projected" in cli_t.stdout
|
|
11524
|
+
and "tools: MWD+HRGM" in cli_t.stdout and cli_w.returncode == 0 and "plan_vs_actual" in cli_w.stdout,
|
|
11525
|
+
"report": pdf.exists() and PR_read_ok(pdf) and "report.plan_vs_actual" in audit and "well.plan" in audit and "well.plan_removed" in audit and "survey_program.declare" in audit,
|
|
11526
|
+
"dossier": bool(names) and f"declarations/wells/{ids[0]}/plan/planA.csv" in names and "declarations/wellpath/survey_program.json" in names
|
|
11527
|
+
and "results/collision.json" in names and f"results/plan_vs_actual/{ids[0]}.json" in names,
|
|
11528
|
+
"page": all(x in page_src for x in ("VIEWS.plan", "['#/plan', 'Plan vs actual']", "/api/plan/attach", "/api/plan/settings", "coCylinder", "#coTcRef", "pvDev")),
|
|
11529
|
+
"help": not H.check("plan") and not H.check("collision") and H.VIEW_TOPIC.get("plan") == "plan" and "travelling cylinder" in (pkg / "help" / "collision.md").read_text(encoding="utf-8"),
|
|
11530
|
+
}
|
|
11531
|
+
failed5 = [k for k, v in c5.items() if not v]
|
|
11532
|
+
ok(not failed5,
|
|
11533
|
+
"CS5 on the API (anyone reads a well against its plan and the tool models; only an operator attaches a plan - its source and "
|
|
11534
|
+
"azimuth reference required - declares a survey program - an unknown tool or a bit offset past 100 m refused - writes the "
|
|
11535
|
+
"report or takes the plan off), the CLI (the models, a program, the comparison, the report), the report as PDF, a signed "
|
|
11536
|
+
"dossier carrying the plans, the programs and both checks, the tabs and the help"
|
|
11537
|
+
+ (f" [failed: {', '.join(failed5)}]" if failed5 else ""))
|
|
11538
|
+
|
|
11539
|
+
|
|
11540
|
+
def PR_read_ok(path) -> bool:
|
|
11541
|
+
from . import pdf_report as PR
|
|
11542
|
+
try:
|
|
11543
|
+
return bool(PR.read(Path(path).read_bytes())["ok"])
|
|
11544
|
+
except Exception:
|
|
11545
|
+
return False
|
|
11546
|
+
|
|
11547
|
+
|
|
11299
11548
|
def main() -> int:
|
|
11300
11549
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
11301
11550
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -11395,6 +11644,7 @@ def main() -> int:
|
|
|
11395
11644
|
section_cp_rig_time(tmp)
|
|
11396
11645
|
section_cq_tied_together(tmp)
|
|
11397
11646
|
section_cr_collision(tmp)
|
|
11647
|
+
section_cs_plan_and_tools(tmp)
|
|
11398
11648
|
if _FAILS:
|
|
11399
11649
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
11400
11650
|
for f in _FAILS:
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""Well collision checks: how close each well's path comes to its neighbours, against how well both are known.
|
|
2
2
|
|
|
3
3
|
Two wells drilled from one pad start metres apart. Each well's position is known only as well as its survey: the
|
|
4
|
-
error model (`wellpos
|
|
4
|
+
error model (`wellpos`: the tool models of the well's survey program, ISCWSA MWD Rev 5.11 unless declared) gives each
|
|
5
|
+
station's covariance, growing with depth. A well not yet drilled is checked along its plan (`wellplan`), weighed as if
|
|
6
|
+
surveyed every 30 m; a well being drilled along its survey and then its plan below it. This module scans every
|
|
5
7
|
well against every other in three dimensions and answers, along the reference well, with the separation factor of the
|
|
6
8
|
ISCWSA collision-avoidance rule (Sawaryn et al., "Well-Collision-Avoidance Separation Rule", SPE Drilling &
|
|
7
9
|
Completion 34(1), 2019):
|
|
@@ -46,6 +48,8 @@ RULE_SOURCE = ('the ISCWSA separation rule (Sawaryn et al., Well-Collision-Avoid
|
|
|
46
48
|
'surface margin 0.3 m and project-ahead 0.5 m as recommended) and the ISCWSA eBook\'s levels (Separation Rules: report below 4.0, '
|
|
47
49
|
'approach limit 1.5, revise below 1.25, dispensation below 1.0)')
|
|
48
50
|
_LOCK = threading.Lock()
|
|
51
|
+
TC_NORTH_BELOW_DEG = 5.0 # the travelling cylinder's angle from north while the reference is within this of vertical
|
|
52
|
+
PLANNED_STATION_M = 30.0 # a plan weighed as if surveyed every 30 m (one stand)
|
|
49
53
|
|
|
50
54
|
|
|
51
55
|
def _path(ws) -> str:
|
|
@@ -113,7 +117,7 @@ def prepare(w: dict, step_m: float = 10.0) -> dict:
|
|
|
113
117
|
p = W3.Path(md, inc, az, w['x0'], w['y0'], w.get('ref_elev_m') or 0.0, 0.0)
|
|
114
118
|
az_true = (az + w.get('az_true_offset_deg', 0.0)) % 360.0
|
|
115
119
|
f = w['field']
|
|
116
|
-
u = WP.
|
|
120
|
+
u = WP.program_uncertainty(md, inc, az_true, p.tvd, f['declination_deg'], f['dip_deg'], f['total_nT'], w.get('program'))
|
|
117
121
|
r = math.radians(-w.get('az_true_offset_deg', 0.0)) # true north -> the frame's north
|
|
118
122
|
R = np.array([[math.cos(r), -math.sin(r), 0.0], [math.sin(r), math.cos(r), 0.0], [0.0, 0.0, 1.0]])
|
|
119
123
|
C = np.einsum('ij,kjl,ml->kim', R, u['cov'], R)
|
|
@@ -125,7 +129,14 @@ def prepare(w: dict, step_m: float = 10.0) -> dict:
|
|
|
125
129
|
t = ((grid - md[j]) / np.where(md[j + 1] > md[j], md[j + 1] - md[j], 1.0)).clip(0.0, 1.0)
|
|
126
130
|
Ci = C[j] * (1 - t)[:, None, None] + C[j + 1] * t[:, None, None]
|
|
127
131
|
Gi = {k: v[j] * (1 - t)[:, None] + v[j + 1] * t[:, None] for k, v in G.items()}
|
|
132
|
+
tng = np.gradient(pos, grid, axis=0) if len(grid) > 1 else np.array([[0.0, 0.0, 1.0]])
|
|
133
|
+
tng = tng / np.maximum(np.linalg.norm(tng, axis=1), 1e-12)[:, None]
|
|
134
|
+
inc_g = np.degrees(np.arccos(np.clip(tng[:, 2], -1.0, 1.0)))
|
|
135
|
+
az_g = np.arctan2(tng[:, 1], tng[:, 0])
|
|
136
|
+
hs = np.stack([np.cos(np.radians(inc_g)) * np.cos(az_g), np.cos(np.radians(inc_g)) * np.sin(az_g), -np.sin(np.radians(inc_g))], axis=1)
|
|
137
|
+
rt = np.stack([-np.sin(az_g), np.cos(az_g), np.zeros(len(grid))], axis=1)
|
|
128
138
|
return {**w, 'grid_md': grid, 'pos': pos, 'cov': Ci, 'glob': Gi, 'radius_m': w.get('hole_in', DEFAULTS['hole_in']) * 0.0254 / 2.0,
|
|
139
|
+
'grid_inc': inc_g, 'hs': hs, 'rt': rt, 'model': u['model'],
|
|
129
140
|
'stations_cov': C, 'stations_md': md, 'td_ellipse': WP.ellipse(C[-1], 1.0)}
|
|
130
141
|
|
|
131
142
|
|
|
@@ -157,13 +168,19 @@ def scan(ref: dict, off: dict, rule: dict) -> dict:
|
|
|
157
168
|
Cr = ref['cov'][i]
|
|
158
169
|
X = np.zeros((3, 3))
|
|
159
170
|
for g_, sr in ref['glob'].items(): # what both wells share moves them together
|
|
171
|
+
if g_ not in off['glob']:
|
|
172
|
+
continue
|
|
160
173
|
so = off['glob'][g_][jj] * (1 - f) + off['glob'][g_][jj + 1] * f
|
|
161
174
|
X += np.outer(sr[i], so)
|
|
162
175
|
var = float(n @ (Cr + Co - X - X.T) @ n)
|
|
163
176
|
sig = math.sqrt(max(var, 0.0))
|
|
164
177
|
sf = (D - ref['radius_m'] - off['radius_m'] - sm) / (k * math.sqrt(sig * sig + spa * spa))
|
|
165
178
|
md_o = float(off['grid_md'][jj] * (1 - f) + off['grid_md'][jj + 1] * f)
|
|
166
|
-
|
|
179
|
+
if ref['grid_inc'][i] < TC_NORTH_BELOW_DEG: # near vertical: the bearing from north
|
|
180
|
+
ang = math.degrees(math.atan2(float(n[1]), float(n[0]))) % 360.0
|
|
181
|
+
else: # clockwise from the reference's high side
|
|
182
|
+
ang = math.degrees(math.atan2(float(n @ ref['rt'][i]), float(n @ ref['hs'][i]))) % 360.0
|
|
183
|
+
out.append((float(ref['grid_md'][i]), float(a[2]), md_o, D, sig, sf, ang))
|
|
167
184
|
arr = np.array(out)
|
|
168
185
|
i_min = int(np.argmin(arr[:, 5]))
|
|
169
186
|
low = arr[:, 5] < float(rule.get('report_below', 4.0))
|
|
@@ -180,7 +197,9 @@ def scan(ref: dict, off: dict, rule: dict) -> dict:
|
|
|
180
197
|
'distance_m': round(float(mn[3]), 3), 'sigma_m': round(float(mn[4]), 3), 'level': lv, 'why': why, 'sections': sections,
|
|
181
198
|
'closest_m': round(float(arr[:, 3].min()), 3), 'closest_at_md_m': round(float(arr[int(np.argmin(arr[:, 3])), 0]), 1),
|
|
182
199
|
'profile': {'md_m': [round(float(x), 1) for x in arr[:, 0]], 'sf': [round(float(min(x, 99.0)), 3) for x in arr[:, 5]],
|
|
183
|
-
'distance_m': [round(float(x), 2) for x in arr[:, 3]], 'sigma_m': [round(float(x), 3) for x in arr[:, 4]]
|
|
200
|
+
'distance_m': [round(float(x), 2) for x in arr[:, 3]], 'sigma_m': [round(float(x), 3) for x in arr[:, 4]],
|
|
201
|
+
'offset_md_m': [round(float(x), 1) for x in arr[:, 2]], 'tc_deg': [round(float(x), 1) for x in arr[:, 6]],
|
|
202
|
+
'tc_north': [bool(x < TC_NORTH_BELOW_DEG) for x in ref['grid_inc']]}}
|
|
184
203
|
|
|
185
204
|
|
|
186
205
|
def _runs(mask):
|
|
@@ -199,16 +218,18 @@ def analyse(wells: List[dict], rule: dict, title: str = '') -> dict:
|
|
|
199
218
|
pairs.sort(key=lambda p: p['min_sf'])
|
|
200
219
|
wl = [{'id': w['id'], 'display': w['display'], 'td_md_m': round(float(w['stations_md'][-1]), 1), 'n_stations': int(len(w['stations_md'])),
|
|
201
220
|
'hole_in': w.get('hole_in', DEFAULTS['hole_in']), 'field': w['field'], 'td_ellipse_1sigma': w['td_ellipse'],
|
|
202
|
-
'slot': [round(float(w['x0']), 2), round(float(w['y0']), 2)], 'field_note': w.get('field_note', ''), 'azimuth_note': w.get('azimuth_note', '')
|
|
221
|
+
'slot': [round(float(w['x0']), 2), round(float(w['y0']), 2)], 'field_note': w.get('field_note', ''), 'azimuth_note': w.get('azimuth_note', ''),
|
|
222
|
+
'model': w['model'], 'basis': w.get('basis', 'survey'), 'basis_note': w.get('basis_note', '')}
|
|
203
223
|
for w in prep]
|
|
204
224
|
worst = pairs[0] if pairs else None
|
|
205
225
|
return {'title': title, 'rule': {k: rule[k] for k in ('k', 'surface_margin_m', 'sigma_pa_m') if k in rule}, 'rule_source': rule.get('rule_source') or RULE_SOURCE,
|
|
206
226
|
'wells': wl, 'pairs': pairs, 'worst': {k: v for k, v in (worst or {}).items() if k != 'profile'} or None,
|
|
207
227
|
'levels': [{'below': lim, 'level': name, 'meaning': why} for lim, name, why in LEVELS],
|
|
208
|
-
'model': '
|
|
228
|
+
'model': 'each well by its survey program\'s tool models (ISCWSA MWD Rev 5.11, MWD+SRGM, unless declared)',
|
|
209
229
|
'not_a_measurement': ['the wells\' true positions: an uncertainty is what the survey tool\'s published error model allows, not a measured miss',
|
|
210
230
|
'a probability of collision: the separation factor is a rule\'s ratio, and the operator\'s standard says what it permits',
|
|
211
|
-
'the hole size when it is not declared (8-1/2 in by default), and the casing beyond it'
|
|
231
|
+
'the hole size when it is not declared (8-1/2 in by default), and the casing beyond it',
|
|
232
|
+
'a plan\'s position: a well not yet drilled is checked along its plan, weighed as if surveyed every 30 m by its program\'s tools']}
|
|
212
233
|
|
|
213
234
|
|
|
214
235
|
# -- the scenes -----------------------------------------------------------------------------------------------------------
|
|
@@ -243,8 +264,11 @@ def workspace_wells(ws) -> Tuple[List[dict], List[dict]]:
|
|
|
243
264
|
sc = W3.workspace_scene(ws)
|
|
244
265
|
s = settings(ws)
|
|
245
266
|
left = list(sc.get('not_placed') or [])
|
|
267
|
+
from . import wellplan as WPL
|
|
246
268
|
out = []
|
|
247
|
-
for
|
|
269
|
+
plans = {p['id']: p for p in sc.get('planned') or []}
|
|
270
|
+
entries = [(w, 'survey') for w in sc['wells']] + [(p, 'plan') for p in plans.values() if not p['surveyed']]
|
|
271
|
+
for w, basis in entries:
|
|
248
272
|
wid = w['id']
|
|
249
273
|
wr = ws.well(wid)
|
|
250
274
|
surf = wr.get('surface') or {}
|
|
@@ -256,16 +280,40 @@ def workspace_wells(ws) -> Tuple[List[dict], List[dict]]:
|
|
|
256
280
|
except Exception:
|
|
257
281
|
pass
|
|
258
282
|
f = GM.field(float(surf.get('lat')), float(surf.get('lon')), 0.0, when or datetime.now(timezone.utc).date())
|
|
259
|
-
st = w['stations']
|
|
260
|
-
|
|
283
|
+
st = dict(w['stations'])
|
|
284
|
+
note = ''
|
|
285
|
+
if basis == 'plan': # a well not yet drilled: its plan, weighed as surveyed every stand
|
|
286
|
+
st = _densify(st, PLANNED_STATION_M)
|
|
287
|
+
note = f'the plan ({w["source"]}), weighed as surveyed every {PLANNED_STATION_M:g} m'
|
|
288
|
+
elif wid in plans and plans[wid]['td_md'] > float(st['md'][-1]) + 1.0: # drilling: the survey, then the plan below it
|
|
289
|
+
pl = _densify(plans[wid]['stations'], PLANNED_STATION_M)
|
|
290
|
+
below = [i for i, m in enumerate(pl['md']) if m > float(st['md'][-1]) + 1.0]
|
|
291
|
+
st = {k: list(st[k]) + [pl[k][i] for i in below] for k in ('md', 'incl', 'azi')}
|
|
292
|
+
basis = 'survey + plan'
|
|
293
|
+
note = f'surveyed to {w["stations"]["md"][-1]:,.1f} m, the plan below it'
|
|
294
|
+
prog = WPL.well_settings(ws, wid)['program']
|
|
295
|
+
out.append({'id': wid, 'display': w['name'] + (' (plan)' if basis == 'plan' else ''), 'md': st['md'], 'inc': st['incl'], 'az': st['azi'], 'az_true_offset_deg': 0.0,
|
|
296
|
+
'program': prog, 'basis': basis, 'basis_note': note,
|
|
261
297
|
'x0': float(w['slot'][0]), 'y0': float(w['slot'][1]), 'ref_elev_m': float(w['ref_elev_m']),
|
|
262
298
|
'field': {'declination_deg': round(f['declination_deg'], 3), 'dip_deg': round(f['dip_deg'], 3), 'total_nT': round(f['total_nT'], 1)},
|
|
263
299
|
'hole_in': s['holes_in'].get(wid, DEFAULTS['hole_in']),
|
|
264
300
|
'field_note': f"WMM2025 at the well for {f['decimal_year']:.2f}" + (f" ({f['note']})" if f['note'] else ''),
|
|
265
301
|
'azimuth_note': w['azimuth']['applied']})
|
|
302
|
+
placed = {x['id'] for x in out}
|
|
303
|
+
left = [x for x in left if x['id'] not in placed]
|
|
266
304
|
return out, left
|
|
267
305
|
|
|
268
306
|
|
|
307
|
+
def _densify(st: dict, step: float) -> dict:
|
|
308
|
+
"""A plan's stations with one added every `step` metres between them, on its arcs (as a survey would see it)."""
|
|
309
|
+
from . import well3d as W3
|
|
310
|
+
from . import wellplan as WPL
|
|
311
|
+
p = W3.Path(st['md'], st['incl'], st['azi'], 0.0, 0.0, 0.0, 0.0)
|
|
312
|
+
mds = sorted(set(np.round(np.concatenate([p.md, np.arange(p.md[0], p.md[-1], step)]), 3).tolist()))
|
|
313
|
+
dirs = [WPL._interp_dir(p, m) for m in mds]
|
|
314
|
+
return {'md': mds, 'incl': [d[0] for d in dirs], 'azi': [d[1] for d in dirs]}
|
|
315
|
+
|
|
316
|
+
|
|
269
317
|
def page(ws, scene: str = 'workspace') -> dict:
|
|
270
318
|
rule = settings(ws)
|
|
271
319
|
if scene == 'volve' or ws is None:
|
|
@@ -277,7 +325,7 @@ def page(ws, scene: str = 'workspace') -> dict:
|
|
|
277
325
|
res = analyse(wells, rule, ws.manifest.get('name') or 'this workspace') if len(wells) >= 2 else {
|
|
278
326
|
'title': ws.manifest.get('name') or 'this workspace', 'wells': [], 'pairs': [], 'worst': None, 'rule': {k: rule[k] for k in ('k', 'surface_margin_m', 'sigma_pa_m')},
|
|
279
327
|
'rule_source': rule.get('rule_source') or RULE_SOURCE, 'levels': [{'below': lim, 'level': name, 'meaning': why} for lim, name, why in LEVELS],
|
|
280
|
-
'model': '
|
|
328
|
+
'model': 'each well by its survey program\'s tool models', 'not_a_measurement': [],
|
|
281
329
|
'detail': f"{len(wells)} well(s) have a surface position, a reference elevation and a survey; a check needs two"}
|
|
282
330
|
res['left_out'] = left
|
|
283
331
|
else:
|