"Balancing Time, Distance, and Production: A Simple Python Approach to Well Route Optimization"

"Balancing Time, Distance, and Production: A Simple Python Approach to Well Route Optimization"

The code aims to optimize routes for well operators, maximizing oil production while respecting distance and time constraints. It uses real-world parameters like office location, maximum distance per operator, maximum time that the operator can work in a day, and average speed travelling from well to well. The approach can be easily scaled to handle larger datasets

Optimization Technique

  • It utilizes linear programming via the PuLP library, which is perfect for this type of constrained optimization problem.
  • The objective function maximizes oil production, while constraints ensure that distance and time limits are not exceeded.

The input dataframe contains

Columns:

Well: API or Name of the well

Lat: Latitude

Long: Longitude

Route; Usually Each well is already assigned a pre determined Route and an operator.

Production : In this case is loss of production due to a well issue.

ServiceTime: Many operators use downtime coding and each code may have times to fix issues. if not you one can manually add the time one would take to tackle the issue.

User inputs:

office_location = (35.09, -95.97)
max_distance = 100  # Maximum distance per operator (in miles)
max_time = 480  # Maximum time per operator (in minutes, e.g., 8 hours)
speed = 50  # Average speed (in mph)        

Here is the code.

import pulp
import pandas as pd
from geopy.distance import geodesic
import folium        


 # Calculate distances and travel times
def calculate_distance(loc1, loc2):
    return geodesic(loc1, loc2).miles

def calculate_travel_time(distance, speed):
    return (distance / speed)  60  # Convert hours to minutes

# Precompute distances and travel times
distances = {}
travel_times = {}
for , well in wells.iterrows():
    welllocation = (well['Lat'], well['Long'])
    distance = calculate_distance(office_location, well_location)
    distances[well['Well']] = distance
    travel_times[well['Well']] = calculate_travel_time(distance, speed)

# Function to solve the optimization problem for a single operator
def optimize_operator_route(operator_wells, office_location, max_distance, max_time):
    # Calculate distances and travel times from office to each well
    distances = {}
    travel_times = {}
    for , well in operatorwells.iterrows():
        well_location = (well['Lat'], well['Long'])
        distance = calculate_distance(office_location, well_location)
        distances[well['Well']] = distance
        travel_times[well['Well']] = calculate_travel_time(distance, speed)

    # Define the problem
    prob = pulp.LpProblem(f"{operator}_Well_Selection", pulp.LpMaximize)

    # Decision variables
    x = pulp.LpVariable.dicts("x", operator_wells['Well'], cat='Binary')

    # Objective function: Maximize oil production
    prob += pulp.lpSum([x[well]  operator_wells.loc[operator_wells['Well'] == well, 'Production'].values[0] for well in operator_wells['Well']])

    # Constraint 1: Total distance must not exceed max_distance
    prob += pulp.lpSum([x[well]  distances[well] for well in operator_wells['Well']]) <= max_distance

    # Constraint 2: Total time (travel + service) must not exceed max_time
    prob += pulp.lpSum([x[well]  (travel_times[well] + operator_wells.loc[operator_wells['Well'] == well, 'ServiceTime'].values[0]) for well in operator_wells['Well']]) <= max_time

    # Solve
    prob.solve()

    # Extract selected wells
    selected_wells = []
    for well in operator_wells['Well']:
        if pulp.value(x[well]) == 1:
            selected_wells.append(well)
    return operator_wells[operator_wells['Well'].isin(selected_wells)]

# Process each operator
results = []
for operator in wells['Route'].unique():
    operator_wells = wells[wells['Route'] == operator]
    optimized_wells = optimize_operator_route(operator_wells, office_location, max_distance, max_time)
    results.append(optimized_wells)

# Combine results into a single dataframe
results_df = pd.concat(results)
wells['Attended'] = wells['Well'].isin(results_df['Well']).map({True: 'Yes', False: 'No'})
wells=wells.sort_values(by=['Route','Attended'],ascending=[True, False])
print("Optimized Wells for Each Operator:")
print(wells)
# Visualize the routes in Folium
m = folium.Map(location=office_location, zoom_start=10)

# Add the office location
folium.Marker(
    location=office_location,
    popup="Office",
    icon=folium.Icon(color="green", icon="home")
).add_to(m)

# Add wells and routes for each operator
colors = ['blue', 'red']  # Different colors for each operator
for i, operator in enumerate(wells['Route'].unique()):
    operator_wells = results_df[results_df['Route'] == operator]
    if not operator_wells.empty:
        # Create a list of coordinates for the route
        route_coords = [office_location]  # Start at the office
        for order, (_, row) in enumerate(operator_wells.iterrows(), start=1):
            well_coords = (row['Lat'], row['Long'])
            route_coords.append(well_coords)
            folium.Marker(
                location=well_coords,
                popup=f"Well {row['Well']}",
                icon=folium.Icon(color=colors[i], icon="tint")
            ).add_to(m)
            # Add label next to the marker
            folium.map.Marker(
                location=well_coords,
                icon=folium.DivIcon(
                    icon_size=(150, 36),
                    icon_anchor=(0, 0),
                    html=f'<div style="font-size: 12px; color: black;">{row["Well"]} - {order}</div>'
                )
            ).add_to(m)

        route_coords.append(office_location)  # Return to the office

        # Draw the route
        folium.PolyLine(
            locations=route_coords,
            color=colors[i],
            weight=2.5,
            opacity=1,
            popup=f"{operator}'s Route"
        ).add_to(m)

# Save and display the map
m.save("optimized_routes.html")        

Resulting Data Table:


Ori Benyamini

Business Advisor at National Business Capital

4 周

Fantastic insights, Dicman! Your approach with Python and open-source tools makes complex route optimization accessible and efficient. Love the humor about driving over water—keeps it light-hearted! ?? Cheers to innovation!

要查看或添加评论,请登录

Dicman Alfred的更多文章

社区洞察

其他会员也浏览了