Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +133 -38
src/streamlit_app.py
CHANGED
@@ -1,40 +1,135 @@
|
|
1 |
-
import altair as alt
|
2 |
-
import numpy as np
|
3 |
-
import pandas as pd
|
4 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
-
""
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
"""
|
15 |
-
|
16 |
-
num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
|
17 |
-
num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
|
18 |
-
|
19 |
-
indices = np.linspace(0, 1, num_points)
|
20 |
-
theta = 2 * np.pi * num_turns * indices
|
21 |
-
radius = indices
|
22 |
-
|
23 |
-
x = radius * np.cos(theta)
|
24 |
-
y = radius * np.sin(theta)
|
25 |
-
|
26 |
-
df = pd.DataFrame({
|
27 |
-
"x": x,
|
28 |
-
"y": y,
|
29 |
-
"idx": indices,
|
30 |
-
"rand": np.random.randn(num_points),
|
31 |
-
})
|
32 |
-
|
33 |
-
st.altair_chart(alt.Chart(df, height=700, width=700)
|
34 |
-
.mark_point(filled=True)
|
35 |
-
.encode(
|
36 |
-
x=alt.X("x", axis=None),
|
37 |
-
y=alt.Y("y", axis=None),
|
38 |
-
color=alt.Color("idx", legend=None, scale=alt.Scale()),
|
39 |
-
size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
|
40 |
-
))
|
|
|
|
|
|
|
|
|
1 |
import streamlit as st
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
st.set_page_config(page_title="Tesla-Inspired Valve: Flow Modeling", layout="wide")
|
5 |
+
|
6 |
+
st.title("Tesla-Inspired Valve: Flow Modeling with Hemolysis Risk Indicator")
|
7 |
+
st.markdown("This tool allows you to model your Tesla valve design and estimate its performance, including hemolysis risk and overall efficiency. Adjust the parameters below to find an optimal configuration.")
|
8 |
+
|
9 |
+
# Constants (fixed)
|
10 |
+
rho = 1060 # Density (kg/m³)
|
11 |
+
mu = 0.0035 # Viscosity (Pa·s)
|
12 |
+
tau_limit = 150 # Pa, Hemolysis shear stress limit
|
13 |
+
D_annulus_cm = 3.5 # cm, Mitral valve annulus diameter
|
14 |
+
|
15 |
+
st.sidebar.title("🔒 Fixed Constants")
|
16 |
+
st.sidebar.markdown(f"**Blood Density (ρ):** {rho} kg/m³")
|
17 |
+
st.sidebar.markdown(f"**Viscosity (μ):** {mu} Pa·s")
|
18 |
+
st.sidebar.markdown(f"**Hemolysis Limit (τ):** {tau_limit} Pa")
|
19 |
+
st.sidebar.markdown(f"**Mitral Annulus Diameter:** {D_annulus_cm} cm")
|
20 |
+
|
21 |
+
# --- User Inputs ---
|
22 |
+
st.header("🔬 Design Parameters")
|
23 |
+
st.markdown("Adjust these sliders to define your Tesla valve's geometry and performance.")
|
24 |
+
col_design1, col_design2, col_design3 = st.columns(3)
|
25 |
+
with col_design1:
|
26 |
+
num_valves = st.slider("Number of Tesla Valve Units", 1, 100, 10, help="Total number of individual Tesla valve units.")
|
27 |
+
with col_design2:
|
28 |
+
valve_width_mm = st.slider("Single Valve Width (mm)", 4, 20, 12, help="The width of a single Tesla valve unit's footprint.")
|
29 |
+
with col_design3:
|
30 |
+
diodicity = st.slider("Diodicity (Di)", 1.0, 50.0, 20.0, help="The ratio of reverse pressure drop to forward pressure drop.")
|
31 |
+
|
32 |
+
# --- Physiological Parameters ---
|
33 |
+
st.header("🩺 Physiological Conditions")
|
34 |
+
st.markdown("These values represent typical heart function under which your device must operate.")
|
35 |
+
col_phys1, col_phys2 = st.columns(2)
|
36 |
+
with col_phys1:
|
37 |
+
deltaP_rev_mmHg = st.slider("Max Reverse Pressure (mmHg)", 60, 160, 100, help="The pressure drop across the valve during systole.")
|
38 |
+
deltaP_fwd_mmHg = st.slider("Forward Pressure (mmHg)", 2, 20, 5, help="The pressure gradient that drives forward flow (filling).")
|
39 |
+
t_rev = st.slider("Systole Time (s)", 0.2, 0.4, 0.3, 0.05, help="Duration of ventricular contraction.")
|
40 |
+
with col_phys2:
|
41 |
+
V_LV_mL = st.slider("Required Forward Volume (mL)", 50, 100, 70, help="The volume of blood the ventricle needs to fill.")
|
42 |
+
HR = st.slider("Heart Rate (BPM)", 50, 120, 70, help="The heart rate in beats per minute.")
|
43 |
+
|
44 |
+
# --- Calculations ---
|
45 |
+
t_fwd = (60 / HR) - t_rev
|
46 |
+
deltaP_rev = deltaP_rev_mmHg * 133.322 # Convert mmHg to Pa
|
47 |
+
deltaP_fwd = deltaP_fwd_mmHg * 133.322
|
48 |
+
|
49 |
+
# Calculate maximum possible valve width based on annulus area and valve count
|
50 |
+
valve_area_total_cm2 = np.pi * (D_annulus_cm / 2)**2
|
51 |
+
valve_width_max_mm = np.sqrt(valve_area_total_cm2 / (num_valves * np.pi)) * 2 * 10
|
52 |
+
# Note: This is a simplified calculation, but it provides a good estimate.
|
53 |
+
|
54 |
+
st.markdown("---")
|
55 |
+
st.header("🧮 Results & Analysis")
|
56 |
+
|
57 |
+
# --- Reverse Flow Calculations ---
|
58 |
+
st.subheader("🔁 Reverse Flow (Regurgitation)")
|
59 |
+
# We use Diodicity to calculate the reverse flow
|
60 |
+
# Assuming a simplified relationship based on the design parameters
|
61 |
+
# A_single is the equivalent cross-sectional area of a single valve's channels
|
62 |
+
A_valve_cross_section_mm2 = (np.pi * (D_annulus_cm / 2)**2 * 100) / num_valves
|
63 |
+
A_single = A_valve_cross_section_mm2 / 1000000
|
64 |
+
|
65 |
+
# Calculate equivalent pressure drop in forward flow
|
66 |
+
deltaP_fwd_equiv = deltaP_rev / diodicity
|
67 |
+
|
68 |
+
# Estimate reverse velocity based on forward pressure drop and equivalent area
|
69 |
+
# Using a simplified orifice flow model for the effective pressure drop
|
70 |
+
v_rev = np.sqrt(2 * deltaP_fwd_equiv / rho)
|
71 |
+
|
72 |
+
Q_rev = A_single * num_valves * v_rev
|
73 |
+
V_rev_L = Q_rev * t_rev * 1000
|
74 |
+
|
75 |
+
# Calculate Regurgitant Fraction (RF)
|
76 |
+
RF = (V_rev_L / (V_LV_mL / 1000)) * 100
|
77 |
+
|
78 |
+
# Hemolysis Risk (Shear Stress)
|
79 |
+
# This is a highly simplified model; real CFD is needed.
|
80 |
+
# We'll assume shear stress is proportional to velocity and inversely proportional to valve width
|
81 |
+
tau = rho * v_rev * v_rev / (valve_width_mm / 1000)
|
82 |
+
|
83 |
+
rf_status = "✅" if RF < 5 else "❌"
|
84 |
+
shear_status = "✅" if tau < tau_limit else "❌"
|
85 |
+
|
86 |
+
st.write(f"Total Reverse Flow Volume: **{V_rev_L:.2f} L**")
|
87 |
+
st.write(f"Regurgitant Fraction (RF): **{RF:.2f}%** {rf_status}")
|
88 |
+
st.write(f"Estimated Peak Shear Stress: **{tau:.1f} Pa** {shear_status}")
|
89 |
+
|
90 |
+
if tau >= tau_limit:
|
91 |
+
st.warning(f"**Warning:** The estimated shear stress ({tau:.1f} Pa) exceeds the hemolysis limit of {tau_limit} Pa. This could cause red blood cell damage. Consider increasing the valve width or the number of valves.")
|
92 |
+
|
93 |
+
# --- Forward Flow Calculations ---
|
94 |
+
st.subheader("✅ Forward Flow")
|
95 |
+
|
96 |
+
v_fwd = np.sqrt(2 * deltaP_fwd / rho)
|
97 |
+
Q_fwd = A_single * num_valves * v_fwd
|
98 |
+
V_fwd_L = Q_fwd * t_fwd * 1000
|
99 |
+
|
100 |
+
forward_status = "✅" if V_fwd_L * 1000 >= V_LV_mL else "❌"
|
101 |
+
tau_fwd = rho * v_fwd * v_fwd / (valve_width_mm / 1000)
|
102 |
+
|
103 |
+
st.write(f"Total Forward Flow Volume: **{V_fwd_L * 1000:.2f} mL**")
|
104 |
+
st.write(f"Required Volume to Fill: **{V_LV_mL:.2f} mL** {forward_status}")
|
105 |
+
st.write(f"Estimated Shear Stress: **{tau_fwd:.1f} Pa**")
|
106 |
+
if V_fwd_L * 1000 < V_LV_mL:
|
107 |
+
st.warning("The forward flow volume is insufficient. Consider increasing the number of valves or their width to improve heart filling.")
|
108 |
+
|
109 |
+
st.markdown("---")
|
110 |
+
st.subheader("📢 Design Guidance")
|
111 |
+
st.write(f"Maximum theoretical width for a single valve unit is **{valve_width_max_mm:.2f} mm** to fit all {num_valves} valves within the annulus.")
|
112 |
+
st.write("A good design will have all checkmarks (✅) and minimize the Regurgitant Fraction.")
|
113 |
+
|
114 |
+
st.markdown("---")
|
115 |
+
st.header("📖 Parameter Explanations")
|
116 |
+
st.subheader("User Inputs (Design & Physiological)")
|
117 |
+
st.markdown("""
|
118 |
+
- **Number of Tesla Valve Units:** The total number of individual Tesla valve units that make up the complete valve. More units can improve overall flow but require a smaller footprint for each.
|
119 |
+
- **Single Valve Width (mm):** The physical width of a single Tesla valve unit's footprint. This is a crucial design parameter that influences shear stress and manufacturability.
|
120 |
+
- **Diodicity (Di):** The primary performance metric for a Tesla valve. It's the ratio of the pressure drop in the reverse direction to the pressure drop in the forward direction. A higher number indicates a more effective valve.
|
121 |
+
- **Max Reverse Pressure (mmHg):** The maximum pressure difference between the left ventricle and left atrium during systole, which drives the regurgitant flow.
|
122 |
+
- **Forward Pressure (mmHg):** The pressure gradient that drives the flow of blood from the left atrium to the left ventricle during diastole. This should be minimal to ensure proper filling.
|
123 |
+
- **Systole Time (s):** The duration of the heart's contraction phase, during which regurgitation can occur.
|
124 |
+
- **Required Forward Volume (mL):** The volume of blood the left ventricle needs to receive from the left atrium in a single heartbeat to function effectively.
|
125 |
+
- **Heart Rate (BPM):** The number of times the heart beats per minute. This determines the total time for the cardiac cycle.
|
126 |
+
""")
|
127 |
|
128 |
+
st.subheader("Outputs (Results & Analysis)")
|
129 |
+
st.markdown("""
|
130 |
+
- **Total Reverse Flow Volume (L):** The total volume of blood that is estimated to leak back into the left atrium per heartbeat. This is what you want to minimize.
|
131 |
+
- **Regurgitant Fraction (RF):** The percentage of the total blood pumped by the heart that leaks backward. A value less than 5% is generally considered non-pathological.
|
132 |
+
- **Estimated Peak Shear Stress (Pa):** The estimated maximum shear force on red blood cells within the valve's channels. Values above 150 Pa are a significant hemolysis risk.
|
133 |
+
- **Total Forward Flow Volume (mL):** The total volume of blood that is estimated to flow from the left atrium into the left ventricle. This should be sufficient to meet the required forward volume.
|
134 |
+
- **Design Guidance:** Provides a maximum theoretical width for your valve units and summarizes the overall health of your design based on the chosen parameters.
|
135 |
+
""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|