def run(self, *args, **kwargs): clear_cache() gflopss, oi, timings, _ = self.func(*args, **kwargs) for key in timings.keys(): self.register(gflopss[key], measure="gflopss", event=key) self.register(oi[key], measure="oi", event=key) self.register(timings[key], measure="timings", event=key)
def test_fd_space_staggered(self, space_order, stagger): """ This test compares the discrete finite-difference scheme against polynomials For a given order p, the finite difference scheme should be exact for polynomials of order p :param derivative: name of the derivative to be tested :param space_order: space order of the finite difference stencil """ clear_cache() # dummy axis dimension nx = 100 xx = np.linspace(-1, 1, nx) dx = xx[1] - xx[0] # Symbolic data grid = Grid(shape=(nx,), dtype=np.float32) x = grid.dimensions[0] # Location of the staggered function if stagger == left: off = -.5 side = -x xx2 = xx - off * dx elif stagger == right: off = .5 side = x xx2 = xx[:-1] - off * dx else: off = 0 side = NODE xx2 = xx u = Function(name="u", grid=grid, space_order=space_order, staggered=(side,)) du = Function(name="du", grid=grid, space_order=space_order) # Define polynomial with exact fd coeffs = np.ones((space_order-1,), dtype=np.float32) polynome = sum([coeffs[i]*x**i for i in range(0, space_order-1)]) polyvalues = np.array([polynome.subs(x, xi) for xi in xx2], np.float32) # Fill original data with the polynomial values u.data[:] = polyvalues # True derivative of the polynome Dpolynome = diff(polynome) Dpolyvalues = np.array([Dpolynome.subs(x, xi) for xi in xx], np.float32) # FD derivative, symbolic u_deriv = generic_derivative(u, deriv_order=1, fd_order=space_order, dim=x, stagger=stagger) # Compute numerical FD stencil = Eq(du, u_deriv) op = Operator(stencil, subs={x.spacing: dx}) op.apply() # Check exactness of the numerical derivative except inside space_brd space_border = space_order error = abs(du.data[space_border:-space_border] - Dpolyvalues[space_border:-space_border]) assert np.isclose(np.mean(error), 0., atol=1e-3)
def test_clear_cache(nx=1000, ny=1000): grid = Grid(shape=(nx, ny), dtype=np.float64) clear_cache() cache_size = len(_SymbolCache) for i in range(10): assert(len(_SymbolCache) == cache_size) Function(name='u', grid=grid, space_order=2) assert(len(_SymbolCache) == cache_size + 1) clear_cache()
def bench(problem, **kwargs): """ Complete benchmark with multiple simulation and performance parameters. """ run = tti_run if problem == 'tti' else acoustic_run resultsdir = kwargs.pop('resultsdir') repeats = kwargs.pop('repeats') bench = get_ob_bench(problem, resultsdir, kwargs) bench.execute(get_ob_exec(run), warmups=0, repeats=repeats) bench.save() # Final clean up, just in case the benchmarker is used from external Python modules clear_cache()
def test_symbol_cache_aliasing_reverse(): """Test to assert that removing he original u[x, y] instance does not impede our alisaing cache or leaks memory. """ # Ensure a clean cache to start with clear_cache() # FIXME: Currently not working, presumably due to our # failure to cache new instances? # assert(len(_SymbolCache) == 0) # Create first instance of u and fill its data grid = Grid(shape=(3, 4)) u = Function(name='u', grid=grid) u.data[:] = 6. u_ref = weakref.ref(u.data) # Create derivative and delete orignal u[x, y] dx = u.dx del u clear_cache() # We still have a references to u # FIXME: Unreliable cache sizes # assert len(_SymbolCache) == 1 # Ensure u[x + h, y] still holds valid data assert np.allclose(dx.args[0].args[1].data, 6.) del dx clear_cache() # FIXME: Unreliable cache sizes # assert len(_SymbolCache) == 0 # We still have a reference to u_h assert u_ref() is None
def test_operator_leakage_sparse(): """ Test to ensure that Operator creation does not cause memory leaks for SparseTimeFunctions. """ grid = Grid(shape=(5, 6)) a = Function(name='a', grid=grid) s = SparseTimeFunction(name='s', grid=grid, npoint=1, nt=1) w_a = weakref.ref(a) w_s = weakref.ref(s) # Create operator and delete everything again op = Operator(s.interpolate(a)) w_op = weakref.ref(op) del op del s del a clear_cache() # Test whether things are still hanging around assert w_a() is None assert w_s() is None assert w_op() is None
def test_operator_leakage_function(): """ Test to ensure that Operator creation does not cause memory leaks for (Time)Functions. """ grid = Grid(shape=(5, 6)) f = Function(name='f', grid=grid) g = TimeFunction(name='g', grid=grid) # Take weakrefs to test whether symbols are dead or alive w_f = weakref.ref(f) w_g = weakref.ref(g) # Create operator and delete everything again op = Operator(Eq(f, 2 * g)) w_op = weakref.ref(op) del op del f del g clear_cache() # Test whether things are still hanging around assert w_f() is None assert w_g() is None assert w_op() is None
def test_symbol_cache_aliasing(): """Test to assert that our aliasing cache isn't defeated by sympys non-aliasing symbol cache. For further explanation consider the symbol u[x, y] and it's first derivative in x, which includes the symbols u[x, y] and u[x + h, y]. The two functions are aliased in devito's caching mechanism to allow multiple stencil indices pointing at the same data object u, but SymPy treats these two instances as separate functions and thus is allowed to delete one or the other when the cache is cleared. The test below asserts that u[x + h, y] is deleted, the data on u is still intact through our own caching mechanism.""" # Ensure a clean cache to start with clear_cache() # FIXME: Currently not working, presumably due to our # failure to cache new instances? # assert(len(_SymbolCache) == 0) # Create first instance of u and fill its data grid = Grid(shape=(3, 4)) u = Function(name='u', grid=grid) u.data[:] = 6. u_ref = weakref.ref(u.data) # Create u[x + h, y] and delete it again dx = u.dx # Contains two u symbols: u[x, y] and u[x + h, y] del dx clear_cache() # FIXME: Unreliable cache sizes # assert len(_SymbolCache) == 1 # We still have a reference to u assert np.allclose(u.data, 6.) # u.data is alive and well # Remove the final instance and ensure u.data got deallocated del u clear_cache() assert u_ref() is None
def test(self, args): init_op = tf.global_variables_initializer() self.sess.run(init_op) if self.load(args.checkpoint_dir): print(" [*] Load SUCCESS") else: print(" [!] Load failed...") self.update_devito(velIndex=0) batch_idxs = list(range(0, self.shape[0])) xsrc = 201 #choice(batch_idxs) if not os.path.isfile( os.path.join(self.sample_dir, 'LearnedFwdSimPrediction.hdf5')): datasetSize = (self.output_c_dim, self.image_size0, self.image_size1, \ self.virtSteps) self.file_prediction = h5py.File(os.path.join(self.sample_dir, \ 'LearnedFwdSimPrediction.hdf5'), 'w-') self.dataset_CNN = self.file_prediction.create_dataset( "result", datasetSize) self.dataset_HF = self.file_prediction.create_dataset( "HF", datasetSize) self.dataset_LF = self.file_prediction.create_dataset( "LF", datasetSize) else: self.file_prediction = h5py.File(os.path.join(self.sample_dir, \ 'LearnedFwdSimPrediction.hdf5'), 'r+') self.dataset_CNN = self.file_prediction["result"] self.dataset_HF = self.file_prediction["HF"] self.dataset_LF = self.file_prediction["LF"] print('Processing shot number: ' + str(xsrc)) HF_wave_history = [] CNN_wave_history = [] CNN_input_history = [] LF_wave_history = [] Rec_SNR = [] self.src.coordinates.data[0, :] = np.array([xsrc*self.spacing[0], \ 2*self.spacing[1]]).astype(np.float32) self.rec.coordinates.data[:, 0] = np.linspace(0., self.model.domain_size[0], \ num=self.num_rec) self.rec.coordinates.data[:, 1:] = self.src.coordinates.data[0, 1:] self.u_HF.data.fill(0.) self.u_LF.data.fill(0.) for time_index in range(self.virtSteps): clear_cache() self.solverLF.forward(m=self.model.m, src=self.src, time_m=time_index*\ self.virt_timestep, time=(time_index+1)*self.virt_timestep, u=self.u_LF) LF_wave_history.append( np.transpose(np.array(self.u_LF.data[:, :, :]), (1, 2, 0)).astype(np.float32)[None, :, :, :]) CNN_wave_history.append( self.sess.run( [self.CNN_wave], feed_dict={self.Noisy_wave[0]: LF_wave_history[-1]})[0]) self.solverHF.forward(m=self.model.m, src=self.src, time_m=time_index*\ self.virt_timestep, time=(time_index+1)*self.virt_timestep, u=self.u_HF) HF_wave_history.append( np.transpose(np.array(self.u_HF.data[:, :, :]), (1, 2, 0)).astype(np.float32)[None, :, :, :]) for iG in range(self.virtSteps): self.dataset_CNN[:, :, :, iG] = np.transpose(CNN_wave_history[iG][0][0, :, :, :], \ (2, 0 , 1)) self.dataset_HF[:, :, :, iG] = np.transpose(HF_wave_history[iG][0, :, :, :], (2, 0, 1)) self.dataset_LF[:, :, :, iG] = np.transpose(LF_wave_history[iG][0, :, :, :], (2, 0, 1)) self.file_prediction.close()
def forward(model, src_coords, rcv_coords, wav, dt=None, space_order=8, save=False): "Compute forward wavefield u = A(m)^{-1}*f and related quantities (u(xrcv))" clear_cache() # Setting time sampling if dt is None: dt = model.critical_dt # Physical parameters m, rho, damp = model.m, model.rho, model.damp # Setting adjoint wavefield nt = wav.shape[0] u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order, save=None if not save else nt) # Set up PDE expression and rearrange ulaplace, rho = laplacian(u, rho) stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace) expression = [Eq(u.forward, stencil)] # Setup adjoint source injected at receiver locations src = PointSource(name="src", grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wav[:] src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m) expression += src_term # Setup adjoint wavefield sampling at source locations rcv = Receiver(name="rcv", grid=model.grid, ntime=nt, coordinates=rcv_coords) adj_rcv = rcv.interpolate(expr=u) expression += adj_rcv # Create operator and run subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse="advanced", dle="advanced", name="forward") op() # Output if save: return rcv.data, u else: return rcv.data, None
def objTWRIdual_devito(model, y, src_coords, rcv_coords, wav, dat, Filter, eps, mode="eval", objfact=np.float32(1), comp_alpha=True, grad_corr=False, weight_fun_pars=None, dt=None, space_order=8): "Evaluate TWRI objective functional/gradients for current (m, y)" clear_cache() # Setting time sampling if dt is None: dt = model.critical_dt # Computing y in reduced mode (= residual) if not provided u0 = None y_was_None = y is None if y_was_None: u0rcv, u0 = forward(model, src_coords, rcv_coords, wav, dt=dt, space_order=space_order, save=(mode == "grad") and grad_corr) y = applyfilt(dat - u0rcv, Filter) PTy = applyfilt_transp(y, Filter) # Normalization constants nx = np.float32(model.m.size) nt, nr = np.float32(y.shape) etaf = npla.norm(wav.reshape(-1)) / np.sqrt(nt * nx) etad = npla.norm(applyfilt(dat, Filter).reshape(-1)) / np.sqrt(nt * nr) # Compute wavefield vy = adjoint(F(m))*Py norm_vPTy2, vPTy_src, vPTy = adjoint_y(model, PTy, src_coords, rcv_coords, weight_fun_pars=weight_fun_pars, dt=dt, space_order=space_order, save=(mode == "grad")) # <PTy, d-F(m)*f> = <PTy, d>-<adjoint(F(m))*PTy, f> PTy_dot_r = np.dot(PTy.reshape(-1), dat.reshape(-1)) - np.dot( vPTy_src.reshape(-1), wav.reshape(-1)) # ||y|| norm_y = npla.norm(y.reshape(-1)) # Optimal alpha c1 = etaf**np.float32(2) / (np.float32(4) * etad**np.float32(2) * nx * nt) c2 = np.float32(1) / (etad * nr * nt) c3 = eps / np.sqrt(nr * nt) alpha = compute_optalpha(c1 * norm_vPTy2, c2 * PTy_dot_r, c3 * norm_y, comp_alpha=comp_alpha) # Lagrangian evaluation fun = -alpha**np.float32( 2) * c1 * norm_vPTy2 + alpha * c2 * PTy_dot_r - np.abs( alpha) * c3 * norm_y # Gradient computation if mode == "grad": # Physical parameters m, rho, damp = model.m, model.rho, model.damp # Create the forward wavefield u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order) # Set up PDE and rearrange ulaplace, rho = laplacian(u, rho) if weight_fun_pars is None: stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * (ulaplace + 2.0 * c1 / c2 * alpha * vPTy)) else: weight = weight_fun(weight_fun_pars, model, src_coords) stencil = damp * ( 2.0 * u - damp * u.backward + dt**2 * rho / m * (ulaplace + 2.0 * c1 / c2 * alpha * vPTy / weight**2)) expression = [Eq(u.forward, stencil)] # Setup source with wavelet nt = wav.shape[0] src = PointSource(name="src", grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wav[:] src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m) ####### expression += src_term # Setup data sampling at receiver locations rcv = Receiver(name="rcv", grid=model.grid, ntime=nt, coordinates=rcv_coords) rcv_term = rcv.interpolate(expr=u) expression += rcv_term # Setup gradient wrt m gradm = Function(name="gradm", grid=model.grid) expression += [Inc(gradm, alpha * c2 * vPTy * u.dt2)] # Create operator and run subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse="advanced", dle="advanced", name="Grad") op() # Compute gradient wrt y if not y_was_None or grad_corr: norm_y = npla.norm(y) if norm_y == 0: grady_data = alpha * c2 * applyfilt(dat - rcv.data, Filter) else: grady_data = alpha * c2 * applyfilt( dat - rcv.data, Filter) - np.abs(alpha) * c3 * y / norm_y # Correcting for reduced gradient if not y_was_None or (y_was_None and not grad_corr): gradm_data = gradm.data else: # Compute wavefield vy_ = adjoint(F(m))*grady _, _, vy_ = adjoint_y(model, applyfilt_transp(grady_data, Filter), src_coords, rcv_coords, dt=dt, space_order=space_order, save=True) # Setup reduced gradient wrt m gradm_corr = Function(name="gradmcorr", grid=model.grid) expression = [Inc(gradm_corr, vy_ * u0.dt2)] # Create operator and run subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse="advanced", dle="advanced", name="GradRed") op() # Reduced gradient post-processing gradm_data = gradm.data + gradm_corr.data # Return output if mode == "eval": return fun / objfact elif mode == "grad" and y_was_None: return fun / objfact, gradm_data / objfact elif mode == "grad" and not y_was_None: return fun / objfact, gradm_data / objfact, grady_data / objfact
def setup_class(cls): clear_cache()
def adjoint_y(model, y, src_coords, rcv_coords, weight_fun_pars=None, dt=None, space_order=8, save=False): "Compute adjoint wavefield v = adjoint(F(m))*y and related quantities (||v||_w, v(xsrc))" clear_cache() # Setting time sampling if dt is None: dt = model.critical_dt # Physical parameters m, rho, damp = model.m, model.rho, model.damp # Setting adjoint wavefield nt = y.shape[0] v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order, save=None if not save else nt) # Set up PDE expression and rearrange vlaplace, rho = laplacian(v, rho) stencil = damp * (2.0 * v - damp * v.forward + dt**2 * rho / m * vlaplace) expression = [Eq(v.backward, stencil)] # Setup adjoint source injected at receiver locations rcv = Receiver(name="rcv", grid=model.grid, ntime=nt, coordinates=rcv_coords) rcv.data[:] = y[:] adj_src = rcv.inject(field=v.backward, expr=rcv * rho * dt**2 / m) expression += adj_src # Setup adjoint wavefield sampling at source locations src = PointSource(name="src", grid=model.grid, ntime=nt, coordinates=src_coords) adj_rcv = src.interpolate(expr=v) expression += adj_rcv # Setup ||v||_w computation norm_vy2_t = Function(name="nvy2t", grid=model.grid) expression += [Inc(norm_vy2_t, Pow(v, 2))] i = Dimension(name="i", ) norm_vy2 = Function(name="nvy2", shape=(1, ), dimensions=(i, ), grid=model.grid) if weight_fun_pars is None: expression += [Inc(norm_vy2[0], norm_vy2_t)] else: weight = weight_fun(weight_fun_pars, model, src_coords) expression += [Inc(norm_vy2[0], norm_vy2_t / weight**2)] # Create operator and run subs = model.spacing_map subs[v.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse="advanced", dle="advanced", name="adjoint_y") op() # Output if save: return norm_vy2.data[0], src.data, v else: return norm_vy2.data[0], src.data, None
def forward_freq_modeling(model, src_coords, wavelet, rec_coords, freq, space_order=8, dt=None, factor=None, free_surface=False): # Forward modeling with on-the-fly DFT of forward wavefields clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp freq_dim = Dimension(name='freq_dim') time = model.grid.time_dim if factor is None: factor = int(1 / (dt * 4 * np.max(freq))) tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) if factor == 1: tsave = time else: tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) print("DFT subsampling factor: ", factor) # Create wavefields nfreq = freq.shape[0] u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) f = Function(name='f', dimensions=(freq_dim, ), shape=(nfreq, )) f.data[:] = freq[:] ufr = Function(name='ufr', dimensions=(freq_dim, ) + u.indices[1:], shape=(nfreq, ) + model.shape_domain) ufi = Function(name='ufi', dimensions=(freq_dim, ) + u.indices[1:], shape=(nfreq, ) + model.shape_domain) ulaplace, rho = acoustic_laplacian(u, rho) # Set up PDE and rearrange stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace) expression = [Eq(u.forward, stencil)] expression += [ Eq(ufr, ufr + factor * u * cos(2 * np.pi * f * tsave * factor * dt)) ] expression += [ Eq(ufi, ufi - factor * u * sin(2 * np.pi * f * tsave * factor * dt)) ] # Source symbol with input wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, expr=src * dt**2 / m) # Data is sampled at receiver locations rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=u) # Create operator and run expression += src_term + rec_term # Free surface if free_surface is True: expression += freesurface(u, space_order // 2, model.nbpml) subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') cf = op.cfunction op() return rec.data, ufr, ufi
def fwi_gradient(vp_in): # AUTO grad = Function(name="grad", grid=model.grid) residual = Receiver(name='rec', grid=model.grid, time_range=geometry.time_axis, coordinates=geometry.rec_positions) objective = 0. u0 = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=4, save=geometry.nt) # MANUAL grad_manual = Function(name="grad", grid=model.grid) residual_man = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates) objective_manual = 0. u0_man = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=4, save=nt) for i in range(9): # AUTO clear_cache() geometry.src_positions[0, :] = source_locations[i, :] true_d, _, _ = solver.forward(vp=model.vp) u0.data.fill(0.) smooth_d, _, _ = solver.forward(vp=vp_in, save=True, u=u0) residual.data[:] = smooth_d.data[:] - true_d.data[:] objective += .5 * np.linalg.norm(residual.data.flatten())**2 solver.gradient(rec=residual, u=u0, vp=vp_in, grad=grad) # MANUAL # source src_true = RickerSource(name='src', grid=model.grid, time_range=time_axis, coordinates=source_locations[i, :], npoint=1, f0=f0) src_term = src_true.inject( field=u.forward, expr=src_true * model.grid.stepping_dim.spacing**2 / model.m) # receiver rec_true = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) rec_term = rec_true.interpolate(expr=u) # operator op_fwd = Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward') op_fwd.apply(src=src_true, rec=rec_true, u=u0_man, vp=model.vp, dt=model.critical_dt) u0_man.data.fill(0.) rec_smooth = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) op_fwd.apply(src=src_true, rec=rec_smooth, u=u0_man, vp=vp_in, dt=model.critical_dt) # back-receiver rec_back = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) rec_back_term = rec_back.inject( field=v.backward, expr=rec_back * model.grid.stepping_dim.spacing**2 / model.m) # gradient gradient_update = Inc(grad_manual, -u.dt2 * v) op_grad = Operator(eqn_back + rec_back_term + [gradient_update], subs=model.spacing_map, name='Gradient') residual_man.data[:] = rec_smooth.data[:] - rec_true.data[:] objective_manual += .5 * np.linalg.norm(residual_man.data.flatten())**2 op_grad.apply(rec=residual_man, u=u0_man, vp=vp_in, dt=model.critical_dt, grad=grad_manual) # sanity-check -> expect for 0! # plot_shotrecord(true_d.data[:] - rec_true.data[:], model, t0, tn) # plot_shotrecord(smooth_d.data[:] - rec_smooth.data[:], model, t0, tn) return objective, -grad.data, objective_manual, -grad_manual.data
def adjoint_born(model, rec_coords, rec_data, u=None, op_forward=None, is_residual=False, space_order=8, nb=40, isic=False, dt=None, n_checkpoints=None, maxmem=None): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create adjoint wavefield and gradient v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) gradient = Function(name='gradient', grid=model.grid) # Set up PDE and rearrange vlaplace, rho = acoustic_laplacian(v, rho) H = symbols('H') eqn = m / rho * v.dt2 - H - damp * v.dt stencil = solve(eqn, v.backward, simplify=False, rational=False)[0] expression = [Eq(v.backward, stencil.subs({H: vlaplace}))] # Data at receiver locations as adjoint source rec_g = Receiver(name='rec_g', grid=model.grid, ntime=nt, coordinates=rec_coords) if op_forward is None: rec_g.data[:] = rec_data[:] adj_src = rec_g.inject(field=v.backward, offset=model.nbpml, expr=rec_g * rho * dt**2 / m) # Gradient update if u is None: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) if isic is not True: gradient_update = [Eq(gradient, gradient - dt * u.dt2 / rho * v)] else: # sum u.dx * v.dx fo x in dimensions. # space_order//2 diff_u_v = sum([ first_derivative(u, dim=d, order=space_order // 2) * first_derivative(v, dim=d, order=space_order // 2) for d in u.space_dimensions ]) gradient_update = [ Eq(gradient, gradient - dt * (u * v.dt2 * m + diff_u_v) / rho) ] # Create operator and run set_log_level('ERROR') expression += adj_src + gradient_update subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Gradient%s" % randint(1e5)) # Optimal checkpointing if op_forward is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) cp = DevitoCheckpoint([u]) if maxmem is not None: n_checkpoints = int( np.floor(maxmem * 10**6 / (cp.size * u.data.itemsize))) wrap_fw = CheckpointOperator(op_forward, u=u, m=model.m, rec=rec) wrap_rev = CheckpointOperator(op, u=u, v=v, m=model.m, rec_g=rec_g) # Run forward wrp = Revolver(cp, wrap_fw, wrap_rev, n_checkpoints, nt - 2) wrp.apply_forward() # Residual and gradient if is_residual is True: # input data is already the residual rec_g.data[:] = rec_data[:] else: rec_g.data[:] = rec.data[:] - rec_data[:] # input is observed data fval = .5 * np.dot(rec_g.data[:].flatten(), rec_g.data[:].flatten()) * dt wrp.apply_reverse() else: op() clear_cache() if op_forward is not None and is_residual is not True: return fval, gradient.data else: return gradient.data
def forward_freq_modeling(model, src_coords, wavelet, rec_coords, freq, space_order=8, nb=40, dt=None, factor=None): # Forward modeling with on-the-fly DFT of forward wavefields clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, damp = model.m, model.damp freq_dim = Dimension(name='freq_dim') time = model.grid.time_dim if factor is None: factor = int(1 / (dt * 4 * np.max(freq))) tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) if factor == 1: tsave = time else: tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) print("DFT subsampling factor: ", factor) # Create wavefields nfreq = freq.shape[0] u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) f = Function(name='f', dimensions=(freq_dim, ), shape=(nfreq, )) f.data[:] = freq[:] ufr = Function(name='ufr', dimensions=(freq_dim, ) + u.indices[1:], shape=(nfreq, ) + model.shape_domain) ufi = Function(name='ufi', dimensions=(freq_dim, ) + u.indices[1:], shape=(nfreq, ) + model.shape_domain) # Set up PDE and rearrange eqn = m * u.dt2 - u.laplace + damp * u.dt stencil = solve(eqn, u.forward, simplify=False, rational=False)[0] expression = [Eq(u.forward, stencil)] expression += [ Eq(ufr, ufr + factor * u * cos(2 * np.pi * f * tsave * factor * dt)) ] expression += [ Eq(ufi, ufi - factor * u * sin(2 * np.pi * f * tsave * factor * dt)) ] # Source symbol with input wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=src * dt**2 / m) # Data is sampled at receiver locations rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=u, offset=model.nbpml) # Create operator and run set_log_level('ERROR') expression += src_term + rec_term subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Forward%s" % randint(1e5)) op() return rec.data, ufr, ufi
def setup_method(self, method): # Some of these tests are memory intensive as it requires to store the entire # forward wavefield to compute the gradient (nx.ny.nz.nt). We therefore call # 'clear_cache()' to release any remaining memory from the previous tests or # previous instances (different parametrizations) of these tests clear_cache()
def adjoint_modeling(model, src_coords, rec_coords, rec_data, space_order=8, nb=40, free_surface=False, dt=None): clear_cache() # If wavelet is file, read it if isinstance(rec_data, str): rec_data = np.load(rec_data) # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create the adjoint wavefield if src_coords is not None: v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order) else: v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order, save=nt) # Set up PDE and rearrange vlaplace, rho = acoustic_laplacian(v, rho) H = symbols('H') eqn = m / rho * v.dt2 - H - damp * v.dt # Input data is wavefield if isinstance(rec_data, TimeFunction): wf_rec = TimeFunction(name='wf_rec', grid=model.grid, time_order=2, space_order=space_order, save=nt) wf_rec._data = rec_data._data eqn -= wf_rec stencil = solve(eqn, v.backward, simplify=False, rational=False)[0] expression = [Eq(v.backward, stencil.subs({H: vlaplace}))] # Free surface if free_surface is True: fs = DefaultDimension(name="fs", default_value=int(space_order / 2)) expression += [ Eq(v.forward.subs({v.indices[-1]: model.nbpml - fs - 1}), -v.forward.subs({v.indices[-1]: model.nbpml + fs + 1})) ] # Adjoint source is injected at receiver locations if rec_coords is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec.data[:] = rec_data[:] adj_src = rec.inject(field=v.backward, offset=model.nbpml, expr=rec * rho * dt**2 / m) expression += adj_src # Data is sampled at source locations if src_coords is not None: src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) adj_rec = src.interpolate(expr=v, offset=model.nbpml) expression += adj_rec # Create operator and run set_log_level('ERROR') subs = model.spacing_map subs[v.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Backward%s" % randint(1e5)) op() if src_coords is None: return v else: return src.data
def adjoint_born(model, rec_coords, rec_data, u=None, op_forward=None, is_residual=False, space_order=8, isic=False, dt=None, n_checkpoints=None, maxmem=None, free_surface=False, tsub_factor=1, checkpointing=False): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create adjoint wavefield and gradient v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) gradient = Function(name='gradient', grid=model.grid) # Set up PDE and rearrange vlaplace, rho = acoustic_laplacian(v, rho) stencil = damp * (2.0 * v - damp * v.forward + dt**2 * rho / m * vlaplace) expression = [Eq(v.backward, stencil)] # Data at receiver locations as adjoint source rec_g = Receiver(name='rec_g', grid=model.grid, ntime=nt, coordinates=rec_coords) if op_forward is None: rec_g.data[:] = rec_data[:] adj_src = rec_g.inject(field=v.backward, expr=rec_g * rho * dt**2 / m) # Gradient update if u is None: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) if isic is not True: gradient_update = [Inc(gradient, - dt * u.dt2 / rho * v)] else: # sum u.dx * v.dx fo x in dimensions. # space_order//2 diff_u_v = sum([first_derivative(u, dim=d, fd_order=space_order//2)* first_derivative(v, dim=d, fd_order=space_order//2) for d in u.space_dimensions]) gradient_update = [Inc(gradient, - tsub_factor * dt * (u * v.dt2 * m + diff_u_v) / rho)] # Create operator and run # Free surface if free_surface is True: expression += freesurface(v, space_order//2, model.nbpml, forward=False) expression += adj_src + gradient_update subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') # Optimal checkpointing summary1 = None summary2 = None if op_forward is not None and checkpointing is True: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) cp = DevitoCheckpoint([u]) if maxmem is not None: n_checkpoints = int(np.floor(maxmem * 10**6 / (cp.size * u.data.itemsize))) wrap_fw = CheckpointOperator(op_forward, u=u, m=model.m, rec=rec) wrap_rev = CheckpointOperator(op, u=u, v=v, m=model.m, rec_g=rec_g) # Run forward wrp = Revolver(cp, wrap_fw, wrap_rev, n_checkpoints, nt-2) wrp.apply_forward() # Residual and gradient if is_residual is True: # input data is already the residual rec_g.data[:] = rec_data[:] else: rec_g.data[:] = rec.data[:] - rec_data[:] # input is observed data fval = .5*np.dot(rec_g.data[:].flatten(), rec_g.data[:].flatten()) * dt wrp.apply_reverse() elif op_forward is not None and checkpointing is False: # Compile first cf1 = op_forward.cfunction cf2 = op.cfunction # Run forward and adjoint summary1 = op_forward.apply() if is_residual is True: rec_g.data[:] = rec_data[:] else: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_g.data[:] = rec.data[:] - rec_data[:] fval = .5*np.dot(rec_g.data[:].flatten(), rec_g.data[:].flatten()) * dt summary2 = op.apply() else: cf = op.cfunction summary1 = op.apply() clear_cache() if op_forward is not None and is_residual is not True: if summary2 is not None: return fval, gradient.data, summary1, summary2 elif summary1 is not None: return fval, gradient.data, summary1 else: return fval, gradient.data else: if summary2 is not None: return gradient.data, summary1, summary2 elif summary1 is not None: return gradient.data, summary1 else: return gradient.data
def forward_born(model, src_coords, wavelet, rec_coords, space_order=8, isic=False, dt=None, free_surface=False): clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, rho, dm, damp = model.m, model.rho, model.dm, model.damp # Create the forward and linearized wavefield u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order) du = TimeFunction(name="du", grid=model.grid, time_order=2, space_order=space_order) if len(model.shape) == 2: x,y = u.space_dimensions else: x,y,z = u.space_dimensions # Set up PDEs and rearrange ulaplace, rho = acoustic_laplacian(u, rho) dulaplace, _ = acoustic_laplacian(du, rho) if isic: # Sum ((u.dx * d, / rho).dx for x in dimensions) # space_order//2 so that u.dx.dx has the same radius as u.laplace du_aux = sum([first_derivative(first_derivative(u, dim=d, fd_order=space_order//2) * dm / rho, fd_order=space_order//2, dim=d) for d in u.space_dimensions]) lin_source = dm /rho * u.dt2 * m - du_aux else: lin_source = dm / rho * u.dt2 stencil_u = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace) stencil_du = damp * (2.0 * du - damp * du.backward + dt**2 * rho / m * (dulaplace - lin_source)) expression_u = [Eq(u.forward, stencil_u)] expression_du = [Eq(du.forward, stencil_du)] # Define source symbol with wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m) # Define receiver symbol rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=du) # Create operator and run expression = expression_u + src_term + expression_du + rec_term # Free surface if free_surface is True: expression += freesurface(u, space_order//2, model.nbpml) expression += freesurface(du, space_order//2, model.nbpml) subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') cf = op.cfunction summary = op.apply() return rec.data, summary
def gradient(model, save=False, space_order=12, sub=None, fs=False, isic=False): clear_cache() # Parameters s = model.grid.stepping_dim.spacing nt = 10 time_range = TimeAxis(start=0, num=nt, step=1) m, damp, epsilon, delta, theta, phi, rho = (model.m, model.damp, model.epsilon, model.delta, model.theta, model.phi, model.rho) m = m * rho # Tilt and azymuth setup ang0 = cos(theta) ang1 = sin(theta) ang2 = cos(phi) ang3 = sin(phi) # Create the forward wavefield f_h = f_t = 1 if sub is not None and (sub[0] > 1 or sub[1] > 1): f_h = sub[1] f_t = sub[0] u, v = subsampled(model, nt, space_order, t_sub=sub[0], space_sub=sub[1]) else: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt) v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order, save=nt) p = TimeFunction(name='p', grid=model.grid, time_order=2, space_order=space_order) q = TimeFunction(name='q', grid=model.grid, time_order=2, space_order=space_order) H0, H1 = kernel_zhang_fwd(p, q, ang0, ang1, ang2, ang3, epsilon, delta, rho) # Stencils s = model.grid.stepping_dim.spacing stencilp = damp * (2 * p - damp * p.forward + s**2 / m * H0) stencilr = damp * (2 * q - damp * q.forward + s**2 / m * H1) first_stencil = Eq(p.backward, stencilp) second_stencil = Eq(q.backward, stencilr) expression = [first_stencil, second_stencil] # Source symbol with input wavelet src = Receiver(name='src', grid=model.grid, time_range=time_range, npoint=1) src_term = src.inject(field=p.backward, expr=src.dt * s**2 / m) src_term += src.inject(field=q.backward, expr=src.dt * s**2 / m) expression += src_term if fs: expression += freesurface(p, model.nbpml, forward=False) expression += freesurface(q, model.nbpml, forward=False) grad = Function(name="grad", grid=u.grid, space_order=0) expression += [ Inc(grad, rho * f_t * f_h * imaging_condition(model, u, v, p, q, isic=isic)) ] op = Operator(expression, subs=model.spacing_map, dse='aggressive', dle='advanced', name="gradient") return op
def setup_method(self, method): # Some of these tests are memory intensive as it requires to store the entire # forward wavefield to compute the gradient (nx.ny.nz.nt). We therefore call # 'clear_cache()' to release any remaining memory from the previous tests or # previous instances (different parametrizations) of these tests clear_cache()
# Create image symbol and instantiate the previously defined imaging operator image = Function(name='image', grid=model.grid) op_imaging = ImagingOperator(model, image) # Create a wavefield for saving to avoid memory overload u0 = TimeFunction(name='u', grid=model0.grid, time_order=2, space_order=4, save=geometry.nt) for i in range(nshots): # Important: We force previous wavefields to be destroyed, # so that we may reuse the memory. clear_cache() print('Imaging source %d out of %d' % (i + 1, nshots)) # Update source location geometry.src_positions[0, :] = source_locations[i, :] # Generate synthetic data from true model true_d, _, _ = solver.forward(vp=model.vp) # Compute smooth data and full forward wavefield u0 u0.data.fill(0.) smooth_d, _, _ = solver.forward(vp=model0.vp, save=True, u=u0) # Compute gradient from the data residual v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=4)
def adjoint_freq_born(model, rec_coords, rec_data, freq, ufr, ufi, space_order=8, dt=None, isic=False, factor=None, free_surface=False): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp nfreq = ufr.shape[0] time = model.grid.time_dim if factor is None: factor = int(1 / (dt*4*np.max(freq))) tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) if factor==1: tsave = time else: tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) dtf = factor * dt ntf = factor / nt print("DFT subsampling factor: ", factor) # Create the forward and adjoint wavefield v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) f = Function(name='f', dimensions=(ufr.indices[0],), shape=(nfreq,)) f.data[:] = freq[:] gradient = Function(name="gradient", grid=model.grid) vlaplace, rho = acoustic_laplacian(v, rho) # Set up PDE and rearrange stencil = damp * (2.0 * v - damp * v.forward + dt**2 * rho / m * vlaplace) expression = [Eq(v.backward, stencil)] # Data at receiver locations as adjoint source rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec.data[:] = rec_data[:] adj_src = rec.inject(field=v.backward, expr=rec * dt**2 / m) # Gradient update if isic is True: if len(model.shape) == 2: gradient_update = [Eq(gradient, gradient + (2*np.pi*f)**2*ntf*(ufr*cos(2*np.pi*f*tsave*dtf) - ufi*sin(2*np.pi*f*tsave*dtf))*v*model.m - (ufr.dx*cos(2*np.pi*f*tsave*dtf) - ufi.dx*sin(2*np.pi*f*tsave*dtf))*v.dx*ntf - (ufr.dy*cos(2*np.pi*f*tsave*dtf) - ufi.dy*sin(2*np.pi*f*tsave*dtf))*v.dy*ntf)] else: gradient_update = [Eq(gradient, gradient + (2*np.pi*f)**2*ntf*(ufr*cos(2*np.pi*f*tsave*dtf) - ufi*sin(2*np.pi*f*tsave*dtf))*v*model.m - (ufr.dx*cos(2*np.pi*f*tsave*dtf) - ufi.dx*sin(2*np.pi*f*tsave*dtf))*v.dx*ntf - (ufr.dy*cos(2*np.pi*f*tsave*dtf) - ufi.dy*sin(2*np.pi*f*tsave*dtf))*v.dy*ntf - (ufr.dz*cos(2*np.pi*f*tsave*dtf) - ufi.dz*sin(2*np.pi*f*tsave*dtf))*v.dz*ntf)] else: gradient_update = [Eq(gradient, gradient + (2*np.pi*f)**2/nt*(ufr*cos(2*np.pi*f*tsave*dtf) - ufi*sin(2*np.pi*f*tsave*dtf))*v)] # Create operator and run # Free surface if free_surface is True: expression += freesurface(v, space_order//2, model.nbpml, forward=False) expression += adj_src + gradient_update subs = model.spacing_map subs[v.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') cf = op.cfunction op() clear_cache() return gradient.data
def adjoint_modeling(model, src_coords, rec_coords, rec_data, space_order=8, free_surface=False, dt=None): clear_cache() # If wavelet is file, read it if isinstance(rec_data, str): rec_data = np.load(rec_data) # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create the adjoint wavefield if src_coords is not None: v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order) else: v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order, save=nt) # Set up PDE and rearrange vlaplace, rho = acoustic_laplacian(v, rho) # Input data is wavefield full_q = 0 if isinstance(rec_data, TimeFunction): wf_rec = TimeFunction(name='wf_rec', grid=model.grid, time_order=2, space_order=space_order, save=nt) wf_rec._data = rec_data._data full_q = wf_rec stencil = damp * (2.0 * v - damp * v.forward + dt**2 * rho / m * (vlaplace + full_q)) expression = [Eq(v.backward, stencil)] # Free surface if free_surface is True: expression += freesurface(v, space_order // 2, model.nbpml, forward=False) # Adjoint source is injected at receiver locations if rec_coords is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec.data[:] = rec_data[:] adj_src = rec.inject(field=v.backward, expr=rec * rho * dt**2 / m) expression += adj_src # Data is sampled at source locations if src_coords is not None: src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) adj_rec = src.interpolate(expr=v) expression += adj_rec # Create operator and run subs = model.spacing_map subs[v.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') cf = op.cfunction summary = op.apply() if src_coords is None: return v, summary else: return src.data, summary
def twri_fun(self, y, src_coords, rcv_coords, wav, dat, Filter, eps, mode="eval", objfact=np.float32(1), comp_alpha=True, grad_corr=False, weight_fun_pars=None): """ Evaluate TWRI objective functional/gradients for current (m, y) """ clear_cache() dt = self.model.critical_dt # Computing y in reduced mode (= residual) if not provided u0 = None y_was_None = y is None if y_was_None: u0rcv, u0 = self.forward_run(wav, src_coords, rcv_coords, save=(mode == "grad") and grad_corr) y = applyfilt(dat - u0rcv, Filter) PTy = applyfilt_transp(y, Filter) else: PTy = y # Normalization constants nx = np.float32(self.model.vp.size) nt, nr = np.float32(y.shape) etaf = npla.norm(wav.reshape(-1)) / np.sqrt((nt * dt) * nx) etad = npla.norm(applyfilt(dat, Filter).reshape(-1)) / np.sqrt( (nt * dt) * nr) # Compute wavefield vy = adjoint(F(m))*Py norm_vPTy2, vPTy_src, vPTy = self.adjoint_y_run( PTy, src_coords, rcv_coords, weight_fun_pars=weight_fun_pars, save=(mode == "grad")) # <PTy, d-F(m)*f> = <PTy, d>-<adjoint(F(m))*PTy, f> PTy_dot_r = (np.dot(PTy.reshape(-1), dat.reshape(-1)) - np.dot(vPTy_src.reshape(-1), wav.reshape(-1))) # ||y|| norm_y = np.sqrt(dt) * npla.norm(y.reshape(-1)) # Optimal alpha c1 = etaf**np.float32(2) / (np.float32(4) * etad**np.float32(2) * nx * (nt * dt)) c2 = np.float32(1) / (etad * nr * (nt * dt)) c3 = eps / np.sqrt(nr * (nt * dt)) alpha = compute_optalpha(c1 * norm_vPTy2, c2 * PTy_dot_r, c3 * norm_y, comp_alpha=comp_alpha) # Lagrangian evaluation fun = (alpha * (-alpha * c1 * norm_vPTy2 + c2 * PTy_dot_r) - np.abs(alpha) * c3 * norm_y) # Gradient computation if mode == "grad": # Set up extebded source w = 2.0 * c1 / c2 * alpha if weight_fun_pars is not None: w /= weight_fun(weight_fun_pars, self.model, src_coords)**2 Q = wf_as_src(vPTy, w=w) # Setup gradient wrt m rcv, _, gradm = self.forward_run(wav, src_coords, rcv_coords, q=Q, grad=True, w=alpha * c2, v=vPTy) # Compute gradient wrt y if not y_was_None or grad_corr: norm_y = npla.norm(y) grady_data = alpha * c2 * applyfilt(dat - rcv.data, Filter) if norm_y != 0: grady_data -= np.abs(alpha) * c3 * y / norm_y # Correcting for reduced gradient if not y_was_None or (y_was_None and not grad_corr): gradm_data = gradm.data else: gradm_corr = self.grad_run( rcv_coords, applyfilt_transp(grady_data, Filter), u0) # Reduced gradient post-processing gradm_data = gradm.data + gradm_corr.data # Return output if mode == "eval": return fun / objfact elif mode == "grad" and y_was_None: return fun / objfact, -gradm_data / objfact elif mode == "grad" and not y_was_None: return fun / objfact, -gradm_data / objfact, grady_data / objfact
def forward_born(model, src_coords, wavelet, rec_coords, space_order=8, nb=40, isic=False, dt=None): clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, dm, damp = model.m, model.dm, model.damp # Create the forward and linearized wavefield u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order) du = TimeFunction(name="du", grid=model.grid, time_order=2, space_order=space_order) if len(model.shape) == 2: x, y = u.space_dimensions else: x, y, z = u.space_dimensions # Set up PDEs and rearrange eqn = m * u.dt2 - u.laplace + damp * u.dt stencil1 = solve(eqn, u.forward)[0] if isic is not True: eqn_lin = m * du.dt2 - du.laplace + damp * du.dt + dm * u.dt2 # born modeling else: du_aux = sum([ first_derivative( first_derivative(u, dim=d, order=space_order // 2) * dm, order=space_order // 2, dim=d) for d in u.space_dimensions ]) eqn_lin = m * du.dt2 - du.laplace + damp * du.dt + (dm * u.dt2 * m - du_aux) if isic is not True: stencil2 = solve(eqn_lin, du.forward)[0] else: stencil2 = solve(eqn_lin, du.forward, simplify=False, rational=False)[0] expression_u = [Eq(u.forward, stencil1)] expression_du = [Eq(du.forward, stencil2)] # Define source symbol with wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=src * dt**2 / m) # Define receiver symbol rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=du, offset=model.nbpml) # Create operator and run set_log_level('ERROR') expression = expression_u + src_term + expression_du + rec_term op = Operator(expression, subs=model.spacing_map, dse='advanced', dle='advanced', name="Born%s" % randint(1e5)) op(dt=dt) return rec.data
def forward_born(model, src_coords, wavelet, rec_coords, space_order=8, nb=40, isic=False, dt=None): clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, rho, dm, damp = model.m, model.rho, model.dm, model.damp # Create the forward and linearized wavefield u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order) du = TimeFunction(name="du", grid=model.grid, time_order=2, space_order=space_order) if len(model.shape) == 2: x, y = u.space_dimensions else: x, y, z = u.space_dimensions # Set up PDEs and rearrange ulaplace, rho = acoustic_laplacian(u, rho) dulaplace, _ = acoustic_laplacian(du, rho) H = symbols('H') S = symbols('S') eqn = m / rho * u.dt2 - H + damp * u.dt stencil1 = solve(eqn, u.forward, simplify=False, rational=False)[0] eqn_lin = m / rho * du.dt2 - H + damp * du.dt + S if isic: # Sum ((u.dx * d, / rho).dx for x in dimensions) # space_order//2 so that u.dx.dx has the same radius as u.laplace du_aux = sum([ first_derivative( first_derivative(u, dim=d, order=space_order // 2) * dm / rho, order=space_order // 2, dim=d) for d in u.space_dimensions ]) lin_source = dm / rho * u.dt2 * m - du_aux else: lin_source = dm / rho * u.dt2 stencil2 = solve(eqn_lin, du.forward, simplify=False, rational=False)[0] expression_u = [Eq(u.forward, stencil1.subs({H: ulaplace}))] expression_du = [ Eq(du.forward, stencil2.subs({ H: dulaplace, S: lin_source })) ] # Define source symbol with wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=src * rho * dt**2 / m) # Define receiver symbol rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=du, offset=model.nbpml) # Create operator and run set_log_level('ERROR') expression = expression_u + src_term + expression_du + rec_term subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Born%s" % randint(1e5)) op() return rec.data
def forward_modeling(model, src_coords, wavelet, rec_coords, save=False, space_order=8, nb=40, op_return=False, dt=None): clear_cache() # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, damp = model.m, model.damp # Create the forward wavefield if save is False: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) else: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt) # Set up PDE and rearrange eqn = m * u.dt2 - u.laplace + damp * u.dt stencil = solve(eqn, u.forward)[0] expression = [Eq(u.forward, stencil)] # Source symbol with input wavelet src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=src * dt**2 / m) # Data is sampled at receiver locations rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=u, offset=model.nbpml) # Create operator and run set_log_level('ERROR') expression += src_term + rec_term op = Operator(expression, subs=model.spacing_map, dse='advanced', dle='advanced', name="Forward%s" % randint(1e5)) if op_return is False: op(dt=dt) return rec.data, u else: return op
def forward_modeling(model, src_coords, wavelet, rec_coords, save=False, space_order=8, nb=40, free_surface=False, op_return=False, dt=None): clear_cache() # If wavelet is file, read it if isinstance(wavelet, str): wavelet = np.load(wavelet) # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create the forward wavefield if save is False and rec_coords is not None: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) else: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt) # Set up PDE and rearrange ulaplace, rho = acoustic_laplacian(u, rho) H = symbols('H') eqn = m / rho * u.dt2 - H + damp * u.dt # Input source is wavefield if isinstance(wavelet, TimeFunction): wf_src = TimeFunction(name='wf_src', grid=model.grid, time_order=2, space_order=space_order, save=nt) wf_src._data = wavelet._data eqn -= wf_src # Rearrange expression stencil = solve(eqn, u.forward, simplify=False, rational=False)[0] expression = [Eq(u.forward, stencil.subs({H: ulaplace}))] # Free surface if free_surface is True: fs = DefaultDimension(name="fs", default_value=int(space_order / 2)) expression += [ Eq(u.forward.subs({u.indices[-1]: model.nbpml - fs - 1}), -u.forward.subs({u.indices[-1]: model.nbpml + fs + 1})) ] # Source symbol with input wavelet if src_coords is not None: src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=src * rho * dt**2 / m) expression += src_term # Data is sampled at receiver locations if rec_coords is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=u, offset=model.nbpml) expression += rec_term # Create operator and run set_log_level('ERROR') subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Forward%s" % randint(1e5)) if op_return is False: op() if rec_coords is None: return u else: return rec.data, u else: return op
def adjoint_born(model, rec_coords, rec_data, u=None, op_forward=None, is_residual=False, space_order=8, nb=40, isic=False, dt=None): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, damp = model.m, model.damp # Create adjoint wavefield and gradient v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) gradient = Function(name='gradient', grid=model.grid) # Set up PDE and rearrange eqn = m * v.dt2 - v.laplace - damp * v.dt stencil = solve(eqn, v.backward)[0] expression = [Eq(v.backward, stencil)] # Data at receiver locations as adjoint source rec_g = Receiver(name='rec_g', grid=model.grid, ntime=nt, coordinates=rec_coords) if op_forward is None: rec_g.data[:] = rec_data[:] adj_src = rec_g.inject(field=v.backward, offset=model.nbpml, expr=rec_g * dt**2 / m) # Gradient update if u is None: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) if isic is not True: gradient_update = [Eq(gradient, gradient - u * v.dt2) ] # zero-lag cross-correlation imaging condition else: # linearized inverse scattering imaging condition (Op't Root et al. 2010; Whitmore and Crawley 2012) if len(model.shape) == 2: gradient_update = [ Eq(gradient, gradient - (u * v.dt2 * m + u.dx * v.dx + u.dy * v.dy)) ] else: gradient_update = [ Eq( gradient, gradient - (u * v.dt2 * m + u.dx * v.dx + u.dy * v.dy + u.dz * v.dz)) ] # Create operator and run set_log_level('ERROR') expression += adj_src + gradient_update op = Operator(expression, subs=model.spacing_map, dse='advanced', dle='advanced', name="Gradient%s" % randint(1e5)) # Optimal checkpointing if op_forward is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) cp = DevitoCheckpoint([u]) n_checkpoints = None wrap_fw = CheckpointOperator(op_forward, u=u, m=model.m.data, rec=rec, dt=dt) wrap_rev = CheckpointOperator(op, u=u, v=v, m=model.m.data, rec_g=rec_g, dt=dt) # Run forward wrp = Revolver(cp, wrap_fw, wrap_rev, n_checkpoints, nt - 2) wrp.apply_forward() # Residual and gradient if is_residual is True: # input data is already the residual rec_g.data[:] = rec_data[:] else: rec_g.data[:] = rec.data[:] - rec_data[:] # input is observed data fval = .5 * np.linalg.norm(rec_g.data[:])**2 wrp.apply_reverse() else: op(dt=dt) clear_cache() if op_forward is not None and is_residual is not True: return fval, gradient.data else: return gradient.data
def adjoint_freq_born(model, rec_coords, rec_data, freq, ufr, ufi, space_order=8, nb=40, dt=None, isic=False, factor=None): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, damp = model.m, model.damp nfreq = ufr.shape[0] time = model.grid.time_dim if factor is None: factor = int(1 / (dt * 4 * np.max(freq))) tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) if factor == 1: tsave = time else: tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor) dtf = factor * dt ntf = factor / nt print("DFT subsampling factor: ", factor) # Create the forward and adjoint wavefield v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) f = Function(name='f', dimensions=(ufr.indices[0], ), shape=(nfreq, )) f.data[:] = freq[:] gradient = Function(name="gradient", grid=model.grid) # Set up PDE and rearrange eqn = m * v.dt2 - v.laplace - damp * v.dt stencil = solve(eqn, v.backward, simplify=False, rational=False)[0] expression = [Eq(v.backward, stencil)] # Data at receiver locations as adjoint source rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec.data[:] = rec_data[:] adj_src = rec.inject(field=v.backward, offset=model.nbpml, expr=rec * dt**2 / m) # Gradient update if isic is True: if len(model.shape) == 2: gradient_update = [ Eq( gradient, gradient + (2 * np.pi * f)**2 * ntf * (ufr * cos(2 * np.pi * f * tsave * dtf) - ufi * sin(2 * np.pi * f * tsave * dtf)) * v * model.m - (ufr.dx * cos(2 * np.pi * f * tsave * dtf) - ufi.dx * sin(2 * np.pi * f * tsave * dtf)) * v.dx * ntf - (ufr.dy * cos(2 * np.pi * f * tsave * dtf) - ufi.dy * sin(2 * np.pi * f * tsave * dtf)) * v.dy * ntf) ] else: gradient_update = [ Eq( gradient, gradient + (2 * np.pi * f)**2 * ntf * (ufr * cos(2 * np.pi * f * tsave * dtf) - ufi * sin(2 * np.pi * f * tsave * dtf)) * v * model.m - (ufr.dx * cos(2 * np.pi * f * tsave * dtf) - ufi.dx * sin(2 * np.pi * f * tsave * dtf)) * v.dx * ntf - (ufr.dy * cos(2 * np.pi * f * tsave * dtf) - ufi.dy * sin(2 * np.pi * f * tsave * dtf)) * v.dy * ntf - (ufr.dz * cos(2 * np.pi * f * tsave * dtf) - ufi.dz * sin(2 * np.pi * f * tsave * dtf)) * v.dz * ntf) ] else: gradient_update = [ Eq( gradient, gradient + (2 * np.pi * f)**2 / nt * (ufr * cos(2 * np.pi * f * tsave * dtf) - ufi * sin(2 * np.pi * f * tsave * dtf)) * v) ] # Create operator and run set_log_level('ERROR') expression += adj_src + gradient_update subs = model.spacing_map subs[v.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced', name="Gradient%s" % randint(1e5)) op() clear_cache() return gradient.data
def adjoint_freq_born(model, rec_coords, rec_data, freq, ufr, ufi, space_order=8, nb=40, dt=None): clear_cache() # Parameters nt = rec_data.shape[0] if dt is None: dt = model.critical_dt m, damp = model.m, model.damp nfreq = ufr.shape[0] time = model.grid.time_dim # Create the forward and adjoint wavefield v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) f = Function(name='f', dimensions=(ufr.indices[0], ), shape=(nfreq, )) f.data[:] = freq[:] gradient = Function(name="gradient", grid=model.grid) # Set up PDE and rearrange eqn = m * v.dt2 - v.laplace - damp * v.dt stencil = solve(eqn, v.backward)[0] expression = [Eq(v.backward, stencil)] # Data at receiver locations as adjoint source rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec.data[:] = rec_data[:] adj_src = rec.inject(field=v.backward, offset=model.nbpml, expr=rec * dt**2 / m) # Gradient update gradient_update = [ Eq( gradient, gradient + (2 * np.pi * f)**2 / nt * (ufr * cos(2 * np.pi * f * time * dt) - ufi * sin(2 * np.pi * f * time * dt)) * v) ] # Create operator and run set_log_level('ERROR') expression += adj_src + gradient_update op = Operator(expression, subs=model.spacing_map, dse='advanced', dle='advanced', name="Gradient%s" % randint(1e5)) op(dt=dt) clear_cache() return gradient.data
def setup_class(cls): clear_cache()
def setup_method(self, method): clear_cache()
def setup_method(self, method): clear_cache()
def forward_modeling(model, src_coords, wavelet, rec_coords, save=False, space_order=8, nb=40, free_surface=False, op_return=False, u_return=False, dt=None, tsub_factor=1): clear_cache() # If wavelet is file, read it if isinstance(wavelet, str): wavelet = np.load(wavelet) # Parameters nt = wavelet.shape[0] if dt is None: dt = model.critical_dt m, rho, damp = model.m, model.rho, model.damp # Create the forward wavefield if save is False and rec_coords is not None: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) eqsave = [] elif save is True and tsub_factor > 1: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) time_subsampled = ConditionalDimension(name='t_sub', parent=u.grid.time_dim, factor=tsub_factor) nsave = (nt-1)//tsub_factor + 2 usave = TimeFunction(name='us', grid=model.grid, time_order=2, space_order=space_order, time_dim=time_subsampled, save=nsave) eqsave = [Eq(usave.forward, u.forward)] else: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt) eqsave = [] # Set up PDE ulaplace, rho = acoustic_laplacian(u, rho) stencil = damp * ( 2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace) # Input source is wavefield if isinstance(wavelet, TimeFunction): wf_src = TimeFunction(name='wf_src', grid=model.grid, time_order=2, space_order=space_order, save=nt) wf_src._data = wavelet._data stencil -= wf_src # Rearrange expression expression = [Eq(u.forward, stencil)] # Data is sampled at receiver locations if rec_coords is not None: rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) rec_term = rec.interpolate(expr=u) expression += rec_term # Create operator and run if save: expression += eqsave # Free surface kwargs = dict() if free_surface is True: expression += freesurface(u, space_order//2, model.nbpml) # Source symbol with input wavelet if src_coords is not None: src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) src.data[:] = wavelet[:] src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m) expression += src_term # Create operator and run set_log_level('ERROR') subs = model.spacing_map subs[u.grid.time_dim.spacing] = dt op = Operator(expression, subs=subs, dse='advanced', dle='advanced') # Return data and wavefields if op_return is False: op() if save is True and tsub_factor > 1: if rec_coords is None: return usave else: return rec.data, usave else: if rec_coords is None: return u else: return rec.data, u # For optimal checkpointing, return operator only else: return op
def test_fd_space_staggered(self, space_order, stagger): """ This test compares the discrete finite-difference scheme against polynomials For a given order p, the finite difference scheme should be exact for polynomials of order p """ clear_cache() # dummy axis dimension nx = 100 xx = np.linspace(-1, 1, nx) dx = xx[1] - xx[0] # Symbolic data grid = Grid(shape=(nx, ), dtype=np.float32) x = grid.dimensions[0] # Location of the staggered function if stagger == left: off = -.5 side = -x xx2 = xx - off * dx elif stagger == right: off = .5 side = x xx2 = xx[:-1] - off * dx else: off = 0 side = NODE xx2 = xx u = Function(name="u", grid=grid, space_order=space_order, staggered=(side, )) du = Function(name="du", grid=grid, space_order=space_order) # Define polynomial with exact fd coeffs = np.ones((space_order - 1, ), dtype=np.float32) polynome = sum([coeffs[i] * x**i for i in range(0, space_order - 1)]) polyvalues = np.array([polynome.subs(x, xi) for xi in xx2], np.float32) # Fill original data with the polynomial values u.data[:] = polyvalues # True derivative of the polynome Dpolynome = diff(polynome) Dpolyvalues = np.array([Dpolynome.subs(x, xi) for xi in xx], np.float32) # FD derivative, symbolic u_deriv = generic_derivative(u, deriv_order=1, fd_order=space_order, dim=x, stagger=stagger) # Compute numerical FD stencil = Eq(du, u_deriv) op = Operator(stencil, subs={x.spacing: dx}) op.apply() # Check exactness of the numerical derivative except inside space_brd space_border = space_order error = abs(du.data[space_border:-space_border] - Dpolyvalues[space_border:-space_border]) assert np.isclose(np.mean(error), 0., atol=1e-3)
def forward(model, save=False, space_order=12, sub=None, norec=False, fs=False): clear_cache() # Parameters s = model.grid.stepping_dim.spacing nt = 10 time_range = TimeAxis(start=0, num=nt, step=1) m, damp, epsilon, delta, theta, phi, rho = (model.m, model.damp, model.epsilon, model.delta, model.theta, model.phi, model.rho) m = m * rho # Tilt and azymuth setup ang0 = cos(theta) ang1 = sin(theta) ang2 = cos(phi) ang3 = sin(phi) # Create the forward wavefield if sub is not None and (sub[0] > 1 or sub[1] > 1): usave, vsave = subsampled(model, nt, space_order, t_sub=sub[0], space_sub=sub[1]) u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) eq_save = [Eq(usave, u), Eq(vsave, v)] elif save: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt) v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order, save=nt) eq_save = [] else: u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, time_order=2, space_order=space_order) eq_save = [] H0, H1 = kernel_zhang_fwd(u, v, ang0, ang1, ang2, ang3, epsilon, delta, rho) # Stencils s = model.grid.stepping_dim.spacing stencilp = damp * (2 * u - damp * u.backward + s**2 / m * H0) stencilr = damp * (2 * v - damp * v.backward + s**2 / m * H1) first_stencil = Eq(u.forward, stencilp) second_stencil = Eq(v.forward, stencilr) expression = [first_stencil, second_stencil] # Source symbol with input wavelet src = Receiver(name='src', grid=model.grid, time_range=time_range, npoint=1) src_term = src.inject(field=u.forward, expr=src.dt * s**2 / m) src_term += src.inject(field=v.forward, expr=src.dt * s**2 / m) expression += src_term if fs: expression += freesurface(u, model.nbpml) expression += freesurface(v, model.nbpml) if not norec: rec = Receiver(name='rec', grid=model.grid, time_range=time_range, npoint=2) expression += rec.interpolate(expr=u + v) kwargs = {'dse': 'aggressive', 'dle': 'advanced'} op = Operator(expression + eq_save, subs=model.spacing_map, name="forward", **kwargs) return op