#!/usr/bin/env python
# coding: utf-8
# # 6 - Sísmica de reflexão: Correção de Normal Moveout (NMO) e empilhamento
#
# Na aula passada, vimos que uma seção CMP é crucial para conseguirmos uma estimativa da velocidade. Nessa prática, veremos como utilizar a correção de NMO para fazer a **análise de velocidades**. Também veremos a técnica do empilhamento e como ela melhora a razão sinal-ruído do dado.
#
#
# Utilizaremos as simulações de ondas da biblioteca [Fatiando a Terra](http://www.fatiando.org). Essas simulações utilizam o [método de diferenças finitas](http://en.wikipedia.org/wiki/Finite_difference_method) para calcular soluções da equação da onda.
# ## Objetivos
#
# * Utilizar a correção de NMO para estimar velocidades.
# * Ver como o empilhamento melhora a qualidade dos dados.
# ## Questão para entregar
#
#
#
# Explique como é feita a análise de velocidades. As velocidades determinadas são as velocidades verdadeiras das camadas? Por que? Qual é vantagem de realizar o empilhamento?
#
#
#
# ### Regras para a resposta
#
# * Coloque **nome, data e o número da prática** em sua resposta.
# * A resposta pode ter no **máximo 1 página** (não uma folha).
# * **Execute o notebook** antes de responder. As simulações abaixo foram feitas para te ajudar.
# * **Pense e organize** sua resposta andtes de começar a escrever.
# ## Instruções
#
# Esse documento é um [Jupyter notebook](http://jupyter.org/), um documento interativo que mistura texto (como esse), código (como abaixo), e o resultado de executar o código (números, texto, figuras, videos, etc).
#
# O notebook te fornecerá exemplos interativos que trabalham os temas abordados no questionário. Utilize esses exemplos para responder as perguntas.
#
# As células com números ao lado, como `In [1]:`, são código [Python](http://python.org/). Algumas dessas células não produzem resultado e servem de preparação para os exemplos interativos. Outras, produzem gráficos interativos. **Você deve executar todas as células, uma de cada vez**, mesmo as que não produzem gráficos.
#
# **Para executar uma célula**, clique em cima dela e aperte `Shift + Enter`. O foco (contorno verde ou cinza em torno da célula) deverá passar para a célula abaixo. Para rodá-la, aperte `Shift + Enter` novamente e assim por diante. Você pode executar células de texto que não acontecerá nada.
# ## Setup
#
# Rode as células abaixo para carregar os módulos necessários para essa prática.
# In[1]:
get_ipython().run_line_magic('matplotlib', 'inline')
from __future__ import division, print_function
import math
from multiprocessing import Pool, cpu_count
import numpy as np
import matplotlib.pyplot as plt
import ipywidgets as ipw
from fatiando.seismic import RickerWavelet, FDAcoustic2D
from fatiando import utils
from fatiando.vis import anim_to_html
from fatiando.vis.mpl import seismic_image, seismic_wiggle
# ## Simulação de um CMP para um modelo de duas camadas
#
# Rode as células abaixo para simular uma seção CMP para um modelo de duas camadas. A célula abaixo cria nosso modelo.
# In[2]:
shape = (150, 200)
spacing = 10
extent = [0, shape[1]*spacing, shape[0]*spacing, 0]
# Velocidades
v1, v2 = 4000, 5000
densidade = np.ones(shape)*1600
velocidade = np.ones(shape)*v1
l1 = 40
densidade[l1:,:] = 1800
velocidade[l1:,:] = v2
l2 = 100
densidade[l2:,:] = 2000
velocidade[l2:,:] = 8000
# Em seguida, precisamos definir onde serão localizadas as fontes e os receptores em nossa simulação. Vamos aproveitar e calcular também os espassamentos (offsets) dos receptores. Lembre-se: offset é a distância da conte ao receptor.
# In[3]:
fontes = np.array(list(reversed(range(55, shape[1]//2 - 3, 3))))
recep = np.array([shape[1] - s for s in fontes])
offsets = (recep - fontes)*spacing
print("Utilizando {} fontes e {} receptores.".format(len(fontes), len(recep)))
print('Fontes: {}'.format(fontes*spacing))
print('Receptores: {}'.format(recep*spacing))
print('Offsets: {}'.format(offsets))
# Vamos rodar as simulações que precisamos (uma por fonte). **A barra de progresso não irá aparecer** pois vamos rodar as simulações em paralelo para agilizar o processo.
# In[4]:
def simul_shot(fonte, its=1200, verbose=False):
shot = FDAcoustic2D(velocidade, densidade, spacing=spacing, taper=0.005, padding=50, verbose=verbose)
shot.add_point_source((0, fonte), RickerWavelet(1, 120))
shot.run(its)
return shot
# In[5]:
get_ipython().run_cell_magic('time', '', "print('Simulando...', end=' ')\npool = Pool(processes=cpu_count())\nshots = pool.map(simul_shot, fontes)\npool.close()\nprint('Pronto.')\n")
# Vamos dar uma olhada na simulação de 1 tiro para ter uuma ideia do que acontece.
# In[6]:
shots[0].animate(embed=True, dpi=60, fps=8, every=20, cutoff=0.5, cmap='Greys')
# Vamos extrair os dados CMP da nossa simulação.
# In[7]:
dt = shots[0].dt
times = np.linspace(0, dt*shots[0].simsize, shots[0].simsize)
CMP = np.empty((shots[0].simsize, len(recep)))
for i, s in enumerate(shots):
CMP[:, i] = s[:, 0, recep[i]]
fig = plt.figure(figsize=(10, 9))
ax = plt.subplot(111)
ax.set_title('CMP')
ax.set_xlabel('offset (m)')
ax.set_ylabel('times (s)')
cutoff = 0.1
ax.imshow(CMP, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=1000, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
fig.tight_layout()
# ### Para pensar
#
# * Tente identificar a onda direta e as reflexões principais na simulação e no CMP.
# * O que é o outro evento que aparece no CMP (acima da segunda reflexão)?
# ## Análise de velocidades
# Agora que temos nosso CMP, podemos aplicar a correção de NMO e fazer a nossa análise de velocidades. Rode a célula abaixo para produzir uma figura interativa.
# In[8]:
def nmo_correction(CMP, times, offsets, v):
nmo = np.zeros_like(CMP)
for i, t0 in enumerate(times):
for j, o in enumerate(offsets):
t = np.sqrt(t0**2 + o**2/v[i]**2)
k = int(math.floor(t/dt))
if k < times.size - 1:
# Linear interpolation of the amplitude
y0, y1 = CMP[k, j], CMP[k + 1, j]
x0, x1 = times[k], times[k + 1]
nmo[i, j] = y0 + (y1 - y0)*(t - x0)/(x1 - x0)
return nmo
def analise_velocidades(CMP):
def aplica_nmo(v1, v2):
v = v1*np.ones_like(times)
v[times > 0.35] = v2
nmo = nmo_correction(CMP, times, offsets, v)
fig = plt.figure(figsize=(12, 6))
ax = plt.subplot(121)
ax.set_title('CMP')
ax.set_xlabel('offset (m)')
ax.set_ylabel('times (s)')
cutoff = 0.1
ax.imshow(CMP, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=1000, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
ax.grid()
ax = plt.subplot(122)
ax.set_title('Corrigido de NMO')
ax.set_xlabel('offset (m)')
ax.set_ylabel('times (s)')
cutoff = 0.1
ax.imshow(nmo, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=1000, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
ax.grid()
fig.tight_layout()
widget = ipw.interactive(aplica_nmo,
v1=ipw.FloatSlider(min=2000, max=6000, step=100, value=2000),
v2=ipw.FloatSlider(min=2000, max=6000, step=100, value=2000))
return widget
analise_velocidades(CMP)
# ### Figura acima
#
# * O painel da esquerda mostra nosso CMP original.
# * O painel da direita mostra o CMP após aplicação da correção NMO usando as velocidades especificadas.
# * Você pode controlar as velocidades utilizadas na correção NMO do nosso CMP.
# ### Para pensar
#
# * **Determine a velocidade das duas reflexões**.
# * Essa velocidade é a velocidade real das camadas? Por que?
# ## Empilhamento
#
# O CMP que simulamos acima não é muito realista pois não está contaminado com qualquer tipo de ruído. Então vamos sacanear o problema adicionando ruído aleatório nos nossos dados.
# In[9]:
ruido = 0.1
CMP_ruido = CMP + np.random.uniform(-ruido, ruido, CMP.shape)
fig = plt.figure(figsize=(10, 9))
ax = plt.subplot(111)
ax.set_title(u'CMP com ruído aleatório')
ax.set_xlabel('offset (m)')
ax.set_ylabel('times (s)')
cutoff = 0.1
ax.imshow(CMP_ruido, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=1000, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
fig.tight_layout()
# Uma técnica que nos possibilita diminuir a influência do ruído aleatório é o **empilhamento**. A ideia é somar diversos dados que possuam um sinal coerente no meio de ruído aleatório.
#
# Rode a célula abaixo para gerar uma figura interativa que ilustra esse conceito.
# In[10]:
def empilhamento(ruido):
N = 500
M = 10
if ruido <= 0:
dados_ruido = np.array([np.zeros(N) for i in range(M)])
else:
dados_ruido = np.array([np.random.uniform(-ruido, ruido, size=N) for i in range(M)])
x = np.arange(N)
sinal = 1*utils.gaussian(x, 250, 2)
dados = dados_ruido + sinal
plt.figure(figsize=(10, 6))
plt.subplot(121)
plt.title(u'Dados com ruído e um sinal não-aleatório')
for i, d in enumerate(dados):
plt.plot(d + i + 1, x, '-k')
plt.xlim(0, len(dados) + 1)
plt.xlabel('# do dado')
plt.grid()
ax = plt.subplot(143)
plt.title('Empilhamento')
plt.plot(dados.sum(0), x, '-k')
plt.grid()
plt.xlim(-15, 15)
plt.tight_layout()
ipw.interactive(empilhamento, ruido=ipw.FloatSlider(min=0, max=0.5, step=0.1, value=0))
# ### Figura acima
#
# * O painel da esquerda mostra 10 conjuntos de dados com 1 sinal coerente no meio.
# * O painel da direita mostra o resultado do empilhamento desses dados.
# * Você pode controlar a quantidade de ruído aleatório que é inserido nos dados da esquerda.
# ### Para pensar
#
# * Com o máximo de ruído você consegue enxergar o sinal nos dados originais? E no empilhamento?
# ### Empilhamento após análise de velocidades
#
# Para poder fazer o empilhamento, precisamos ter um sinal coerente entre todos os traços. Isso significa que a nossa reflexão precisa acontecer no mesmo tempo em todos os traços. Felizmente, é exatamente isso que obtemos após a análise de velocidades e correção NMO.
#
# Rode a célula abaixo para gerar a figura interativa da análise de velocidades. Dessa vez vamos motrar também o resultado do empilhamento da seção corrigida de NMO.
# In[11]:
def nmo_empilhamento(v1, v2):
v = v1*np.ones_like(times)
v[times > 0.35] = v2
nmo = nmo_correction(CMP_ruido, times, offsets, v)
stack = np.atleast_2d(nmo.sum(1)).T
fig = plt.figure(figsize=(12, 6))
ax = plt.subplot(131)
ax.set_title('CMP')
ax.set_xlabel('offset (m)')
ax.set_ylabel('times (s)')
cutoff = 0.1
ax.imshow(CMP_ruido, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=2500, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
ax.grid()
ax = plt.subplot(132)
ax.set_title('Corrigido de NMO')
cutoff = 0.1
ax.imshow(nmo, extent=[offsets.min(), offsets.max(), times.max(), times.min()],
aspect=2500, cmap='Greys', vmin=-cutoff, vmax=cutoff, interpolation='nearest')
ax.grid()
ax = plt.subplot(165)
ax.set_title(u'Primeiro traço do NMO')
seismic_wiggle(np.atleast_2d(nmo[:, 0]).T, dt=dt, scale=1)
ax.set_xlim(-1, 1)
ax.grid()
ax = plt.subplot(166)
ax.set_title('Empilhamento')
seismic_wiggle(stack, dt=dt, scale=1)
ax.set_xlim(-10, 10)
ax.grid()
fig.tight_layout(pad=0, w_pad=0)
ipw.interactive(nmo_empilhamento,
v1=ipw.FloatSlider(min=2000, max=6000, step=100, value=2000),
v2=ipw.FloatSlider(min=2000, max=6000, step=100, value=2000))
# ### Figura acima
#
# * O painel 1 mostra o CMP contaminado com ruído aleatório.
# * O painel 2 mostra o resultado da correção de NMO.
# * O painel 3 mostra o primeiro traço da seção corrigida de NMO (sem empilhamento).
# * O painel 4 mostra o resultado do empilhamento da seção corrigida de NMO.
# ### Para pensar
#
# * Como o resultado do empilhamento muda quando você utiliza as velocidades correta para NMO?
# * Como o traço empilhado se compara a um traço normal do NMO (sem empilhamento)?
# ## License and information
#
# **Course website**: https://github.com/leouieda/geofisica2
#
# **Note**: This notebook is part of the course "Geofísica 2" of Geology program of the
# [Universidade do Estado do Rio de Janeiro](http://www.uerj.br/).
# All content can be freely used and adapted under the terms of the
# [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
#
# ![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png)