Skip to content

Commit

Permalink
EditFiles
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderJuestel committed Feb 23, 2024
1 parent f59e884 commit 7cca835
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 7 deletions.
51 changes: 46 additions & 5 deletions pyborehole/deviation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.ticker import FormatStrFormatter


class Deviation:
Expand Down Expand Up @@ -194,7 +195,8 @@ def __init__(self,
self.tvd = pos.depth
if add_origin:
if borehole.crs == 'EPSG:4326':
raise ValueError('Please use location coordinates in a cartesian coordinate system for the borehole when adding the origin to desurveyed borehole')
raise ValueError(
'Please use location coordinates in a cartesian coordinate system for the borehole when adding the origin to desurveyed borehole')
self.northing_rel = pos.northing + borehole.y
self.easting_rel = pos.easting + borehole.x
else:
Expand All @@ -206,13 +208,41 @@ def __init__(self,
self.northing_rel)
self.radius = np.sqrt(self.northing_rel ** 2 + self.easting_rel ** 2)

# Storing coordinates
coords = np.c_[self.easting_rel,
self.northing_rel]

# Calculating total distance from origin
total_distance = [np.linalg.norm(coords[0] - coords[i + 1]) for i in range(len(coords) - 1)]
total_distance.insert(0, 0)
self.total_distance = total_distance

# Calculating total direction
self.total_angle = []
for i in range(len(coords)):
if coords[0][0] < coords[i][0] and coords[0][1] >= coords[i][1]:
angle = 180 - np.rad2deg(np.arccos((coords[0][1] - coords[i][1]) / total_distance[i]))

elif coords[0][0] > coords[i][0] and coords[0][1] < coords[i][1]:
angle = 180 + np.rad2deg(np.arccos((coords[0][1] - coords[i][1]) / total_distance[i]))

elif coords[0][0] < coords[i][0] and coords[0][1] < coords[i][1]:
angle = 180 - np.rad2deg(np.arccos((coords[0][1] - coords[i][1]) / total_distance[i]))

else:
angle = 180 + np.rad2deg(np.arccos((coords[0][1] - coords[i][1]) / total_distance[i]))

self.total_angle.append(angle)

# Creating data dict
data_dict = {'Measured Depth': [self.md],
'Inclination': [self.inc],
'Azimuth': [self.azi],
'Easting_rel': [self.easting_rel],
'Northing_rel': [self.northing_rel],
'True Vertical Depth': [self.tvd],
'Total Distance': [self.total_distance],
'Total Direction': [self.total_angle]
}

# Assigning data_dict
Expand All @@ -228,7 +258,10 @@ def __init__(self,
# Creating DataFrame from position data
self.desurveyed_df = pd.DataFrame.from_dict({'Easting_rel': self.easting_rel,
'Northing_rel': self.northing_rel,
'True Vertical Depth': self.tvd},
'True Vertical Depth': self.tvd,
'Total Distance': self.total_distance,
'Total Direction': self.total_angle
},
orient='columns',
)

Expand Down Expand Up @@ -304,7 +337,8 @@ def add_origin_to_desurveying(self,
"""
# Raising a ValueError if the CRS is WGS84
if self.crs == 'EPSG:4326':
raise ValueError('Please use location coordinates in a cartesian coordinate system for the borehole when adding the origin to desurveyed borehole')
raise ValueError(
'Please use location coordinates in a cartesian coordinate system for the borehole when adding the origin to desurveyed borehole')

# Checking that the x coordinate is of type float or int
if not isinstance(x, (float, int, type(None))):
Expand Down Expand Up @@ -338,7 +372,8 @@ def add_origin_to_desurveying(self,
# Creating Data Dict
data_dict = {'Northing': [self.desurveyed_df['Northing'].values],
'Easting': [self.desurveyed_df['Easting'].values],
'True Vertical Depth Below Sea Level': [self.desurveyed_df['True Vertical Depth Below Sea Level'].values],
'True Vertical Depth Below Sea Level': [
self.desurveyed_df['True Vertical Depth Below Sea Level'].values],
}
self._borehole.update_df(data_dict=data_dict)

Expand Down Expand Up @@ -445,7 +480,10 @@ def plot_deviation_polar_plot(self,
ax.autoscale_view()

# Setting rlims
ax.set_rlim(0, 1.05*np.max(self.radius))
ax.set_rlim(0, 1.05 * np.max(self.radius))

# Adding units to deviation
ax.yaxis.set_major_formatter(FormatStrFormatter('%d m'))

else:
ax.plot(self.az,
Expand All @@ -454,6 +492,9 @@ def plot_deviation_polar_plot(self,
# Setting rlims
ax.set_rlim(0, 1.05 * np.max(self.radius))

# Adding units to deviation
ax.yaxis.set_major_formatter(FormatStrFormatter('%d m'))

return fig, ax

def plot_deviation_3d(self,
Expand Down
202 changes: 200 additions & 2 deletions pyborehole/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,11 +480,20 @@ def plot_well_logs(self,
if not isinstance(add_net_to_gross, (int, type(None))):
raise TypeError('The add_net_to_gross variable must be provided as int')

if isinstance(tracks, str):
tracks_str = tracks
tracks = [tracks]

# Selecting tracks
df = self.df[tracks + [depth_column]].reset_index()

# Converting list back to string
if len(tracks) == 1:
tracks = tracks_str

# Creating plot if tracks is of type string
if isinstance(tracks, str):

# Creating plot
fig, ax = plt.subplots(1, 1, figsize=(1 * 2, 8))

Expand Down Expand Up @@ -1172,6 +1181,194 @@ def calculating_ng(row,

return net_to_gross

def add_curve_to_curve(self,
original_mnemonic: str,
mnemonic: str,
descr: str,
unit: str):
"""Add curve to curves DataFrame so it can also be used for plotting.
Parameters
__________
original_mnemonic : str
Original mnemonic of the track.
mnemonic : str
Mnemonic of the track.
descr : str
Description of the track.
unit : str
Unit of the data of the track.
Raises
______
TypeError
If the wrong input data types are provided.
Examples
________
>>> borehole.logs.add_curve_to_curves(original_mnemonic='Velocity', mnemonic='Velocity', descr='Velocity', unit='m/s')
>>> borehole.logs.curves
.. versionadded:: 0.0.1
"""

# Checking that the original mnemonic is provided as string
if not isinstance(original_mnemonic, str):
raise TypeError('original_mnemonic must be provided as string')

# Checking that the mnemonic is provided as string
if not isinstance(mnemonic, str):
raise TypeError('mnemonic must be provided as string')

# Checking that the description is provided as string
if not isinstance(descr, str):
raise TypeError('descr must be provided as string')

# Checking that the unit is provided as string
if not isinstance(unit, str):
raise TypeError('unit must be provided as string')

# Checking that track is not available in the curves DataFrame
if original_mnemonic in self.curves:
raise ValueError('Track is already present in Curve DataFrame')

# Concatenate new curve to existing curves
self.curves = pd.concat([self.curves,
pd.DataFrame.from_dict(
{'original_mnemonic': [original_mnemonic],
'mnemonic': [mnemonic],
'descr': [descr],
'unit': [unit]}),
],
ignore_index=True)

def despike_curve(self,
track: str,
window_length: int):

self.df[track + '_rolling'] = self.df.rolling(window=window_length)[track].mean()

curve_df = self.curves[self.curves['original_mnemonic'] == track].reset_index(drop=True).iloc[0]

self.add_curve_to_curve(original_mnemonic=track + '_rolling',
mnemonic=curve_df['mnemonic'] + '_rolling',
descr=curve_df['descr'] + '_rolling',
unit=curve_df['unit'])

def calculate_time_depth_relationship(self,
track: str,
depth_column: str = 'DEPTH',
replacement_velocity: Union[int, float] = 2000):
log_start = self.df[depth_column].iloc[0]
altitude = self._borehole.altitude_above_sea_level
gap_int = log_start - altitude
log_start_time = 2 * gap_int / replacement_velocity

increment = \
self.well_header[self.well_header['mnemonic'] == 'STEP'].reset_index(drop=True)['value'].iloc[0]

dt_interval = np.nan_to_num(self.df[track].values) * increment / 1e6
t_cum = np.cumsum(dt_interval) * 2
self.df['TWT'] = t_cum + log_start_time

self.add_curve_to_curve(original_mnemonic='TWT',
mnemonic='TWT',
descr='TWT',
unit='s')

def calculate_acoustic_impedance(self,
velocity_track: Union[str, np.ndarray],
density_track: Union[str, np.ndarray],
add_to_well_logs: bool = True):

if isinstance(velocity_track, str) and isinstance(density_track, str):
velocity = self.df[velocity_track].values
density = self.df[density_track].values

values = np.c_[velocity, density]

if isinstance(velocity_track, np.ndarray) and isinstance(density_track, np.ndarray):
values = np.c_[velocity_track, density_track]

acoustic_impedance = np.apply_along_axis(np.product, -1,
values)

if add_to_well_logs:
self.df['Acoustic Impedance'] = acoustic_impedance

self.add_curve_to_curve(original_mnemonic='Acoustic Impedance',
mnemonic='Acoustic Impedance',
descr='Acoustic Impedance',
unit=' ')
else:
return acoustic_impedance

def calculate_reflection_coefficient(self,
velocity_track: Union[str, np.ndarray],
density_track: Union[str, np.ndarray],
add_to_well_logs: bool = True):

if add_to_well_logs:
self.calculate_acoustic_impedance(velocity_track=velocity_track,
density_track=density_track,
add_to_well_logs=add_to_well_logs)
acoustic_impedance = self.df['Acoustic Impedance'].values

else:
acoustic_impedance = self.calculate_acoustic_impedance(velocity_track=velocity_track,
density_track=density_track,
add_to_well_logs=add_to_well_logs)

reflection_coefficient = (acoustic_impedance[1:] - acoustic_impedance[:-1]) / (
acoustic_impedance[1:] + acoustic_impedance[:-1])

reflection_coefficient = np.append(reflection_coefficient, 0)

if add_to_well_logs:

self.df['Reflection Coefficient'] = reflection_coefficient

self.add_curve_to_curve(original_mnemonic='Reflection Coefficient',
mnemonic='Reflection Coefficient',
descr='Reflection Coefficient',
unit=' ')

else:
return reflection_coefficient

def resample_log_from_depth_to_time_domain(self,
dt: float,
track: str):

if 'TWT' not in self.df.columns:
raise ValueError(
'Please calculate time-depth relationship first before resampling log from depth to the time domain')

t_max = self.df['TWT'].iloc[-1]
t = np.arange(0, t_max, dt)

log_time_domain = np.interp(x=t,
xp=self.df['TWT'],
fp=self.df[track])

return log_time_domain

def calculate_ricker_wavelet(self,
f,
length,
dt):
t0 = np.arange(-length / 2, (length - dt) / 2, dt)
y = (1.0 - 2.0 * (np.pi ** 2) * (f ** 2) * (t0 ** 2)) * np.exp(-(np.pi ** 2) * (f ** 2) * (t0 ** 2))
return t0, y

def calculate_synthetic_seismic(self,
t0,
w,
rc_tdom):
synth = np.apply_along_axis(lambda t0: np.convolve(t0, w, mode="same"), axis=0, arr=rc_tdom)

return synth


class DLISLogs:
"""Class to initiate a Well Log Object.
Expand Down Expand Up @@ -1244,6 +1441,7 @@ class DLISLogs:
.. versionadded:: 0.0.1
"""

# Initiate class
def __init__(self,
borehole,
Expand Down Expand Up @@ -2491,8 +2689,8 @@ def resample_logs(logs: pd.DataFrame,
resampling_start=0,
resampling_end=None,
rounding_precision=5,
drop_first: bool=True,
drop_last: bool=True) -> pd.DataFrame:
drop_first: bool = True,
drop_last: bool = True) -> pd.DataFrame:
"""Resample logs.
Parameters
Expand Down

0 comments on commit 7cca835

Please sign in to comment.