Some time ago, I started a collaboration with Alan at CrowdField, where he provided guidance and support for me to develop my first Streamlit app.
I was eager to learn how to use Python to build simple, user-friendly applications that run in a browser and have real-world applications in the oil and gas industry. After discussing several options with Alan, I decided to take on the challenge of building an interactive interface for relative permeability curves.
The process and dynamics of our collaboration were described in a blog post Alan published on the CrowdField website:
Case Study: Collaborating with a Young Engineer to Develop a Streamlit Relative Permeability App
Here’s a short YouTube demo showcasing an app run-through:
And here’s a link to the Streamlit app itself, which you can run in any browser:
👉 Link to Rel Perm StreamLit App
In this article, I want to go deeper into the technical aspects and provide a detailed, step-by-step guide on how to develop a Streamlit app like this one.
My goal is to encourage others to explore this powerful tool.
When we decided to implement a Streamlit app for relative permeability curves, we envisioned an interface that would:
For the following sections, you can either paste this code and modify it as you go on your editor, or simply skim through it to understand the general structure.
Don’t worry if the code feels overwhelming—it will all make sense by the end.
To get started, you need Python installed on your system along with the necessary libraries.
python --version
You should see an output like Python 3.x.x.
Create a virtual environment to isolate dependencies and install necessary libraries.
Open your terminal or command prompt and navigate to your working directory:
mkdir streamlit_app
cd streamlit_app
Create and activate a virtual environment:
python -m venv env
env\\Scripts\\activate# Windows
source env/bin/activate# Mac/Linux
Install the required libraries:
pip install streamlit numpy pandas plotly openpyxl requests PyPDF2
Inside your project folder, create a new Python file:
touch Myapp.py
Open Myapp.py in your preferred text editor (e.g. VSCode) and add the following imports:
import streamlit as st
import numpy as np
import pandas as pd
import plotly.graph_objs as go
from PyPDF2 import PdfReader
Functions serve as the backbone of the application, each dedicated to a specific task such as calculating permeability, exporting data, or generating plots.
For relative permeability calculations, I've implemented Corey functions, using exact formulas sourced from the references listed at the end of this guide.
Now, let's define the key functions that will compute relative permeability and capillary pressure curves.
def calculate_properties_water_oil(Sw, Swc, Sorw, Kro_max, Krw_max, no, nw, pc_max, npc):
kro = Kro_max * np.maximum(((1 - Sw - Sorw) / (1 - Swc - Sorw)), 0) ** no
krw = Krw_max * np.maximum(((Sw - Swc) / (1 - Swc - Sorw)), 0) ** nw
pcwo = pc_max * np.maximum(((1 - Sw - Sorw) / (1 - Swc - Sorw)), 0) ** npc
return kro, krw, pcwo
def calculate_properties_gas_oil(Sg, Sgc, Sl, Kro_max, krg_max, ng, ngo, pc_max, npg):
kro = Kro_max * np.maximum(((1 - Sg - Sl) / (1 - Sgc - Sl)), 0) ** ngo
krg = krg_max * np.maximum(((Sg - Sgc) / (1 - Sl - Sgc)), 0) ** ng
pcgo = pc_max * np.maximum(((Sg - Sgc) / (1 - Sl - Sgc)), 0) ** npg
return kro, krg, pcgo
def calculate_properties_gas_water(Sg, Sw, Sgc, Swc, Krg_max, krw_max, ng, nw, pc_max, npc):
krg = Krg_max * np.maximum(((Sg - Sgc) / (1 - Swc - Sgc)), 0) ** ng
krw = krw_max * np.maximum(((Sw - Swc) / (1 - Swc)), 0) ** nw
pcgw = pc_max * np.maximum(((Sg - Sgc) / (1 - Swc - Sgc)), 0) ** npc
return krg, krw, pcgw
def export_to_ecl(system, saturation, kro, krw_or_krg, pc):
lines = []
if system == 'Water-Oil System':
lines.append("SWOF")
lines.append("-- Sw Krw Kro Pcwo")
elif system == 'Gas-Oil System':
lines.append("SGOF")
lines.append("-- Sg Krg Kro Pcgo")
elif system == 'Gas-Water System':
lines.append("SGWFN")
lines.append("-- Sg Krg Krw Pcgw")
for row in zip(saturation, kro, krw_or_krg, pc):
lines.append(f"{row[0]:.4f} {row[1]:.4f} {row[2]:.4f} {row[3]:.4f}")
lines.append("/")
return "\\n".join(lines)
def plot_properties(system, x_values, y_values_1, y_values_2):
fig = go.Figure()
if system == 'Water-Oil System':
x_label = 'Water Saturation (Sw)'
y1_label = 'Oil Relative Permeability (kro)'
y2_label = 'Water Relative Permeability (krw)'
elif system == 'Gas-Oil System':
x_label = 'Liquid Saturation (Sl)'
y1_label = 'Gas Relative Permeability (krg)'
y2_label = 'Oil Relative Permeability (kro)'
elif system == 'Gas-Water System':
x_label = 'Water Saturation (Sw)'
y1_label = 'Gas Relative Permeability (krg)'
y2_label = 'Water Relative Permeability (krw)'
fig.add_trace(go.Scatter(x=x_values, y=y_values_1, mode='lines', name=y1_label))
fig.add_trace(go.Scatter(x=x_values, y=y_values_2, mode='lines', name=y2_label))
return fig
def plot_capillary_pressure(system, S, pc):
fig = go.Figure()
if system == 'Water-Oil System':
x_label = 'Water Saturation (Sw)'
elif system == 'Gas-Oil System':
x_label = 'Liquid Saturation (Sl)'
elif system == 'Gas-Water System':
x_label = 'Water Saturation (Sw)'
fig.add_trace(go.Scatter(x=S, y=pc, mode='lines', name='Capillary Pressure (pc)'))
return fig
def generate_plots_and_data(system, params):
if system == 'Water-Oil System':
Sw = np.linspace(params['Swc'], 1 - params['Sorw'], 100)
kro, krw, pcwo = calculate_properties_water_oil(Sw, params['Swc'], params['Sorw'],
params['Kro_max'], params['krw_max'], params['no'], params['nw'],
params['pc_max'], params['npc'])
fig = plot_properties(system, Sw, kro, krw)
pc_fig = plot_capillary_pressure(system, Sw, pcwo)
return fig, pc_fig
The Streamlit library allows us to create an intuitive interface where users can select the system type, adjust parameters, and view results dynamically.
st.title('Relative Permeability Curves Generator')
default_params = {
'Water-Oil System': {'Swc': 0.25, 'Kro_max': 0.85, 'Sorw': 0.35, 'krw_max': 0.4,
'no': 0.9, 'nw': 1.5, 'npc': 0.71, 'pc_max': 20.0},
'Gas-Oil System': {'Sgc': 0.05, 'Kro_max': 0.60, 'Sl': 0.48, 'krg_max': 0.95,
'ng': 0.6, 'ngo': 1.2, 'npg': 0.51, 'pc_max': 30.0},
'Gas-Water System': {'Sgc': 0.05, 'Krg_max': 0.90, 'Swc': 0.2, 'krw_max': 0.35,
'ng': 0.8, 'nw': 1.4, 'npc': 0.61, 'pc_max': 20.0}
}
system = st.selectbox('Select System Type', ['Water-Oil System', 'Gas-Oil System', 'Gas-Water System'])
params = default_params[system]
Example: Water-Oil System Parameters
if system == 'Water-Oil System':
params['Swc'] = st.slider('Swc', 0.0, 1.0, value=params['Swc'], step=0.01)
params['Kro_max'] = st.slider('Kro_max', 0.0, 1.0, value=params['Kro_max'], step=0.01)
params['Sorw'] = st.slider('Sorw', 0.0, 1.0, value=params['Sorw'], step=0.01)
params['krw_max'] = st.slider('krw_max', 0.0, 1.0, value=params['krw_max'], step=0.01)
params['no'] = st.slider('no', 0.3, 5.0, value=params['no'], step=0.01)
params['nw'] = st.slider('nw', 0.3, 5.0, value=params['nw'], step=0.01)
params['npc'] = st.slider('npc', 0.3, 5.0, value=params['npc'], step=0.01)
params['pc_max'] = st.number_input('pc_max [psi]', min_value=0.0, max_value=1000.0, value=params['pc_max'], step=0.1)
Key Elements:
This block dynamically changes based on the selected system. Similar sliders are defined for Gas-Oil and Gas-Water systems.
Call the generate_plots_and_data Function:
try:
fig, pc_fig, df = generate_plots_and_data(system, params)
Display the Plots in Streamlit:
col1, col2 = st.columns([0.4, 0.6])
with col2:
st.plotly_chart(fig, use_container_width=True)
st.plotly_chart(pc_fig, use_container_width=True)
Export Data as Excel:
buffer = io.BytesIO()
with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer:
df.to_excel(writer, sheet_name="Relative_Permeability", index=False)
buffer.seek(0)
Add a Download Button:
st.download_button(
label="Download Excel File",
data=buffer,
file_name="relative_permeability.xlsx",
use_container_width=True
)
Export Data as Simulation Input File:
ecl_data = export_to_ecl(system, df.iloc[:, 0], df.iloc[:, 1], df.iloc[:, 2], df.iloc[:, 3])
st.download_button(
label="Download E-100 Sim INC File",
data=ecl_data.encode('utf-8'),
file_name="relative_permeability.INC",
mime="text/plain",
use_container_width=True
)
Include PDF Documentation for Download:
pdf_data = BytesIO(requests.get(pdf_url).content)
st.download_button(
label="Equations Used",
data=pdf_data,
file_name="Equations_Used.pdf",
mime="application/pdf",
use_container_width=True
)
st.markdown(
"""
---
Developed by [Shubham B. Patel](<https://www.linkedin.com/in/shubham-patel-1045/>) under the guidance of [Alan Mourgues](<https://www.linkedin.com/in/alan-mourgues/>).
Visit [CrowdField.net](<https://www.crowdfield.net/>) for more case studies.
"""
)
streamlit run Saturation functions app.py
my-streamlit-app
Clone the repository to your local machine:
git clone <https://github.com/your-username/my-streamlit-app.git>
Move your app files (e.g., app.py
) into the cloned folder
Add a .gitignore
file to exclude unnecessary files:
echo "__pycache__/" > .gitignore
Commit and push your code:
git add .
git commit -m "Initial commit"
git push
Create a file named requirements.txt
in the repository folder.
Add the Python libraries your app needs:
streamlit==1.24.0# Streamlit for web applications
numpy>=1.21.0# NumPy for numerical operations
pandas>=1.4.0# Pandas for data manipulation
matplotlib>=3.5.0# Matplotlib for plotting
scikit-learn>=1.1.0# Scikit-learn for machine learning
requests>=2.27.0# Requests for HTTP requests
plotly>=5.10.0# Plotly for interactive plotting
PyPDF2>=3.0.0
xlsxwriter>=3.2.0
Save and push this file to GitHub:
git add requirements.txt
git commit -m "Add requirements file"
git push
main
(or select your branch if it's different)app.py
)requirements.txt
and deploy your app
Once deployed, your app will be live, and you'll get a URL like:
https://your-username-your-repo-name.streamlit.app
Share this link with others to allow them to view your app.
Make changes to your app code locally.
Push changes to GitHub:
git add .
git commit -m "Update app"
git push
Streamlit Cloud will automatically detect changes and redeploy your app.
requirements.txt
That's it! Your app is now live on Streamlit and linked with GitHub for easy updates.
This project taught me several valuable lessons:
This Streamlit app offers a powerful yet user-friendly tool for calculating and visualizing relative permeability and capillary pressure curves. By combining technical rigor with modern visualization, it enhances understanding and accelerates decision-making in reservoir engineering.
These are the resources I used while developing this body of work:
I'm putting together a complete package to help you build this app:
To gauge interest, I’m offering this package as a pre-sale for only $20. This early release will help me gather user feedback and fine-tune the product before its final public launch at a higher price point.
With this pre-purchase, you'll get access to the final product, giving you everything you need to start building your own engineering applications.
Pre-purchase for only $20:
👉 https://subscribepage.io/qKBwNA
I hope this article has shown that creating useful tools is within your reach—even if you're just starting with Python.
Feel free to reach out if you have any questions. Happy coding!
Explore a curated collection of valuable resources in our Store, both free and paid, all designed to help you upskill.
Shubham is a Reservoir Engineer who specializes in deep-water and unconventional gas fields, focusing on reserve estimation, production forecasting, and reservoir modeling.
With expertise in well test interpretation, reservoir characterization, and economic analysis, he integrates analytical and numerical methods to optimize production and maximize asset value.
Committed to efficiency and sustainability, he enhances operations while promoting responsible reservoir management.
Subscribe to O&G AI Wave – your indispensable guide to the evolving world of AI and NoCode and their practical applications for Oil & Gas professionals.
Our newsletter brings you the latest trends and insights in AI and NoCode technologies directly impacting the O&G sector.
Every issue is packed with expert analyses and practical tips to help you navigate and leverage these transformative technologies.
Don’t miss out on the opportunity to stay ahead of the trend and future-proof your career in this incredibly dynamic field.
At CrowdField, our mission is to empower YOU—helping you showcase your skills in the open market and monetize them effectively. Here's how you benefit from being with us:
👉 Make your mark and find freelance opportunities by listing yourself in our freelancer directory to get noticed. Join us for free here.
👉 Turn your skills into digital products that sell. We'll help you polish, launch, and list them in our Store, promote them on our LinkedIn page, to our email subscribers, and feature your success in a case study on our Blog, amplifying both your product and personal brand. Whether you're at the idea stage, midway through implementation, or nearing completion, if you see potential for monetization, we're interested. Take the first step by getting in touch to start a conversation at hello@crowdfield.net.
👉 Discover bargains in our digital store with heavily discounted prices during our market discovery period. Take advantage of these limited-time offers as we expand our network. Dive in now and find your gem! Got to Store