def test_write_vm(self): """ Should write in the native VM format """ sl = np.random.rand(512, 1, 64) vm = VM(sl=sl) self.assertEqual(vm.grid.shape, sl.shape) self.assertAlmostEqual(vm.sl[0, 0, 0], sl[0, 0, 0], 7) fname = 'temp_out.vm' if os.path.isfile(fname): os.remove(fname) # should write to VM format vm.write(fname) self.assertTrue(os.path.isfile(fname)) # should have the same data vm1 = VM(fname) self.assertEqual(vm1.sl.shape, vm.sl.shape) self.assertEqual(vm1.sl[0, 0, 0], vm.sl[0, 0, 0]) self.assertEqual(vm1.sl[-1, -1, -1], vm.sl[-1, -1, -1]) # clean up if os.path.isfile(fname): os.remove(fname)
def test_insert_interface(self): """ Should insert a new interface """ # Initialize a new model vm = VM(r1=(0, 0, 0), r2=(50, 0, 30), dx=0.5, dy=0.5, dz=0.5) # Should add a new, flat interface at 10 km z0 = 10. vm.insert_interface(z0 * np.ones((vm.nx, vm.ny))) self.assertEqual(vm.nr, 1) self.assertEqual(vm.rf[0].min(), z0) self.assertEqual(vm.rf[0].max(), z0) # New interfaces should have jp=0 self.assertEqual(vm.jp[0].min(), 0) self.assertEqual(vm.jp[0].max(), 0) # New layers should have ir and ij = index of new interface self.assertEqual(vm.ir[0].min(), 0) self.assertEqual(vm.ir[0].max(), 0) self.assertEqual(vm.ij[0].min(), 0) self.assertEqual(vm.ij[0].max(), 0) # Adding a new interface should increase ir and ij of deeper layers for z0 in [5., 15., 1., 20.]: vm.insert_interface(z0 * np.ones((vm.nx, vm.ny))) for iref in range(0, vm.nr): self.assertEqual(vm.ir[iref].min(), iref) self.assertEqual(vm.ir[iref].max(), iref) self.assertEqual(vm.ij[iref].min(), iref) self.assertEqual(vm.ij[iref].max(), iref) # should take a scalar value for a constant depth interface vm = VM(r1=(0, 0, 0), r2=(50, 0, 30), dx=0.5, dy=0.5, dz=0.5) z0 = 10. vm.insert_interface(z0) self.assertEqual(vm.nr, 1) self.assertEqual(vm.rf[0].min(), z0) self.assertEqual(vm.rf[0].max(), z0)
def test_read_vm(self): """ Should read the native VM format """ example_file = 'benchmark2d.vm' # make sure example can be found path = get_example_file(example_file) self.assertTrue(os.path.isfile(path)) # should load the example file vm = VM(example_file, head_only=False) self.assertTrue(hasattr(vm, 'grid')) self.assertEqual(vm.grid.nx, 1041) self.assertEqual(vm.grid.ny, 1) self.assertEqual(vm.grid.nz, 506) self.assertEqual(vm.sl.shape[0], 1041) self.assertEqual(vm.sl.shape[1], 1) self.assertEqual(vm.sl.shape[2], 506) self.assertAlmostEqual(1. / vm.grid.values[0, 0, 0], 0.333, 3) self.assertEqual(vm.rf.shape, (5, vm.grid.nx, vm.grid.ny)) self.assertEqual(vm.jp.shape, (5, vm.grid.nx, vm.grid.ny)) self.assertEqual(vm.ir.shape, (5, vm.grid.nx, vm.grid.ny)) self.assertEqual(vm.ij.shape, (5, vm.grid.nx, vm.grid.ny))
def test_plot(self): """ Should plot velocity grid with interfaces """ vm = VM('benchmark2d.vm') vm.plot()
def dev_raytrace(self): """ Model should be compatible with the raytracer """ #XXX testing with raytracer from Rockfish, for now #TODO update test with PyVM raytracer, when it exists from rockfish.tomography.forward import raytrace_from_ascii temp_path = 'temp_raytrace_input' if os.path.isdir(temp_path): shutil.rmtree(temp_path) os.makedirs(temp_path) # simple vm model shape = (128, 1, 64) vm = VM(shape=shape, dx=1, dy=1, dz=1) vm.insert_interface(5) vm.define_constant_layer_velocity(0, 1500) vm.define_constant_layer_gradient(1, 0.2) vmfile = os.path.join(temp_path, 'model.vm') vm.write(vmfile) self.assertTrue(os.path.isfile(vmfile)) # simple geometry and picks instfile = os.path.join(temp_path, 'inst.dat') shotfile = os.path.join(temp_path, 'shot.dat') pickfile = os.path.join(temp_path, 'pick.dat') f = open(instfile, 'w') f.write('100 25. 0.0 3.0\n') f.write('101 30. 0.0 3.0\n') f.close() f = open(shotfile, 'w') f.write('9000 5. 0.0 0.006\n') f.write('9001 10. 0.0 0.006\n') f.close() f = open(pickfile, 'w') f.write('100 9000 1 0 9.999 9.999 0.000\n') f.write('101 9001 1 0 9.999 9.999 0.000\n') f.close() rayfile = os.path.join(temp_path, 'out.rays') raytrace_from_ascii(vmfile, rayfile, instfile=instfile, shotfile=shotfile, pickfile=pickfile, verbose=1000) self.assertTrue(os.path.isfile(rayfile))
def test_init_model(self): """ Should initialize a new model """ shape = (128, 1, 64) vm = VM(shape=shape) # should have a created the 3D grid manager self.assertTrue(hasattr(vm, 'grid')) self.assertEqual(vm.grid.nx, shape[0]) self.assertEqual(vm.grid.ny, shape[1]) self.assertEqual(vm.grid.nz, shape[2]) # should have default attributes needed by other routines for attr in [ 'sl', 'nr', 'nx', 'ny', 'nz', 'dx', 'dy', 'dz', 'rf', 'jp', 'ij', 'ir', 'r1', 'r2', 'ilyr' ]: self.assertTrue(hasattr(vm, attr)) # grid should be initialized to zeros self.assertEqual(vm.sl[0, 0, 0], 0) # setting certain aliases should set parent vm.sl[0, 0, 0] = 999 self.assertEqual(vm.grid.values[0, 0, 0], 999) for attr in ['dx', 'dy', 'dz']: vm.__setattr__(attr, 999) self.assertEqual(vm.__getattribute__(attr), 999) self.assertEqual(vm.grid.__getattribute__(attr), 999) vm.r1 = (9.99, 8.88, 7.77) self.assertEqual(vm.r1, (9.99, 8.88, 7.77)) self.assertEqual(vm.grid.origin, (9.99, 8.88, 7.77)) # setting r2 should update grid spacing nx0, ny0, nz0 = vm.grid.shape[:] dx0, dy0, dz0 = vm.grid.spacing[:] vm.r2 = (400, 200, 300) self.assertEqual(vm.nx, nx0) self.assertEqual(vm.ny, ny0) self.assertEqual(vm.nz, nz0) self.assertNotEqual(vm.dx, dx0) self.assertNotEqual(vm.dy, dy0) self.assertNotEqual(vm.dz, dz0) # extents must be 3D for attr in ['r1', 'r2']: with self.assertRaises(ValueError) as context: vm.__setattr__(attr, (0, 0)) # should not allow certain aliases to be set for attr in ['nx', 'ny', 'nz', 'nr']: with self.assertRaises(AttributeError) as context: vm.__setattr__(attr, 999)
def test_define_constant_layer_velocity(self): """ Should flood a layer with one velocity """ vm = VM() vm.insert_interface(5) vm.define_constant_layer_velocity(0, vel=8.5) self.assertAlmostEqual(vm.sl[0, 0, 0], 1. / 8.5, 6) vm.define_constant_layer_velocity(1, vel=9.5) self.assertAlmostEqual(1. / np.min(vm.sl), 9.5, 6)
def test_define_stretched_layer_velocities(self): """ Should stretch a velocity function to fit within a layer """ vm = VM() vm.insert_interface(5) vm.define_stretched_layer_velocities(0, vel=[1.500, 1.500]) self.assertAlmostEqual(vm.sl[0, 0, 0], 1. / 1.5, 7) vm.define_stretched_layer_velocities(1, vel=[None, 8.1]) self.assertAlmostEqual(1. / np.min(vm.sl), 8.1, 6)
def test_ilyr(self): """ Should assign grid nodes to layers """ shape = (128, 1, 64) vm = VM(shape=shape) # top layer should be 0 for i in vm.ilyr.flatten(): self.assertEqual(i, 0) # last layer should be equal to the number of interfaces for nr in [1, 2, 10]: vm.rf = 5 * np.ones((nr, vm.nx, vm.ny)) self.assertEqual(np.max(vm.ilyr), nr)
def test_define_constant_layer_gradient(self): """ Should define a constant layer gradient in a layer """ vm = VM() vm.insert_interface(5) vm.define_constant_layer_gradient(0, 0, v0=1.500) self.assertAlmostEqual(vm.sl[0, 0, 0], 1. / 1.5, 7) vm.define_constant_layer_gradient(1, 0.1, v0=3.0) self.assertAlmostEqual(1. / np.min(vm.sl), 15.19999945, 7)
def dev_readwrite_interface_flags(self): """ Should handle Fortran vs. Python indexing for interface flags """ sl = np.random.rand(8, 1, 12) vm = VM(sl=sl) vm.insert_interface(1) vm.ir = np.zeros((1, vm.nx, vm.ny)) vm.ij = np.zeros((1, vm.nx, vm.ny)) fname = 'temp_out.vm' if os.path.isfile(fname): os.remove(fname) vm.write(fname) # writing should not change flags for ilyr in range(vm.nr): for ix in range(vm.nx): for iy in range(vm.ny): self.assertEqual(vm.ir[ilyr, ix, iy], 0) self.assertEqual(vm.ij[ilyr, ix, iy], 0) # read should handle -1 for indexing vm1 = VM(fname) for ilyr in range(vm1.nr): for ix in range(vm1.nx): for iy in range(vm1.ny): self.assertEqual(vm1.ir[ilyr, ix, iy], 0) self.assertEqual(vm1.ij[ilyr, ix, iy], 0) # clean up if os.path.isfile(fname): os.remove(fname)
def __init__(self, pickdb=None, model=None, rays=None): if pickdb: self.pickdb = pickdb else: self.pickdb = PickDatabase() if isinstance(model, VM): # connect to existing model instance self.model = model else: # create a new default model or read existing file self.model = VM(filename=model) if rays: self.rays = rays
def test_fix_pinchouts(self): """ Should fix layer pinchouts so that boundaries do not cross """ vm = VM() z = np.reshape(2 + 0.05 * (vm.grid.x), (vm.nx, 1)) vm.insert_interface(z) vm.insert_interface(6) nerror0 = len(np.nonzero((vm.rf[1] - vm.rf[0]) < 0)[0]) assert nerror0 > 0 # should fix crossings and pinchouts vm.fix_pinchouts() nerror = len(np.nonzero((vm.rf[1] - vm.rf[0]) < 0)[0]) self.assertEqual(nerror, 0)
def test_r1_r2(self): """ Should force reflectors to be the same shape as the grid """ shape = (128, 1, 64) vm = VM(shape=shape) for attr in ['rf', 'jp', 'ir', 'ij']: # should allow (nr, nx, ny)-sized arrays vm.__setattr__(attr, np.ones((1, vm.nx, vm.ny))) self.assertEqual(vm.nr, 1) # should not allow other sizes with self.assertRaises(ValueError) as context: vm.__setattr__(attr, np.ones((1, 999, vm.ny))) with self.assertRaises(ValueError) as context: vm.__setattr__(attr, np.ones((1, vm.nx, 999)))
def test_verify(self): """ Should inherit verify functions """ shape = (128, 1, 64) vm = VM(shape=shape) vm.sl = np.ones(vm.sl.shape) self.assertTrue(hasattr(vm, 'verify')) self.assertTrue(vm.verify()) # should return false if NaNs are on the grid vm.sl[0, 0, 0] = np.nan self.assertFalse(vm.verify()) # should return false if zeros are on the grid vm.sl = np.ones(vm.sl.shape) self.assertTrue(vm.verify()) vm.sl[0, 0, 0] = 0.0 self.assertFalse(vm.verify())
def test_write_bin(self): """ Should write grid to headerless binary format """ sl = np.random.rand(512, 1, 64) vm = VM(sl=sl) fname = 'temp_out.bin' if os.path.isfile(fname): os.remove(fname) vm.write(fname) f = open(fname, 'rb') dat = np.fromstring(f.read(), dtype='float32').reshape(sl.shape) for v1, v2 in zip(dat.flatten(), vm.sl.flatten()): self.assertEqual(v1, v2) if os.path.isfile(fname): os.remove(fname)
def test_get_layer_bounds(self): """ Should get surfaces bounding a layer. """ shape = (128, 1, 64) vm = VM(shape=shape) # top and bottom should be model boundary if no layers self.assertEqual(vm.nr, 0) z0, z1 = vm.get_layer_bounds(0) for _z in z0: self.assertEqual(_z, vm.r1[2]) for _z in z1: self.assertEqual(_z, vm.r2[2]) # bottom of first layer should be first interface vm.rf = 5 * np.ones((1, vm.nx, vm.ny)) z0, z1 = vm.get_layer_bounds(0) for _z in z0: self.assertEqual(_z, vm.r1[2]) for _z in z1: self.assertEqual(_z, 5) # top of second layer should be first interface z0, z1 = vm.get_layer_bounds(1) for _z in z0: self.assertEqual(_z, 5) for _z in z1: self.assertEqual(_z, vm.r2[2])
import numpy as np from pyvm.models.vm import VM # define the model domain in terms of grid dimensions, spacing, and origin ny = 460 vm = VM(shape=(500, ny, 100), spacing=(1, 1, 1), origin=(0, 0, -5)) ## # sloping boundary - SEA FLOOR & BATHYMETRY specs = [ #xstart, xend, slope [0., 230., 0], [230., 275., -0.05], [275., 330., 0], [330., 350., 0.07], [350., 400., 0], [400., 450., -0.04], [450., 500., 0] ] z0 = 0 # intial depth at left-hand side of model # build full boundary z = np.ones(vm.nx) for x0, x1, m in specs: ix = vm.xrange2i(x0, x1) x = vm.grid.x[ix] z[ix] = z0 + m * (x - x[0]) z0 = z[ix[-1]] # expand into 3D n = np.ones((vm.nx, 1)) for i in range(0, ny): n[i] = z[i] s = np.ones((vm.nx, vm.ny)) for i in range(0, ny):
def raytrace_from_ascii(vmfile, rayfile, instfile='inst.dat', shotfile='shot.dat', pickfile='pick.dat', grid_size=None, forward_star_size=[12, 12, 24], min_angle=0.5, min_velocity=1.4, max_node_size=620, top_layer=0, bottom_layer=None, stdout=None, stderr=None, verbose=True): """ Wrapper for running the VM Tomography raytracer using a ASCII input files. Parameters ---------- vmfile : str Filename of the VM Tomography slowness model to raytrace. rayfile : str Filename of the output VM Tomography rayfan file. instfile : str Filename of the ASCII-formatted instrument location file with the four columns: ``inst_id, x, y, z``. shotfile : str Filename of the ASCII-formatted shot location file with the four columns: ``shot_id, x, y, z``. pickfile : str Filename of the ASCII-formatted pick time file with the seven columns: ``inst_id, shot_id, branch, subbranch_id, range, pick_time, pick_error``. grid_size : (int, int, int), optional Tuple of ``(nx, ny, nz)`` dimensions for the graphing grid. Default is to match the graphing grid to the slowness model dimensions. min_angle : float, optional Minimum angle between search directions in forward star in degrees. min_velocity : float, optional Minimum velocity to trace rays through. max_node_size : int, optional Average number of nodes to allocate for each raypath. The raytracing program will adjust this size if needed. top_layer : int, optional The index of the top-most layer to trace rays through. bottom_layer : int, optional The index of the bottom-most layer to trace rays through. Default is the index of the bottom-most layer in the model. stdout, stderr : {'PIPE', int, file, None}, optional stdout and stderr specify the raytracing program's standard output and standard error file handles, respectively. Valid values are ``'PIPE'``, an existing file descriptor (a positive integer), an existing file object, and ``None``. See :mod:`subprocess` for more information. verbose : {bool, int}, optional Determines whether or not to print information from the raytracing program. Valid values are ``True``, ``False``, or numeric level. """ # set numeric verbosity level if verbose and (type(verbose) == bool): verbose = 4 #XXX # ensure full path for vm programs #vmfile = os.path.abspath(vmfile) #rayfile = os.path.abspath(rayfile) # set grid size for shortest path algortithm vm = VM(vmfile) if grid_size is None: grid_size = (vm.nx, vm.ny, vm.nz) # set forward star size for 2D cases if vm.nx == 1: forward_star_size[0] = 0 elif vm.ny == 1: forward_star_size[1] = 0 # Set bottom-most layer if bottom_layer is None: bottom_layer = vm.nr # Get instrument locations finst = open(instfile, 'rb') inst = {} for row in finst: dat = row.split() inst[int(dat[0])] = [float(d) for d in dat[1:4]] finst.close() # Raytrace each instrument ninst = len(inst) if verbose >= 2: print('Raytracing paths to {:} receiver(s)...'.format(ninst)) if os.path.isfile(rayfile): os.remove(rayfile) start_all = time.clock() for i, _inst in enumerate(inst): # Set flag to leave rayfan file open for additional instruments if i == 0: irayfile_exists = 0 else: irayfile_exists = 1 recx, recy, recz = inst[_inst] # Build input if verbose >= 3: print(' Tracing rays for receiver #{:} ({:} of {:})'\ .format(_inst, i + 1, ninst)) sh = '#!/bin/bash\n' sh += '#\n' sh += '{:} << eof\n'.format(RAYTR_PROGRAM) sh += '{:}\n'.format(vmfile) sh += '{:}\n'.format(_inst) sh += '{:},{:},{:}\n'.format(grid_size[0], grid_size[1], grid_size[2]) sh += '{:}\n'.format(1. / min_velocity) sh += '{:}\n'.format(max_node_size) sh += '{:<10.5f} {:<10.5f} {:<10.5f}\n'.format(recx, recy, recz) sh += '{:},{:}\n'.format(top_layer, bottom_layer) sh += '{:},{:},{:}\n'.format(forward_star_size[0], forward_star_size[1], forward_star_size[2]) sh += '{:}\n'.format(min_angle) sh += '{:}\n'.format(shotfile) sh += '{:}\n'.format(pickfile) sh += '{:}\n'.format(rayfile) sh += '{:}\n'.format(irayfile_exists) sh += '0.0\n' # XXX seting instrument static to 0. here! # TODO take as input sh += 'eof\n' start = time.clock() if os.path.isfile(rayfile): raysize0 = os.path.getsize(rayfile) else: raysize0 = 0 if (verbose >= 4): print(sh) if (verbose >= 4) or (stdout is not None): subprocess.call(sh, shell=True, stdout=stdout, stderr=stderr) else: with open(os.devnull, "w") as fnull: subprocess.call(sh, shell=True, stdout=fnull, stderr=stderr) elapsed = (time.clock() - start) if os.path.isfile(rayfile): raysize1 = os.path.getsize(rayfile) else: raysize1 = 0 if (raysize1 == raysize0) and verbose >= 1: msg = 'Did not appear to trace rays for receiver #{:}'\ .format(_inst) warnings.warn(msg) if verbose >= 3: print('Completed raytracing for receiver #{:} in {:} seconds.'\ .format(_inst, elapsed)) if verbose >= 2: print('Completed raytracing for all recievers in {:} seconds.'\ .format(time.clock() - start_all)) if os.path.isfile(rayfile) and verbose > 1: print('Output rayfile is: {:}'.format(rayfile)) elif not os.path.isfile(rayfile) and (verbose >= 1): msg = 'Did not create a rayfile.' warnings.warn(msg)
import numpy as np import copy import matplotlib.pyplot as plt from pyvm.models.vm import VM vm = VM('Myers_3D.vm') rf0 = copy.copy(vm.rf[0][:, :]) fig = plt.figure(figsize=(20, 10)) ax = fig.add_subplot(131) ax.imshow(np.flipud(rf0.T)) plt.title('Before smoothing') vm.smooth_interface(0, nwin=25) ax = fig.add_subplot(132) ax.imshow(np.flipud(vm.rf[0].T)) plt.title('After smoothing') ax = fig.add_subplot(133) ax.imshow(np.flipud((vm.rf[0] - rf0).T), cmap='seismic') plt.title('Difference') plt.show()
""" Build a simple VM model from scratch """ import numpy as np from pyvm.models.vm import VM # create a 2D model vm = VM(shape=(512, 1, 256), spacing=(0.5, 1, 0.1), origin=(412, 412, -2)) # add interfaces vm.insert_interface(0) vm.insert_interface(3) vm.insert_interface(5) vm.insert_interface(12) # add velocities vm.define_constant_layer_velocity(0, 0.333) vm.define_stretched_layer_velocities(1, vel=[1.49, 1.51]) vm.define_stretched_layer_velocities(2, vel=[None, 2.3]) vm.define_stretched_layer_velocities(3, vel=[4.4, 6.8, 6.9, 7.2]) vm.define_constant_layer_gradient(4, 0.1) # plot vm.plot(aspect=10)