/
source.py
163 lines (129 loc) · 5.36 KB
/
source.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
from devito import Dimension
from devito.function import SparseTimeFunction
from devito.logger import error
import numpy as np
try:
import matplotlib.pyplot as plt
except:
plt = None
__all__ = ['PointSource', 'Receiver', 'Shot', 'RickerSource', 'GaborSource']
class PointSource(SparseTimeFunction):
"""Symbolic data object for a set of sparse point sources
:param name: Name of the symbol representing this source
:param grid: :class:`Grid` object defining the computational domain.
:param coordinates: Point coordinates for this source
:param data: (Optional) Data values to initialise point data
:param ntime: (Optional) Number of timesteps for which to allocate data
:param npoint: (Optional) Number of sparse points represented by this source
:param dimension: :(Optional) class:`Dimension` object for
representing the number of points in this source
Note, either the dimensions `ntime` and `npoint` or the fully
initialised `data` array need to be provided.
"""
def __new__(cls, name, grid, ntime=None, npoint=None, data=None,
coordinates=None, **kwargs):
p_dim = kwargs.get('dimension', Dimension(name='p_%s' % name))
npoint = npoint or coordinates.shape[0]
if data is None:
if ntime is None:
error('Either data or ntime are required to'
'initialise source/receiver objects')
else:
ntime = ntime or data.shape[0]
# Create the underlying SparseTimeFunction object
obj = SparseTimeFunction.__new__(cls, name=name, grid=grid,
dimensions=[grid.time_dim, p_dim],
npoint=npoint, nt=ntime,
coordinates=coordinates, **kwargs)
# If provided, copy initial data into the allocated buffer
if data is not None:
obj.data[:] = data
return obj
def __init__(self, *args, **kwargs):
if not self._cached():
super(PointSource, self).__init__(*args, **kwargs)
Receiver = PointSource
Shot = PointSource
class WaveletSource(PointSource):
"""
Abstract base class for symbolic objects that encapsulate a set of
sources with a pre-defined source signal wavelet.
:param name: Name for the resulting symbol
:param grid: :class:`Grid` object defining the computational domain.
:param f0: Peak frequency for Ricker wavelet in kHz
:param time: Discretized values of time in ms
"""
def __new__(cls, *args, **kwargs):
time = kwargs.get('time')
npoint = kwargs.get('npoint', 1)
kwargs['ntime'] = len(time)
kwargs['npoint'] = npoint
obj = PointSource.__new__(cls, *args, **kwargs)
obj.time = time
obj.f0 = kwargs.get('f0')
for p in range(npoint):
obj.data[:, p] = obj.wavelet(obj.f0, obj.time)
return obj
def __init__(self, *args, **kwargs):
if not self._cached():
super(WaveletSource, self).__init__(*args, **kwargs)
def wavelet(self, f0, t):
"""
Defines a wavelet with a peak frequency f0 at time t.
:param f0: Peak frequency in kHz
:param t: Discretized values of time in ms
"""
raise NotImplementedError('Wavelet not defined')
def show(self, idx=0, time=None, wavelet=None):
"""
Plot the wavelet of the specified source.
:param idx: Index of the source point for which to plot wavelet
:param wavelet: Prescribed wavelet instead of one from this symbol
:param time: Prescribed time instead of time from this symbol
"""
wavelet = wavelet or self.data[:, idx]
time = time or self.time
plt.figure()
plt.plot(time, wavelet)
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.tick_params()
plt.show()
class RickerSource(WaveletSource):
"""
Symbolic object that encapsulate a set of sources with a
pre-defined Ricker wavelet:
http://subsurfwiki.org/wiki/Ricker_wavelet
:param name: Name for the resulting symbol
:param grid: :class:`Grid` object defining the computational domain.
:param f0: Peak frequency for Ricker wavelet in kHz
:param time: Discretized values of time in ms
"""
def wavelet(self, f0, t):
"""
Defines a Ricker wavelet with a peak frequency f0 at time t.
:param f0: Peak frequency in kHz
:param t: Discretized values of time in ms
"""
r = (np.pi * f0 * (t - 1./f0))
return (1-2.*r**2)*np.exp(-r**2)
class GaborSource(WaveletSource):
"""
Symbolic object that encapsulate a set of sources with a
pre-defined Gabor wavelet:
https://en.wikipedia.org/wiki/Gabor_wavelet
:param name: Name for the resulting symbol
:param grid: :class:`Grid` object defining the computational domain.
:param f0: Peak frequency for Ricker wavelet in kHz
:param time: Discretized values of time in ms
"""
def wavelet(self, f0, t):
"""
Defines a Gabor wavelet with a peak frequency f0 at time t.
:param f0: Peak frequency in kHz
:param t: Discretized values of time in ms
"""
agauss = 0.5 * f0
tcut = 1.5 / agauss
s = (t-tcut) * agauss
return np.exp(-2*s**2) * np.cos(2 * np.pi * s)