Surfaces and surface attributes#
This section offers an overview of the different functions and properties available for the Petrel Surface object subcategories.
Surfaces#
Check out the API documentation to view a detailed description of all the functions and properties available for working with surfaces.
[2]:
from cegalprizm.pythontool import PetrelConnection
petrel = PetrelConnection()
The .surface property returns all the surfaces as a dictionary where the keys represent the path of the surface within the Petrel input tree and the values represent the name of each surface:
[3]:
petrel.surfaces
[3]:
Surfaces({'Input/Depth surfaces/Top Etive (Depth 1)': Surface(petrel_name="Top Etive (Depth 1)"), 'Input/Velocity Data/Top Ness [Final]': Surface(petrel_name="Top Ness [Final]"), 'Input/Surfaces (Time)/Top Etive': Surface(petrel_name="Top Etive"), 'Input/Surfaces (Time)/Base Cretaceous': Surface(petrel_name="Base Cretaceous"), 'Input/Isochores (depth)/Ness/Ness-2': Surface(petrel_name="Ness-2"), 'Input/Depth surfaces/Top Tarbert (Depth 1)': Surface(petrel_name="Top Tarbert (Depth 1)"), 'Input/AOI Model': Surface(petrel_name="AOI Model"), 'Input/Depth surfaces/Base Cretaceous (Depth 1)': Surface(petrel_name="Base Cretaceous (Depth 1)"), 'Input/Surfaces (Time)/Seabed': Surface(petrel_name="Seabed"), 'Input/Velocity Data/Top Tarbert [Final]': Surface(petrel_name="Top Tarbert [Final]"), 'Input/Depth surfaces/Top Ness (Depth 1)': Surface(petrel_name="Top Ness (Depth 1)"), 'Input/Surfaces (Time)/Top Ness': Surface(petrel_name="Top Ness"), 'Input/Isochores (depth)/Tarbert/Tarbert-1': Surface(petrel_name="Tarbert-1"), 'Input/Velocity Data/Base Cretaceous [Final]': Surface(petrel_name="Base Cretaceous [Final]"), 'Input/Surfaces (Time)/Top Tarbert': Surface(petrel_name="Top Tarbert"), 'Input/Velocity Data/Top Etive [Final]': Surface(petrel_name="Top Etive [Final]")})
We can iterate over all the surfaces within the dictionary and print out their names:
[4]:
for s in petrel.surfaces:
print(s.petrel_name)
Top Etive (Depth 1)
Top Ness [Final]
Top Etive
Base Cretaceous
Ness-2
Top Tarbert (Depth 1)
AOI Model
Base Cretaceous (Depth 1)
Seabed
Top Tarbert [Final]
Top Ness (Depth 1)
Top Ness
Tarbert-1
Base Cretaceous [Final]
Top Tarbert
Top Etive [Final]
To select the Top Etive surface, we can create a list of paths for all of the surfaces and then use list slicing to access the surface we want. The argument paths[2], selects the third item from the list you get from paths = list(all_surfaces.keys()):
[50]:
all_surfaces = petrel.surfaces
paths = list(all_surfaces.keys())
Top_Etive = petrel.surfaces[paths[2]]
print(Top_Etive)
Surface(petrel_name="Top Etive")
To determine the size of the surface we can use the .extent property, which returns the number of surface nodes in the i and j directions:
[6]:
extent = Top_Etive.extent
print(extent)
Extent(i=236, j=268, k=1)
The .coords_extent returns the extent of the surface in world-coordinates (Xmin, Xmax, Ymin, Ymax, Zmin, Zmax):
[80]:
coord_extent = Top_Etive.coords_extent
print(coord_extent, '\n')
print(f'x: {coord_extent.x_axis}')
print(f'y: {coord_extent.y_axis}')
print(f'z: {coord_extent.z_axis}')
print()
CoordinatesExtent(x_axis=AxisExtent(min=450800.000000, max=459080.000000), y_axis=AxisExtent(min=6780240.000000, max=6790240.000000), z_axis=AxisExtent(min=-2278.070000, max=-1643.700000))
x: AxisExtent(min=450800.000000, max=459080.000000)
y: AxisExtent(min=6780240.000000, max=6790240.000000)
z: AxisExtent(min=-2278.070000, max=-1643.700000)
The returned results of the .extent and .coords_extent properties can also be visualized in Petrel by accessing the Statistics of the selected surface:
Using the .position() function we can retrieve the x,y,z position of the surface node by specifying the i and j-index of the surface node:
[8]:
i = 11
j = 20
pos = Top_Etive.position(i, j)
print(f' {i}, {j}: {pos}')
11, 20: Point(x=451000.00, y=6781040.00, z=nan)
Similarly, using the .indices() function we can retrieve the indices of the surface node nearest the specified point. Note that the node indices are 0-based, but in the Petrel UI they are 1-based:
[10]:
inds = Top_Etive.indices(pos.x, pos.y)
print(f'{pos}: {inds.i}, {inds.j}')
Point(x=451000.00, y=6781040.00, z=nan): 11, 20
The .parent_collection property will return the selected surface and all its siblings in the Petrel Input Tree:
[11]:
sibling_surfaces = Top_Etive.parent_collection
for Top_Etive in sibling_surfaces:
print(f'\t{Top_Etive.extent}\t{Top_Etive.petrel_name}')
Extent(i=286, j=180, k=1) Seabed
Extent(i=238, j=291, k=1) Base Cretaceous
Extent(i=237, j=269, k=1) Top Tarbert
Extent(i=235, j=269, k=1) Top Ness
Extent(i=236, j=268, k=1) Top Etive
To check the available surface attributes for the selected surface we can use the .surface_attributes property:
[13]:
for atr in Top_Etive.surface_attributes:
print(atr)
SurfaceAttribute(petrel_name="TWT")
SurfaceAttribute(petrel_name="Depth 1")
Surface attributes#
Check out the API documentation to view a detailed description of all the functions and properties available for working with surface attributes:
The .surface_attributes property returns all the continuous surface attributes as a dictionary where the keys represent the path of the surface attribute within the Petrel input tree and the value represents its name:
[14]:
petrel.surface_attributes
[14]:
SurfaceAttributes({'Input/Surfaces (Time)/Base Cretaceous/Depth 1': SurfaceAttribute(petrel_name="Depth 1"), 'Input/Surfaces (Time)/Top Tarbert/TWT': SurfaceAttribute(petrel_name="TWT"), 'Input/Surfaces (Time)/Top Ness/Depth 1': SurfaceAttribute(petrel_name="Depth 1"), 'Input/Surfaces (Time)/Top Etive/TWT': SurfaceAttribute(petrel_name="TWT"), 'Input/Surfaces (Time)/Top Tarbert/Depth 1': SurfaceAttribute(petrel_name="Depth 1"), 'Input/Surfaces (Time)/Top Etive/Depth 1': SurfaceAttribute(petrel_name="Depth 1"), 'Input/Surfaces (Time)/Top Ness/TWT': SurfaceAttribute(petrel_name="TWT"), 'Input/Surfaces (Time)/Base Cretaceous/TWT': SurfaceAttribute(petrel_name="TWT")})
Similarly, we can retrieve a dictionary of all the discrete surface attributes by using the .surface_discrete_attributes property:
[20]:
petrel.surface_discrete_attributes
[20]:
SurfaceDiscreteAttributes({'Input/Surfaces (Time)/Top Etive/Facies': SurfaceDiscreteAttribute(petrel_name="Facies")})
We can iterate over all the surface attributes and return their names:
[56]:
print('Continuous surface attributes:', '\n')
for sa in petrel.surface_attributes:
print(sa.petrel_name)
print('\n','Discrete surface attributes:', '\n')
for sa in petrel.surface_discrete_attributes:
print(sa.petrel_name)
Continous surface attributes
Depth 1
TWT
Depth 1
TWT
Depth 1
Depth 1
TWT
TWT
Discrete surface attributes
Facies
Let’s select the depth surface attribute which belongs to the Top Etive surface:
[59]:
all_surfaces_atr = petrel.surface_attributes
paths = list(all_surfaces_atr.keys())
Top_Etive_Depth = petrel.surface_attributes[paths[5]]
print(Top_Etive_Depth)
SurfaceAttribute(petrel_name="Depth 1")
We can check if the selected attribute belongs to the Top Etive surface using the .surface property:
[61]:
parent_surf = Top_Etive_Depth.surface
print(parent_surf)
Surface(petrel_name="Top Etive")
To check what other attributes the selected surface has we can use the .surface_attributes property:
[63]:
for attr in parent_surf.surface_attributes:
print(f'{attr}')
SurfaceAttribute(petrel_name="TWT")
SurfaceAttribute(petrel_name="Depth 1")
SurfaceDiscreteAttribute(petrel_name="Facies")
Petrel represents some undefined values by MAX_INT, and others by NaN. The undef value of the surface attribute can be returned using the .undef_value property:
[45]:
print(Top_Etive_Depth.undef_value)
nan
The .template property returns the Petrel template for the surface as a string. If no template is available, it will return an empty string. 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 opening the global settings for the selected property template.
[66]:
print('Template:', Top_Etive_Depth.template)
print('\n')
print('Unit:',Top_Etive_Depth.unit_symbol)
Template: Elevation depth
Unit: m
The .has_same_parent() function checks if two attributes belong to the same parent surface. In the example, below we assign two different surface attributes to the variables attr0 and attr1. The .has_same_parent() checks if the two belong to the Top Etive surface and returns a boolean value:
[72]:
attr0 = petrel.surface_attributes[paths[0]]
attr1 = petrel.surface_attributes[paths[3]]
print(f'{attr1} and {Top_Etive} has same parent: {attr1.has_same_parent(Top_Etive_Depth)}')
print(f'{attr0} and {Top_Etive} has same parent: {attr0.has_same_parent(Top_Etive_Depth)}')
SurfaceAttribute(petrel_name="TWT") and Surface(petrel_name="Top Etive") has same parent: True
SurfaceAttribute(petrel_name="Depth 1") and Surface(petrel_name="Top Etive") has same parent: False
We can create a chunk that contains all the values for the attribute by using the .all() function. To learn more about chunks please view the Working with chunks subchapter of the User Guide.
[73]:
Top_Etive_Depth.all()
[73]:
<cegalprizm.pythontool.chunk.Chunk at 0x1fc8683f040>
Alternatively, using the .chunk() function, we can select only a range of the surface attribute that we want to convert into a chunk:
[77]:
i = (11, 25)
j = (20, 40)
Top_Etive_Depth.chunk(i,j)
[77]:
<cegalprizm.pythontool.chunk.Chunk at 0x1fc7a0d4070>
For the discrete surface attributes, we can return a dictionary of the discrete codes and values using the .discrete_codes property:
[79]:
all_surfaces_atr = petrel.surface_discrete_attributes
paths = list(all_surfaces_atr.keys())
Top_Etive_Facies = petrel.surface_discrete_attributes[paths[0]]
Top_Etive_Facies.discrete_codes
[79]:
{0: 'Clay', 1: 'Sand', 2: 'Silt', 3: 'Fine Silt'}