gea-program 0.52.0__tar.gz → 0.53.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.
Files changed (360) hide show
  1. {gea_program-0.52.0 → gea_program-0.53.0}/PKG-INFO +13 -1
  2. {gea_program-0.52.0 → gea_program-0.53.0}/README.md +12 -0
  3. {gea_program-0.52.0 → gea_program-0.53.0}/gea/__init__.py +1 -1
  4. {gea_program-0.52.0 → gea_program-0.53.0}/gea/__main__.py +43 -0
  5. {gea_program-0.52.0 → gea_program-0.53.0}/gea/acceptance_tests.py +161 -0
  6. {gea_program-0.52.0 → gea_program-0.53.0}/gea/dossier.py +15 -3
  7. gea_program-0.53.0/gea/help/torque-drag.md +17 -0
  8. {gea_program-0.52.0 → gea_program-0.53.0}/gea/helplib.py +2 -1
  9. {gea_program-0.52.0 → gea_program-0.53.0}/gea/service.py +17 -0
  10. gea_program-0.53.0/gea/torque_drag.py +509 -0
  11. {gea_program-0.52.0 → gea_program-0.53.0}/gea/web/app.html +63 -1
  12. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/PKG-INFO +13 -1
  13. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/SOURCES.txt +2 -0
  14. {gea_program-0.52.0 → gea_program-0.53.0}/pyproject.toml +1 -1
  15. {gea_program-0.52.0 → gea_program-0.53.0}/LICENSE +0 -0
  16. {gea_program-0.52.0 → gea_program-0.53.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  17. {gea_program-0.52.0 → gea_program-0.53.0}/gea/accuracy_statement.py +0 -0
  18. {gea_program-0.52.0 → gea_program-0.53.0}/gea/alarm_engine.py +0 -0
  19. {gea_program-0.52.0 → gea_program-0.53.0}/gea/alerts.py +0 -0
  20. {gea_program-0.52.0 → gea_program-0.53.0}/gea/backup.py +0 -0
  21. {gea_program-0.52.0 → gea_program-0.53.0}/gea/bench.py +0 -0
  22. {gea_program-0.52.0 → gea_program-0.53.0}/gea/blind_harness.py +0 -0
  23. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  24. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  25. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  26. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  27. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  28. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  29. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  30. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  31. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  32. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  33. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  34. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  35. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  36. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  37. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  38. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  39. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  40. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  41. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  42. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  43. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  44. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  45. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  46. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  47. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  48. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  49. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  50. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  51. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  52. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  53. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  54. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  55. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  56. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  57. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  58. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  59. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  60. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  61. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  62. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  63. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  64. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  65. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  66. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  67. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  68. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  69. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  70. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  71. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  72. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  73. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  74. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  75. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  76. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  77. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  78. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  79. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  80. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  81. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  82. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  83. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  84. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  85. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  86. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  87. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  88. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  89. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  90. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/med_160_sapropels.txt +0 -0
  91. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  92. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  93. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  94. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  95. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  96. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  97. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  98. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  99. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  100. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  101. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  102. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  103. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  104. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  105. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  106. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  107. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  108. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  109. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  110. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  111. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  112. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  113. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  114. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  115. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  116. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  117. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  118. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  119. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  120. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  121. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  122. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  123. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  124. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  125. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  126. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  127. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog_map.py +0 -0
  128. {gea_program-0.52.0 → gea_program-0.53.0}/gea/catalog_register.py +0 -0
  129. {gea_program-0.52.0 → gea_program-0.53.0}/gea/certificates.py +0 -0
  130. {gea_program-0.52.0 → gea_program-0.53.0}/gea/cli.py +0 -0
  131. {gea_program-0.52.0 → gea_program-0.53.0}/gea/client_reports.py +0 -0
  132. {gea_program-0.52.0 → gea_program-0.53.0}/gea/collision.py +0 -0
  133. {gea_program-0.52.0 → gea_program-0.53.0}/gea/config_versioning.py +0 -0
  134. {gea_program-0.52.0 → gea_program-0.53.0}/gea/conformance.py +0 -0
  135. {gea_program-0.52.0 → gea_program-0.53.0}/gea/control_room.py +0 -0
  136. {gea_program-0.52.0 → gea_program-0.53.0}/gea/correlation.py +0 -0
  137. {gea_program-0.52.0 → gea_program-0.53.0}/gea/dashboard.py +0 -0
  138. {gea_program-0.52.0 → gea_program-0.53.0}/gea/declarations.py +0 -0
  139. {gea_program-0.52.0 → gea_program-0.53.0}/gea/deviation.py +0 -0
  140. {gea_program-0.52.0 → gea_program-0.53.0}/gea/dlis.py +0 -0
  141. {gea_program-0.52.0 → gea_program-0.53.0}/gea/dnp3.py +0 -0
  142. {gea_program-0.52.0 → gea_program-0.53.0}/gea/doctor.py +0 -0
  143. {gea_program-0.52.0 → gea_program-0.53.0}/gea/dossier_verify.py +0 -0
  144. {gea_program-0.52.0 → gea_program-0.53.0}/gea/downhole_engine.py +0 -0
  145. {gea_program-0.52.0 → gea_program-0.53.0}/gea/drift_monitor.py +0 -0
  146. {gea_program-0.52.0 → gea_program-0.53.0}/gea/drill_string.py +0 -0
  147. {gea_program-0.52.0 → gea_program-0.53.0}/gea/earth_model.py +0 -0
  148. {gea_program-0.52.0 → gea_program-0.53.0}/gea/economics.py +0 -0
  149. {gea_program-0.52.0 → gea_program-0.53.0}/gea/ed25519.py +0 -0
  150. {gea_program-0.52.0 → gea_program-0.53.0}/gea/edr.py +0 -0
  151. {gea_program-0.52.0 → gea_program-0.53.0}/gea/elevation.py +0 -0
  152. {gea_program-0.52.0 → gea_program-0.53.0}/gea/etp.py +0 -0
  153. {gea_program-0.52.0 → gea_program-0.53.0}/gea/etp12_schemas.json +0 -0
  154. {gea_program-0.52.0 → gea_program-0.53.0}/gea/example_register_map.json +0 -0
  155. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fat_sat.py +0 -0
  156. {gea_program-0.52.0 → gea_program-0.53.0}/gea/files.py +0 -0
  157. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fixtures/README.md +0 -0
  158. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  159. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  160. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  161. {gea_program-0.52.0 → gea_program-0.53.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  162. {gea_program-0.52.0 → gea_program-0.53.0}/gea/follower.py +0 -0
  163. {gea_program-0.52.0 → gea_program-0.53.0}/gea/forward_model.py +0 -0
  164. {gea_program-0.52.0 → gea_program-0.53.0}/gea/frac_hits.py +0 -0
  165. {gea_program-0.52.0 → gea_program-0.53.0}/gea/friction_priors.py +0 -0
  166. {gea_program-0.52.0 → gea_program-0.53.0}/gea/gamma.py +0 -0
  167. {gea_program-0.52.0 → gea_program-0.53.0}/gea/gauge_aging.py +0 -0
  168. {gea_program-0.52.0 → gea_program-0.53.0}/gea/gauge_specs.py +0 -0
  169. {gea_program-0.52.0 → gea_program-0.53.0}/gea/geodesy.py +0 -0
  170. {gea_program-0.52.0 → gea_program-0.53.0}/gea/geomag.py +0 -0
  171. {gea_program-0.52.0 → gea_program-0.53.0}/gea/gravity_reference.py +0 -0
  172. {gea_program-0.52.0 → gea_program-0.53.0}/gea/hartip.py +0 -0
  173. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/TESTER_GUIDE.md +0 -0
  174. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/alarms.md +0 -0
  175. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/alerts.md +0 -0
  176. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/audit-update.md +0 -0
  177. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/backup.md +0 -0
  178. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/catalog.md +0 -0
  179. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/charts.md +0 -0
  180. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/collision.md +0 -0
  181. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/conformance.md +0 -0
  182. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/control-room.md +0 -0
  183. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/data-in.md +0 -0
  184. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/declare.md +0 -0
  185. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/dlis.md +0 -0
  186. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/doctor.md +0 -0
  187. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/dossier.md +0 -0
  188. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/drift.md +0 -0
  189. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/drillstring.md +0 -0
  190. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/economics.md +0 -0
  191. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/edr.md +0 -0
  192. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/etp.md +0 -0
  193. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/field-ports.md +0 -0
  194. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/files.md +0 -0
  195. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/frac-hits.md +0 -0
  196. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/historian.md +0 -0
  197. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/instruments.md +0 -0
  198. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/interval.md +0 -0
  199. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/invoice-check.md +0 -0
  200. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/map.md +0 -0
  201. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/month-end.md +0 -0
  202. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/notifications.md +0 -0
  203. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/opseis.md +0 -0
  204. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/osdu.md +0 -0
  205. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/pad-summary.md +0 -0
  206. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/patches.md +0 -0
  207. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/penetrator.md +0 -0
  208. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/plan.md +0 -0
  209. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/pore-pressure.md +0 -0
  210. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/ppdm.md +0 -0
  211. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/quakeml.md +0 -0
  212. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/quality.md +0 -0
  213. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/report-history.md +0 -0
  214. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/rig-time.md +0 -0
  215. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/seedlink.md +0 -0
  216. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/seismic.md +0 -0
  217. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/setup.md +0 -0
  218. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/simulation.md +0 -0
  219. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/site.md +0 -0
  220. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/sites.md +0 -0
  221. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/slip.md +0 -0
  222. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/soak.md +0 -0
  223. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/sra.md +0 -0
  224. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/start.md +0 -0
  225. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/structure.md +0 -0
  226. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/tools.md +0 -0
  227. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/transients.md +0 -0
  228. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/upkeep.md +0 -0
  229. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/vibration.md +0 -0
  230. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/well-report.md +0 -0
  231. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/well-tests.md +0 -0
  232. {gea_program-0.52.0 → gea_program-0.53.0}/gea/help/well3d.md +0 -0
  233. {gea_program-0.52.0 → gea_program-0.53.0}/gea/housekeeping.py +0 -0
  234. {gea_program-0.52.0 → gea_program-0.53.0}/gea/interval.py +0 -0
  235. {gea_program-0.52.0 → gea_program-0.53.0}/gea/inverse_engine.py +0 -0
  236. {gea_program-0.52.0 → gea_program-0.53.0}/gea/invoice_check.py +0 -0
  237. {gea_program-0.52.0 → gea_program-0.53.0}/gea/jobs.py +0 -0
  238. {gea_program-0.52.0 → gea_program-0.53.0}/gea/live_ports.py +0 -0
  239. {gea_program-0.52.0 → gea_program-0.53.0}/gea/loadtest.py +0 -0
  240. {gea_program-0.52.0 → gea_program-0.53.0}/gea/matplotlib_demo.py +0 -0
  241. {gea_program-0.52.0 → gea_program-0.53.0}/gea/modbus.py +0 -0
  242. {gea_program-0.52.0 → gea_program-0.53.0}/gea/modbus_rtu.py +0 -0
  243. {gea_program-0.52.0 → gea_program-0.53.0}/gea/model_card.py +0 -0
  244. {gea_program-0.52.0 → gea_program-0.53.0}/gea/month_end.py +0 -0
  245. {gea_program-0.52.0 → gea_program-0.53.0}/gea/mqtt_port.py +0 -0
  246. {gea_program-0.52.0 → gea_program-0.53.0}/gea/notify.py +0 -0
  247. {gea_program-0.52.0 → gea_program-0.53.0}/gea/op_seismicity.py +0 -0
  248. {gea_program-0.52.0 → gea_program-0.53.0}/gea/opcua_port.py +0 -0
  249. {gea_program-0.52.0 → gea_program-0.53.0}/gea/operator_app.py +0 -0
  250. {gea_program-0.52.0 → gea_program-0.53.0}/gea/osdu.py +0 -0
  251. {gea_program-0.52.0 → gea_program-0.53.0}/gea/pad_summary.py +0 -0
  252. {gea_program-0.52.0 → gea_program-0.53.0}/gea/patches.py +0 -0
  253. {gea_program-0.52.0 → gea_program-0.53.0}/gea/pdf_report.py +0 -0
  254. {gea_program-0.52.0 → gea_program-0.53.0}/gea/penetrator.py +0 -0
  255. {gea_program-0.52.0 → gea_program-0.53.0}/gea/permits.py +0 -0
  256. {gea_program-0.52.0 → gea_program-0.53.0}/gea/piwebapi.py +0 -0
  257. {gea_program-0.52.0 → gea_program-0.53.0}/gea/pore_pressure.py +0 -0
  258. {gea_program-0.52.0 → gea_program-0.53.0}/gea/ports.py +0 -0
  259. {gea_program-0.52.0 → gea_program-0.53.0}/gea/ppdm.py +0 -0
  260. {gea_program-0.52.0 → gea_program-0.53.0}/gea/profile_catalog.py +0 -0
  261. {gea_program-0.52.0 → gea_program-0.53.0}/gea/project.py +0 -0
  262. {gea_program-0.52.0 → gea_program-0.53.0}/gea/qt6_downhole_app.py +0 -0
  263. {gea_program-0.52.0 → gea_program-0.53.0}/gea/quakeml.py +0 -0
  264. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reconciler.py +0 -0
  265. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  266. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  267. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/WMM2025.COF +0 -0
  268. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  269. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/eia_prices.provenance.json +0 -0
  270. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  271. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  272. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  273. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  274. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  275. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  276. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  277. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  278. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  279. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/mahoning_example.json +0 -0
  280. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/mud_motor_specs.json +0 -0
  281. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/owsg_tool_models.json +0 -0
  282. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/penetrator_ratings.json +0 -0
  283. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/seismicity_protocols.json +0 -0
  284. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/tool_sources.json +0 -0
  285. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/us_outline.json +0 -0
  286. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/us_outline.provenance.json +0 -0
  287. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_3d.provenance.json +0 -0
  288. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  289. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  290. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  291. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_surfaces.json.gz +0 -0
  292. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  293. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  294. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  295. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  296. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  297. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  298. {gea_program-0.52.0 → gea_program-0.53.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  299. {gea_program-0.52.0 → gea_program-0.53.0}/gea/report_history.py +0 -0
  300. {gea_program-0.52.0 → gea_program-0.53.0}/gea/rig_state.py +0 -0
  301. {gea_program-0.52.0 → gea_program-0.53.0}/gea/rock_inventory.py +0 -0
  302. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sample_record.py +0 -0
  303. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sample_well_profile.csv +0 -0
  304. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sbom.py +0 -0
  305. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seedlink.py +0 -0
  306. {gea_program-0.52.0 → gea_program-0.53.0}/gea/segy.py +0 -0
  307. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic.py +0 -0
  308. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_array.py +0 -0
  309. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_assoc.py +0 -0
  310. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_detect.py +0 -0
  311. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_film.py +0 -0
  312. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_harmonic.py +0 -0
  313. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_qc.py +0 -0
  314. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_response.py +0 -0
  315. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_signature.py +0 -0
  316. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_track.py +0 -0
  317. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_uncertainty.py +0 -0
  318. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_unlisted.py +0 -0
  319. {gea_program-0.52.0 → gea_program-0.53.0}/gea/seismic_watch.py +0 -0
  320. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sensor_swap.py +0 -0
  321. {gea_program-0.52.0 → gea_program-0.53.0}/gea/series_cache.py +0 -0
  322. {gea_program-0.52.0 → gea_program-0.53.0}/gea/service_life.py +0 -0
  323. {gea_program-0.52.0 → gea_program-0.53.0}/gea/setup_checklist.py +0 -0
  324. {gea_program-0.52.0 → gea_program-0.53.0}/gea/shapefile.py +0 -0
  325. {gea_program-0.52.0 → gea_program-0.53.0}/gea/shell.py +0 -0
  326. {gea_program-0.52.0 → gea_program-0.53.0}/gea/shut_in.py +0 -0
  327. {gea_program-0.52.0 → gea_program-0.53.0}/gea/simulation.py +0 -0
  328. {gea_program-0.52.0 → gea_program-0.53.0}/gea/site_map.py +0 -0
  329. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sla_report.py +0 -0
  330. {gea_program-0.52.0 → gea_program-0.53.0}/gea/slip.py +0 -0
  331. {gea_program-0.52.0 → gea_program-0.53.0}/gea/soak.py +0 -0
  332. {gea_program-0.52.0 → gea_program-0.53.0}/gea/sra.py +0 -0
  333. {gea_program-0.52.0 → gea_program-0.53.0}/gea/store_forward.py +0 -0
  334. {gea_program-0.52.0 → gea_program-0.53.0}/gea/strata_join.py +0 -0
  335. {gea_program-0.52.0 → gea_program-0.53.0}/gea/structure.py +0 -0
  336. {gea_program-0.52.0 → gea_program-0.53.0}/gea/supervisor.py +0 -0
  337. {gea_program-0.52.0 → gea_program-0.53.0}/gea/survey_cmd.py +0 -0
  338. {gea_program-0.52.0 → gea_program-0.53.0}/gea/survey_view.py +0 -0
  339. {gea_program-0.52.0 → gea_program-0.53.0}/gea/telemetry.py +0 -0
  340. {gea_program-0.52.0 → gea_program-0.53.0}/gea/tool_catalog.py +0 -0
  341. {gea_program-0.52.0 → gea_program-0.53.0}/gea/tool_library.py +0 -0
  342. {gea_program-0.52.0 → gea_program-0.53.0}/gea/tool_taxonomy.py +0 -0
  343. {gea_program-0.52.0 → gea_program-0.53.0}/gea/transient.py +0 -0
  344. {gea_program-0.52.0 → gea_program-0.53.0}/gea/vibration.py +0 -0
  345. {gea_program-0.52.0 → gea_program-0.53.0}/gea/well3d.py +0 -0
  346. {gea_program-0.52.0 → gea_program-0.53.0}/gea/well_assembler.py +0 -0
  347. {gea_program-0.52.0 → gea_program-0.53.0}/gea/well_report.py +0 -0
  348. {gea_program-0.52.0 → gea_program-0.53.0}/gea/well_test_validation.py +0 -0
  349. {gea_program-0.52.0 → gea_program-0.53.0}/gea/wellplan.py +0 -0
  350. {gea_program-0.52.0 → gea_program-0.53.0}/gea/wellpos.py +0 -0
  351. {gea_program-0.52.0 → gea_program-0.53.0}/gea/wits0.py +0 -0
  352. {gea_program-0.52.0 → gea_program-0.53.0}/gea/witsml.py +0 -0
  353. {gea_program-0.52.0 → gea_program-0.53.0}/gea/workspace.py +0 -0
  354. {gea_program-0.52.0 → gea_program-0.53.0}/gea/xlsx_read.py +0 -0
  355. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/dependency_links.txt +0 -0
  356. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/entry_points.txt +0 -0
  357. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/requires.txt +0 -0
  358. {gea_program-0.52.0 → gea_program-0.53.0}/gea_program.egg-info/top_level.txt +0 -0
  359. {gea_program-0.52.0 → gea_program-0.53.0}/setup.cfg +0 -0
  360. {gea_program-0.52.0 → gea_program-0.53.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.52.0
3
+ Version: 0.53.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,18 @@ 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
+ ### Torque and drag
652
+
653
+ The hook load and torque the drill string should take at each bit depth, by
654
+ the soft-string model of Johancsik et al.: pick-up, slack-off and rotating
655
+ off bottom for the declared friction factors and a fan of others (the
656
+ broomstick), the torque rotating off bottom. Against them, the rig's own
657
+ hook loads and torque from the drilling record, read by the rig states -
658
+ tripping out and in, rotating off bottom - and the friction factors that fit
659
+ them, cased and open hole apart. Volve 15/9-F-10 with an example string is
660
+ the worked example. The **Torque & drag** tab, `gea torque-drag`,
661
+ `gea help torque-drag`.
662
+
651
663
  ### Pore pressure
652
664
 
653
665
  The mud-weight window from a well's logs or its drilling record. The
@@ -609,6 +609,18 @@ 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
+ ### Torque and drag
613
+
614
+ The hook load and torque the drill string should take at each bit depth, by
615
+ the soft-string model of Johancsik et al.: pick-up, slack-off and rotating
616
+ off bottom for the declared friction factors and a fan of others (the
617
+ broomstick), the torque rotating off bottom. Against them, the rig's own
618
+ hook loads and torque from the drilling record, read by the rig states -
619
+ tripping out and in, rotating off bottom - and the friction factors that fit
620
+ them, cased and open hole apart. Volve 15/9-F-10 with an example string is
621
+ the worked example. The **Torque & drag** tab, `gea torque-drag`,
622
+ `gea help torque-drag`.
623
+
612
624
  ### Pore pressure
613
625
 
614
626
  The mud-weight window from a well's logs or its drilling record. The
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.52.0"
126
+ __version__ = "0.53.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -622,6 +622,20 @@ def main(argv=None) -> int:
622
622
  p_pl.add_argument("--actor", type=str, default="cli")
623
623
  p_pl.add_argument("--json", action="store_true")
624
624
 
625
+ p_td = sub.add_parser("torque-drag", help="the hook load and torque the string should take at each bit depth (soft-string model), the broomstick, and the friction factors that fit the rig's own trips")
626
+ p_td.add_argument("--workspace", type=str, default=None)
627
+ p_td.add_argument("--well", type=str, default=None)
628
+ p_td.add_argument("--example", action="store_true", help="the worked example (Volve 15/9-F-10 with an example string)")
629
+ p_td.add_argument("--string", type=str, default=None, help="sections from the bit up: 'BHA:300:6.75:95; drill pipe::5:22.6:6.625' (what:length_ft:od_in:lb_ft[:contact_od_in])")
630
+ p_td.add_argument("--mud", type=str, default=None, help="mud density, ppg")
631
+ p_td.add_argument("--mu-cased", type=str, default=None)
632
+ p_td.add_argument("--mu-open", type=str, default=None)
633
+ p_td.add_argument("--block", type=str, default=None, help="the travelling block's weight, klbf (estimated from the record when not declared)")
634
+ p_td.add_argument("--source", type=str, default="", help="where the string and its figures came from")
635
+ p_td.add_argument("--write", action="store_true")
636
+ p_td.add_argument("--actor", type=str, default="cli")
637
+ p_td.add_argument("--json", action="store_true")
638
+
625
639
  p_pp = sub.add_parser("pore-pressure", help="the mud-weight window: overburden, pore pressure by Eaton from the sonic, the resistivity or the d-exponent, and the fracture gradient")
626
640
  p_pp.add_argument("--workspace", type=str, default=None)
627
641
  p_pp.add_argument("--well", type=str, default=None)
@@ -2472,6 +2486,35 @@ def main(argv=None) -> int:
2472
2486
  raise SystemExit(f"collision: {e.args[0] if e.args else e}")
2473
2487
  print(_json.dumps({k: v for k, v in r.items()}, default=str) if a.json else _CO.text(r))
2474
2488
  return 0
2489
+ elif a.cmd == "torque-drag":
2490
+ import json as _json
2491
+ from . import torque_drag as _TND
2492
+ from .cli import _safe_stdout
2493
+ from .workspace import Workspace, WorkspaceError
2494
+ _safe_stdout()
2495
+ try:
2496
+ ws = Workspace(a.workspace) if a.workspace else None
2497
+ scene = "example" if (a.example or ws is None) else "workspace"
2498
+ if ws is not None and any(v is not None for v in (a.string, a.mud, a.mu_cased, a.mu_open, a.block)):
2499
+ if not a.well:
2500
+ raise ValueError("--well is needed")
2501
+ c_ = _TND.set_well(ws, a.actor, a.well, a.source, _TND.parse_string(a.string) if a.string else None, a.mud, a.mu_cased, a.mu_open, a.block)
2502
+ print(f"{a.well}: " + "; ".join(f"{x['what']} {('to surface' if x['length_ft'] is None else format(x['length_ft'], ',.0f') + ' ft')}" for x in (c_.get('string') or []))
2503
+ + f"; mud {c_['mud_ppg']:g} ppg, mu cased {c_['mu_cased']:g}, open {c_['mu_open']:g}")
2504
+ return 0
2505
+ if a.write:
2506
+ if ws is None:
2507
+ raise ValueError("--write needs --workspace")
2508
+ r_ = _TND.write_report(ws, __version__, a.well, a.actor, scene)
2509
+ print(f"wrote {r_['report_id']}: {r_['paths']['html']}")
2510
+ if r_['paths'].get('pdf'):
2511
+ print(f" printable: {r_['paths']['pdf']}")
2512
+ return 0
2513
+ r = _TND.page(ws, scene, a.well)
2514
+ except (KeyError, ValueError, OSError, WorkspaceError) as e:
2515
+ raise SystemExit(f"torque-drag: {e.args[0] if e.args else e}")
2516
+ print(_json.dumps(r, default=str) if a.json else _TND.text(r))
2517
+ return 0
2475
2518
  elif a.cmd == "pore-pressure":
2476
2519
  import json as _json
2477
2520
  from . import pore_pressure as _PPF
@@ -11905,6 +11905,166 @@ def section_cu_pore_pressure(tmp: str) -> None:
11905
11905
  + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
11906
11906
 
11907
11907
 
11908
+ def section_cv_torque_drag(tmp: str) -> None:
11909
+ """Section CV - torque and drag: the soft-string model against closed forms (a vertical string, a straight inclined
11910
+ one pulled and rotated, the capstan over a bend in the vertical plane and in azimuth); a drilling record made by the
11911
+ model with known friction factors, read back by the rig states and fitted to them; the worked example; the API, the
11912
+ CLI, the report, the dossier, the tab and the help."""
11913
+ import http.cookiejar
11914
+ import math as _m
11915
+ import subprocess as _sp
11916
+ import urllib.request
11917
+ import urllib.error
11918
+ import zipfile as _zf
11919
+ import numpy as _np
11920
+ from . import __version__ as _ver
11921
+ from . import dossier as DZ
11922
+ from . import helplib as H
11923
+ from . import rig_state as RS
11924
+ from . import torque_drag as TND
11925
+ from . import well3d as W
11926
+ from .workspace import Workspace
11927
+ from .service import Service, Users
11928
+ pkg = Path(__file__).parent
11929
+ d = Path(tmp, "torquedrag"); d.mkdir()
11930
+
11931
+ # -- CV1 the model against closed forms ------------------------------------------------------------------------------
11932
+ md = _np.linspace(0.0, 10000.0, 101); n = len(md)
11933
+ bf = TND.buoyancy(10.0)
11934
+ Fv, _ = TND.soft_string(md, _np.zeros(n), _np.zeros(n), _np.full(n - 1, 20.0 * bf), _np.full(n - 1, 3.3125), _np.full(n - 1, 0.3), "out")
11935
+ s60, c60 = _m.sin(_m.radians(60)), _m.cos(_m.radians(60))
11936
+ Fo, _ = TND.soft_string(md, _np.full(n, 60.0), _np.zeros(n), _np.full(n - 1, 20.0), _np.full(n - 1, 3.0), _np.full(n - 1, 0.3), "out")
11937
+ Fi, _ = TND.soft_string(md, _np.full(n, 60.0), _np.zeros(n), _np.full(n - 1, 20.0), _np.full(n - 1, 3.0), _np.full(n - 1, 0.3), "in")
11938
+ Fr, Mr = TND.soft_string(md, _np.full(n, 60.0), _np.zeros(n), _np.full(n - 1, 20.0), _np.full(n - 1, 3.0), _np.full(n - 1, 0.3), "rotate")
11939
+ N_ = 9001
11940
+ mc = _np.linspace(0.0, 1000.0, N_)
11941
+ Fc, _ = TND.soft_string(mc, _np.linspace(0.0, 90.0, N_), _np.zeros(N_), _np.zeros(N_ - 1), _np.full(N_ - 1, 3.0), _np.full(N_ - 1, 0.3), "out", 10000.0)
11942
+ Fa, _ = TND.soft_string(mc, _np.full(N_, 90.0), _np.linspace(0.0, 90.0, N_), _np.zeros(N_ - 1), _np.full(N_ - 1, 3.0), _np.full(N_ - 1, 0.3), "out", 10000.0)
11943
+ cap = 10000.0 * _m.exp(0.3 * _m.pi / 2)
11944
+ refused = 0
11945
+ for bad in ([], [{"what": "x", "length_ft": None, "od_in": 5, "weight_lb_ft": 20}, {"what": "y", "length_ft": None, "od_in": 5, "weight_lb_ft": 20}],
11946
+ [{"what": "x", "length_ft": 100, "od_in": 0.5, "weight_lb_ft": 20}], [{"what": "x", "length_ft": 100, "od_in": 5, "weight_lb_ft": 900}],
11947
+ [{"what": "x", "length_ft": 100, "od_in": 6, "weight_lb_ft": 20, "contact_od_in": 5}]):
11948
+ try:
11949
+ TND.check_string(bad)
11950
+ except ValueError:
11951
+ refused += 1
11952
+ c1 = {
11953
+ "vertical": abs(Fv[0] - 20.0 * bf * 10000.0) < 1e-6 and abs(bf - (1 - 10.0 / 65.5)) < 1e-12,
11954
+ "inclined": abs(Fo[0] - 200000.0 * (c60 + 0.3 * s60)) < 1e-6 and abs(Fi[0] - 200000.0 * (c60 - 0.3 * s60)) < 1e-6 and abs(Fr[0] - 200000.0 * c60) < 1e-6
11955
+ and abs(Mr[0] - 0.3 * 200000.0 * s60 * 3.0 / 12.0) < 1e-6,
11956
+ "capstan": abs(Fc[0] / cap - 1) < 5e-5 and abs(Fa[0] / cap - 1) < 5e-5,
11957
+ "string": refused == 5 and TND.parse_string("BHA:300:6.75:95; dp::5:22.6:6.625")[1]["length_ft"] is None,
11958
+ }
11959
+ failed1 = [k for k, v in c1.items() if not v]
11960
+ ok(not failed1,
11961
+ "CV1 the soft-string model against closed forms: a vertical string weighs its buoyed weight; a straight 60-degree string "
11962
+ "pulled, run and rotated gives W(cos + mu sin), W(cos - mu sin), W cos and the torque mu W sin r exactly; a weightless string "
11963
+ "over a 90-degree bend, in the vertical plane or in azimuth, comes to the capstan's e^(mu theta) as the elements shrink; a "
11964
+ "string without sections, with two open-ended, or with a diameter, weight or contact diameter out of range refused"
11965
+ + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
11966
+
11967
+ # -- CV2 a record made by the model, read back ---------------------------------------------------------------------------
11968
+ f = TND.selftest_files(str(d))
11969
+ wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
11970
+ wid = ws.add_well_file(f["record"], display="TD-1", actor="tester")["id"]
11971
+ ws.set_well(wid, surface={"lat": 31.42, "lon": -104.10, "datum": "NAD83", "elevation": {"ft": 3000.0, "datum": "KB", "source": "test plat"}}, actor="tester")
11972
+ no_survey = TND.page(ws, "workspace", wid)["detail"]
11973
+ W.attach_trajectory(ws, wid, "s.csv", Path(f["survey"]).read_bytes(), "tester", "true", "ft", None, None, None, "test survey")
11974
+ no_string = TND.page(ws, "workspace", wid)["detail"]
11975
+ RS.set_casing(ws, "tester", wid, "9-5/8", 4000, "tally (test)")
11976
+ TND.set_well(ws, "tester", wid, "BHA report (test)", f["string"], 10.0, 0.25, 0.30)
11977
+ r = TND.page(ws, "workspace", wid)["result"]
11978
+ fi = r["fits"]
11979
+ m_ = r["measured"]
11980
+ c2 = {
11981
+ "needs": "survey" in no_survey and "string" in no_string,
11982
+ "measured": len(m_["out"]["depth_ft"]) >= 70 and len(m_["in"]["depth_ft"]) >= 70 and len(m_["rotate"]["depth_ft"]) == 9 and abs(r["block_klbf"] - 40.0) < 0.5 and m_["block_estimated"],
11983
+ "open": all(abs(fi[k]["mu"] - 0.24) <= 0.02 for k in ("out:open", "in:open", "torque:open")),
11984
+ "cased": all(abs(fi[k]["mu"] - 0.18) <= 0.02 for k in ("out:cased", "in:cased", "torque:cased")),
11985
+ "weights": abs(r["string_air_klbf"] - (300 * 95.0 + (r["td_ft"] - 300) * 22.6) / 1000.0) < 0.05 and r["shoe_ft"] == 4000.0,
11986
+ }
11987
+ failed2 = [k for k, v in c2.items() if not v]
11988
+ ok(not failed2,
11989
+ "CV2 a drilling record made by the model - a trip out and in stand by stand, the string rotated off bottom every 900 ft, "
11990
+ "friction 0.18 cased above a 4,000 ft shoe and 0.24 open, a 40 klbf block, noise - read back by the rig states: the block "
11991
+ "estimated to half a klbf, the pick-up, slack-off and torque each fitting 0.18 cased and 0.24 open to within 0.02; a well "
11992
+ "without a survey or a string says what it needs"
11993
+ + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
11994
+
11995
+ # -- CV3 the worked example -----------------------------------------------------------------------------------------------
11996
+ ex = TND.example()
11997
+ de = ex["declared"]
11998
+ c3 = {
11999
+ "example": ex["well"] == "15/9-F-10" and abs(ex["td_ft"] - 5300.07 / 0.3048) < 5.0 and ex["max_inc_deg"] > 80
12000
+ and all(de["out"][i] >= de["rotate"][i] >= de["in"][i] for i in range(len(de["depth_ft"])))
12001
+ and de["torque"][-1] > de["torque"][len(de["torque"]) // 2] > 0 and "not from Volve" in ex["config"]["source"],
12002
+ "fan": sorted(ex["fan"]) == ["0.1", "0.2", "0.3", "0.4", "0.5"] and ex["fan"]["0.5"]["out"][-1] > ex["fan"]["0.1"]["out"][-1] and ex["fan"]["0.5"]["in"][-1] < ex["fan"]["0.1"]["in"][-1],
12003
+ }
12004
+ failed3 = [k for k, v in c3.items() if not v]
12005
+ ok(not failed3,
12006
+ "CV3 the worked example, Volve 15/9-F-10's survey to its 5,300 m TD with a string declared for the example: pick-up above "
12007
+ "rotating above slack-off at every depth, the torque growing with depth, the broomstick fanning out with the friction factor"
12008
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
12009
+
12010
+ # -- CV4 the API, the CLI, the report, the dossier, the tab and the help -------------------------------------------------
12011
+ Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
12012
+ svc = Service(wsp, port=0, scheduler=False).start()
12013
+ base_url = svc.url.rstrip("/")
12014
+
12015
+ def opener(name, pw_):
12016
+ o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
12017
+ rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
12018
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
12019
+ return o
12020
+
12021
+ def call(o, method, path, body=None):
12022
+ rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
12023
+ if method == "POST":
12024
+ rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
12025
+ try:
12026
+ with o.open(rq, timeout=120) as rr_:
12027
+ return rr_.status, json.loads(rr_.read())
12028
+ except urllib.error.HTTPError as e:
12029
+ return e.code, json.loads(e.read())
12030
+ try:
12031
+ V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
12032
+ s_vg, vg = call(V, "GET", "/api/torque-drag?well=" + wid)
12033
+ s_ve, ve = call(V, "GET", "/api/torque-drag?scene=example")
12034
+ s_vs, _ = call(V, "POST", "/api/torque-drag/settings", {"well_id": wid, "mud_ppg": 11, "source": "x"})
12035
+ s_os, os_ = call(O, "POST", "/api/torque-drag/settings", {"well_id": wid, "mud_ppg": "11", "string": "BHA:300:6.75:95:6.75; dp::5:22.6:6.625", "source": "mud report (test)"})
12036
+ s_bs, _ = call(O, "POST", "/api/torque-drag/settings", {"well_id": wid, "string": "BHA:300", "source": "x"})
12037
+ s_bm, _ = call(O, "POST", "/api/torque-drag/settings", {"well_id": wid, "mu_open": 0.9, "source": "x"})
12038
+ s_ns, _ = call(O, "POST", "/api/torque-drag/settings", {"well_id": wid, "mud_ppg": 12})
12039
+ s_vw, _ = call(V, "POST", "/api/torque-drag/write", {"well_id": wid})
12040
+ s_ow, ow = call(O, "POST", "/api/torque-drag/write", {"well_id": wid})
12041
+ finally:
12042
+ svc.stop()
12043
+ cli_x = _sp.run([sys.executable, "-m", "gea", "torque-drag", "--example"], capture_output=True, text=True, cwd=str(pkg.parent))
12044
+ cli_s = _sp.run([sys.executable, "-m", "gea", "torque-drag", "--workspace", wsp, "--well", wid, "--mu-open", "0.26", "--source", "offset well (test)"], capture_output=True, text=True, cwd=str(pkg.parent))
12045
+ cli_t = _sp.run([sys.executable, "-m", "gea", "torque-drag", "--workspace", wsp, "--well", wid], capture_output=True, text=True, cwd=str(pkg.parent))
12046
+ dz = DZ.build(ws, "tester", _ver, None)
12047
+ names = _zf.ZipFile(Path(ws.reports_dir, dz["path"])).namelist()
12048
+ audit = Path(ws.audit_path).read_text(encoding="utf-8")
12049
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
12050
+ c4 = {
12051
+ "api": s_vg == 200 and vg["result"]["fits"] and s_ve == 200 and ve["result"]["well"] == "15/9-F-10" and s_vs == 403 and s_os == 200 and os_["mud_ppg"] == 11.0
12052
+ and len(os_["string"]) == 2 and s_bs == 400 and s_bm == 400 and s_ns == 400 and s_vw == 403 and s_ow == 200 and ow["report_id"].startswith("TND-"),
12053
+ "cli": cli_x.returncode == 0 and "15/9-F-10" in cli_x.stdout and cli_s.returncode == 0 and "open 0.26" in cli_s.stdout and cli_t.returncode == 0
12054
+ and "fits mu" in cli_t.stdout and "mud 11 ppg" in cli_t.stdout,
12055
+ "report": PR_read_ok(Path(ws.reports_dir, "wells", wid, "torque_drag.pdf")) and "torque_drag.declare" in audit and "report.torque_drag" in audit,
12056
+ "dossier": "declarations/drillstring/torque_drag.json" in names and f"results/torque_drag/{wid}.json" in names,
12057
+ "page": all(x in page_src for x in ("VIEWS.torquedrag", "['#/torquedrag', 'Torque & drag']", "/api/torque-drag/settings", "tdChart")),
12058
+ "help": not H.check("torque-drag") and H.VIEW_TOPIC.get("torquedrag") == "torque-drag",
12059
+ }
12060
+ failed4 = [k for k, v in c4.items() if not v]
12061
+ ok(not failed4,
12062
+ "CV4 on the API (anyone reads a well's model and the worked example; only an operator declares the string, the mud and the "
12063
+ "friction factors - a section without its figures, a friction factor of 0.9 or a change without its source refused - or "
12064
+ "writes the report), the CLI, the report as PDF, a signed dossier carrying the string and the model, the tab and the help"
12065
+ + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
12066
+
12067
+
11908
12068
  def PR_read_ok(path) -> bool:
11909
12069
  from . import pdf_report as PR
11910
12070
  try:
@@ -12015,6 +12175,7 @@ def main() -> int:
12015
12175
  section_cs_plan_and_tools(tmp)
12016
12176
  section_ct_frac_hits(tmp)
12017
12177
  section_cu_pore_pressure(tmp)
12178
+ section_cv_torque_drag(tmp)
12018
12179
  if _FAILS:
12019
12180
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
12020
12181
  for f in _FAILS:
@@ -277,7 +277,8 @@ def _gather(ws, well_id: Optional[str]) -> Dict[str, List[tuple]]:
277
277
  ('seismicity', 'catalogs.json'), ('seismicity', 'settings.json'), ('config', 'fleet.json'), ('workspace.json',),
278
278
  ('economics', 'invoices', 'terms.json'), ('economics', 'invoices', 'files.json'), ('drillstring', 'rig_time.json'),
279
279
  ('drillstring', 'casing.json'), ('wellpath', 'collision.json'), ('wellpath', 'survey_program.json'),
280
- ('completion', 'frac', 'stages.json'), ('completion', 'frac', 'settings.json'), ('geomech', 'pore_pressure.json')):
280
+ ('completion', 'frac', 'stages.json'), ('completion', 'frac', 'settings.json'), ('geomech', 'pore_pressure.json'),
281
+ ('drillstring', 'torque_drag.json')):
281
282
  p = os.path.join(ws.path, *rel)
282
283
  if os.path.isfile(p):
283
284
  out_list.append((p, 'declarations/' + '/'.join(rel)))
@@ -299,8 +300,8 @@ def _gather(ws, well_id: Optional[str]) -> Dict[str, List[tuple]]:
299
300
 
300
301
  def _results(ws, well_id: Optional[str]) -> List[tuple]:
301
302
  """The invoice cross-check of each well with invoices or reports attached, the rig time of each well with a drilling
302
- record, the collision check, each surveyed well against its plan, each declared well's pore pressure and the
303
- frac-hit check, as JSON computed when the dossier is signed (a check that cannot run is left out, and says why)."""
303
+ record, the collision check, each surveyed well against its plan, each declared well's pore pressure and torque and
304
+ drag, and the frac-hit check, as JSON computed when the dossier is signed (a check that cannot run is left out, and says why)."""
304
305
  out = []
305
306
  wells = [well_id] if well_id else [w['id'] for w in ws.wells()]
306
307
  try:
@@ -338,6 +339,17 @@ def _results(ws, well_id: Optional[str]) -> List[tuple]:
338
339
  indent=1, sort_keys=True, default=str).encode('utf-8')))
339
340
  except Exception as e:
340
341
  out.append(('results/collision_not_run.txt', f'the collision check did not run: {type(e).__name__}: {e}\n'.encode('utf-8')))
342
+ try:
343
+ from . import torque_drag as TND
344
+ declared = (TND._load(ws).get('wells') or {})
345
+ for wid in wells:
346
+ if wid in declared:
347
+ r = TND.page(ws, 'workspace', wid).get('result')
348
+ if r:
349
+ out.append((f'results/torque_drag/{wid}.json', json.dumps({k: v for k, v in r.items() if k != 'fan'}, indent=1, sort_keys=True,
350
+ default=str).encode('utf-8')))
351
+ except Exception as e:
352
+ out.append(('results/torque_drag_not_run.txt', f'the torque-and-drag model did not run: {type(e).__name__}: {e}\n'.encode('utf-8')))
341
353
  try:
342
354
  from . import pore_pressure as PPF
343
355
  declared = (PPF._load(ws).get('wells') or {})
@@ -0,0 +1,17 @@
1
+ # Torque and drag
2
+
3
+ > The hook load and torque the drill string should take at each bit depth, by the soft-string model: pulling out (pick-up), running in (slack-off) and rotating off bottom, for the declared friction factors and a fan of others (the broomstick); against the rig's own hook loads and torque from the drilling record, and the friction factors that fit them, cased and open hole apart. Volve 15/9-F-10 with an example string is the worked example.
4
+
5
+ **The command**: the **Torque & drag** tab: the hook load against bit depth - pick-up, slack-off and rotating for the declared friction factors, faint lines for 0.1 to 0.5, the rig's own points - and the off-bottom torque; the friction factors that fit the rig; the string, the mud, the friction factors and the block weight (the operator role); **Write the report**. From a terminal: `gea torque-drag --workspace C:\site --well W` prints it; `--example` the worked example; `--string "BHA:300:6.75:95; drill pipe::5:22.6:6.625" --mud 10 --mu-cased 0.25 --mu-open 0.3 --block 40 --source "BHA report, pipe tally"` declares the string; `--write` writes the report.
6
+
7
+ **What it needs**: the well's directional survey; the string, from the bit up - each section's name, length (ft; the top section has none: it runs to the surface), outside diameter (in), weight per foot in air with its tool joints (lb/ft) and the diameter it turns on (in; the tool joint's) - with the mud density and its source. The deepest casing shoe declared (Rig time) divides cased from open hole. For the rig's side, a drilling record with hook load, bit depth and hole depth (block height, pump output or standpipe pressure, rotary speed and torque when it has them).
8
+
9
+ **How it is computed**: the soft-string model of Johancsik, Friesen and Dawson (SPE-11380-PA, 1984), element by element from the bit up every 30 ft of the survey's arcs: the normal force N = sqrt((F d_alpha sin theta)^2 + (W sin theta - F d_theta)^2) from the tension below F and the buoyed weight W (weight in air times 1 - mud/65.5 ppg); the tension above F + W cos theta plus (pulling out) or minus (running in) mu N, or without friction rotating; the torque plus mu N r rotating, r the contact radius. The hook load is the surface tension plus the travelling block, declared or estimated from the record (the rig-time rule). From the record, the rig states of Rig time give the hook load tripping out and in with the pumps off, and the hook load and torque rotating off bottom with the pumps on; each is the median of each 100 ft of bit depth. The friction factor that fits each is found over the bins in cased hole first, then in open hole with the cased factor held.
10
+
11
+ **What it writes**: the string and its figures in `drillstring\torque_drag.json` (audit line `torque_drag.declare`), the audit line `report.torque_drag`, and the reports `reports\wells\<well>\torque_drag.*` (or `reports\torque_drag_example.*`; PDF, HTML, markdown, JSON).
12
+
13
+ **The number to check**: the string's buoyed weight against the hook load of a vertical well at TD less the block; one depth's pick-up against the driller's broomstick sheet; a fitted friction factor against the field's usual range.
14
+
15
+ **What this page will not call a measurement**: the friction factor - it is fitted, a number that makes the model match the rig, not a property measured in the hole. Where the string touches - the soft-string model lays the string on the hole as a cable, without its stiffness or the hole's clearance. Buckling - a string pushed past its buckling load in compression is not modelled.
16
+
17
+ **Sources**: Johancsik, Friesen and Dawson, "Torque and Drag in Directional Wells - Prediction and Measurement", SPE-11380-PA, JPT 36(6), 1984. The worked example: Volve 15/9-F-10's survey (Equinor's released data) with a string, mud and friction factors declared for the example.
@@ -58,6 +58,7 @@ INDEX: List[tuple] = [
58
58
  ('plan', 'Plan vs actual', "a well against its directional plan: the distance high or low and right or left at each survey against the survey's own uncertainty, the bit projected, the one arc back to the plan and its toolface; each well's survey program by tool model"),
59
59
  ('frac-hits', 'Frac hits', "what each fracturing stage did to the pressure in the wells around it - none, poroelastic, mixed or a frac hit - the first response and the fluid pumped by then, the distance and the earthquakes beside each stage"),
60
60
  ('pore-pressure', 'Pore pressure', "the mud-weight window from a well's logs or its drilling record: the overburden, the pore pressure by Eaton from the sonic, the resistivity or the d-exponent against a normal compaction trend, the fracture gradient, against measured pressures and the mud used; L07-01 as the worked example"),
61
+ ('torque-drag', 'Torque and drag', "the hook load and torque the drill string should take at each bit depth by the soft-string model, the broomstick of friction factors, and the friction factors that fit the rig's own trips and off-bottom rotation; Volve 15/9-F-10 as the worked example"),
61
62
  ('rig-time', 'Rig time', "what the rig did each second of the drilling record - drilling, the slips, tripping, circulating - its connections timed weight to weight, its trips by speed, and the time lost against the pad's own best quarter"),
62
63
  ('invoice-check', 'The invoice cross-check', "the drilling contractor's daywork invoice, day by day, against the daily drilling reports and the drilling record at the contract's terms: hours, rates, standby, the repair allowance, depth and footage, with the dollars each difference puts in question"),
63
64
  ('economics', 'Economics', 'each well\'s days, footage and cost by the operator\'s own declared rates, against the EIA oil and gas spot prices while it was drilled, and any series the site imports'),
@@ -90,7 +91,7 @@ REQUIRED_LINES = ('**The command**', '**What it writes**', '**The number to chec
90
91
  VIEW_TOPIC: Dict[str, str] = {
91
92
  'home': 'start', 'wells': 'data-in', 'well': 'drift', 'live': 'patches', 'patch': 'patches', 'files': 'files', 'alarms': 'alarms',
92
93
  'approvals': 'well-tests', 'config': 'site', 'reports': 'drift', 'verify': 'start', 'survey': 'data-in', 'jobs': 'site',
93
- 'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'setup': 'setup', 'map': 'map', '3d': 'well3d', 'simulation': 'simulation', 'drillstring': 'drillstring', 'completion': 'penetrator', 'opseis': 'opseis', 'economics': 'economics', 'invoices': 'invoice-check', 'rigtime': 'rig-time', 'collision': 'collision', 'plan': 'plan', 'frac': 'frac-hits', 'porepressure': 'pore-pressure', 'control': 'control-room', 'wall': 'control-room', 'audit': 'audit-update', 'tools': 'tools', 'catalog': 'catalog',
94
+ 'admin': 'site', 'prefs': 'site', 'search': 'start', 'welcome': 'start', 'seismic': 'seismic', 'seismic_station': 'seismic', 'track': 'seismic', 'sar': 'seismic', 'sites': 'sites', 'setup': 'setup', 'map': 'map', '3d': 'well3d', 'simulation': 'simulation', 'drillstring': 'drillstring', 'completion': 'penetrator', 'opseis': 'opseis', 'economics': 'economics', 'invoices': 'invoice-check', 'rigtime': 'rig-time', 'collision': 'collision', 'plan': 'plan', 'frac': 'frac-hits', 'porepressure': 'pore-pressure', 'torquedrag': 'torque-drag', 'control': 'control-room', 'wall': 'control-room', 'audit': 'audit-update', 'tools': 'tools', 'catalog': 'catalog',
94
95
  }
95
96
 
96
97
 
@@ -1921,6 +1921,9 @@ def make_handler(app: App):
1921
1921
  if path == '/api/plan':
1922
1922
  from . import wellplan as WPL
1923
1923
  return self._json(200, App._cr(WPL.page, app.ws, (qs.get('well') or [None])[0]))
1924
+ if path == '/api/torque-drag':
1925
+ from . import torque_drag as TND
1926
+ return self._json(200, App._cr(TND.page, app.ws, (qs.get('scene') or ['workspace'])[0], (qs.get('well') or [None])[0]))
1924
1927
  if path == '/api/pore-pressure':
1925
1928
  from . import pore_pressure as PPF
1926
1929
  return self._json(200, App._cr(PPF.page, app.ws, (qs.get('scene') or ['workspace'])[0], (qs.get('well') or [None])[0]))
@@ -2341,6 +2344,20 @@ def make_handler(app: App):
2341
2344
  return self._json(200, App._cr(RS.remove_casing, app.ws, user['name'], str(b_.get('well_id') or ''), str(b_.get('size') or '')))
2342
2345
  return self._json(200, App._cr(RS.set_casing, app.ws, user['name'], str(b_.get('well_id') or ''), str(b_.get('size') or ''),
2343
2346
  b_.get('shoe_md_ft'), str(b_.get('source') or ''), b_.get('set')))
2347
+ if path in ('/api/torque-drag/settings', '/api/torque-drag/write'):
2348
+ from . import torque_drag as TND
2349
+ from . import __version__ as _v
2350
+ App.require(user, 'operator')
2351
+ b_ = dict(body or {})
2352
+ wid = str(b_.get('well_id') or '')
2353
+ if path.endswith('/settings'):
2354
+ st_ = b_.get('string')
2355
+ if isinstance(st_, str):
2356
+ st_ = App._cr(TND.parse_string, st_) if st_.strip() else None
2357
+ return self._json(200, App._cr(TND.set_well, app.ws, user['name'], wid, str(b_.get('source') or ''), st_, b_.get('mud_ppg'),
2358
+ b_.get('mu_cased'), b_.get('mu_open'), b_.get('block_klbf')))
2359
+ r_ = App._cr(TND.write_report, app.ws, _v, wid or None, user['name'], str(b_.get('scene') or 'workspace'))
2360
+ return self._json(200, {'report_id': r_['report_id']})
2344
2361
  if path in ('/api/pore-pressure/settings', '/api/pore-pressure/measure', '/api/pore-pressure/unmeasure', '/api/pore-pressure/write'):
2345
2362
  from . import pore_pressure as PPF
2346
2363
  from . import __version__ as _v