UCS2014 commited on
Commit
9354b76
·
verified ·
1 Parent(s): 47e7e1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -15
app.py CHANGED
@@ -120,6 +120,22 @@ add_password_gate()
120
  # Utilities
121
  # =========================
122
  def rmse(y_true, y_pred): return float(np.sqrt(mean_squared_error(y_true, y_pred)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  def pearson_r(y_true, y_pred):
124
  a = np.asarray(y_true, dtype=float); p = np.asarray(y_pred, dtype=float)
125
  if a.size < 2: return float("nan")
@@ -414,6 +430,7 @@ def preview_tracks(df: pd.DataFrame, cols: list[str]):
414
  if i == 0: ax.set_ylabel(y_label)
415
  else: ax.tick_params(labelleft=False); ax.set_ylabel("")
416
  fig.tight_layout(); return fig
 
417
  # =========================
418
  # Load models + metas
419
  # =========================
@@ -424,7 +441,6 @@ def _first_in_dirs(names): # prefer uploaded over repo copy
424
  if p.exists() and p.stat().st_size > 0:
425
  return p
426
  return None
427
-
428
 
429
  def _load_meta(p: Path) -> dict:
430
  if not p or not p.exists(): return {}
@@ -471,12 +487,8 @@ model_bo, info_bo = _unwrap(payload_bo)
471
  model_bd, info_bd = _unwrap(payload_bd)
472
 
473
  # Resolve features per model (prefer model_info → meta → fallback)
474
- features_bo = list((info_bo.get("features")
475
- or meta_bo.get("features")
476
- or FEATURES_DEFAULT))
477
- features_bd = list((info_bd.get("features")
478
- or meta_bd.get("features")
479
- or FEATURES_DEFAULT))
480
 
481
  # Use the UNION so BD's 'Depth (ft)' is required and both models can run from one input
482
  # Order: keep BO order, then append BD-only columns in order
@@ -495,7 +507,6 @@ st.session_state["TARGET_BO"] = TARGET_BO
495
  st.session_state["TARGET_BD"] = TARGET_BD
496
  st.session_state["X_UNITS"] = X_UNITS
497
 
498
-
499
  # =========================
500
  # Session state
501
  # =========================
@@ -539,6 +550,7 @@ def sticky_header(title, message):
539
  if st.session_state.app_step == "intro":
540
  st.header("Welcome!")
541
  st.markdown("This software estimates **Breakout** and **Breakdown** mud-weight limits from drilling data.")
 
542
  st.subheader("How It Works")
543
  st.markdown("1) **Upload data** and preview.\n2) **Run Model** to compute Train/Test metrics.\n3) Go to **Validation** (with actual BO/BD) or **Prediction** (no actuals).\n4) Use **Combined** tab to see both limits on one track.")
544
  if st.button("Start Showcase", type="primary"):
@@ -589,6 +601,7 @@ if st.session_state.app_step == "dev":
589
  sticky_header("Case Building", "📄 **Preview** then click **Run Model**.")
590
  else:
591
  sticky_header("Case Building", "**Upload your data** and run the model.")
 
592
 
593
  if run and st.session_state.dev_file_bytes:
594
  book = read_book_bytes(st.session_state.dev_file_bytes)
@@ -605,14 +618,12 @@ if st.session_state.app_step == "dev":
605
  Xtr_bd = _make_X(tr, st.session_state["FEATURES_BD"])
606
  Xte_bo = _make_X(te, st.session_state["FEATURES_BO"])
607
  Xte_bd = _make_X(te, st.session_state["FEATURES_BD"])
608
-
609
  tr[PRED_BO] = model_bo.predict(Xtr_bo)
610
  tr[PRED_BD] = model_bd.predict(Xtr_bd)
611
  te[PRED_BO] = model_bo.predict(Xte_bo)
612
  te[PRED_BD] = model_bd.predict(Xte_bd)
613
 
614
-
615
-
616
  st.session_state.results["Train"]=tr; st.session_state.results["Test"]=te
617
  st.session_state.results["m_train_bo"]={"R": pearson_r(tr[TARGET_BO], tr[PRED_BO]), "RMSE": rmse(tr[TARGET_BO], tr[PRED_BO]), "MAE": mean_absolute_error(tr[TARGET_BO], tr[PRED_BO])}
618
  st.session_state.results["m_train_bd"]={"R": pearson_r(tr[TARGET_BD], tr[PRED_BD]), "RMSE": rmse(tr[TARGET_BD], tr[PRED_BD]), "MAE": mean_absolute_error(tr[TARGET_BD], tr[PRED_BD])}
@@ -630,14 +641,15 @@ if st.session_state.app_step == "dev":
630
  _metrics_block("BO", mbo); _metrics_block("BD", mbd)
631
  st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'><strong>R</strong> = Pearson correlation • <strong>RMSE/MAE</strong> in MW (pcf)</div>", unsafe_allow_html=True)
632
  t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
 
633
  with t1:
634
  st.plotly_chart(track_plot_single(df, PRED_BO, actual_col=TARGET_BO, title_suffix="Breakout"),
635
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
636
- st.pyplot(cross_plot_static(df[TARGET_BO], df[PRED_BO], f"Actual {TARGET_BO}", f"Predicted {TARGET_BO}", COLORS["pred_bo"]), use_container_width=False)
637
  with t2:
638
  st.plotly_chart(track_plot_single(df, PRED_BD, actual_col=TARGET_BD, title_suffix="Breakdown"),
639
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
640
- st.pyplot(cross_plot_static(df[TARGET_BD], df[PRED_BD], f"Actual {TARGET_BD}", f"Predicted {TARGET_BD}", COLORS["pred_bd"]), use_container_width=False)
641
  with t3:
642
  st.plotly_chart(track_plot_combined(df), use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
643
 
@@ -667,6 +679,7 @@ if st.session_state.app_step == "validate":
667
  if st.sidebar.button("Proceed to Prediction ▶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
668
 
669
  sticky_header("Validate the Models", "Upload a dataset with the same **feature** columns and **BO/BD** actuals.")
 
670
 
671
  if go_btn and up is not None:
672
  book = read_book_bytes(up.getvalue())
@@ -702,15 +715,16 @@ if st.session_state.app_step == "validate":
702
  st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'>R = Pearson correlation</div>", unsafe_allow_html=True)
703
 
704
  t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
 
705
  with t1:
706
  st.plotly_chart(track_plot_single(df, PRED_BO, actual_col=TARGET_BO, title_suffix="Breakout"),
707
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
708
- st.pyplot(cross_plot_static(df[TARGET_BO], df[PRED_BO], f"Actual {TARGET_BO}", f"Predicted {TARGET_BO}", COLORS["pred_bo"]),
709
  use_container_width=False)
710
  with t2:
711
  st.plotly_chart(track_plot_single(df, PRED_BD, actual_col=TARGET_BD, title_suffix="Breakdown"),
712
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
713
- st.pyplot(cross_plot_static(df[TARGET_BD], df[PRED_BD], f"Actual {TARGET_BD}", f"Predicted {TARGET_BD}", COLORS["pred_bd"]),
714
  use_container_width=False)
715
  with t3:
716
  st.plotly_chart(track_plot_combined(df), use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
@@ -738,6 +752,7 @@ if st.session_state.app_step == "predict":
738
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
739
 
740
  sticky_header("Prediction", "Upload a dataset with **feature columns only** (no BO/BD actuals).")
 
741
 
742
  if go_btn and up is not None:
743
  book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]
 
120
  # Utilities
121
  # =========================
122
  def rmse(y_true, y_pred): return float(np.sqrt(mean_squared_error(y_true, y_pred)))
123
+
124
+ def render_bo_bd_note():
125
+ st.markdown(
126
+ """
127
+ <div class="st-message-box">
128
+ <b>What do BO and BD mean?</b><br>
129
+ <ul style="margin-top:6px;">
130
+ <li><b>BO (Breakout)</b> — the <i>lower</i> mud-weight bound to avoid compressive/shear failure of the wellbore (breakout). Drilling below BO increases breakout risk.</li>
131
+ <li><b>BD (Breakdown)</b> — the <i>upper</i> mud-weight bound to avoid tensile fracturing (hydraulic breakdown). Drilling above BD risks induced fractures and losses.</li>
132
+ </ul>
133
+ The safe mud-weight window is typically between <b>BO</b> and <b>BD</b>.
134
+ </div>
135
+ """,
136
+ unsafe_allow_html=True,
137
+ )
138
+
139
  def pearson_r(y_true, y_pred):
140
  a = np.asarray(y_true, dtype=float); p = np.asarray(y_pred, dtype=float)
141
  if a.size < 2: return float("nan")
 
430
  if i == 0: ax.set_ylabel(y_label)
431
  else: ax.tick_params(labelleft=False); ax.set_ylabel("")
432
  fig.tight_layout(); return fig
433
+
434
  # =========================
435
  # Load models + metas
436
  # =========================
 
441
  if p.exists() and p.stat().st_size > 0:
442
  return p
443
  return None
 
444
 
445
  def _load_meta(p: Path) -> dict:
446
  if not p or not p.exists(): return {}
 
487
  model_bd, info_bd = _unwrap(payload_bd)
488
 
489
  # Resolve features per model (prefer model_info → meta → fallback)
490
+ features_bo = list((info_bo.get("features") or meta_bo.get("features") or FEATURES_DEFAULT))
491
+ features_bd = list((info_bd.get("features") or meta_bd.get("features") or FEATURES_DEFAULT))
 
 
 
 
492
 
493
  # Use the UNION so BD's 'Depth (ft)' is required and both models can run from one input
494
  # Order: keep BO order, then append BD-only columns in order
 
507
  st.session_state["TARGET_BD"] = TARGET_BD
508
  st.session_state["X_UNITS"] = X_UNITS
509
 
 
510
  # =========================
511
  # Session state
512
  # =========================
 
550
  if st.session_state.app_step == "intro":
551
  st.header("Welcome!")
552
  st.markdown("This software estimates **Breakout** and **Breakdown** mud-weight limits from drilling data.")
553
+ render_bo_bd_note()
554
  st.subheader("How It Works")
555
  st.markdown("1) **Upload data** and preview.\n2) **Run Model** to compute Train/Test metrics.\n3) Go to **Validation** (with actual BO/BD) or **Prediction** (no actuals).\n4) Use **Combined** tab to see both limits on one track.")
556
  if st.button("Start Showcase", type="primary"):
 
601
  sticky_header("Case Building", "📄 **Preview** then click **Run Model**.")
602
  else:
603
  sticky_header("Case Building", "**Upload your data** and run the model.")
604
+ render_bo_bd_note()
605
 
606
  if run and st.session_state.dev_file_bytes:
607
  book = read_book_bytes(st.session_state.dev_file_bytes)
 
618
  Xtr_bd = _make_X(tr, st.session_state["FEATURES_BD"])
619
  Xte_bo = _make_X(te, st.session_state["FEATURES_BO"])
620
  Xte_bd = _make_X(te, st.session_state["FEATURES_BD"])
621
+
622
  tr[PRED_BO] = model_bo.predict(Xtr_bo)
623
  tr[PRED_BD] = model_bd.predict(Xtr_bd)
624
  te[PRED_BO] = model_bo.predict(Xte_bo)
625
  te[PRED_BD] = model_bd.predict(Xte_bd)
626
 
 
 
627
  st.session_state.results["Train"]=tr; st.session_state.results["Test"]=te
628
  st.session_state.results["m_train_bo"]={"R": pearson_r(tr[TARGET_BO], tr[PRED_BO]), "RMSE": rmse(tr[TARGET_BO], tr[PRED_BO]), "MAE": mean_absolute_error(tr[TARGET_BO], tr[PRED_BO])}
629
  st.session_state.results["m_train_bd"]={"R": pearson_r(tr[TARGET_BD], tr[PRED_BD]), "RMSE": rmse(tr[TARGET_BD], tr[PRED_BD]), "MAE": mean_absolute_error(tr[TARGET_BD], tr[PRED_BD])}
 
641
  _metrics_block("BO", mbo); _metrics_block("BD", mbd)
642
  st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'><strong>R</strong> = Pearson correlation • <strong>RMSE/MAE</strong> in MW (pcf)</div>", unsafe_allow_html=True)
643
  t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
644
+ units = st.session_state.get("X_UNITS","MW (pcf)")
645
  with t1:
646
  st.plotly_chart(track_plot_single(df, PRED_BO, actual_col=TARGET_BO, title_suffix="Breakout"),
647
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
648
+ st.pyplot(cross_plot_static(df[TARGET_BO], df[PRED_BO], f"Actual {TARGET_BO} ({units})", f"Predicted {TARGET_BO} ({units})", COLORS["pred_bo"]), use_container_width=False)
649
  with t2:
650
  st.plotly_chart(track_plot_single(df, PRED_BD, actual_col=TARGET_BD, title_suffix="Breakdown"),
651
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
652
+ st.pyplot(cross_plot_static(df[TARGET_BD], df[PRED_BD], f"Actual {TARGET_BD} ({units})", f"Predicted {TARGET_BD} ({units})", COLORS["pred_bd"]), use_container_width=False)
653
  with t3:
654
  st.plotly_chart(track_plot_combined(df), use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
655
 
 
679
  if st.sidebar.button("Proceed to Prediction ▶", use_container_width=True): st.session_state.app_step="predict"; st.rerun()
680
 
681
  sticky_header("Validate the Models", "Upload a dataset with the same **feature** columns and **BO/BD** actuals.")
682
+ render_bo_bd_note()
683
 
684
  if go_btn and up is not None:
685
  book = read_book_bytes(up.getvalue())
 
715
  st.markdown("<div style='text-align:left;font-size:0.8em;color:#6b7280;margin-top:-16px;margin-bottom:8px;'>R = Pearson correlation</div>", unsafe_allow_html=True)
716
 
717
  t1, t2, t3 = st.tabs(["Breakout", "Breakdown", "Combined"])
718
+ units = st.session_state.get("X_UNITS","MW (pcf)")
719
  with t1:
720
  st.plotly_chart(track_plot_single(df, PRED_BO, actual_col=TARGET_BO, title_suffix="Breakout"),
721
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
722
+ st.pyplot(cross_plot_static(df[TARGET_BO], df[PRED_BO], f"Actual {TARGET_BO} ({units})", f"Predicted {TARGET_BO} ({units})", COLORS["pred_bo"]),
723
  use_container_width=False)
724
  with t2:
725
  st.plotly_chart(track_plot_single(df, PRED_BD, actual_col=TARGET_BD, title_suffix="Breakdown"),
726
  use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
727
+ st.pyplot(cross_plot_static(df[TARGET_BD], df[PRED_BD], f"Actual {TARGET_BD} ({units})", f"Predicted {TARGET_BD} ({units})", COLORS["pred_bd"]),
728
  use_container_width=False)
729
  with t3:
730
  st.plotly_chart(track_plot_combined(df), use_container_width=False, config={"displayModeBar": False, "scrollZoom": True})
 
752
  if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
753
 
754
  sticky_header("Prediction", "Upload a dataset with **feature columns only** (no BO/BD actuals).")
755
+ render_bo_bd_note()
756
 
757
  if go_btn and up is not None:
758
  book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]