# -*- coding: utf-8 -*-
"""
Class for defining a seismic survey
Created on Fri Dec 11 20:24:38 2015
"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from builtins import str, range, open
__author__ = "yuhao"
import json
from itertools import product
from future.utils import native
import numpy as np
from .seisegy import SeiSEGY
from .well import Well
from pygeopressure.basic.horizon import Horizon
from .survey_setting import SurveySetting
from .threepoints import ThreePoints
from . import Path
[docs]class Survey(SurveySetting):
"""
Survey object for combining seismic data and well log data.
Parameters
----------
survey_dir : str
survey directory.
Attributes
----------
seis_json : str
associated seismic data information file.
well_json : str
associated well data information file.
wells : dict
dictionary holding all Well objects.
seisCube : SeisCube
SeisCube object holding seismic data.
inl_crl : dict
well position in reference to seismic survey setting (inl/crl)
Methods
-------
add_well(well)
add a well to survey
get_seis(well_name, attr, radius=0)
get seismic data in the vicinity of a given well
"""
def __init__(self, survey_dir):
"""
Parameters
----------
survey_dir : str
survey directory.
"""
self.survey_dir = Path(native(survey_dir))
self.setting_json = None
self._check_dir()
super(Survey, self).__init__(ThreePoints(self.setting_json))
self.wells = dict()
self.seismics = dict()
self.inl_crl = dict()
self.horizons = dict()
self._add_seis_wells()
self._add_seismic()
self._add_horizon()
def _check_dir(self):
survey_file = self.survey_dir / '.survey'
if survey_file.exists():
self.setting_json = native(str(survey_file))
else:
raise Exception("No survey setting file in folder!")
def _add_seismic(self):
seis_dir = self.survey_dir / "Seismics"
for seis_name in get_data_files(seis_dir):
info_file = str(self.survey_dir.absolute() / \
"Seismics" / "{}.seis".format(seis_name))
data_path = None
with open(info_file, "r") as fl:
data_path = Path(native(json.load(fl)["path"]))
if not data_path.is_absolute() and \
data_path.name == str(data_path):
data_path = self.survey_dir.absolute() / "Seismics" / data_path
self.seismics[seis_name] = SeiSEGY.from_json(info_file,
str(data_path))
def _add_seis_wells(self):
well_dir = self.survey_dir / "Wellinfo"
for well_name in get_data_files(well_dir):
info_file = str(self.survey_dir.absolute() / \
"Wellinfo" / "{}.well".format(well_name))
data_path = None
with open(info_file, "r") as fl:
data_path = Path(native(json.load(fl)["hdf_file"]))
if not data_path.is_absolute() and \
data_path.name == str(data_path):
data_path = self.survey_dir.absolute() / "Wellinfo" / data_path
temp = Well(info_file, data_path)
self.wells[temp.well_name] = temp
for well in self.wells.values():
loc = self._tie(well)
self.inl_crl[well.well_name] = loc
def _add_horizon(self):
surf_dir = self.survey_dir / "Surfaces"
for f in surf_dir.iterdir():
if f.is_file() and f.suffix == '.hor':
tmp = Horizon(str(f))
tmp.horizon_name = f.stem
self.horizons[f.stem] = tmp
def _tie(self, well):
return self.coord_2_line(well.loc)
[docs] def get_seis(self, seis_name, well_name, radius=0):
"""
Get seismic trace data nearest to the well location.
"""
radius = int(radius)
if well_name in self.inl_crl.keys():
loc = self.inl_crl[well_name]
if radius == 0:
data = self.seismics[seis_name].cdp(loc)
return [loc], [data]
else:
inlines, crlines = self._get_traces(seis_name, radius, loc)
loc = list()
data = list()
for inl, crl in product(inlines, crlines):
loc.append((inl, crl))
data.append(self.seismics[seis_name].cdp((inl, crl)))
return loc, data
else:
print("Well not found!")
return []
def _get_traces(self, seis_name, radius, cdp):
inline, crline = cdp
start_inline = self.seismics[seis_name].startInline
end_inline = self.seismics[seis_name].endInline
step_inline = self.seismics[seis_name].stepInline
start_crline = self.seismics[seis_name].startCrline
end_crline = self.seismics[seis_name].endCrline
step_crline = self.seismics[seis_name].stepCrline
inl_min = inline - radius * step_inline
if inl_min < start_inline:
inl_min = start_inline
inl_max = inline + radius * step_inline
if inl_max > end_inline:
inl_max = end_inline
crl_min = crline - radius * step_crline
if crl_min < start_crline:
crl_min = start_crline
crl_max = crline + radius * step_crline
if crl_max > end_crline:
crl_max = end_crline
inlines = np.arange(inl_min, inl_max+1, step_inline)
crlines = np.arange(crl_min, crl_max+1, step_crline)
return (inlines, crlines)
[docs] def sparse_mesh(self, seis_name, depth, log_name):
depth_range = range(
self.seismics[seis_name].startDepth,
(self.seismics[seis_name].endDepth + 1),
self.seismics[seis_name].stepDepth)
if depth > self.seismics[seis_name].endDepth:
print("input depth larger than maximum depth")
# depth = self.seismics[seis_name].endDepth
elif depth < self.seismics[seis_name].startDepth:
print("input depth smaller than minimum depth")
# depth = self.seismics[seis_name].startDepth
elif depth not in depth_range:
print("return values on nearest depth")
else:
pass
depth = min(depth_range, key=lambda x: abs(x-depth))
mesh = np.array([np.nan] * self.seismics[seis_name].nNorth * \
self.seismics[seis_name].nEast)
mesh.shape = (self.seismics[seis_name].nNorth,
self.seismics[seis_name].nEast)
for we in self.wells.values():
log_depth = we.get_log("depth")
log_data = we.get_log(log_name)
log_index = range(len(log_depth))
d = log_data[min(log_index, key=lambda x: abs(log_depth[x]-depth))]
# print("d = ", d)
w_inline = self.inl_crl[we.name][0]
w_crline = self.inl_crl[we.name][1]
a = (w_crline - self.seismics[seis_name].startCrline) // \
self.seismics[seis_name].stepCrline
b = (w_inline - self.seismics[seis_name].startInline) // \
self.seismics[seis_name].stepInline
mesh[a, b] = d
return mesh
[docs] def get_sparse_list(self, seis_name, depth, log_name):
depth_range = range(self.seismics[seis_name].startDepth,
(self.seismics[seis_name].endDepth + 1),
self.seismics[seis_name].stepDepth)
if depth > self.seismics[seis_name].endDepth:
print("input depth larger than maximum depth")
# depth = self.seismics[seis_name].endDepth
elif depth < self.seismics[seis_name].startDepth:
print("input depth smaller than minimum depth")
# depth = self.seismics[seis_name].startDepth
elif depth not in depth_range:
print("return values on nearest depth")
else:
pass
depth = min(depth_range, key=lambda x: abs(x-depth))
sparse_list = list()
for we in self.wells.values():
log_depth = we.get_log("depth")
log_data = we.get_log(log_name)
log_index = range(len(log_depth))
d = log_data[min(log_index, key=lambda x: abs(log_depth[x]-depth))]
w_inline = self.inl_crl[we.name][0]
w_crline = self.inl_crl[we.name][1]
# a = (w_crline - self.seismics[seis_name].startCrline) // \
# self.seismics[seis_name].stepCrline
# b = (w_inline - self.seismics[seis_name].startInline) // \
# self.seismics[seis_name].stepInline
sparse_list.append([w_inline, w_crline, d])
return sparse_list
# -----------------------------------------------------------------------------
# Utilities
# -----------------------------------------------------------------------------
[docs]def create_survey_directory(root_dir, survey_name):
"""
Create survey folder structure
Parameters
----------
root_dir : str
Root directory for storing surveys
survey_nam : str
"""
root_dir = Path(root_dir)
survey_root = root_dir / survey_name
try:
survey_root.mkdir()
dir_to_create = [root_dir / survey_name / 'Seismics',
root_dir / survey_name / 'Wellinfo',
root_dir / survey_name / 'Surfaces']
for directory in dir_to_create:
directory.mkdir()
(survey_root / ".survey").touch()
return survey_root
except OSError:
raise DuplicateSurveyNameExeption()
[docs]class DuplicateSurveyNameExeption(Exception):
def __init__(self):
self.message = ""
super(DuplicateSurveyNameExeption, self).__init__(self.message)
[docs]def get_data_files(dir_path):
"""
get all dot file with given path
dir_path: Path
"""
fnames = list()
# dir_path = Path(dir_path)
if dir_path.exists():
# if list(dir_path.glob('.*')):
# for item in list(dir_path.glob('.*')):
# fnames.append(item.name[1:])
for f in dir_path.iterdir():
if f.suffix == '.seis' or f.suffix == '.well':
fnames.append(f.stem)
return fnames