Skip to content

Commit 19033e1

Browse files
committed
Migrating pygeosx microseismic analysis tool
1 parent 7dc048f commit 19033e1

File tree

5 files changed

+881
-0
lines changed

5 files changed

+881
-0
lines changed

pygeosx_tools_package/pygeosx_tools/geophysics/__init__.py

Whitespace-only changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import os
2+
import numpy as np
3+
from pygeosx_tools import wrapper, parallel_io, plot_tools
4+
import matplotlib.pyplot as plt
5+
from matplotlib import cm
6+
from pyevtk.hl import gridToVTK
7+
8+
9+
class Fiber():
10+
def __init__(self):
11+
self.time = []
12+
self.channel_position = []
13+
self.gage_length = -1.0
14+
15+
self.x = []
16+
self.dudx = []
17+
self.dudt = []
18+
self.dudxdt = []
19+
20+
21+
class FiberAnalysis():
22+
def __init__(self):
23+
"""
24+
InSAR Analysis class
25+
"""
26+
self.set_names = []
27+
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
2+
import os
3+
import numpy as np
4+
from pygeosx_tools import wrapper, parallel_io, plot_tools
5+
import hdf5_wrapper
6+
import matplotlib.pyplot as plt
7+
from matplotlib import cm
8+
from pyevtk.hl import gridToVTK
9+
from scipy import interpolate
10+
11+
12+
class InSAR_Analysis():
13+
def __init__(self, restart_fname=''):
14+
"""
15+
InSAR Analysis class
16+
"""
17+
self.set_names = []
18+
self.set_keys = []
19+
self.local_insar_map = []
20+
21+
self.node_position_key = ''
22+
self.node_displacement_key = ''
23+
self.node_ghost_key = ''
24+
25+
self.satellite_vector = [0.0, 0.0, 1.0]
26+
self.wavelength = 1.0
27+
28+
self.x_grid = []
29+
self.y_grid = []
30+
self.elevation = 0.0
31+
self.times = []
32+
self.mask = []
33+
self.displacement = []
34+
self.range_change = []
35+
self.phase = []
36+
37+
if restart_fname:
38+
self.resume_from_restart(restart_fname)
39+
40+
def resume_from_restart(self, fname):
41+
with hdf5_wrapper.hdf5_wrapper(fname) as r:
42+
for k in dir(self):
43+
if ('_' not in k):
44+
setattr(self, k, r[k])
45+
46+
def write_restart(self, fname):
47+
with hdf5_wrapper.hdf5_wrapper(fname, mode='w') as r:
48+
for k in dir(self):
49+
if ('_' not in k):
50+
r[k] = getattr(self, k)
51+
52+
def setup_grid(self, problem, set_names=[], x_range=[], y_range=[], dx=1.0, dy=1.0):
53+
"""
54+
Setup the InSAR grid
55+
56+
Args:
57+
problem (pygeosx.group): GEOSX problem handle
58+
set_names (list): List of set names to apply to the analysis to
59+
x_range (list): Extents of the InSAR image in the x-direction (optional)
60+
y_range (list): Extents of the InSAR image in the y-direction (optional)
61+
dx (float): Resolution of the InSAR image in the x-direction (default=1)
62+
dy (float): Resolution of the InSAR image in the y-direction (default=1)
63+
"""
64+
# Determine pygeosx keys
65+
self.set_names = set_names
66+
self.set_keys = [wrapper.get_matching_wrapper_path(problem, ['nodeManager', s]) for s in set_names]
67+
self.node_position_key = wrapper.get_matching_wrapper_path(problem, ['nodeManager', 'ReferencePosition'])
68+
self.node_displacement_key = wrapper.get_matching_wrapper_path(problem, ['nodeManager', 'TotalDisplacement'])
69+
self.node_ghost_key = wrapper.get_matching_wrapper_path(problem, ['nodeManager', 'ghostRank'])
70+
71+
# If not specified, then setup the grid extents
72+
ghost_rank = wrapper.get_wrapper(problem, self.node_ghost_key)
73+
x = wrapper.get_wrapper(problem, self.node_position_key)
74+
set_ids = np.concatenate([wrapper.get_wrapper(problem, k) for k in self.set_keys], axis=0)
75+
76+
# Choose non-ghost set members
77+
xb = x[set_ids, :]
78+
gb = ghost_rank[set_ids]
79+
xc = xb[gb < 0, :]
80+
global_min, global_max = parallel_io.get_global_array_range(xc)
81+
82+
if (len(x_range) == 0):
83+
x_range = [global_min[0], global_max[0]]
84+
if (len(y_range) == 0):
85+
y_range = [global_min[1], global_max[1]]
86+
87+
# Choose the grid
88+
Nx = int(np.ceil((x_range[1] - x_range[0]) / dx))
89+
Ny = int(np.ceil((y_range[1] - y_range[0]) / dy))
90+
self.x_grid = np.linspace(x_range[0], x_range[1], Nx + 1)
91+
self.y_grid = np.linspace(y_range[0], y_range[1], Ny + 1)
92+
93+
# Save the average elevation for vtk outputs
94+
self.elevation = global_min[0]
95+
96+
# Trigger the map build
97+
self.build_map(problem)
98+
99+
def build_map(self, problem):
100+
"""
101+
Build the map between the mesh, InSAR image.
102+
Note: this method can be used to update the map after
103+
significant changes to the mesh.
104+
105+
Args:
106+
problem (pygeosx.group): GEOSX problem handle
107+
"""
108+
# Load the data
109+
ghost_rank = wrapper.get_wrapper(problem, self.node_ghost_key)
110+
x = wrapper.get_wrapper(problem, self.node_position_key)
111+
set_ids = np.concatenate([wrapper.get_wrapper(problem, k) for k in self.set_keys], axis=0)
112+
113+
# Choose non-ghost set members
114+
xb = x[set_ids, :]
115+
gb = ghost_rank[set_ids]
116+
xc = xb[gb < 0, :]
117+
118+
# Setup the node to insar map
119+
self.local_insar_map = []
120+
dx = self.x_grid[1] - self.x_grid[0]
121+
dy = self.y_grid[1] - self.y_grid[0]
122+
x_bins = np.concatenate([[self.x_grid[0] - 0.5 * dx],
123+
0.5*(self.x_grid[1:] + self.x_grid[:-1]),
124+
[self.x_grid[-1] + 0.5 * dx]])
125+
y_bins = np.concatenate([[self.y_grid[0] - 0.5 * dy],
126+
0.5*(self.y_grid[1:] + self.y_grid[:-1]),
127+
[self.y_grid[-1] + 0.5 * dy]])
128+
if len(xc):
129+
Ix = np.digitize(np.squeeze(xc[:, 0]), x_bins) - 1
130+
Iy = np.digitize(np.squeeze(xc[:, 1]), y_bins) - 1
131+
for ii in range(len(self.x_grid)):
132+
for jj in range(len(self.y_grid)):
133+
tmp = np.where((Ix == ii) & (Iy == jj))[0]
134+
if len(tmp):
135+
self.local_insar_map.append([ii, jj, tmp])
136+
137+
def extract_insar(self, problem):
138+
"""
139+
Extract InSAR image for current step
140+
141+
Args:
142+
problem (pygeosx.group): GEOSX problem handle
143+
"""
144+
# Load values
145+
time = wrapper.get_wrapper(problem, 'Events/time')[0]
146+
ghost_rank = wrapper.get_wrapper(problem, self.node_ghost_key)
147+
x = wrapper.get_wrapper(problem, self.node_displacement_key)
148+
set_ids = np.concatenate([wrapper.get_wrapper(problem, k) for k in self.set_keys], axis=0)
149+
150+
# Choose non-ghost set members
151+
xb = x[set_ids, :]
152+
gb = ghost_rank[set_ids]
153+
xc = xb[gb < 0, :]
154+
155+
# Find local displacements
156+
Nx = len(self.x_grid)
157+
Ny = len(self.y_grid)
158+
local_displacement_sum = np.zeros((Nx, Ny, 3))
159+
local_N = np.zeros((Nx, Ny), dtype='int')
160+
for m in self.local_insar_map:
161+
local_N[m[0], m[1]] += len(m[2])
162+
for ii in m[2]:
163+
local_displacement_sum[m[0], m[1], :] += xc[ii, :]
164+
165+
# Communicate values
166+
global_displacement_sum = np.sum(np.array(parallel_io.gather_array(local_displacement_sum, concatenate=False)), axis=0)
167+
global_N = np.sum(np.array(parallel_io.gather_array(local_N, concatenate=False)), axis=0)
168+
169+
# Find final 3D displacement
170+
global_displacement = np.zeros((Nx, Ny, 3))
171+
if (parallel_io.rank == 0):
172+
range_change = np.zeros((Nx, Ny))
173+
for ii in range(3):
174+
d = np.squeeze(global_displacement_sum[:, :, ii]) / (global_N + 1e-10)
175+
d[global_N == 0] = np.NaN
176+
global_displacement[:, :, ii] = self.fill_nan_gaps(d)
177+
range_change += global_displacement[:, :, ii] * self.satellite_vector[ii]
178+
179+
# Filter nans
180+
self.displacement.append(global_displacement)
181+
self.range_change.append(range_change)
182+
self.phase.append(np.angle(np.exp(2j * np.pi * range_change / self.wavelength)))
183+
self.mask.append(global_N > 0)
184+
self.times.append(time)
185+
186+
def fill_nan_gaps(self, values):
187+
"""
188+
Fill gaps in the insar data which are specified via NaN's
189+
"""
190+
z = np.isnan(values)
191+
if np.sum(z):
192+
N = np.shape(values)
193+
grid = np.meshgrid(self.x_grid, self.y_grid, indexing='ij')
194+
195+
# Filter out values in flattened arrays
196+
x_flat = np.reshape(grid[0], (-1))
197+
y_flat = np.reshape(grid[1], (-1))
198+
v_flat = np.reshape(values, (-1))
199+
t_flat = np.reshape(z, (-1))
200+
I_valid = np.where(~t_flat)[0]
201+
x_valid = x_flat[I_valid]
202+
y_valid = y_flat[I_valid]
203+
v_valid = v_flat[I_valid]
204+
205+
# Re-interpolate values
206+
vb = interpolate.griddata((x_valid, y_valid), v_valid, tuple(grid), method='linear')
207+
values = np.reshape(vb, N)
208+
return values
209+
210+
def save_hdf5(self, header='insar', output_root='./results'):
211+
if (parallel_io.rank == 0):
212+
os.makedirs(output_root, exist_ok=True)
213+
with hdf5_wrapper.hdf5_wrapper('%s/%s.hdf5' % (output_root, header), mode='w') as data:
214+
data['x'] = self.x_grid
215+
data['y'] = self.y_grid
216+
data['time'] = self.times
217+
data['displacement'] = np.array(self.displacement)
218+
data['range_change'] = np.array(self.range_change)
219+
data['phase'] = np.array(self.phase)
220+
221+
def save_csv(self, header='insar', output_root='./results'):
222+
if (parallel_io.rank == 0):
223+
os.makedirs(output_root, exist_ok=True)
224+
np.savetxt('%s/%s_x_grid.csv' % (output_root, header),
225+
self.x_grid,
226+
delimiter=', ')
227+
np.savetxt('%s/%s_y_grid.csv' % (output_root, header),
228+
self.y_grid,
229+
delimiter=', ')
230+
for ii, t in enumerate(self.times):
231+
comments = 'T (days), %1.8e' % (t / (60 * 60 * 24))
232+
np.savetxt('%s/%s_range_change_%03d.csv' % (output_root, header, ii),
233+
self.range_change[ii],
234+
delimiter=', ',
235+
header=comments)
236+
np.savetxt('%s/%s_phase_%03d.csv' % (output_root, header, ii),
237+
self.phase[ii],
238+
delimiter=', ',
239+
header=comments)
240+
241+
def save_vtk(self, header='insar', output_root='./results'):
242+
if (parallel_io.rank == 0):
243+
os.makedirs(output_root, exist_ok=True)
244+
x = np.ascontiguousarray(self.x_grid)
245+
y = np.ascontiguousarray(self.y_grid)
246+
z = np.array([self.elevation])
247+
248+
for ii, t in enumerate(self.times):
249+
data = {'range_change': np.ascontiguousarray(np.expand_dims(self.range_change[ii], -1)),
250+
'phase': np.ascontiguousarray(np.expand_dims(self.phase[ii], -1)),
251+
'dx': np.ascontiguousarray(np.expand_dims(self.displacement[ii][:, :, 0], -1)),
252+
'dy': np.ascontiguousarray(np.expand_dims(self.displacement[ii][:, :, 1], -1)),
253+
'dz': np.ascontiguousarray(np.expand_dims(self.displacement[ii][:, :, 2], -1))}
254+
255+
gridToVTK('%s/%s_%03d' % (output_root, header, ii),
256+
x,
257+
y,
258+
z,
259+
pointData=data)
260+
261+
def save_image(self, header='insar', output_root='./results', interp_method='quadric'):
262+
if (parallel_io.rank == 0):
263+
os.makedirs(output_root, exist_ok=True)
264+
fig = plot_tools.HighResPlot()
265+
266+
for ii, t in enumerate(self.times):
267+
# Range change
268+
fig.reset()
269+
extents = [self.x_grid[0], self.x_grid[-1], self.y_grid[0], self.y_grid[-1]]
270+
ca = plt.imshow(np.transpose(np.flipud(self.range_change[ii])),
271+
extent=extents,
272+
cmap=cm.jet,
273+
aspect='auto',
274+
interpolation=interp_method)
275+
plt.title('T = %1.4e (days)' % (t / (60 * 60 * 24)))
276+
plt.xlabel('X (m)')
277+
plt.ylabel('Y (m)')
278+
cb = plt.colorbar(ca)
279+
cb.set_label('Range Change (m)')
280+
fig.save('%s/%s_range_change_%03d' % (output_root, header, ii))
281+
282+
# Wrapped phase
283+
fig.reset()
284+
extents = [self.x_grid[0], self.x_grid[-1], self.y_grid[0], self.y_grid[-1]]
285+
ca = plt.imshow(np.transpose(np.flipud(self.phase[ii])),
286+
extent=extents,
287+
cmap=cm.jet,
288+
aspect='auto',
289+
interpolation=interp_method)
290+
plt.title('T = %1.4e (days)' % (t / (60 * 60 * 24)))
291+
plt.xlabel('X (m)')
292+
plt.ylabel('Y (m)')
293+
cb = plt.colorbar(ca)
294+
cb.set_label('Phase (radians)')
295+
fig.save('%s/%s_wrapped_phase_%03d' % (output_root, header, ii))
296+
297+

0 commit comments

Comments
 (0)