Retrieving data objects#

Python Tool Pro allows Petrel objects to be accessed from an external Python IDE and utilized in a wide range of Python functions. The image below summarizes the petrel objects supported by Python Tool Pro alongside the python property used to retrieve the data objects. All these domain objects will be returned as a Python dictionary using the Petrel path as keys. If multiple objects have the same path, a list of them is returned.

image.png

Python is a versatile language and often multiple ways are possible to achieve what you want. To work with a Petrel domain object, it needs to be assigned to a Python variable. This can be done by using the path of the Petrel object in the matching property of the PetrelConnection ‘petrel’. E.g. to retrieve a specific well, use the property ‘petrel.wells[‘Petrel path]’.

However, instead of explicitly using the Petrel path to assign a Python variable, it is recommended to iterate over the returned dictionary. When iterated over, the objects are returned, not their paths (unlike a standard Python dictionary which returns the keys).

Using list comprehensions you can create a list of data objects that you can then assign to your Python variable.

Let’s look at an example on how to retrieve all the wells from our Petrel project by using the .wells property.

[2]:
from cegalprizm.pythontool import PetrelConnection
petrel = PetrelConnection()

all_wells = petrel.wells
print(all_wells)
{'Input/Wells/Injectors/C2': Well(petrel_name="C2"), 'Input/Wells/Producers/B9': Well(petrel_name="B9"), 'Input/Wells/Wells with Sw-Por/34-5': Well(petrel_name="34-5"), 'Input/Wells/Injectors/C4': Well(petrel_name="C4"), 'Input/Wells/Other wells/C1': Well(petrel_name="C1"), 'Input/Wells/Producers/A15': Well(petrel_name="A15"), 'Input/Wells/Other wells/B1': Well(petrel_name="B1"), 'Input/Wells/34/10 wells/34/10-A 10': Well(petrel_name="34/10-A 10"), 'Input/Wells/Injectors/C5': Well(petrel_name="C5"), 'Input/Wells/Injectors/C6': Well(petrel_name="C6"), 'Input/Wells/Producers/A10': Well(petrel_name="A10"), 'Input/Wells/Producers/A16': Well(petrel_name="A16"), 'Input/Wells/Other wells/C7': Well(petrel_name="C7"), 'Input/Wells/Wells with Sw-Por/34-2': Well(petrel_name="34-2"), 'Input/Wells/34/10 wells/34/10-A 11': Well(petrel_name="34/10-A 11"), 'Input/Wells/34/10 wells/34/10-A 12': Well(petrel_name="34/10-A 12"), 'Input/Wells/Wells with Sw-Por/G12': Well(petrel_name="G12"), 'Input/Wells/Injectors/C3': Well(petrel_name="C3"), 'Input/Wells/Producers/B8': Well(petrel_name="B8"), 'Input/Wells/Other wells/B2': Well(petrel_name="B2"), 'Input/Wells/Other wells/B4': Well(petrel_name="B4")}

The cell above returned all the wells from the project in a dictionary where the keys represents the path of the well within the Petrel input tree (i.e Input/Wells/Injectors/C3 ) and the value represents the name of the well ( Well(petrel_name=“C3”) ). We can also save all the well paths to a list and then use slicing to get the name of a particular well:

[3]:
# Get all the well paths from the dictionary keys
all_wells_paths=petrel.wells.keys()
# Save them in a list
paths = list(all_wells_paths)
#Slice the list to get the first well
well = petrel.wells[paths[0]]
print(well)
Well(petrel_name="C3")

We can also iterate through all the wells within the Petrel project by using a for loop:

[4]:
for obj in petrel.wells:
    print(obj)
Well(petrel_name="C3")
Well(petrel_name="C6")
Well(petrel_name="B8")
Well(petrel_name="C1")
Well(petrel_name="B1")
Well(petrel_name="A15")
Well(petrel_name="C2")
Well(petrel_name="34/10-A 12")
Well(petrel_name="B9")
Well(petrel_name="34-2")
Well(petrel_name="34/10-A 10")
Well(petrel_name="B2")
Well(petrel_name="B4")
Well(petrel_name="C5")
Well(petrel_name="A10")
Well(petrel_name="34/10-A 11")
Well(petrel_name="G12")
Well(petrel_name="C7")
Well(petrel_name="34-5")
Well(petrel_name="A16")
Well(petrel_name="C4")

Note: When iterated over, the objects are returned, not their paths (unlike a standard Python dictionary which returns the keys).

Functions and properties#

Properties indicate an intrinsic property of the object which is not going to change.

Function calls are requests for data or instructions to do something, and most often contain parameters which specify what kind of data. Functions are called with a parenthesis after the function name, which can receive one or more parameters.

The image below illustrates some of the most common functions and properties supported by most of the Petrel objects. However, each Petrel object also has dedicated functions and properties. To get a detailed description of all of them for each Petrel object type, please navigate to the Python API documentation chapter.

retrievedata.png

Properties Examples

The .droid property returns the object id or guid which represents the Petrel filename in the project directory.

.droid2.png

[5]:
well.droid
[5]:
'dbae9e2e-3eea-4f7f-a357-b2d8141eaf3e'

To access the path of an object which represents the key of the dictionary used to retrieve the data, we can use the .path property:

[24]:
well.path
[24]:
'Input/Wells/Injectors/C3'

Similarly, we can access the name of the object which represents the value of the dictionary used to retrieve the data. Note that by using the .petrel_name property we are returning just the name of the object without the prefix petrel_name= as seen in previous examples.

[7]:
well.petrel_name
[7]:
'C3'

Now we can combine the .wells property with the .petrel_name and .path properties to iterate over the wells in our project and retrieve their name and path.

[14]:
for obj in petrel.wells:
    print(obj.petrel_name)
    print(obj.path)
C3
Input/Wells/Injectors/C3
C6
Input/Wells/Injectors/C6
B8
Input/Wells/Producers/B8
C1
Input/Wells/Other wells/C1
B1
Input/Wells/Other wells/B1
A15
Input/Wells/Producers/A15
C2
Input/Wells/Injectors/C2
34/10-A 12
Input/Wells/34/10 wells/34/10-A 12
B9
Input/Wells/Producers/B9
34-2
Input/Wells/Wells with Sw-Por/34-2
34/10-A 10
Input/Wells/34/10 wells/34/10-A 10
B2
Input/Wells/Other wells/B2
B4
Input/Wells/Other wells/B4
C5
Input/Wells/Injectors/C5
A10
Input/Wells/Producers/A10
34/10-A 11
Input/Wells/34/10 wells/34/10-A 11
G12
Input/Wells/Wells with Sw-Por/G12
C7
Input/Wells/Other wells/C7
34-5
Input/Wells/Wells with Sw-Por/34-5
A16
Input/Wells/Producers/A16
C4
Input/Wells/Injectors/C4

The .readonly property retrieves a boolean value that indicates if the object is in a read-only format or not.

[15]:
well.readonly
[15]:
True

We can modify the readonly status of any object by assigning it a True or False value. The default value is True.

[26]:
well.readonly = False
well.readonly
[26]:
False

Let’s explore the template and unit symbol using some of the grids properties in our project. Similarly to the .wells property the .grid_properties will return a dictionary of the path and the name of each property within our 3D model.

[22]:
petrel.grid_properties
[22]:
Properties({'Models/Gullfaks2004/Gullfaks Final (DC)/Properties/NG': GridProperty(petrel_name="NG"), 'Models/Final model/Training/Properties/Conditioned porosity': GridProperty(petrel_name="Conditioned porosity"), 'Models/Final model/Training/Properties/Porosity': GridProperty(petrel_name="Porosity"), 'Models/Gullfaks2004/Gullfaks Final (DC)/Properties/Porosity': GridProperty(petrel_name="Porosity")})

Let’s go ahead and retrieve the Porosity property of our model:

[19]:
# Get all the properties paths from the dictionary keys
all_grids_properties_paths=petrel.grid_properties.keys()
# Save them in a list
grid_prop_paths = list(all_grids_properties_paths)
#Slice the list to get the first well
grid_prop = petrel.grid_properties[grid_prop_paths[2]]
print(grid_prop)
GridProperty(petrel_name="Porosity")

The .template property returns the Petrel template for the object as a string. If no template is available,it will return an empty string. In Petrel, for the grid property example the template can be found by accessing the setting of a property. Similarly, using the .unit_symbol property we can access the unit for any object associated with a certain template. In Petrel you can access this data by propping up the global settings for the selected property template.

templateUnitSymbol2.png

[20]:
grid_prop.template
[20]:
'Porosity'
[21]:
grid_prop.unit_symbol
[21]:
'm3/m3'

Functions examples

In the code block below we call the function retrieve_stats(), notice that the parenthesis are empty, but in reality we input a reference to the object the function is called on, although we do not need to state it. The statistics are a snapshot of the information in the Statistics page of the Settings panel of the object in the Petrel tree. Both the dictionary key and value are strings, and may contain punctuation, English phrases or just filler information. Any changes to the returned dictionary will not be saved or affect anything.

retrieveStats2.png

[17]:
well.retrieve_stats()
[17]:
{'X Min': '456244.15',
 'X Max': '456651.29',
 'X Delta': '407.139999999956',
 'Y Min': '6788724.75',
 'Y Max': '6788724.75',
 'Y Delta': '0',
 'Elevation depth [m] Min': '-2239.19',
 'Elevation depth [m] Max': '-1852.23',
 'Elevation depth [m] Delta': '386.96',
 'Lat Min': '61.2289616388889',
 'Lat Max': '61.229007',
 'Lat Delta': '4.53611111126406E-05',
 'Long Min': '2.18514680555556',
 'Long Max': '2.19272786111111',
 'Long Delta': '0.00758105555555533',
 'Wellhead X-coord.': '456244.15',
 'Wellhead Y-coord.': '6788724.75',
 'Well datum': 'KB[0.00]',
 'Number of points': '582',
 'Length of deviation': '581.29',
 'Md at first point': '1852.23',
 'TVD at first point': '1852.23',
 'TVDSS at first point': '1852.23',
 'Md at last point': '2433.52',
 'TVD at last point': '2239.19',
 'TVDSS at last point': '2239.19',
 'Bottom hole X': '456651.29',
 'Bottom hole Y': '6788724.75',
 'Number of logs': '',
 '   In this folder': '3',
 '   Includes sub folders': '25',
 'Active time depth log': 'One-way time 1'}

To get and overview of the changes made to a Petrel domain object over time we can use the .retrieve_history() function to return the Petrel history of the object as a Pandas dataframe.

[23]:
well.retrieve_history()
[23]:
Date User Action Description
0 Jan 01 0001 01:00 Import U:\Doc\PETREL Course\Data for course\Updated d...
1 Apr 24 2002 16:05 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
2 Apr 24 2002 16:06 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
3 Apr 24 2002 16:06 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
4 Apr 24 2002 16:07 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
5 Apr 24 2002 16:08 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
6 Apr 24 2002 16:09 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
7 Apr 24 2002 16:15 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
8 Apr 24 2002 16:16 marit Import C:\Documents and Settings\marit\Desktop... Well logs (ASCII)
9 Nov 04 2002 11:35 marit Import C:\Demo\Dip data for Gullfaks2002\C3.txt Well logs (ASCII)
10 Dec 30 2015 11:32 schulte9 Upgraded flow correlations 2
11 Jan 09 2017 17:51 maximeg Survey activated Explicit survey 1

We can also clone an object and create a copy of it within Petrel. The clone will be placed in the same collection as the source object. This function is useful for creating back-ups of the data we are working with as well as writing new results back to Petrel.

[30]:
grid_prop.clone("new_prop", copy_values= True)
[30]:
GridProperty(petrel_name="new_prop")

By running the cell above we’ve successfully created a new property called new_prop in our model. It represents a copy of the existing porosity property, having the same template and values. We could also create a copy without copying the values by setting the copy_values=False . This is particularly useful when writing results back to Petrel. We can create a copy of a property that has the correct template but assign values that were modeled by us, in Python.