<jupyter_start><jupyter_text><jupyter_code>import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.interpolate import interp1d 

plt.style.use("classic")

!pip install lasio
import lasio
import missingno as msno
import plotly.express as px
!git clone https://github.com/yohanesnuwara/geostatistics<jupyter_output>Cloning into 'geostatistics'...
remote: Enumerating objects: 55, done.[K
remote: Counting objects: 100% (55/55), done.[K
remote: Compressing objects: 100% (49/49), done.[K
remote: Total 199 (delta 19), reused 0 (delta 0), pack-reused 144[K
Receiving objects: 100% (199/199), 31.65 MiB | 6.99 MiB/s, done.
Resolving deltas: 100% (78/78), done.<jupyter_text>LWD data Copying script from the previous notebook, "EDA_realtime_volve_well_15_9_F-15.ipynb". There are two files, merged into one.<jupyter_code># Realtime data
LAS_file1 = "/content/geostatistics/data/volve-realtime/well_15_9_F-15/WL_RAW_CAL-DEN-ELEM-GR-NEU-REMP_MWD_1~LF1~FRM1.las"
LAS_file2 = "/content/geostatistics/data/volve-realtime/well_15_9_F-15/WL_RAW_CAL-DEN-ELEM-GR-NEU-REMP_MWD_2~LF1~FRM1.las"

mwd1 = lasio.read(LAS_file1)
mwd2 = lasio.read(LAS_file2)

# Convert LAS to dataframe
mwd1_df = mwd1.df().reset_index()
mwd2_df = mwd2.df().reset_index()

# Selected LWD logs. Special here is Bit size (BS_ARC)
mwd_lognames = ["TDEP", "GRMA", "BCAV", "WCLA", "WCAR", "WQFM", 
                "RHOB", "BPHI", "PEF", "BS_ARC"]

# Select subset dataframe
mwd1_df = mwd1_df[mwd_lognames]
mwd2_df = mwd2_df[mwd_lognames]

# Merging dataframes
mwd_df = pd.concat([mwd1_df, mwd2_df], axis=0)

# Converting ft to m
mwd_df["TDEP"] = mwd_df["TDEP"] / 3.281

# Converting NPHI in % to v/v
mwd_df["BPHI"] = mwd_df["BPHI"] / 100

mwd_df.head()
mwd_df.describe()<jupyter_output><empty_output><jupyter_text>Openhole data<jupyter_code># Open hole data 
LAS_file3 = "/content/geostatistics/data/volve-openhole/well_15_9_F-15/WLC_PETRO_COMPUTED_INPUT_1~LF1~FRM1.las"

oh = lasio.read(LAS_file3)
oh_df = oh.df().reset_index()

# Converting ft to m
oh_df["DEPTH"] = oh_df["DEPTH"] / 3.281

oh_df.head()
oh_df.describe()<jupyter_output><empty_output><jupyter_text>Merge Openhole to LWD data by interpolation I have shown interpolation method in the previous notebook. I'll now use Scipy cubic interpolation that's found to be more accurate than Numpy linear interpolation.<jupyter_code>def interpolate(df_data, df_new, x_data, y_data, x_new):
  xd, yd = df_data[x_data], df_data[y_data]
  f = interp1d(xd, yd)
  xn = df_new[x_new]
  return f(xn)

lognames_data = ["CALI",	"DT",	"GR",	"NPHI",	"PEF",	"RD",	"RHOB"]
lognames_new = ["CALI_OH",	"DT_OH",	"GR_OH",	"NPHI_OH",	"PEF_OH",	"RD_OH",	"RHOB_OH"]

new_logs = []
for i in lognames_data:
  _ = interpolate(oh_df, mwd_df, x_data="DEPTH", y_data=i, x_new="TDEP")
  new_logs.append(_)

# Merge the result to LWD dataframe
for i in range(len(lognames_new)):
  mwd_df[lognames_new[i]] = new_logs[i]

mwd_df.head()
msno.matrix(mwd_df)
plt.show()<jupyter_output><empty_output><jupyter_text>Scatter plot between openhole and LWD I make a scatter plot below to compare measurements between openhole and LWD. As we see below, only GR fits perfectly on the 1:1 line.<jupyter_code># LWD
lwd_rec_name = ["GRMA", "RHOB", "PEF", "BPHI"]
lwd_recs = []
for i in lwd_rec_name:
  _ = mwd_df[i].values
  lwd_recs.append(_)

# Openhole
oh_rec_name = ["GR_OH", "RHOB_OH", "PEF_OH", "NPHI_OH"]
oh_recs = []
for i in oh_rec_name:
  _ = mwd_df[i].values
  oh_recs.append(_)

# Scatter plot
plt.figure(figsize=(8,8))

xlabels = ["GR Openhole", "RHOB Openhole", "PEF Openhole", "NPHI Openhole"]
ylabels = ["GR LWD", "RHOB LWD", "PEF LWD", "NPHI LWD"]

for i in range(len(lwd_rec_name)):
  plt.subplot(2,2,i+1)
  plt.scatter(lwd_recs[i], oh_recs[i])

  # Plot 1:1 line
  x = [0, max(oh_recs[i])]
  plt.plot(x, x, '--', color='red') 

  plt.xlabel(xlabels[i])
  plt.ylabel(ylabels[i])

plt.tight_layout(1.3)
plt.show()<jupyter_output><empty_output><jupyter_text>Adding formation tops and facies  Percent clay, quartz, and carbonates Actually there are not only WCLA (clay), WCAR (carb), & WQFM (qtz), but also siderite, pyrite, anhydrite, etc. So, not all WCLA+WCAR+WQFM sums up to 1. 

To assume a composition of ONLY clay, carb, & qtz, I need to make correction, e.g. for clay: %WCLA / (%WCLA + %WCAR + %WQFM) * 100%<jupyter_code># Correction for WCLA, WCAR, WQM to sum up 1
xsum = mwd_df["WCLA"] + mwd_df["WCAR"] + mwd_df["WQFM"]
mwd_df["XCLA"] = mwd_df["WCLA"] / xsum 
mwd_df["XCAR"] = mwd_df["WCAR"] / xsum 
mwd_df["XQFM"] = mwd_df["WQFM"] / xsum 
# Ternary plot
fig = px.scatter_ternary(mwd_df, a="XCLA", b="XCAR", c="XQFM", color="TDEP")
fig.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14616346955796497, 'fraction_numerical': 0.02648040033361134, 'mean_word_length': 4.738038277511961, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '38986', 'license': 'MIT', 'n_tokens_mistral': 2252, 'n_tokens_neox': 2071, 'n_words': 452, 'path': 'project_notebooks/EDA_LWD_openhole_volve_well_15_9_F_15.ipynb', 'repo_name': 'yohanesnuwara/geostatistics', 'size': '4796'}