Well Placement Optimization using Python PyMRST
Well placement optimization is one of the most challenging and expensive problems in the oil and gas industry. Well placement involves enhancing oil recovery by strategically drilling new infill wells within a reservoir. This process is pivotal but inherently difficult in field development, as identifying optimal well locations is often uncertain and challenging due to the complexities of reservoir heterogeneity.
In the previous tutorial, we have shown PyMRST as an open-source solution for running reservoir simulations in Python. Recently, I just released new functionality for well placement optimization in PyMRST. In this tutorial, I would like to share how to do it on a five-spot waterflooding case. Check this notebook for the complete code.
Objective Function
The first step in optimization is defining the objective function. The objective function in well placement optimization can be the cumulative oil production or the Net Present Value (NPV). For simplicity, we will use the cumulative oil production, which is the volume of oil produced after the injection of water from 4 injector wells. It is defined as the difference between Oil in Place (OIP) at time before injection and OIP at time after injection.
We create the first line of the objective function in Python
def objective(x1, y1, x2, y2, x3, y3, x4, y4):
... The rest of code
This function depends on 8 variables being the coordinates of the 1st to 4th wells which will be searched by the optimizer. The next lines indicate the action to round the numbers from decimal to integer, and put into array. Note that the optimizer searches the variables in decimal. The next line runs the model input, run the waterflooding simulation, and get the cumulative oil production result. In other words, the whole simulation is located inside this function. We will use the SPE10 static model.
def objective(x1, y1, x2, y2, x3, y3, x4, y4):
"""
Objective function
"""
# Round the number given by the optimizer
x1, y1, x2, y2 = np.round(x1), np.round(y1), np.round(x2), np.round(y2)
x3, y3, x4, y4 = np.round(x3), np.round(y3), np.round(x4), np.round(y4)
# Define well coordinates
locs = np.array([[x1, x2, x3, x4, 30],
[y1, y2, y3, y4, 111],
[1, 1, 1, 1, 1]])
well = dict({"cellx_loc": locs[0,:],
"celly_loc": locs[1,:],
"cellz_loc": locs[2,:],
"type": types,
"value": values,
"phase": phases,
"radius": radii,
"skin": skins,
"direction": directions})
pymrst.model_input(model, fluid, well, bc_front, bc_back, bc_left, bc_right,
numSteps, totTime, steps)
# run simulation
pymrst.run_simulation()
# Get Np from txt
Np = np.loadtxt('/content/result_oilwater_2phase/Np.txt').item()
return Np
Let's use initial well coordinates and run the objective function to calculate how much cumulative oil production we will get after waterflooding.
objective(1,1,60,1,1,220,60,220)
We will get 15,660 MMSTB.
Create search bounds
The optimizer will search the best locations/coordinates of water injector wells that will give the highest cumulative oil production as possible after waterflooding. In the following Figure, each well has its search bounds where the oil well is located in the center of the reservoir.
We write the bounds into the code as follows:
领英推荐
pbounds = {"x1": (1, 30), "y1": (1, 111),
"x2": (30, 60), "y2": (1, 111),
"x3": (1, 30), "y3": (111,220),
"x4": (30, 60), "y4": (111,220)}
Run Bayesian optimization
Different from MRST which uses adjoint and flow diagnostics algorithm, PyMRST uses Bayesian optimization as the algorithm for well placement optimization. Bayesian optimization is an optimization algorithm that aims to find the maximum or minimum of a black-box objective function by iteratively updating a surrogate model, typically a Gaussian process, and selecting the next evaluation point based on an acquisition function that balances exploration and exploitation. This iterative process converges to an optimal or satisfactory solution.
In PyMRST, just run the following code to start the well placement optimization.
pymrst.optimize(objective, pbounds)
The optimization process will take up to 30 minutes to finish 20 iterations, but we have satisfactory result. The output of optimization is a Table that summarizes the iterations. The optimization gives iteration 19 as the optimum result, where we get 119,000 MMSTB (improved by 103,340 MMSTB!!!) given the new coordinates as follows.
Well placement optimization results
We can create plots of new location of wells after optimization. The following Figure shows the comparison between the optimized injector well location (orange) and the initial injector well location (blue). The oil producer well is located in the center of the reservoir. We can see well 1 and well 3 are pushed farther towards to oil producer.
Lastly, we can also plot the oil saturation plot in the reservoir for 5 years.
Conclusion
We have seen how easy is handling well placement optimization problem in PyMRST. You just need to sit down and relax to wait until the optimization solves and gives recommendations of the best well locations. In a more advanced situation, try doing well placement optimization for 5 injector wells and 2 producer wells, and share with us your result!
Data Engineer @XL Axiata | Geophysicist
11 个月Will check this, thanks!!