gea-program 0.61.0__tar.gz → 0.62.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 (372) hide show
  1. {gea_program-0.61.0 → gea_program-0.62.0}/PKG-INFO +4 -2
  2. {gea_program-0.61.0 → gea_program-0.62.0}/README.md +3 -1
  3. {gea_program-0.61.0 → gea_program-0.62.0}/gea/__init__.py +1 -1
  4. {gea_program-0.61.0 → gea_program-0.62.0}/gea/__main__.py +5 -2
  5. {gea_program-0.61.0 → gea_program-0.62.0}/gea/acceptance_tests.py +140 -2
  6. {gea_program-0.61.0 → gea_program-0.62.0}/gea/casing_design.py +200 -34
  7. {gea_program-0.61.0 → gea_program-0.62.0}/gea/declarations.py +6 -3
  8. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/casing.md +4 -4
  9. {gea_program-0.61.0 → gea_program-0.62.0}/gea/web/app.html +3 -2
  10. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/PKG-INFO +4 -2
  11. {gea_program-0.61.0 → gea_program-0.62.0}/pyproject.toml +1 -1
  12. {gea_program-0.61.0 → gea_program-0.62.0}/LICENSE +0 -0
  13. {gea_program-0.61.0 → gea_program-0.62.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
  14. {gea_program-0.61.0 → gea_program-0.62.0}/gea/accuracy_statement.py +0 -0
  15. {gea_program-0.61.0 → gea_program-0.62.0}/gea/alarm_engine.py +0 -0
  16. {gea_program-0.61.0 → gea_program-0.62.0}/gea/alerts.py +0 -0
  17. {gea_program-0.61.0 → gea_program-0.62.0}/gea/backup.py +0 -0
  18. {gea_program-0.61.0 → gea_program-0.62.0}/gea/bench.py +0 -0
  19. {gea_program-0.61.0 → gea_program-0.62.0}/gea/blind_harness.py +0 -0
  20. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
  21. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
  22. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
  23. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
  24. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
  25. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
  26. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
  27. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
  28. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
  29. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
  30. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
  31. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
  32. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
  33. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
  34. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
  35. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
  36. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
  37. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
  38. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
  39. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
  40. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
  41. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
  42. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
  43. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
  44. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
  45. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
  46. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
  47. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
  48. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
  49. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
  50. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
  51. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
  52. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
  53. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
  54. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
  55. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
  56. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
  57. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
  58. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
  59. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
  60. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
  61. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
  62. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
  63. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
  64. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
  65. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
  66. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
  67. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
  68. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
  69. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
  70. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
  71. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
  72. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
  73. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
  74. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
  75. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
  76. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
  77. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
  78. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
  79. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
  80. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
  81. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
  82. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
  83. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
  84. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
  85. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
  86. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
  87. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/med_160_sapropels.txt +0 -0
  88. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
  89. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
  90. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
  91. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
  92. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
  93. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
  94. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
  95. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
  96. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
  97. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
  98. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
  99. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
  100. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
  101. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
  102. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
  103. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
  104. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
  105. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
  106. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
  107. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
  108. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
  109. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
  110. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
  111. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
  112. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
  113. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
  114. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
  115. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
  116. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
  117. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
  118. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
  119. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
  120. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
  121. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
  122. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
  123. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
  124. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog_map.py +0 -0
  125. {gea_program-0.61.0 → gea_program-0.62.0}/gea/catalog_register.py +0 -0
  126. {gea_program-0.61.0 → gea_program-0.62.0}/gea/certificates.py +0 -0
  127. {gea_program-0.61.0 → gea_program-0.62.0}/gea/cli.py +0 -0
  128. {gea_program-0.61.0 → gea_program-0.62.0}/gea/client_reports.py +0 -0
  129. {gea_program-0.61.0 → gea_program-0.62.0}/gea/collision.py +0 -0
  130. {gea_program-0.61.0 → gea_program-0.62.0}/gea/config_versioning.py +0 -0
  131. {gea_program-0.61.0 → gea_program-0.62.0}/gea/conformance.py +0 -0
  132. {gea_program-0.61.0 → gea_program-0.62.0}/gea/control_room.py +0 -0
  133. {gea_program-0.61.0 → gea_program-0.62.0}/gea/correlation.py +0 -0
  134. {gea_program-0.61.0 → gea_program-0.62.0}/gea/dashboard.py +0 -0
  135. {gea_program-0.61.0 → gea_program-0.62.0}/gea/decline.py +0 -0
  136. {gea_program-0.61.0 → gea_program-0.62.0}/gea/deviation.py +0 -0
  137. {gea_program-0.61.0 → gea_program-0.62.0}/gea/dlis.py +0 -0
  138. {gea_program-0.61.0 → gea_program-0.62.0}/gea/dnp3.py +0 -0
  139. {gea_program-0.61.0 → gea_program-0.62.0}/gea/doctor.py +0 -0
  140. {gea_program-0.61.0 → gea_program-0.62.0}/gea/dossier.py +0 -0
  141. {gea_program-0.61.0 → gea_program-0.62.0}/gea/dossier_verify.py +0 -0
  142. {gea_program-0.61.0 → gea_program-0.62.0}/gea/downhole_engine.py +0 -0
  143. {gea_program-0.61.0 → gea_program-0.62.0}/gea/drift_monitor.py +0 -0
  144. {gea_program-0.61.0 → gea_program-0.62.0}/gea/drill_string.py +0 -0
  145. {gea_program-0.61.0 → gea_program-0.62.0}/gea/earth_model.py +0 -0
  146. {gea_program-0.61.0 → gea_program-0.62.0}/gea/economics.py +0 -0
  147. {gea_program-0.61.0 → gea_program-0.62.0}/gea/ed25519.py +0 -0
  148. {gea_program-0.61.0 → gea_program-0.62.0}/gea/edr.py +0 -0
  149. {gea_program-0.61.0 → gea_program-0.62.0}/gea/elevation.py +0 -0
  150. {gea_program-0.61.0 → gea_program-0.62.0}/gea/etp.py +0 -0
  151. {gea_program-0.61.0 → gea_program-0.62.0}/gea/etp12_schemas.json +0 -0
  152. {gea_program-0.61.0 → gea_program-0.62.0}/gea/example_register_map.json +0 -0
  153. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fat_sat.py +0 -0
  154. {gea_program-0.61.0 → gea_program-0.62.0}/gea/files.py +0 -0
  155. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fixtures/README.md +0 -0
  156. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
  157. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
  158. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
  159. {gea_program-0.61.0 → gea_program-0.62.0}/gea/fixtures/ne_110m_coastline.json +0 -0
  160. {gea_program-0.61.0 → gea_program-0.62.0}/gea/follower.py +0 -0
  161. {gea_program-0.61.0 → gea_program-0.62.0}/gea/forward_model.py +0 -0
  162. {gea_program-0.61.0 → gea_program-0.62.0}/gea/frac_hits.py +0 -0
  163. {gea_program-0.61.0 → gea_program-0.62.0}/gea/friction_priors.py +0 -0
  164. {gea_program-0.61.0 → gea_program-0.62.0}/gea/gamma.py +0 -0
  165. {gea_program-0.61.0 → gea_program-0.62.0}/gea/gauge_aging.py +0 -0
  166. {gea_program-0.61.0 → gea_program-0.62.0}/gea/gauge_specs.py +0 -0
  167. {gea_program-0.61.0 → gea_program-0.62.0}/gea/geodesy.py +0 -0
  168. {gea_program-0.61.0 → gea_program-0.62.0}/gea/geomag.py +0 -0
  169. {gea_program-0.61.0 → gea_program-0.62.0}/gea/gravity_reference.py +0 -0
  170. {gea_program-0.61.0 → gea_program-0.62.0}/gea/hartip.py +0 -0
  171. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/IT_SECURITY.md +0 -0
  172. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/TESTER_GUIDE.md +0 -0
  173. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/alarms.md +0 -0
  174. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/alerts.md +0 -0
  175. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/audit-update.md +0 -0
  176. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/backup.md +0 -0
  177. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/catalog.md +0 -0
  178. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/charts.md +0 -0
  179. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/collision.md +0 -0
  180. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/company-sign-in.md +0 -0
  181. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/conformance.md +0 -0
  182. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/control-room.md +0 -0
  183. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/data-in.md +0 -0
  184. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/declare.md +0 -0
  185. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/decline.md +0 -0
  186. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/dlis.md +0 -0
  187. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/doctor.md +0 -0
  188. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/dossier.md +0 -0
  189. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/drift.md +0 -0
  190. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/drillstring.md +0 -0
  191. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/economics.md +0 -0
  192. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/edr.md +0 -0
  193. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/etp.md +0 -0
  194. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/field-ports.md +0 -0
  195. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/files.md +0 -0
  196. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/frac-hits.md +0 -0
  197. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/historian.md +0 -0
  198. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/https.md +0 -0
  199. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/hydraulics.md +0 -0
  200. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/instruments.md +0 -0
  201. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/interval.md +0 -0
  202. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/invoice-check.md +0 -0
  203. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/map.md +0 -0
  204. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/month-end.md +0 -0
  205. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/notifications.md +0 -0
  206. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/opseis.md +0 -0
  207. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/osdu.md +0 -0
  208. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/pad-summary.md +0 -0
  209. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/patches.md +0 -0
  210. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/penetrator.md +0 -0
  211. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/plan.md +0 -0
  212. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/pore-pressure.md +0 -0
  213. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/ppdm.md +0 -0
  214. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/quakeml.md +0 -0
  215. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/quality.md +0 -0
  216. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/report-history.md +0 -0
  217. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/rig-time.md +0 -0
  218. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/seedlink.md +0 -0
  219. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/seismic.md +0 -0
  220. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/setup.md +0 -0
  221. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/simulation.md +0 -0
  222. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/site.md +0 -0
  223. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/sites.md +0 -0
  224. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/slip.md +0 -0
  225. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/soak.md +0 -0
  226. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/sra.md +0 -0
  227. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/start.md +0 -0
  228. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/structure.md +0 -0
  229. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/tools.md +0 -0
  230. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/torque-drag.md +0 -0
  231. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/transients.md +0 -0
  232. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/upkeep.md +0 -0
  233. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/vibration.md +0 -0
  234. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/well-report.md +0 -0
  235. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/well-tests.md +0 -0
  236. {gea_program-0.61.0 → gea_program-0.62.0}/gea/help/well3d.md +0 -0
  237. {gea_program-0.61.0 → gea_program-0.62.0}/gea/helplib.py +0 -0
  238. {gea_program-0.61.0 → gea_program-0.62.0}/gea/housekeeping.py +0 -0
  239. {gea_program-0.61.0 → gea_program-0.62.0}/gea/hydraulics.py +0 -0
  240. {gea_program-0.61.0 → gea_program-0.62.0}/gea/interval.py +0 -0
  241. {gea_program-0.61.0 → gea_program-0.62.0}/gea/inverse_engine.py +0 -0
  242. {gea_program-0.61.0 → gea_program-0.62.0}/gea/invoice_check.py +0 -0
  243. {gea_program-0.61.0 → gea_program-0.62.0}/gea/jobs.py +0 -0
  244. {gea_program-0.61.0 → gea_program-0.62.0}/gea/live_ports.py +0 -0
  245. {gea_program-0.61.0 → gea_program-0.62.0}/gea/loadtest.py +0 -0
  246. {gea_program-0.61.0 → gea_program-0.62.0}/gea/matplotlib_demo.py +0 -0
  247. {gea_program-0.61.0 → gea_program-0.62.0}/gea/modbus.py +0 -0
  248. {gea_program-0.61.0 → gea_program-0.62.0}/gea/modbus_rtu.py +0 -0
  249. {gea_program-0.61.0 → gea_program-0.62.0}/gea/model_card.py +0 -0
  250. {gea_program-0.61.0 → gea_program-0.62.0}/gea/month_end.py +0 -0
  251. {gea_program-0.61.0 → gea_program-0.62.0}/gea/mqtt_port.py +0 -0
  252. {gea_program-0.61.0 → gea_program-0.62.0}/gea/notify.py +0 -0
  253. {gea_program-0.61.0 → gea_program-0.62.0}/gea/oidc.py +0 -0
  254. {gea_program-0.61.0 → gea_program-0.62.0}/gea/oidc_mock.py +0 -0
  255. {gea_program-0.61.0 → gea_program-0.62.0}/gea/op_seismicity.py +0 -0
  256. {gea_program-0.61.0 → gea_program-0.62.0}/gea/opcua_port.py +0 -0
  257. {gea_program-0.61.0 → gea_program-0.62.0}/gea/operator_app.py +0 -0
  258. {gea_program-0.61.0 → gea_program-0.62.0}/gea/osdu.py +0 -0
  259. {gea_program-0.61.0 → gea_program-0.62.0}/gea/pad_summary.py +0 -0
  260. {gea_program-0.61.0 → gea_program-0.62.0}/gea/patches.py +0 -0
  261. {gea_program-0.61.0 → gea_program-0.62.0}/gea/pdf_report.py +0 -0
  262. {gea_program-0.61.0 → gea_program-0.62.0}/gea/penetrator.py +0 -0
  263. {gea_program-0.61.0 → gea_program-0.62.0}/gea/permits.py +0 -0
  264. {gea_program-0.61.0 → gea_program-0.62.0}/gea/piwebapi.py +0 -0
  265. {gea_program-0.61.0 → gea_program-0.62.0}/gea/pore_pressure.py +0 -0
  266. {gea_program-0.61.0 → gea_program-0.62.0}/gea/ports.py +0 -0
  267. {gea_program-0.61.0 → gea_program-0.62.0}/gea/ppdm.py +0 -0
  268. {gea_program-0.61.0 → gea_program-0.62.0}/gea/profile_catalog.py +0 -0
  269. {gea_program-0.61.0 → gea_program-0.62.0}/gea/project.py +0 -0
  270. {gea_program-0.61.0 → gea_program-0.62.0}/gea/qt6_downhole_app.py +0 -0
  271. {gea_program-0.61.0 → gea_program-0.62.0}/gea/quakeml.py +0 -0
  272. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reconciler.py +0 -0
  273. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
  274. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
  275. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/WMM2025.COF +0 -0
  276. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
  277. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/eia_prices.provenance.json +0 -0
  278. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
  279. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/iscwsa_rev4_example.json +0 -0
  280. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/iscwsa_rev5_example.json +0 -0
  281. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/l0701_sonic_gr.las.gz +0 -0
  282. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/l0701_sonic_gr.provenance.json +0 -0
  283. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/libmseed_steim.provenance.json +0 -0
  284. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
  285. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
  286. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
  287. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/mahoning_example.json +0 -0
  288. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/mud_motor_specs.json +0 -0
  289. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/owsg_tool_models.json +0 -0
  290. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/penetrator_ratings.json +0 -0
  291. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/seismicity_protocols.json +0 -0
  292. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/tool_sources.json +0 -0
  293. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/us_outline.json +0 -0
  294. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/us_outline.provenance.json +0 -0
  295. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_3d.provenance.json +0 -0
  296. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
  297. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
  298. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
  299. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_surfaces.json.gz +0 -0
  300. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
  301. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
  302. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
  303. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
  304. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
  305. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
  306. {gea_program-0.61.0 → gea_program-0.62.0}/gea/reference/volve_well_picks.csv.gz +0 -0
  307. {gea_program-0.61.0 → gea_program-0.62.0}/gea/report_history.py +0 -0
  308. {gea_program-0.61.0 → gea_program-0.62.0}/gea/rig_state.py +0 -0
  309. {gea_program-0.61.0 → gea_program-0.62.0}/gea/rock_inventory.py +0 -0
  310. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sample_record.py +0 -0
  311. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sample_well_profile.csv +0 -0
  312. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sbom.py +0 -0
  313. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seedlink.py +0 -0
  314. {gea_program-0.61.0 → gea_program-0.62.0}/gea/segy.py +0 -0
  315. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic.py +0 -0
  316. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_array.py +0 -0
  317. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_assoc.py +0 -0
  318. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_detect.py +0 -0
  319. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_film.py +0 -0
  320. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_harmonic.py +0 -0
  321. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_qc.py +0 -0
  322. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_response.py +0 -0
  323. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_signature.py +0 -0
  324. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_track.py +0 -0
  325. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_uncertainty.py +0 -0
  326. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_unlisted.py +0 -0
  327. {gea_program-0.61.0 → gea_program-0.62.0}/gea/seismic_watch.py +0 -0
  328. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sensor_swap.py +0 -0
  329. {gea_program-0.61.0 → gea_program-0.62.0}/gea/series_cache.py +0 -0
  330. {gea_program-0.61.0 → gea_program-0.62.0}/gea/service.py +0 -0
  331. {gea_program-0.61.0 → gea_program-0.62.0}/gea/service_life.py +0 -0
  332. {gea_program-0.61.0 → gea_program-0.62.0}/gea/setup_checklist.py +0 -0
  333. {gea_program-0.61.0 → gea_program-0.62.0}/gea/shapefile.py +0 -0
  334. {gea_program-0.61.0 → gea_program-0.62.0}/gea/shell.py +0 -0
  335. {gea_program-0.61.0 → gea_program-0.62.0}/gea/shut_in.py +0 -0
  336. {gea_program-0.61.0 → gea_program-0.62.0}/gea/simulation.py +0 -0
  337. {gea_program-0.61.0 → gea_program-0.62.0}/gea/site_map.py +0 -0
  338. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sla_report.py +0 -0
  339. {gea_program-0.61.0 → gea_program-0.62.0}/gea/slip.py +0 -0
  340. {gea_program-0.61.0 → gea_program-0.62.0}/gea/soak.py +0 -0
  341. {gea_program-0.61.0 → gea_program-0.62.0}/gea/sra.py +0 -0
  342. {gea_program-0.61.0 → gea_program-0.62.0}/gea/store_forward.py +0 -0
  343. {gea_program-0.61.0 → gea_program-0.62.0}/gea/strata_join.py +0 -0
  344. {gea_program-0.61.0 → gea_program-0.62.0}/gea/structure.py +0 -0
  345. {gea_program-0.61.0 → gea_program-0.62.0}/gea/supervisor.py +0 -0
  346. {gea_program-0.61.0 → gea_program-0.62.0}/gea/survey_cmd.py +0 -0
  347. {gea_program-0.61.0 → gea_program-0.62.0}/gea/survey_view.py +0 -0
  348. {gea_program-0.61.0 → gea_program-0.62.0}/gea/telemetry.py +0 -0
  349. {gea_program-0.61.0 → gea_program-0.62.0}/gea/tls.py +0 -0
  350. {gea_program-0.61.0 → gea_program-0.62.0}/gea/tool_catalog.py +0 -0
  351. {gea_program-0.61.0 → gea_program-0.62.0}/gea/tool_library.py +0 -0
  352. {gea_program-0.61.0 → gea_program-0.62.0}/gea/tool_taxonomy.py +0 -0
  353. {gea_program-0.61.0 → gea_program-0.62.0}/gea/torque_drag.py +0 -0
  354. {gea_program-0.61.0 → gea_program-0.62.0}/gea/transient.py +0 -0
  355. {gea_program-0.61.0 → gea_program-0.62.0}/gea/vibration.py +0 -0
  356. {gea_program-0.61.0 → gea_program-0.62.0}/gea/well3d.py +0 -0
  357. {gea_program-0.61.0 → gea_program-0.62.0}/gea/well_assembler.py +0 -0
  358. {gea_program-0.61.0 → gea_program-0.62.0}/gea/well_report.py +0 -0
  359. {gea_program-0.61.0 → gea_program-0.62.0}/gea/well_test_validation.py +0 -0
  360. {gea_program-0.61.0 → gea_program-0.62.0}/gea/wellplan.py +0 -0
  361. {gea_program-0.61.0 → gea_program-0.62.0}/gea/wellpos.py +0 -0
  362. {gea_program-0.61.0 → gea_program-0.62.0}/gea/wits0.py +0 -0
  363. {gea_program-0.61.0 → gea_program-0.62.0}/gea/witsml.py +0 -0
  364. {gea_program-0.61.0 → gea_program-0.62.0}/gea/workspace.py +0 -0
  365. {gea_program-0.61.0 → gea_program-0.62.0}/gea/xlsx_read.py +0 -0
  366. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/SOURCES.txt +0 -0
  367. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/dependency_links.txt +0 -0
  368. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/entry_points.txt +0 -0
  369. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/requires.txt +0 -0
  370. {gea_program-0.61.0 → gea_program-0.62.0}/gea_program.egg-info/top_level.txt +0 -0
  371. {gea_program-0.61.0 → gea_program-0.62.0}/setup.cfg +0 -0
  372. {gea_program-0.61.0 → gea_program-0.62.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.61.0
3
+ Version: 0.62.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
@@ -689,7 +689,9 @@ Each casing string's burst, collapse and tension ratings by API TR 5C3,
689
689
  from its size, weight and grade, against the loads the hole can put on it
690
690
  - gas to the surface held by the shoe, an emptied string, the buoyed
691
691
  weight with overpull - with the smallest safety factor and where, and the
692
- gas kick each open hole below a shoe can take and still be shut in. `gea
692
+ gas kick each open hole below a shoe can take and still be shut in - the
693
+ gas a real gas at the well's pressure and temperature, with a swabbed
694
+ kick beside each. `gea
693
695
  casing --example`; declared on the **Casing & kick tolerance** tab, with
694
696
  `gea casing --workspace C:\site --well SWD-1 --strings ...`, or in the
695
697
  declarations sheet. `gea help casing`.
@@ -650,7 +650,9 @@ Each casing string's burst, collapse and tension ratings by API TR 5C3,
650
650
  from its size, weight and grade, against the loads the hole can put on it
651
651
  - gas to the surface held by the shoe, an emptied string, the buoyed
652
652
  weight with overpull - with the smallest safety factor and where, and the
653
- gas kick each open hole below a shoe can take and still be shut in. `gea
653
+ gas kick each open hole below a shoe can take and still be shut in - the
654
+ gas a real gas at the well's pressure and temperature, with a swabbed
655
+ kick beside each. `gea
654
656
  casing --example`; declared on the **Casing & kick tolerance** tab, with
655
657
  `gea casing --workspace C:\site --well SWD-1 --strings ...`, or in the
656
658
  declarations sheet. `gea help casing`.
@@ -123,7 +123,7 @@ from .profile_catalog import (
123
123
  read_pangaea_txt,
124
124
  )
125
125
 
126
- __version__ = "0.61.0"
126
+ __version__ = "0.62.0"
127
127
  __all__ = [
128
128
  "aging_rate", "rate_psi_yr", "accuracy_psi",
129
129
  "Sensor", "SimulatorConfig", "DownholeEngine",
@@ -653,7 +653,9 @@ def main(argv=None) -> int:
653
653
  p_cs.add_argument("--strings", type=str, default=None, help="shallowest shoe first: 'surface:13-3/8:54.5:J55:0-1500:17.5:9.0; intermediate:9-5/8:47:N80:0-7000:12.25:9.8' (what:od:lb_ft:grade:top-shoe:hole_in:mud_ppg[:wall_in])")
654
654
  for k_, h_ in (("td", "the well's TD below the deepest string, ft MD"), ("td-hole", "the hole below the deepest string, in"), ("td-mw", "the mud below the deepest string, ppg"),
655
655
  ("pp", "a pore pressure for the well when the Pore pressure tab has none, ppg"), ("fg", "a fracture gradient for the well when the Pore pressure tab has none, ppg"),
656
- ("kick", "kick intensity above the mud, ppg (0.5)"), ("gas", "gas gradient, psi/ft (0.1)"), ("backup", "burst backup gradient outside, psi/ft (0.465)"),
656
+ ("kick", "kick intensity above the mud, ppg (0.5)"), ("gas", "a fixed gas gradient, psi/ft, in place of the real gas ('none' for the real gas again)"),
657
+ ("gas-sg", "the gas's specific gravity, air 1 (0.65)"), ("surface-temp", "the temperature at the surface, F (70)"),
658
+ ("geothermal", "the geothermal gradient, F per 100 ft (1.5)"), ("backup", "burst backup gradient outside, psi/ft (0.465)"),
657
659
  ("evacuation", "how far the string is emptied for collapse, 0 to 1 (1: to the shoe)"), ("df-burst", "burst design factor (1.1)"),
658
660
  ("df-collapse", "collapse design factor (1.125)"), ("df-tension", "tension design factor (1.6)"), ("overpull", "overpull, klbf (100)"),
659
661
  ("bha-od", "BHA outside diameter, in"), ("bha-length", "BHA length, ft"), ("dp-od", "drill pipe outside diameter, in")):
@@ -2625,7 +2627,8 @@ def main(argv=None) -> int:
2625
2627
  ws = Workspace(a.workspace) if a.workspace else None
2626
2628
  scene = "example" if (a.example or ws is None) else "workspace"
2627
2629
  keys_ = {"td": "td_md_ft", "td_hole": "td_hole_in", "td_mw": "td_mw_ppg", "pp": "pp_ppg", "fg": "fg_ppg", "kick": "kick_intensity_ppg",
2628
- "gas": "gas_gradient_psi_ft", "backup": "backup_gradient_psi_ft", "evacuation": "evacuation", "df_burst": "df_burst",
2630
+ "gas": "gas_gradient_psi_ft", "gas_sg": "gas_sg", "surface_temp": "surface_temp_f", "geothermal": "geothermal_f_100ft",
2631
+ "backup": "backup_gradient_psi_ft", "evacuation": "evacuation", "df_burst": "df_burst",
2629
2632
  "df_collapse": "df_collapse", "df_tension": "df_tension", "overpull": "overpull_klbf", "bha_od": "bha_od_in",
2630
2633
  "bha_length": "bha_length_ft", "dp_od": "dp_od_in"}
2631
2634
  vals_ = {v: getattr(a, k) for k, v in keys_.items() if getattr(a, k) is not None}
@@ -13378,7 +13378,8 @@ def section_dd_casing_design(tmp: str) -> None:
13378
13378
  "match its weight, a string that does not pass through the one above and a short line each answered" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
13379
13379
 
13380
13380
  # -- DD2 the loads and the kick tolerance, by hand on the example -------------------------------------------------------------------
13381
- ex = CSG.example()
13381
+ ex0 = CSG.example() # worked by hand with the fixed 0.1 psi/ft gas of the textbook method (section DE: the real gas)
13382
+ ex = CSG.analyse({**ex0["config"], "gas_gradient_psi_ft": 0.1}, lambda md: float(md), CSG.EXAMPLE_WINDOW)
13382
13383
  sv, iv_, pv = ex["strings"]
13383
13384
  win = CSG.EXAMPLE_WINDOW
13384
13385
 
@@ -13439,7 +13440,9 @@ def section_dd_casing_design(tmp: str) -> None:
13439
13440
  cols_d, cols_l = DC.TABLES["casing_design"]["cols"], DC.TABLES["casing_loads"]["cols"]
13440
13441
  rows = [["[casing_design]", *cols_d], ["", "HY-2", "surface", "13-3/8", "54.5", "J55", "0", "1500", "17.5", "9.0", "", "casing tally (test)"],
13441
13442
  ["", "HY-2", "intermediate", "9.625", "47", "N80", "0", "6000", "12.25", "10", "", "casing tally (test)"],
13442
- ["[casing_loads]", *cols_l], ["", "HY-2", "10000", "8.5", "11", "9.5", "14.5", "0.5", "", "", "", "", "", "", "", "6.75", "400", "5", "drilling program (test)"]]
13443
+ ["[casing_loads]", *cols_l], [""] + [{"well": "HY-2", "td_md_ft": "10000", "td_hole_in": "8.5", "td_mw_ppg": "11", "pp_ppg": "9.5", "fg_ppg": "14.5",
13444
+ "kick_intensity_ppg": "0.5", "bha_od_in": "6.75", "bha_length_ft": "400", "dp_od_in": "5",
13445
+ "source": "drilling program (test)"}.get(c_, "") for c_ in cols_l]]
13443
13446
  import csv as _csv
13444
13447
  import io as _io
13445
13448
  buf = _io.StringIO(); _csv.writer(buf).writerows(rows); sheet.write_text(buf.getvalue(), encoding="utf-8")
@@ -13526,6 +13529,140 @@ def section_dd_casing_design(tmp: str) -> None:
13526
13529
  "RESOLVED and says how far it reaches" + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
13527
13530
 
13528
13531
 
13532
+ def section_de_real_gas(tmp: str) -> None:
13533
+ """Section DE - the kick and the burst load on a real gas: Sutton's pseudocritical properties and Dranchuk and
13534
+ Abou-Kassem's z against an independent implementation; the gas's density, and a column of it integrated up the well
13535
+ along the geothermal temperature; the kick tolerance with the gas's gradient at the bubble's own pressure and
13536
+ temperature and the volume carried between shoe and bottom by p V / z T, and a swabbed kick beside it; a fixed
13537
+ gradient still taken when declared, and the real gas back with 'none'."""
13538
+ import subprocess as _sp
13539
+ from . import casing_design as CSG
13540
+ from . import declarations as DC
13541
+ from . import helplib as H
13542
+ from .workspace import Workspace
13543
+ pkg = Path(__file__).parent
13544
+
13545
+ # -- DE1 the gas's properties ------------------------------------------------------------------------------------------------
13546
+ # reference values from pyrestoolbox 3.8.9 (gas_z / gas_den, zmethod DAK, cmethod SUT), an independent open-source implementation
13547
+ ref = [(3000, 0.65, 200, 0.9048073771833917, 8.819352273478), (6000, 0.65, 250, 1.0923431854133714, 13.58107045798391),
13548
+ (1000, 0.8, 120, 0.8335178869315637, 4.469708326242926), (10000, 0.7, 300, 1.3920860511301727, 17.868657631013313),
13549
+ (500, 0.6, 80, 0.9330965197803314, 1.6082418312797764)]
13550
+ got = [CSG.gas_state(p_ - CSG.ATM, f_, sg_) for p_, sg_, f_, _, _ in ref]
13551
+ tpc, ppc = CSG.pseudo_critical(0.65)
13552
+ tpc8, ppc8 = CSG.pseudo_critical(0.8)
13553
+ low = CSG.z_factor(1.5, 0.01)
13554
+ c1 = {
13555
+ "sutton": abs(tpc - 365.11) < 0.01 and abs(ppc - 670.129) < 0.01 and abs(tpc8 - 401.44) < 0.01 and abs(ppc8 - 649.696) < 0.01,
13556
+ "z": all(abs(g_["z"] - r_[3]) < 1e-5 for g_, r_ in zip(got, ref)),
13557
+ "density": all(abs(g_["rho_lb_ft3"] - r_[4]) / r_[4] < 1e-5 for g_, r_ in zip(got, ref)),
13558
+ "gradient": all(abs(g_["psi_ft"] - g_["rho_lb_ft3"] / 144.0) < 1e-12 for g_ in got),
13559
+ "ideal_limit": abs(low - 1.0) < 0.005 and CSG.z_factor(1.5, 0.0) == 1.0,
13560
+ "chart_shape": CSG.z_factor(1.5, 2.0) < CSG.z_factor(1.5, 1.0) < 1.0 and CSG.z_factor(1.5, 10.0) > 1.0 and CSG.z_factor(1.2, 2.0) < CSG.z_factor(2.0, 2.0),
13561
+ }
13562
+ failed1 = [k for k, v in c1.items() if not v]
13563
+ ok(not failed1,
13564
+ "DE1 the gas: Sutton's pseudocritical temperature and pressure (365.11 R and 670.13 psia for a 0.65 gas), Dranchuk and Abou-Kassem's z and "
13565
+ "the density p M / z R T within 1e-5 of an independent implementation (pyrestoolbox) from 500 to 10,000 psia, 80 to 300 F, gravities 0.6 "
13566
+ "to 0.8; z to 1 as the pressure falls, the Standing-Katz chart's dip and rise" + (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
13567
+
13568
+ # -- DE2 a column of gas up the well ------------------------------------------------------------------------------------------
13569
+ cfg = {**CSG.DEFAULTS}
13570
+ p0 = 0.052 * 11.0 * 10000.0
13571
+ top = CSG.gas_column(cfg, p0, 10000.0, 0.0)
13572
+ p_, z_ = p0, 10000.0 # a fine Euler integration of the same gas, 1 ft at a time
13573
+ while z_ > 0.0:
13574
+ p_ -= CSG.gas_state(p_, CSG.temperature_f(cfg, z_ - 0.5), 0.65)["psi_ft"]
13575
+ z_ -= 1.0
13576
+ hot = CSG.gas_column({**cfg, "geothermal_f_100ft": 2.5}, p0, 10000.0, 0.0)
13577
+ heavy = CSG.gas_column({**cfg, "gas_sg": 0.9}, p0, 10000.0, 0.0)
13578
+ fixed = CSG.gas_column({**cfg, "gas_gradient_psi_ft": 0.1}, p0, 10000.0, 0.0)
13579
+ c2 = {
13580
+ "integrated": abs(top - p_) < 0.5 and abs(top - 4658.6) < 1.0,
13581
+ "hotter_lighter": hot > top and heavy < top,
13582
+ "fixed": abs(fixed - (p0 - 1000.0)) < 1e-9,
13583
+ "temperature": CSG.temperature_f(cfg, 0.0) == 70.0 and abs(CSG.temperature_f(cfg, 10000.0) - 220.0) < 1e-9,
13584
+ }
13585
+ failed2 = [k for k, v in c2.items() if not v]
13586
+ ok(not failed2,
13587
+ "DE2 a column of real gas from 5,720 psi at 10,000 ft (an 11 ppg pore pressure) integrated to the surface along 70 F rising 1.5 F per 100 ft: "
13588
+ "4,659 psi at the surface (an average 0.106 psi/ft), as a 1 ft step integration gives; a hotter well's gas lighter, a heavier gas heavier; a "
13589
+ "declared 0.1 psi/ft taken as it is" + (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
13590
+
13591
+ # -- DE3 the kick tolerance and the burst load on the real gas -----------------------------------------------------------------
13592
+ ex = CSG.example()
13593
+ exf = CSG.analyse({**ex["config"], "gas_gradient_psi_ft": 0.1}, lambda md: float(md), CSG.EXAMPLE_WINDOW)
13594
+ k_, kf = ex["kicks"][1], exf["kicks"][1]
13595
+ win = CSG.EXAMPLE_WINDOW
13596
+ fg_s = float(np.interp(7000.0, win["tvd_ft"], win["fg_ppg"]))
13597
+ p_frac, p_bot = 0.052 * fg_s * 7000.0, 0.052 * k_["kick_ppg"] * 10000.0
13598
+ maasp, sidpp = 0.052 * (fg_s - 11.5) * 7000.0, 0.052 * (k_["kick_ppg"] - 11.5) * 10000.0
13599
+ gm = 0.052 * 11.5
13600
+ h_b = (maasp - sidpp) / (gm - k_["gas_gradient_bottom_psi_ft"])
13601
+ st_b = CSG.gas_state(p_bot - k_["gas_gradient_bottom_psi_ft"] * h_b / 2, CSG.temperature_f(ex["config"], 10000.0 - h_b / 2), 0.65)
13602
+ h_s = (maasp - sidpp) / (gm - k_["gas_gradient_shoe_psi_ft"])
13603
+ st_s = CSG.gas_state(p_frac + k_["gas_gradient_shoe_psi_ft"] * h_s / 2, CSG.temperature_f(ex["config"], 7000.0 + h_s / 2), 0.65)
13604
+ carried = k_["volume_at_shoe_bbl"] * (st_s["p_psia"] / (st_s["z"] * st_s["t_r"])) / (st_b["p_psia"] / (st_b["z"] * st_b["t_r"]))
13605
+ sv = ex["strings"][0]
13606
+ top_load = CSG.gas_column(ex["config"], 0.052 * float(np.interp(1500.0, win["tvd_ft"], win["fg_ppg"])) * 1500.0, 1500.0, 0.0)
13607
+ c3 = {
13608
+ "bubble_gradient": abs(k_["gas_gradient_bottom_psi_ft"] - st_b["psi_ft"]) < 1e-5 and abs(k_["gas_gradient_shoe_psi_ft"] - st_s["psi_ft"]) < 1e-5
13609
+ and k_["gas_gradient_bottom_psi_ft"] > k_["gas_gradient_shoe_psi_ft"],
13610
+ "heights": abs(k_["height_ft"] - h_b) < 0.2 and abs(k_["height_shoe_ft"] - h_s) < 0.2,
13611
+ "carried": abs(k_["volume_shoe_as_bottom_bbl"] - carried) < 0.15 and "real-gas law" in k_["carried_by"] and "Boyle" in kf["carried_by"],
13612
+ "z_t": k_["z_bottom"] > 0 and abs(k_["temp_bottom_f"] - CSG.temperature_f(ex["config"], 10000.0 - h_b / 2)) < 0.1,
13613
+ "swabbed": all(k["swabbed"]["kick_ppg"] == k["mw_ppg"] and k["swabbed"]["volume_bbl"] > k["volume_bbl"] for k in ex["kicks"]),
13614
+ "burst_real": abs(sv["rows"][0]["burst_net_psi"] - top_load) <= 1.0 and sv["rows"][0]["burst_limited_by_shoe"]
13615
+ and "real gas" in sv["gas"] and "0.1 psi/ft" in exf["strings"][0]["gas"],
13616
+ }
13617
+ failed3 = [k for k, v in c3.items() if not v]
13618
+ ok(not failed3,
13619
+ "DE3 on the worked example: the gas's gradient in the bubble at its own middle's pressure and temperature, heavier on bottom than at the shoe; "
13620
+ "the bubble's heights from them; the shoe's volume carried to the bottom by p V / z T (Boyle's law with a fixed gradient); a swabbed kick "
13621
+ "(no underbalance) beside each, larger; the burst load at the top the real gas's column from the fracture pressure at the shoe"
13622
+ + (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
13623
+
13624
+ # -- DE4 declared --------------------------------------------------------------------------------------------------------------
13625
+ d = Path(tmp, "realgas"); d.mkdir()
13626
+ wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad 3", actor="tester")
13627
+ wid = ws.add_well_catalog("volve_f12_f14_production_excerpt", "15/9-F-12", 10000.0, actor="tester")["id"]
13628
+ prog = "surface:13-3/8:54.5:J55:0-1500:17.5:9.0; intermediate:9-5/8:47:N80:0-7000:12.25:9.8"
13629
+ run = lambda *a: _sp.run([sys.executable, "-m", "gea", "casing", "--workspace", wsp, "--well", wid, *a], capture_output=True, text=True, cwd=str(pkg.parent))
13630
+ r1 = run("--strings", prog, "--td", "10000", "--td-hole", "8.5", "--td-mw", "11.5", "--pp", "10", "--fg", "15", "--gas-sg", "0.7", "--surface-temp", "80",
13631
+ "--geothermal", "1.2", "--bha-od", "6.5", "--bha-length", "600", "--dp-od", "5", "--source", "test")
13632
+ c_a = CSG.well_config(ws, wid)
13633
+ r2 = run("--gas", "0.1", "--source", "test")
13634
+ c_b = CSG.well_config(ws, wid)
13635
+ r3 = run("--gas", "none", "--source", "test")
13636
+ c_c = CSG.well_config(ws, wid)
13637
+ pr = run()
13638
+ cols = DC.TABLES["casing_loads"]["cols"]
13639
+ sheet = "\n".join([",".join(["[casing_loads]", *cols]), ",".join([""] + [{"well": wid, "gas_sg": "0.75", "surface_temp_f": "60", "geothermal_f_100ft": "1.8",
13640
+ "source": "drilling program (test)"}.get(c_, "") for c_ in cols])])
13641
+ ps = DC.apply(ws, sheet, "tester", str(d), write=True)
13642
+ c_d = CSG.well_config(ws, wid)
13643
+ try:
13644
+ CSG.set_well(ws, "tester", wid, "x", geothermal_f_100ft=9)
13645
+ lim = ""
13646
+ except ValueError as e:
13647
+ lim = str(e)
13648
+ page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
13649
+ help_txt = H.page("casing") or ""
13650
+ c4 = {
13651
+ "cli": r1.returncode == 0 and c_a["gas_sg"] == 0.7 and c_a["surface_temp_f"] == 80.0 and c_a["geothermal_f_100ft"] == 1.2 and c_a["gas_gradient_psi_ft"] is None,
13652
+ "fixed_and_back": r2.returncode == 0 and c_b["gas_gradient_psi_ft"] == 0.1 and r3.returncode == 0 and c_c["gas_gradient_psi_ft"] is None,
13653
+ "printed": pr.returncode == 0 and "specific gravity 0.7 as a real gas" in pr.stdout and "swabbed (no underbalance)" in pr.stdout,
13654
+ "sheet": ps["applied"] and c_d["gas_sg"] == 0.75 and c_d["surface_temp_f"] == 60.0 and c_d["geothermal_f_100ft"] == 1.8,
13655
+ "limits": "geothermal_f_100ft must be between" in lim,
13656
+ "page_help": "name=\"gas_gradient_psi_ft\"" in page_src and "'gas_sg', 'Gas gravity'" in page_src and "Swabbed (bbl)" in page_src
13657
+ and not H.check("casing") and "Dranchuk and Abou-Kassem" in help_txt and "--gas none" in help_txt,
13658
+ }
13659
+ failed4 = [k for k, v in c4.items() if not v]
13660
+ ok(not failed4,
13661
+ "DE4 the gas declared from the command line (its gravity, the surface temperature, the geothermal gradient), a fixed gradient taken in its place "
13662
+ "and the real gas back with 'none'; the declarations sheet's [casing_loads] carries them; out of range answered; the tab, its kick table and "
13663
+ "the help" + (f" [failed: {', '.join(failed4)}]" if failed4 else ""))
13664
+
13665
+
13529
13666
  def PR_read_ok(path) -> bool:
13530
13667
  from . import pdf_report as PR
13531
13668
  try:
@@ -13645,6 +13782,7 @@ def main() -> int:
13645
13782
  section_db_declarations_engineering(tmp)
13646
13783
  section_dc_every_tab(tmp)
13647
13784
  section_dd_casing_design(tmp)
13785
+ section_de_real_gas(tmp)
13648
13786
  if _FAILS:
13649
13787
  print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
13650
13788
  for f in _FAILS:
@@ -15,9 +15,12 @@ outside diameter D, the wall t and the grade's minimum yield Yp:
15
15
  The loads are the textbook ones (Bourgoyne et al., Applied Drilling Engineering, ch. 7; Rabia, Well Engineering and
16
16
  Construction), on the true vertical depth z:
17
17
 
18
- - burst: inside, gas to the surface from the deepest pore pressure the hole below the shoe reaches (gas gradient 0.1
19
- psi/ft unless declared), no more than the fracture pressure at the shoe less the gas column above it when there is
20
- open hole below; outside, a backup of formation water (0.465 psi/ft unless declared);
18
+ - burst: inside, gas to the surface from the deepest pore pressure the hole below the shoe reaches, no more than the
19
+ fracture pressure at the shoe less the gas column above it when there is open hole below; outside, a backup of
20
+ formation water (0.465 psi/ft unless declared). The gas is a real gas: its density p M / (z R T) at each depth's
21
+ pressure and temperature (the surface temperature and the geothermal gradient), z by Dranchuk and Abou-Kassem's fit
22
+ of the Standing-Katz chart on Sutton's pseudocritical properties for the declared gas gravity, the column integrated
23
+ up the well; a gas gradient declared in psi/ft replaces it;
21
24
  - collapse: outside, the mud the string was run in; inside, the string emptied (or emptied to a declared fraction of
22
25
  its depth) with the next hole's mud below the level;
23
26
  - tension: the string's buoyed weight hanging from its top (the buoyancy factor 1 - MW/65.5), checked against the
@@ -62,10 +65,11 @@ WALLS: Dict[float, Dict[float, float]] = {
62
65
  20.0: {94.0: 0.438, 106.5: 0.500, 133.0: 0.635},
63
66
  }
64
67
  DEFAULTS = {'strings': [], 'td_md_ft': None, 'td_hole_in': None, 'td_mw_ppg': None, 'pp_ppg': None, 'fg_ppg': None, 'kick_intensity_ppg': 0.5,
65
- 'gas_gradient_psi_ft': 0.1, 'backup_gradient_psi_ft': 0.465, 'evacuation': 1.0, 'df_burst': 1.1, 'df_collapse': 1.125, 'df_tension': 1.6,
68
+ 'gas_gradient_psi_ft': None, 'gas_sg': 0.65, 'surface_temp_f': 70.0, 'geothermal_f_100ft': 1.5, 'backup_gradient_psi_ft': 0.465, 'evacuation': 1.0, 'df_burst': 1.1, 'df_collapse': 1.125, 'df_tension': 1.6,
66
69
  'overpull_klbf': 100.0, 'bha_od_in': None, 'bha_length_ft': None, 'dp_od_in': None, 'step_ft': 100.0}
67
70
  LIMITS = {'td_md_ft': (100.0, 40000.0), 'td_hole_in': (2.0, 40.0), 'td_mw_ppg': (6.0, 22.0), 'pp_ppg': (6.0, 22.0), 'fg_ppg': (6.0, 25.0),
68
- 'kick_intensity_ppg': (0.0, 5.0), 'gas_gradient_psi_ft': (0.0, 0.3), 'backup_gradient_psi_ft': (0.0, 0.6), 'evacuation': (0.0, 1.0),
71
+ 'kick_intensity_ppg': (0.0, 5.0), 'gas_gradient_psi_ft': (0.0, 0.3), 'gas_sg': (0.55, 1.5), 'surface_temp_f': (-20.0, 150.0),
72
+ 'geothermal_f_100ft': (0.5, 4.0), 'backup_gradient_psi_ft': (0.0, 0.6), 'evacuation': (0.0, 1.0),
69
73
  'df_burst': (1.0, 2.0), 'df_collapse': (0.8, 2.0), 'df_tension': (1.0, 3.0), 'overpull_klbf': (0.0, 1000.0), 'bha_od_in': (2.0, 20.0),
70
74
  'bha_length_ft': (0.0, 5000.0), 'dp_od_in': (2.0, 10.0), 'step_ft': (20.0, 1000.0)}
71
75
  NOT_A_MEASUREMENT = [
@@ -74,8 +78,8 @@ NOT_A_MEASUREMENT = [
74
78
  "the loads: the textbook cases on the declared mud and the pore pressure and fracture gradient (the Pore pressure tab's, or declared), "
75
79
  "not a well's measured pressures; the temperature and the cement are not in them",
76
80
  "tension: the buoyed weight on the measured length, hanging straight; the drag of a deviated hole and the bending in a dogleg are not added",
77
- "kick tolerance: a single bubble of gas at the gas gradient, Boyle's law without temperature or compressibility; the volume a well can take, "
78
- "not one it has taken",
81
+ "kick tolerance: a single bubble of gas, a sweet natural gas of the declared gravity (no correction for CO2, H2S or nitrogen), at the "
82
+ "declared geothermal temperature, not the circulating one; the volume a well can take, not one it has taken",
79
83
  ]
80
84
  BBL_PER_IN2_FT = 1.0 / 1029.4 # annular capacity: (D^2 - d^2) / 1029.4 bbl per ft
81
85
 
@@ -291,6 +295,120 @@ def set_well(ws, actor: str, well_id: str, source: str = '', strings=None, **val
291
295
  return well_config(ws, well_id)
292
296
 
293
297
 
298
+ # -- the gas: a real gas at the well's pressure and temperature -----------------------------------------------------------------
299
+ SUTTON_TPC = (169.2, 349.5, -74.0) # deg R: Tpc = a + b sg + c sg^2 (Sutton, SPE 14265, 1985)
300
+ SUTTON_PPC = (756.8, -131.0, -3.6) # psia
301
+ DAK = (0.3265, -1.0700, -0.5339, 0.01569, -0.05165, 0.5475, -0.7361, 0.1844, 0.1056, 0.6134, 0.7210) # Dranchuk and Abou-Kassem, 1975
302
+ R_GAS = 10.7316 # psia ft3 / (lb-mol deg R)
303
+ M_AIR = 28.97 # lb / lb-mol
304
+ ATM = 14.696 # psi
305
+
306
+
307
+ def pseudo_critical(sg: float) -> Tuple[float, float]:
308
+ """Sutton's pseudocritical temperature (deg R) and pressure (psia) of a sweet natural gas of specific gravity sg."""
309
+ return (SUTTON_TPC[0] + SUTTON_TPC[1] * sg + SUTTON_TPC[2] * sg * sg, SUTTON_PPC[0] + SUTTON_PPC[1] * sg + SUTTON_PPC[2] * sg * sg)
310
+
311
+
312
+ def z_factor(tpr: float, ppr: float) -> float:
313
+ """The gas deviation factor by Dranchuk and Abou-Kassem's fit of the Standing-Katz chart: the reduced density rho_r
314
+ solving 0 = 1 + C1 rho + C2 rho^2 - C3 rho^5 + C4 (1 + A11 rho^2) rho^2 exp(-A11 rho^2) - 0.27 Ppr / (Tpr rho),
315
+ found by Newton's method from the ideal gas; z = 0.27 Ppr / (Tpr rho_r)."""
316
+ if ppr <= 1e-9:
317
+ return 1.0
318
+ A = DAK
319
+ c1 = A[0] + A[1] / tpr + A[2] / tpr ** 3 + A[3] / tpr ** 4 + A[4] / tpr ** 5
320
+ c2 = A[5] + A[6] / tpr + A[7] / tpr ** 2
321
+ c3 = A[8] * (A[6] / tpr + A[7] / tpr ** 2)
322
+ c4 = A[9] / tpr ** 3
323
+
324
+ def f(r):
325
+ e = math.exp(-A[10] * r * r)
326
+ return 1 + c1 * r + c2 * r * r - c3 * r ** 5 + c4 * (1 + A[10] * r * r) * r * r * e - 0.27 * ppr / (tpr * r)
327
+
328
+ def df(r):
329
+ e = math.exp(-A[10] * r * r)
330
+ return (c1 + 2 * c2 * r - 5 * c3 * r ** 4 + 2 * c4 * r * e * (1 + 2 * A[10] * r * r - A[10] * r * r * (1 + A[10] * r * r))
331
+ + 0.27 * ppr / (tpr * r * r))
332
+ r = 0.27 * ppr / tpr
333
+ for _ in range(100):
334
+ step = f(r) / df(r)
335
+ nr = r - step
336
+ if nr <= 0:
337
+ nr = r / 2
338
+ if abs(nr - r) < 1e-12:
339
+ r = nr
340
+ break
341
+ r = nr
342
+ if not (math.isfinite(r) and r > 0 and abs(f(r)) < 1e-8):
343
+ lo, hi = 1e-6, 3.0 # the gas root lies where f rises through zero; bisect on it
344
+ for _ in range(200):
345
+ mid = 0.5 * (lo + hi)
346
+ if f(mid) < 0:
347
+ lo = mid
348
+ else:
349
+ hi = mid
350
+ r = 0.5 * (lo + hi)
351
+ return 0.27 * ppr / (tpr * r)
352
+
353
+
354
+ def gas_state(p_psig: float, t_f: float, sg: float) -> dict:
355
+ """The gas at a gauge pressure and a temperature: z, its density (lb/ft3, ppg) and its gradient (psi/ft)."""
356
+ tpc, ppc = pseudo_critical(sg)
357
+ pa, tr = max(0.0, p_psig) + ATM, t_f + 459.67
358
+ z = z_factor(tr / tpc, pa / ppc)
359
+ rho = pa * M_AIR * sg / (z * R_GAS * tr)
360
+ return {'z': z, 'rho_lb_ft3': rho, 'ppg': rho / 7.48052, 'psi_ft': rho / 144.0, 'p_psia': pa, 't_r': tr}
361
+
362
+
363
+ def temperature_f(cfg: dict, tvd_ft: float) -> float:
364
+ return float(cfg['surface_temp_f']) + float(cfg['geothermal_f_100ft']) * max(0.0, tvd_ft) / 100.0
365
+
366
+
367
+ def real_gas(cfg: dict) -> bool:
368
+ return cfg.get('gas_gradient_psi_ft') in (None, '')
369
+
370
+
371
+ def gas_column(cfg: dict, p0_psig: float, z0_ft: float, z_ft: float, step_ft: float = 50.0) -> float:
372
+ """The pressure at z_ft in a column of gas whose pressure at z0_ft is p0_psig: the declared gradient, or the real gas's
373
+ own weight integrated along the geothermal temperature (fourth-order Runge-Kutta, 50 ft steps)."""
374
+ if not real_gas(cfg):
375
+ return p0_psig - float(cfg['gas_gradient_psi_ft']) * (z0_ft - z_ft)
376
+ sg = float(cfg['gas_sg'])
377
+ n = max(1, int(math.ceil(abs(z0_ft - z_ft) / step_ft)))
378
+ h = (z_ft - z0_ft) / n
379
+
380
+ def g(z, p):
381
+ return gas_state(p, temperature_f(cfg, z), sg)['psi_ft']
382
+ z, p = z0_ft, p0_psig
383
+ for _ in range(n):
384
+ k1 = g(z, p); k2 = g(z + h / 2, p + h * k1 / 2); k3 = g(z + h / 2, p + h * k2 / 2); k4 = g(z + h, p + h * k3)
385
+ p += h * (k1 + 2 * k2 + 2 * k3 + k4) / 6
386
+ z += h
387
+ return p
388
+
389
+
390
+ def _bubble(cfg: dict, gm: float, maasp: float, sidpp: float, p_anchor: float, z_anchor: float, down: bool) -> dict:
391
+ """A gas bubble whose top (down=True: at the shoe, the anchor) or bottom (down=False: at the bottom of the hole) is at the
392
+ anchor pressure: its height H = (MAASP - SIDPP) / (mud gradient - gas gradient), the gas gradient taken at the bubble's
393
+ middle, found by fixed point; its middle's pressure, temperature and z."""
394
+ gg = float(cfg['gas_gradient_psi_ft']) if not real_gas(cfg) else 0.1
395
+ st = None
396
+ for _ in range(30):
397
+ h = (maasp - sidpp) / (gm - gg) if gm > gg else -1.0
398
+ hm = max(0.0, h) / 2
399
+ zm = z_anchor + hm if down else z_anchor - hm
400
+ pm = p_anchor + gg * hm if down else p_anchor - gg * hm
401
+ if not real_gas(cfg):
402
+ break
403
+ st = gas_state(pm, temperature_f(cfg, zm), float(cfg['gas_sg']))
404
+ if abs(st['psi_ft'] - gg) < 1e-7:
405
+ gg = st['psi_ft']
406
+ break
407
+ gg = st['psi_ft']
408
+ h = (maasp - sidpp) / (gm - gg) if gm > gg else -1.0
409
+ return {'h': h, 'gg': gg, 'mid_p_psig': pm, 'mid_tvd_ft': zm, 'state': st}
410
+
411
+
294
412
  # -- the loads -------------------------------------------------------------------------------------------------------------------
295
413
  def _section_below(cfg: dict, i: int) -> Optional[dict]:
296
414
  """The hole drilled below string i's shoe: to the next string's shoe (its hole, its mud), or for the deepest to the
@@ -318,9 +436,28 @@ def _fg(win, tvd: float) -> Optional[float]:
318
436
  return _at(win, tvd)[1]
319
437
 
320
438
 
439
+ def gas_how(cfg: dict) -> str:
440
+ if real_gas(cfg):
441
+ return (f"a natural gas of specific gravity {float(cfg['gas_sg']):g} as a real gas (z by Dranchuk and Abou-Kassem, pseudocritical properties by "
442
+ f"Sutton) at the well's temperature, {float(cfg['surface_temp_f']):g} F at the surface rising {float(cfg['geothermal_f_100ft']):g} F per 100 ft")
443
+ return f"a gas gradient of {float(cfg['gas_gradient_psi_ft']):g} psi/ft as declared"
444
+
445
+
446
+ def _column_at(cfg: dict, p0: float, z0: float, zs: List[float]) -> List[float]:
447
+ """The gas column's pressure at each of the TVDs zs (shallower than z0), from p0 at z0: integrated once, upward, through them."""
448
+ order = sorted(range(len(zs)), key=lambda k: -zs[k])
449
+ out = [0.0] * len(zs)
450
+ z, p = z0, p0
451
+ for k in order:
452
+ p = gas_column(cfg, p, z, min(zs[k], z)) if zs[k] < z else p
453
+ z = min(zs[k], z)
454
+ out[k] = p if zs[k] <= z0 else p0
455
+ return out
456
+
457
+
321
458
  def string_loads(cfg: dict, i: int, tvd_of, win) -> dict:
322
459
  s = cfg['strings'][i]
323
- gg, gb = float(cfg['gas_gradient_psi_ft']), float(cfg['backup_gradient_psi_ft'])
460
+ gb = float(cfg['backup_gradient_psi_ft'])
324
461
  below = _section_below(cfg, i)
325
462
  ds = tvd_of(s['shoe_md_ft'])
326
463
  open_below = below is not None
@@ -341,12 +478,15 @@ def string_loads(cfg: dict, i: int, tvd_of, win) -> dict:
341
478
  mds = sorted(set([s['top_md_ft'], s['shoe_md_ft']] + [float(x) for x in np.arange(math.ceil(s['top_md_ft'] / step) * step, s['shoe_md_ft'], step)]))
342
479
  rows = []
343
480
  level = float(cfg['evacuation']) * ds
344
- for md in mds:
345
- z = tvd_of(md)
346
- pin_b = p_res - gg * (dres - z)
481
+ zs = [tvd_of(md) for md in mds]
482
+ col_res = _column_at(cfg, p_res, dres, zs)
483
+ col_frac = _column_at(cfg, p_frac, ds, zs) if p_frac is not None else None
484
+ for k, md in enumerate(mds):
485
+ z = zs[k]
486
+ pin_b = col_res[k]
347
487
  limited = False
348
- if p_frac is not None and p_frac - gg * (ds - z) < pin_b:
349
- pin_b, limited = p_frac - gg * (ds - z), True
488
+ if col_frac is not None and col_frac[k] < pin_b:
489
+ pin_b, limited = col_frac[k], True
350
490
  pout_b = gb * z
351
491
  net_b = pin_b - pout_b
352
492
  pout_c = 0.052 * s['mw_ppg'] * z
@@ -380,6 +520,7 @@ def string_loads(cfg: dict, i: int, tvd_of, win) -> dict:
380
520
  return {'string': s, 'below': below, 'shoe_tvd_ft': round(ds, 1), 'reservoir_tvd_ft': round(dres, 1), 'pore_ppg': round(pp, 3), 'pore_how': pp_how,
381
521
  'fg_shoe_ppg': round(fg_shoe, 3) if fg_shoe is not None else None, 'mud_inside_ppg': mw_in, 'buoyancy_factor': round(bf, 4),
382
522
  'rows': rows, 'checks': checks, 'ok': all(c['ok'] for c in checks.values()),
523
+ 'gas': gas_how(cfg),
383
524
  'burst_case': ('gas to the surface from the pore pressure at the bottom of the hole below (' + pp_how + ')'
384
525
  + (', no more than the fracture pressure at the shoe less the gas above it' if p_frac is not None else '')
385
526
  if open_below else 'gas to the surface from the pore pressure at the shoe (' + pp_how + ')'),
@@ -439,33 +580,46 @@ def kick_tolerance(cfg: dict, i: int, tvd_of, win) -> Optional[dict]:
439
580
  if fg is None:
440
581
  out.update({'status': 'NOT KNOWN', 'detail': 'the fracture gradient at the shoe is not known (the Pore pressure tab, or declare one)'})
441
582
  return out
442
- gm, gg = 0.052 * mw, float(cfg['gas_gradient_psi_ft'])
583
+ gm = 0.052 * mw
443
584
  maasp = 0.052 * (fg - mw) * ds
444
585
  sidpp = 0.052 * (pp - mw) * dt
445
- out.update({'maasp_psi': round(maasp), 'sidpp_psi': round(sidpp)})
446
- if gm <= gg:
447
- out.update({'status': 'NOT KNOWN', 'detail': 'the mud is lighter than the gas gradient declared'})
586
+ p_frac, p_bot = 0.052 * fg * ds, 0.052 * pp * dt
587
+ out.update({'maasp_psi': round(maasp), 'sidpp_psi': round(sidpp), 'gas': gas_how(cfg)})
588
+ bot = _bubble(cfg, gm, maasp, sidpp, p_bot, dt, down=False) # the bubble on bottom, as it is shut in
589
+ sho = _bubble(cfg, gm, maasp, sidpp, p_frac, ds, down=True) # the bubble circulated up to the shoe
590
+ out.update({'gas_gradient_bottom_psi_ft': round(bot['gg'], 6), 'gas_gradient_shoe_psi_ft': round(sho['gg'], 6)})
591
+ if real_gas(cfg):
592
+ out.update({'z_bottom': round(bot['state']['z'], 4), 'z_shoe': round(sho['state']['z'], 4),
593
+ 'temp_bottom_f': round(temperature_f(cfg, bot['mid_tvd_ft']), 1), 'temp_shoe_f': round(temperature_f(cfg, sho['mid_tvd_ft']), 1)})
594
+ if gm <= max(bot['gg'], sho['gg']):
595
+ out.update({'status': 'NOT KNOWN', 'detail': 'the mud is no heavier than the gas'})
448
596
  return out
449
- h = (maasp - sidpp) / (gm - gg)
450
597
  open_h = dt - ds
451
- out['height_ft'] = round(max(0.0, min(h, open_h)), 1)
452
- out['height_capped'] = h > open_h
453
- if h <= 0:
598
+ hb, hs = min(bot['h'], open_h), min(sho['h'], open_h)
599
+ out['height_ft'] = round(max(0.0, hb), 1)
600
+ out['height_shoe_ft'] = round(max(0.0, hs), 1)
601
+ out['height_capped'] = bot['h'] > open_h
602
+ if bot['h'] <= 0:
454
603
  out.update({'volume_bbl': 0.0, 'detail': 'the shoe cannot hold the shut-in pressure of a kick of this intensity: no kick tolerance'})
455
604
  return out
456
605
  cap = _capacity_profile(cfg, below['hole_in'] or 0.0, md_b)
457
606
  if cap is None:
458
607
  out.update({'status': 'HEIGHT ONLY', 'detail': 'declare the BHA (outside diameter, length) and the drill pipe (outside diameter) for the volume'})
459
608
  return out
460
- hh = min(h, open_h)
461
- md_top_bottom = _md_at_tvd(tvd_of, dt - hh, md_s, md_b)
609
+ md_top_bottom = _md_at_tvd(tvd_of, dt - hb, md_s, md_b)
462
610
  v_bottom = _volume(cap, tvd_of, md_top_bottom, md_b)
463
- md_low_shoe = _md_at_tvd(tvd_of, ds + hh, md_s, md_b)
611
+ md_low_shoe = _md_at_tvd(tvd_of, ds + max(0.0, hs), md_s, md_b)
464
612
  v_shoe = _volume(cap, tvd_of, md_s, md_low_shoe)
465
- p_frac, p_bot = 0.052 * fg * ds, 0.052 * pp * dt
466
- v_shoe_at_bottom = v_shoe * p_frac / p_bot
613
+ if real_gas(cfg): # the same moles of gas: p V / (z T) at the shoe's middle and at the bottom's
614
+ sb, ss = bot['state'], sho['state']
615
+ v_shoe_at_bottom = v_shoe * (ss['p_psia'] / (ss['z'] * ss['t_r'])) / (sb['p_psia'] / (sb['z'] * sb['t_r']))
616
+ law = "the real-gas law (p V / z T) from the shoe's conditions to the bottom's"
617
+ else:
618
+ v_shoe_at_bottom = v_shoe * p_frac / p_bot
619
+ law = "Boyle's law (p V) from the fracture pressure at the shoe to the pressure at the bottom"
467
620
  out.update({'volume_at_bottom_bbl': round(v_bottom, 1), 'volume_at_shoe_bbl': round(v_shoe, 1), 'volume_shoe_as_bottom_bbl': round(v_shoe_at_bottom, 1),
468
- 'volume_bbl': round(min(v_bottom, v_shoe_at_bottom), 1), 'governs': 'the bubble at the bottom' if v_bottom <= v_shoe_at_bottom else 'the bubble at the shoe'})
621
+ 'volume_bbl': round(min(v_bottom, v_shoe_at_bottom), 1), 'carried_by': law,
622
+ 'governs': 'the bubble at the bottom' if v_bottom <= v_shoe_at_bottom else 'the bubble at the shoe'})
469
623
  return out
470
624
 
471
625
 
@@ -474,6 +628,11 @@ def analyse(cfg: dict, tvd_of, win, path_how: str = '', window_how: str = '') ->
474
628
  raise ValueError('declare the casing strings: what:od:weight:grade:top-shoe:hole:mw for each, shallowest shoe first')
475
629
  strings = [string_loads(cfg, i, tvd_of, win) for i in range(len(cfg['strings']))]
476
630
  kicks = [k for k in (kick_tolerance(cfg, i, tvd_of, win) for i in range(len(cfg['strings']))) if k]
631
+ if float(cfg['kick_intensity_ppg']) > 0: # a swabbed kick: gas pulled in with no underbalance
632
+ sw = {k['shoe_md_ft']: k for k in (kick_tolerance({**cfg, 'kick_intensity_ppg': 0.0}, i, tvd_of, win) for i in range(len(cfg['strings']))) if k}
633
+ for k in kicks:
634
+ s_ = sw.get(k['shoe_md_ft']) or {}
635
+ k['swabbed'] = {x: s_.get(x) for x in ('kick_ppg', 'kick_how', 'sidpp_psi', 'height_ft', 'volume_bbl', 'status', 'detail', 'governs')}
477
636
  return {'strings': strings, 'kicks': kicks, 'ok': all(s['ok'] for s in strings), 'config': cfg, 'path_how': path_how, 'window_how': window_how}
478
637
 
479
638
 
@@ -543,7 +702,7 @@ def text(p: dict) -> str:
543
702
  r = p.get('result')
544
703
  if not r:
545
704
  return f"Casing design: {p.get('detail', '')}"
546
- L = [f"Casing design - {r['display']} ({r['path_how']}; window: {r['window_how']})"]
705
+ L = [f"Casing design - {r['display']} ({r['path_how']}; window: {r['window_how']})", f" the gas: {gas_how(r['config'])}"]
547
706
  for s in r['strings']:
548
707
  st, c = s['string'], s['checks']
549
708
  L.append(f" {st['what']}: {st['od_in']:g} in {st['weight_lbft']:g} lb/ft {st['grade']} to {st['shoe_md_ft']:,.0f} ft MD - burst {st['burst_psi']:,} psi, "
@@ -551,7 +710,9 @@ def text(p: dict) -> str:
551
710
  L.append(' ' + '; '.join(f"{k} SF {('%.2f' % v['sf']) if v['sf'] is not None else '-'} (design {v['df']:g}) {'OK' if v['ok'] else 'BELOW'}" for k, v in c.items()))
552
711
  for k in r['kicks']:
553
712
  if k.get('volume_bbl') is not None:
554
- L.append(f" kick tolerance below {k['shoe_what']}: {k['volume_bbl']:g} bbl ({k['governs'] if k.get('governs') else k.get('detail', '')}); MAASP {k['maasp_psi']:,} psi")
713
+ sw = k.get('swabbed') or {}
714
+ L.append(f" kick tolerance below {k['shoe_what']}: {k['volume_bbl']:g} bbl at {k['kick_ppg']:.2f} ppg ({k['governs'] if k.get('governs') else k.get('detail', '')}); "
715
+ f"MAASP {k['maasp_psi']:,} psi" + (f"; swabbed (no underbalance) {sw['volume_bbl']:g} bbl" if sw.get('volume_bbl') is not None else ''))
555
716
  else:
556
717
  L.append(f" kick tolerance below {k['shoe_what']}: {k['status']} - {k.get('detail', '')}" + (f"; MAASP {k['maasp_psi']:,} psi, height {k.get('height_ft', 0):,.0f} ft" if k.get('maasp_psi') is not None else ''))
557
718
  return '\n'.join(L)
@@ -603,14 +764,19 @@ def build_report(ws, version: str, well: Optional[str] = None, scene: str = 'wor
603
764
  f"{s['rows'][i]['collapse_rating_psi']:,}", '-' if s['rows'][i]['sf_collapse'] is None else f"{s['rows'][i]['sf_collapse']:.2f}",
604
765
  f"{s['rows'][i]['axial_klbf']:,.0f}"] for i in idx]))
605
766
  secs.append(sec)
606
- s4 = CR.Section('4', 'Kick tolerance', [f"A single gas bubble at {cfg['gas_gradient_psi_ft']:g} psi/ft; MAASP = 0.052 (FG - MW) D_shoe; SIDPP = 0.052 (kick - MW) D_bottom; "
607
- f"the tallest bubble H = (MAASP - SIDPP) / (mud gradient - gas gradient); its volume at the bottom and at the shoe "
608
- f"(Boyle's law back to the bottom), the smaller governing. Annulus: BHA {cfg.get('bha_od_in') or '-'} in over "
767
+ s4 = CR.Section('4', 'Kick tolerance', [f"A single gas bubble: {gas_how(cfg)}. MAASP = 0.052 (FG - MW) D_shoe; SIDPP = 0.052 (kick - MW) D_bottom; "
768
+ f"the tallest bubble H = (MAASP - SIDPP) / (mud gradient - gas gradient), the gas's gradient taken at the bubble's middle on bottom "
769
+ f"and at the shoe; its volume at the bottom and at the shoe "
770
+ f"({'the real-gas law, p V / z T' if real_gas(cfg) else 'Boyle' + chr(39) + 's law'} back to the bottom), the smaller governing; "
771
+ f"and the same for a swabbed kick, gas pulled in with no underbalance. Annulus: BHA {cfg.get('bha_od_in') or '-'} in over "
609
772
  f"{cfg.get('bha_length_ft') or '-'} ft, drill pipe {cfg.get('dp_od_in') or '-'} in."], [])
610
- s4.tables.append(CR.Table(['Below', 'Open hole (ft MD)', 'Mud (ppg)', 'Kick (ppg)', 'FG at shoe (ppg)', 'MAASP (psi)', 'Height (ft)', 'Kick tolerance (bbl)'],
773
+ s4.tables.append(CR.Table(['Below', 'Open hole (ft MD)', 'Mud (ppg)', 'Kick (ppg)', 'FG at shoe (ppg)', 'MAASP (psi)', 'Gas (psi/ft) bottom / shoe', 'Height (ft)',
774
+ 'Kick tolerance (bbl)', 'Swabbed (bbl)'],
611
775
  [[k['shoe_what'], f"{k['shoe_md_ft']:,.0f}-{k['bottom_md_ft']:,.0f}", f"{k['mw_ppg']:g}", f"{k['kick_ppg']:.2f}",
612
776
  '-' if k['fg_shoe_ppg'] is None else f"{k['fg_shoe_ppg']:.2f}", '-' if k.get('maasp_psi') is None else f"{k['maasp_psi']:,}",
613
- '-' if k.get('height_ft') is None else f"{k['height_ft']:,.0f}", f"{k['volume_bbl']:g}" if k.get('volume_bbl') is not None else k['status']]
777
+ '-' if k.get('gas_gradient_bottom_psi_ft') is None else f"{k['gas_gradient_bottom_psi_ft']:.3f} / {k['gas_gradient_shoe_psi_ft']:.3f}",
778
+ '-' if k.get('height_ft') is None else f"{k['height_ft']:,.0f}", f"{k['volume_bbl']:g}" if k.get('volume_bbl') is not None else k['status'],
779
+ f"{(k.get('swabbed') or {}).get('volume_bbl'):g}" if (k.get('swabbed') or {}).get('volume_bbl') is not None else '-']
614
780
  for k in r['kicks']]))
615
781
  secs += [s4, CR.Section('5', 'What this will not call a measurement', ['; '.join(p['not_a_measurement']) + '.'], [])]
616
782
  return CR.Document(f"Casing design and kick tolerance - {r['display']}", rid, front, secs,
@@ -829,10 +829,10 @@ ENG_TABLES: Dict[str, dict] = {
829
829
  'casing_design': {'cols': ('well', 'what', 'od_in', 'weight_lbft', 'grade', 'top_md_ft', 'shoe_md_ft', 'hole_in', 'mw_ppg', 'wall_in', 'source'),
830
830
  'need': ('well', 'what', 'od_in', 'weight_lbft', 'grade', 'shoe_md_ft', 'hole_in', 'mw_ppg', 'source'),
831
831
  'about': "the casing program for casing design and kick tolerance: a row per string - its outside diameter (9.625 or 9-5/8), nominal weight (lb/ft), grade (H40 to Q125), top (0 to the surface) and shoe (ft MD), the hole it was run in (in), the mud it was run in (ppg), the wall (in) for a size not in the program's table; a well's rows together replace its program"},
832
- 'casing_loads': {'cols': ('well', 'td_md_ft', 'td_hole_in', 'td_mw_ppg', 'pp_ppg', 'fg_ppg', 'kick_intensity_ppg', 'gas_gradient_psi_ft', 'backup_gradient_psi_ft',
833
- 'evacuation', 'df_burst', 'df_collapse', 'df_tension', 'overpull_klbf', 'bha_od_in', 'bha_length_ft', 'dp_od_in', 'source'),
832
+ 'casing_loads': {'cols': ('well', 'td_md_ft', 'td_hole_in', 'td_mw_ppg', 'pp_ppg', 'fg_ppg', 'kick_intensity_ppg', 'gas_gradient_psi_ft', 'gas_sg',
833
+ 'surface_temp_f', 'geothermal_f_100ft', 'backup_gradient_psi_ft', 'evacuation', 'df_burst', 'df_collapse', 'df_tension', 'overpull_klbf', 'bha_od_in', 'bha_length_ft', 'dp_od_in', 'source'),
834
834
  'need': ('well', 'source'),
835
- 'about': "the casing loads' terms: the hole below the deepest string (TD ft MD, hole in, mud ppg), a pore pressure and fracture gradient when the Pore pressure tab has none, the kick intensity (ppg), the gas and backup gradients (psi/ft), the evacuation (0 to 1), the design factors, the overpull (klbf), and the BHA and drill pipe for the kick volume; blank keeps the default"},
835
+ 'about': "the casing loads' terms: the hole below the deepest string (TD ft MD, hole in, mud ppg), a pore pressure and fracture gradient when the Pore pressure tab has none, the kick intensity (ppg), the gas (its gravity, the surface temperature in F and the geothermal gradient in F per 100 ft; or a fixed gradient in psi/ft in place of the real gas), the backup gradient (psi/ft), the evacuation (0 to 1), the design factors, the overpull (klbf), and the BHA and drill pipe for the kick volume; blank keeps the default"},
836
836
  'frac_stages': {'cols': ('well', 'file', 'depth_unit', 'utc_offset_h', 'source'), 'need': ('well', 'file', 'source'),
837
837
  'about': "a treatment well's stage table (a path beside this sheet: CSV or Excel, one row per stage with its start and end of pumping), its depth unit (ft or m), the stage clock's hours from UTC, and the report it came from"},
838
838
  'frac_monitors': {'cols': ('well', 'channel'), 'need': ('well', 'channel'),
@@ -1073,6 +1073,9 @@ def _plan_engineering(ws, tables, wells, add, guard, base_dir: str) -> None:
1073
1073
  for k in CSG.LIMITS:
1074
1074
  if k == 'step_ft' or not (rec.get(k) or '').strip():
1075
1075
  continue
1076
+ if rec[k].strip().lower() == 'none' and CSG.DEFAULTS.get(k) is None:
1077
+ want[k] = None
1078
+ continue
1076
1079
  v = CSG.size_in(rec[k]) if k in ('td_hole_in', 'bha_od_in', 'dp_od_in') else _f(rec.get(k), k, False)
1077
1080
  lo, hi = CSG.LIMITS[k]
1078
1081
  if not lo <= v <= hi: