# ------------------------------------------------------------------------------ # Initializing and plotting the finite-difference model # Initialize a blank finite-difference grid with a spacing of your choosing # shape = BP_2004_vpModel_sq.shape shape = cana_vel_clip.shape ds = 0.15 # spacing in meters area = [0, shape[0] * ds, 0, shape[1] * ds] # Fill the velocity field velocity = cana_vel_clip # Instantiate the source fc = 35. # The approximate frequency of the source source = [wavefd.GaussSource((velocity.shape[0] / 2 -2) * ds, 2 * ds, area, shape, 15000., fc)] # source = [wavefd.MexHatSource(950 * ds, 2 * ds, area, shape, 400., fc)] dt = wavefd.scalar_maxdt(area, shape, np.max(velocity)) duration = 1 maxit = int(duration / dt) # Generate the stations and reciever location num_stations = 2 spac = velocity.shape[0]/num_stations # station spacing # stations = [velocity.shape[0] / 2 * ds, 3 * ds] stations = [[i*spac*ds, 3 * ds] for i in range(1,num_stations)] # geophone coordinates (x,z) seismogram_list = ['seis' + str(i) for i in range(1,num_stations)] # Supposed to be for labeling geophones snapshots = 50 # number of iterations before the plot updates simulation = wavefd.scalar(velocity, area, dt, maxit, source, stations, snapshots, padding = 500, taper = 0.0005)
def pre_rtmshot(shot, dt, vdepth, area, fc, source): """ Perform pre-stack reverse in time depth migration on a 2D shot gather, Forward and reverse modelling of shots are done using scalar wave equation. For image condition uses the normalized cross-correlation of every grid node. Parameters: * shot : 2D-array The shot gather, time x space * dt : float sample rate * vdepth : 2D-array The depth velocity field at all receiver positions * area : [xmin, xmax, zmin, zmax] The x, z limits of the shot/velocity area, e.g., the shallowest point is at zmin, the deepest at zmax * fc : source frequency Used for forward modelling based on a Gauss Source * source: (sx, sz) x, z coordinates of source source Returns: * migrated shot : 2D the depth migrated shot same shape as vdepth """ # Basic parameters # Set the parameters of the finite difference grid nz, nx = vdepth.shape x1, x2, z1, z2 = area dz, dx = (z2 - z1) / (nz - 1), (x2 - x1) / (nx - 1) ns = shot.shape[0] # number samples per trace # avoiding spatial alias and numerical dispersion based on plane waves v=l*f and Alford et al. # # and using at least 5 points per wavelength eps = 0.98 * 1. / (5 * max(dx, dz) * min(1. / (2 * dx), 1. / (2 * dz))) idealfc = eps * numpy.min(vdepth) / (max(2 * dx, 2 * dz)) if fc > idealfc: sys.stdout.write( "Warning: the simulation might have strong numerical dispersion making it unusable\n" ) sys.stdout.write("Warning: consider using a finer velocity model") simsource = [wavefd.GaussSource(source, area, (nz, nx), 1., fc)] # forward simulation source simdt = wavefd.scalar_maxdt( area, vdepth.shape, numpy.max(vdepth)) # forward simulation time step simit = int(numpy.floor( ns * dt / simdt)) # maximum number of iterations needed for forward modelling # run forward modelling of the shot fwdsimulation = wavefd.scalar(vdepth, area, simdt, simit, simsource, snapshot=1, padding=50) # dt from signal must be equal to dt from simulation, so resample it first # resample the input signal is better then resampling everything else simshot = shot if dt != simdt: # resample shot if needed if dt > simdt: # low pass filtering on Nyquest first of shot sample rate # 1/(2*simdt) is equal of Nyquest=1 for the input signal b, a = signal.butter(8, dt / simdt) simshot = signal.filtfilt(b, a, shot, axis=0) simshot = signal.resample(simshot, simit, axis=0) # run the forward simulation and record every time step of the grid fwdfield = numpy.zeros((simit, nz, nx)) for i, u, seismograms in fwdsimulation: fwdfield[i, :, :] = u sys.stdout.write("\rforward modeling progressing .. %.1f%% time %.3f" % (100.0 * float(i) / simit, (simdt * i))) sys.stdout.flush() # Reverse in time shot basic parameters same from forward modelling rtmsimulation = rt_scalar(vdepth, area, simdt, simit, simshot, snapshot=1, padding=50) # run the reverse time simulation and record every time step of the grid rtmfield = numpy.zeros((simit, nz, nx)) for i, u in rtmsimulation: rtmfield[i, :, :] = u sys.stdout.write( "\rreverse in time modeling progressing .. %.1f%% time %.3f" % (100.0 * float(i) / simit, (simdt * i))) sys.stdout.flush() # normalized cross-correlation image condition migratedshot = numpy.zeros((nz, nx)) for i in xrange(nz): for j in xrange(nx): migratedshot[i, j] = numpy.dot(rtmfield[:, i, j], fwdfield[::-1, i, j]) migratedshot[i, j] /= numpy.sum(fwdfield[:, i, j]**2) return migratedshot # def rt_scalar(vel, area, dt, iterations, boundary, snapshot=None, padding=-1, taper=0.006): # """ # # Simulate reverse in time scalar waves using an explicit finite differences scheme 4th order # space. Uses a boundary condition at z=0, re-inserting the recorded values back on the # wave-field simulation from the last values to the first. # Used to make reverse time depth migration of zero-offset sections or shot gathers. # # The top implements a free-surface boundary condition (TODO: change to absorbing). # For the left, right and lower uses boundaries uses Transparent condition of Reynolds, A. C. # (Boundary conditions for numerical solution of wave propagation problems Geophysics p 1099-1110 - 1978) # # Parameters: # # * vel : 2D-array (defines shape simulation) # The wave velocity at all the grid nodes, must be half the original velocity. # The depth velocity model. # * area : [xmin, xmax, zmin, zmax] # The x, z limits of the simulation area, e.g., the shallowest point is # at zmin, the deepest at zmax. # * dt : float # The time interval between iterations # * iterations : int # Number of time steps to take # * boundary : 2D-array # Those are the boundary values at z=0 for all iteration times. # For zero-offset section migration, shot-gather migration # this is a matrix of traces. # Boundary must have same shape as vel and sample rate must be equal of dt. # * snapshot : None or int # If not None, than yield a snapshot of the scalar quantity disturbed at every # *snapshot* iterations. # * padding : int # Number of grid nodes to use for the absorbing boundary region # default 5 percent nz # * taper : float (TODO: implement real gaussian) # The intensity of the Gaussian taper function used for the absorbing # boundary conditions. Adjust it for better absorption. # # Yields: # # * i, u : int, 2D-array # The current iteration, the scalar quantity disturbed # # The last iteration is the migrated section in depth # # """ # # if boundary.shape[1] != vel.shape[1]: # just x must be equal # raise IndexError("boundary must have same shape as velocity") # if iterations != boundary.shape[0]: # raise IndexError("Same number of interations needed for rtm") # # nz, nx = numpy.shape(vel) # get simulation dimensions # x1, x2, z1, z2 = area # dz, dx = (z2 - z1)/(nz - 1), (x2 - x1)/(nx - 1) # # # Add some padding to x and z. The padding region is where the wave is # # absorbed by gaussian dumping # pad = int(padding) # if pad == -1: # default 5% percent nz # pad = int(0.05*nz) + 2 # plus 2 due 4th order # nx += 2*pad # nz += pad # # Pad the velocity as well # vel_pad = wavefd._add_pad(vel, pad, (nz, nx)) # # Pack the particle position u at 3 different times in one 3d array # u = numpy.zeros((3, nz, nx), dtype=numpy.float) # # insert the zero-offset samples reversed in time last ones first. For utp1 at z=0 for every x # for j in xrange(nx-2*pad): # tp1 # u[0, 0, j + pad] = boundary[iterations-1, j] # if snapshot is not None: # yield 0, u[0, :-pad, pad:-pad] # for j in xrange(nx-2*pad): # t # u[1, 0, j + pad] = boundary[iterations-2, j] # if snapshot is not None: # yield 1, u[1, :-pad, pad:-pad] # for iteration in xrange(2, iterations): # tm1, t, tp1 = iteration % 3, (iteration-1) % 3, (iteration-2) % 3 # to avoid copying between panels # # invert the order of the input parameters to make it reverse in time # wavefd._step_scalar(u[tm1], u[t], u[tp1], 2, nx - 2, 2, nz - 2, # dt, dx, dz, vel_pad) # # _apply_damping(u[tp1], nx-2, nz-2, pad-2, taper) # # forth order +2-2 indexes needed # # apply Reynolds 1d plane wave absorbing condition # wavefd._nonreflexive_scalar_boundary_conditions(u[tm1], u[t], u[tp1], vel_pad, dt, dx, dz, nx, nz) # # insert the zero-offset samples reversed in time last ones first. For utp1 at z=0 for every x # for j in xrange(nx-2*pad): # u[t, 0, j + pad] = boundary[iterations-(iteration+1), j] # if snapshot is not None and iteration%snapshot == 0: # yield iteration, u[tm1, :-pad, pad:-pad] # yield iteration, u[tm1, :-pad, pad:-pad]
pvel[int(600 / dz):int(600 / dz) + int(120 / dz), :] = 4800 # basalt flow 1 pvel[int(600 / dz) + int(120 / dz):int(600 / dz) + int(240 / dz), :] = 3540 # basalt flow 2 svel = 1600 * np.ones(shape) # botucatu svel[0:int(600 / dz), :] = 1166 # bauru svel[int(600 / dz):int(600 / dz) + int(120 / dz), :] = 2611 # basalt flow 1 svel[int(600 / dz) + int(120 / dz):int(600 / dz) + int(240 / dz), :] = 1900 # basalt flow 2 mu = wavefd.lame_mu(svel, density) lamb = wavefd.lame_lamb(pvel, svel, density) # Make a wave source from a gauss derivative that vibrates in the z direction only # (removes the shear component amplitude equals zero, simulating a default seismic acquisition) sources = [ [wavefd.GaussSource(2000, 0, area, shape, 0.0, 5.)], # x source or shear source [wavefd.GaussSource(2000, 0, area, shape, 100.0, 25.)] ] # z source or z compressional source # Get the iterator for the simulation dt = wavefd.maxdt(area, shape, np.max(pvel)) duration = 3.0 maxit = int(duration / dt) stations = [[2200 + i * dx, 0] for i in range(220)] # x, z coordinate of the seismometers snapshot = int(0.004 / dt) # Plot a snapshot of the simulation every 4 miliseconds print "dt for simulation is ", dt print "max iteration for simulation is ", maxit print "duration for simulation is ", duration simulation = wavefd.elastic_psv(lamb,
Geophysics 1974 """ import numpy as np from matplotlib import animation from fatiando.seismic import wavefd from fatiando.vis import mpl # Set the parameters of the finite difference grid shape = (200, 200) ds = 100. # spacing area = [0, shape[0] * ds, 0, shape[1] * ds] # Set the parameters of the finite difference grid velocity = np.zeros(shape) + 6000. velocity[100:, 100:] = 0. fc = 15. sources = [wavefd.GaussSource(125 * ds, 75 * ds, area, shape, 1., fc)] dt = wavefd.scalar_maxdt(area, shape, np.max(velocity)) duration = 2.5 maxit = int(duration / dt) stations = [[75 * ds, 125 * ds]] # x, z coordinate of the seismometer snapshots = 3 # every 3 iterations plots one simulation = wavefd.scalar(velocity, area, dt, maxit, sources, stations, snapshots) # This part makes an animation using matplotlibs animation API background = (velocity - 4000) * 10**-1 fig = mpl.figure(figsize=(8, 6)) mpl.subplots_adjust(right=0.98, left=0.11, hspace=0.5, top=0.93) mpl.subplot2grid((4, 3), (0, 0), colspan=3, rowspan=3) wavefield = mpl.imshow(np.zeros_like(velocity), extent=area,
""" import numpy as np import sys from fatiando.seismic import wavefd # Set the parameters of the finite difference grid 3D shape = (100, 100, 100) ds = 10. # spacing area = [0, shape[2]*ds, 0, shape[1]*ds, 0, shape[0]*ds] # Set the parameters of the finite difference grid velocity = np.ones(shape)*2500. # m/s velocity[50:100, 50:100, 50:100] = 1500. # m/s # avoiding spatial alias, frequency of source should be smaller than this fc = 0.5*np.min(velocity)/ds # based on plane waves v=l*f fc -= 0.5*fc sources = [wavefd.GaussSource((40*ds, 40*ds, 30*ds), area, shape, 10**(-8), fc)] dt = wavefd.maxdt(area, shape, np.max(velocity)) duration = 0.6 maxit = int(duration/dt) # x, y, z coordinate of the seismometer stations = [[45*ds, 45*ds, 65*ds], [65*ds, 65*ds, 30*ds]] snapshots = 5 # every 1 iterations plots one simulation = wavefd.scalar3(velocity, area, dt, maxit, sources, stations, snapshots) movie = np.zeros(((maxit/snapshots)+2, 100, 100, 100)) i = 0 for t, u, seismogram in simulation: movie[i] = u sys.stdout.write("\rprogressing .. %.1f%% time %.3f"%(100.0*float(t)/maxit, (dt*t))) sys.stdout.flush() i += 1