def test_forward(): tn = 1000. shape = (101, 101) nbl = 40 model = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) model0 = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) gaussian_smooth(model0.vp, sigma=(1, 1)) geometry0 = setup_geometry(model0, tn) geometry = setup_geometry(model, tn) # Pure Devito solver = AcousticWaveSolver(model, geometry, space_order=8) solver0 = AcousticWaveSolver(model0, geometry0, space_order=8) d = solver.forward()[0] d0, u0 = solver0.forward(save=True, vp=model0.vp)[:2] residual = d.data - d0.data rec = geometry0.rec rec.data[:] = -residual[:] grad_devito = solver0.jacobian_adjoint(rec, u0)[0].data grad_devito = np.array(grad_devito)[nbl:-nbl, nbl:-nbl] # Devito4PyTorch d = torch.from_numpy(np.array(d.data)).to(device) forward_modeling = ForwardModelingLayer(model0, geometry0, device) m0 = np.array(model0.vp.data**(-2))[nbl:-nbl, nbl:-nbl] m0 = torch.Tensor(m0).unsqueeze(0).unsqueeze(0).to(device) m0.requires_grad = True loss = 0.5 * torch.norm(forward_modeling(m0) - d)**2 grad = torch.autograd.grad(loss, m0, create_graph=False)[0] # Test rel_err = np.linalg.norm(grad.cpu().numpy() - grad_devito) / np.linalg.norm(grad_devito) assert np.isclose(rel_err, 0., atol=1.e-6)
def test_forward_born(): tn = 1000. shape = (101, 101) nbl = 40 model = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) model0 = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) gaussian_smooth(model0.vp, sigma=(1, 1)) geometry0 = setup_geometry(model0, tn) geometry = setup_geometry(model, tn) # Pure Devito solver = AcousticWaveSolver(model, geometry, space_order=8) solver0 = AcousticWaveSolver(model0, geometry0, space_order=8) d = solver.forward(vp=model.vp)[0] d0, u0 = solver0.forward(save=True, vp=model0.vp)[:2] d_lin = d.data - d0.data rec = geometry0.rec rec.data[:] = -d_lin[:] grad_devito = solver0.jacobian_adjoint(rec, u0)[0].data grad_devito = np.array(grad_devito)[nbl:-nbl, nbl:-nbl] # Devito4PyTorch d_lin = torch.from_numpy(np.array(d_lin)).to(device) forward_born = ForwardBornLayer(model0, geometry0, device) dm_est = torch.zeros([1, 1, shape[0], shape[1]], requires_grad=True, device=device) loss = 0.5 * torch.norm(forward_born(dm_est) - d_lin)**2 grad = torch.autograd.grad(loss, dm_est, create_graph=False)[0] # Test rel_err = np.linalg.norm(grad.cpu().numpy() - grad_devito) / np.linalg.norm(grad_devito) assert np.isclose(rel_err, 0., atol=1.e-6)
def test_acousticJ(shape, space_order): t0 = 0.0 # Start time tn = 500. # Final time nrec = shape[0] # Number of receivers nbpml = 10 + space_order / 2 spacing = [15. for _ in shape] # Create two-layer "true" model from preset with a fault 1/3 way down model = demo_model('layers-isotropic', ratio=3, vp_top=1.5, vp_bottom=2.5, spacing=spacing, space_order=space_order, shape=shape, nbpml=nbpml, dtype=np.float64) # Derive timestepping from model spacing dt = model.critical_dt time_range = TimeAxis(start=t0, stop=tn, step=dt) # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = 30. # Define receiver geometry (same as source, but spread across x) rec = Receiver(name='nrec', grid=model.grid, time_range=time_range, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, source=src, receiver=rec, kernel='OT2', space_order=space_order) # Create initial model (m0) with a constant velocity throughout model0 = demo_model('layers-isotropic', ratio=3, vp_top=1.5, vp_bottom=1.5, spacing=spacing, space_order=space_order, shape=shape, nbpml=nbpml, dtype=np.float64) # Compute the full wavefield u0 _, u0, _ = solver.forward(save=True, m=model0.m) # Compute initial born perturbation from m - m0 dm = model.m.data - model0.m.data du, _, _, _ = solver.born(dm, m=model0.m) # Compute gradientfrom initial perturbation im, _ = solver.gradient(du, u0, m=model0.m) # Adjoint test: Verify <Ax,y> matches <x, A^Ty> closely term1 = np.dot(im.data.reshape(-1), dm.reshape(-1)) term2 = linalg.norm(du.data)**2 info('<Ax,y>: %f, <x, A^Ty>: %f, difference: %12.12f, ratio: %f' % (term1, term2, term1 - term2, term1 / term2)) assert np.isclose(term1 / term2, 1.0, atol=0.001)
def acoustic_setup(shape=(50, 50, 50), spacing=(15.0, 15.0, 15.0), tn=500., time_order=2, space_order=4, nbpml=10, constant=False, **kwargs): nrec = shape[0] preset = 'constant-isotropic' if constant else 'layers-isotropic' model = demo_model(preset, shape=shape, spacing=spacing, nbpml=nbpml) # Derive timestepping from model spacing dt = model.critical_dt * (1.73 if time_order == 4 else 1.0) t0 = 0.0 nt = int(1 + (tn-t0) / dt) # Number of timesteps time = np.linspace(t0, tn, nt) # Discretized time axis # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time=time) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = model.origin[-1] + 2 * spacing[-1] # Define receiver geometry (spread across x, just below surface) rec = Receiver(name='nrec', grid=model.grid, ntime=nt, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, source=src, receiver=rec, time_order=time_order, space_order=space_order, **kwargs) return solver
def tti_setup(shape=(50, 50, 50), spacing=(20.0, 20.0, 20.0), tn=250.0, kernel='centered', space_order=4, nbl=10, preset='layers-tti', **kwargs): # Two layer model for true velocity model = demo_model(preset, shape=shape, spacing=spacing, space_order=space_order, nbl=nbl, **kwargs) # Source and receiver geometries geometry = setup_geometry(model, tn) return AnisotropicWaveSolver(model, geometry, space_order=space_order, kernel=kernel, **kwargs)
def acoustic_setup(shape=(50, 50, 50), spacing=(15.0, 15.0, 15.0), tn=500., kernel='OT2', space_order=4, nbpml=10, preset='layers-isotropic', **kwargs): nrec = kwargs.pop('nrec', shape[0]) model = demo_model(preset, space_order=space_order, shape=shape, nbpml=nbpml, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, geometry, kernel=kernel, space_order=space_order, **kwargs) return solver
def _setup_model_and_acquisition(self, shape, spacing, nbpml, tn): nrec = shape[0] model = demo_model('layers-isotropic', shape=shape, spacing=spacing, nbpml=nbpml) self.model = model t0 = 0.0 self.nt = int(1 + (tn-t0) / self.dt) # Number of timesteps time = np.linspace(t0, tn, self.nt) # Discretized time axis # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time=time) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = model.origin[-1] + 2 * spacing[-1] self.src = src # Define receiver geometry (spread across x, just below surface) # We need two receiver fields - one for the true (verification) run rec_t = Receiver(name='rec_t', grid=model.grid, ntime=self.nt, npoint=nrec) rec_t.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec_t.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] self.rec_t = rec_t # and the other for the smoothed run self.rec = Receiver(name='rec', grid=model.grid, ntime=self.nt, npoint=nrec, coordinates=rec_t.coordinates.data) # Receiver for Gradient self.rec_g = Receiver(name="rec_g", coordinates=self.rec.coordinates.data, grid=model.grid, dt=self.dt, ntime=self.nt) # Gradient symbol self.grad = Function(name="grad", grid=model.grid)
def viscoelastic_setup(shape=(50, 50), spacing=(15.0, 15.0), tn=500., space_order=4, nbl=10, constant=True, **kwargs): preset = 'constant-viscoelastic' if constant else 'layers-viscoelastic' model = demo_model(preset, space_order=space_order, shape=shape, nbl=nbl, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Source and receiver geometries geometry = setup_geometry(model, tn) # Create solver object to provide relevant operators solver = ViscoelasticWaveSolver(model, geometry, space_order=space_order, **kwargs) return solver
def test_geometry(): shape = (50, 50, 50) spacing = [10. for _ in shape] nbpml = 10 nrec = 10 tn = 150. # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=1., vp_bottom=2., spacing=spacing, shape=shape, nbpml=nbpml) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) pkl_geom = pickle.dumps(geometry) new_geom = pickle.loads(pkl_geom) assert np.all(new_geom.src_positions == geometry.src_positions) assert np.all(new_geom.rec_positions == geometry.rec_positions) assert new_geom.f0 == geometry.f0 assert np.all(new_geom.src_type == geometry.src_type) assert np.all(new_geom.src.data == geometry.src.data) assert new_geom.t0 == geometry.t0 assert new_geom.tn == geometry.tn
def tti_operator(dse=False, dle='advanced', space_order=4): nrec = 101 t0 = 0.0 tn = 250. nbpml = 10 shape = (50, 50, 50) spacing = (20., 20., 20.) # Two layer model for true velocity model = demo_model('layers-tti', ratio=3, nbpml=nbpml, space_order=space_order, shape=shape, spacing=spacing) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec_coordinates[:, 1:] = src_coordinates[0, 1:] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=t0, tn=tn, src_type='Gabor', f0=0.010) return AnisotropicWaveSolver(model, geometry, space_order=space_order, dse=dse)
def viscoelastic_setup(shape=(50, 50), spacing=(15.0, 15.0), tn=500., space_order=4, nbl=10, constant=True, **kwargs): nrec = 2*shape[0] preset = 'constant-viscoelastic' if constant else 'layers-viscoelastic' model = demo_model(preset, space_order=space_order, shape=shape, nbl=nbl, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.12) # Create solver object to provide relevant operators solver = ViscoelasticWaveSolver(model, geometry, space_order=space_order, **kwargs) return solver
def viscoacoustic_setup(shape=(50, 50), spacing=(15.0, 15.0), tn=500., space_order=4, nbl=40, preset='layers-viscoacoustic', kernel='sls', time_order=2, **kwargs): model = demo_model(preset, space_order=space_order, shape=shape, nbl=nbl, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Source and receiver geometries geometry = setup_geometry(model, tn) # Create solver object to provide relevant operators solver = ViscoacousticWaveSolver(model, geometry, space_order=space_order, kernel=kernel, time_order=time_order, **kwargs) return solver
def acoustic_setup(shape=(50, 50, 50), spacing=(15.0, 15.0, 15.0), tn=500., kernel='OT2', space_order=4, nbl=10, preset='layers-isotropic', fs=False, **kwargs): model = demo_model(preset, space_order=space_order, shape=shape, nbl=nbl, dtype=kwargs.pop('dtype', np.float32), spacing=spacing, fs=fs, **kwargs) # Source and receiver geometries geometry = setup_geometry(model, tn) # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, geometry, kernel=kernel, space_order=space_order, **kwargs) return solver
def test_geometry(): shape = (50, 50, 50) spacing = [10. for _ in shape] nbl = 10 nrec = 10 tn = 150. # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=1., vp_bottom=2., spacing=spacing, shape=shape, nbl=nbl) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) pkl_geom = pickle.dumps(geometry) new_geom = pickle.loads(pkl_geom) assert np.all(new_geom.src_positions == geometry.src_positions) assert np.all(new_geom.rec_positions == geometry.rec_positions) assert new_geom.f0 == geometry.f0 assert np.all(new_geom.src_type == geometry.src_type) assert np.all(new_geom.src.data == geometry.src.data) assert new_geom.t0 == geometry.t0 assert new_geom.tn == geometry.tn
def tti_operator(dse=False, space_order=4): nrec = 101 t0 = 0.0 tn = 250. nbpml = 10 shape = (50, 50, 50) spacing = (20., 20., 20.) # Two layer model for true velocity model = demo_model('layers-tti', ratio=3, nbpml=nbpml, space_order=space_order, shape=shape, spacing=spacing) # Derive timestepping from model spacing # Derive timestepping from model spacing dt = model.critical_dt time_range = TimeAxis(start=t0, stop=tn, step=dt) # Define source geometry (center of domain, just below surface) src = GaborSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = model.origin[-1] + 2 * spacing[-1] # Define receiver geometry (spread across x, lust below surface) rec = Receiver(name='nrec', grid=model.grid, time_range=time_range, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] return AnisotropicWaveSolver(model, source=src, receiver=rec, space_order=space_order, dse=dse)
def elastic_setup(shape=(50, 50), spacing=(15.0, 15.0), tn=500., space_order=4, nbpml=10, constant=False, **kwargs): nrec = 2*shape[0] preset = 'constant-elastic' if constant else 'layers-elastic' model = demo_model(preset, space_order=space_order, shape=shape, nbpml=nbpml, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) # Create solver object to provide relevant operators solver = ElasticWaveSolver(model, geometry, space_order=space_order, **kwargs) return solver
def run_acoustic_forward(dse=None): shape = (50, 50, 50) spacing = (10., 10., 10.) nbpml = 10 nrec = 101 t0 = 0.0 tn = 250.0 # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=3., vp_bottom=4.5, spacing=spacing, shape=shape, nbpml=nbpml) # Derive timestepping from model spacing dt = model.critical_dt time_range = TimeAxis(start=t0, stop=tn, step=dt) # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = 20. # Define receiver geometry (same as source, but spread across x) rec = Receiver(name='nrec', grid=model.grid, time_range=time_range, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] solver = AcousticWaveSolver(model, source=src, receiver=rec, dse=dse, dle='basic') rec, u, _ = solver.forward(save=False) return u, rec
def run_acoustic_forward(dse=None): shape = (50, 50, 50) spacing = (10., 10., 10.) nbpml = 10 nrec = 101 t0 = 0.0 tn = 250.0 # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=3., vp_bottom=4.5, spacing=spacing, shape=shape, nbpml=nbpml) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec_coordinates[:, 1:] = src_coordinates[0, 1:] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=t0, tn=tn, src_type='Ricker', f0=0.010) solver = AcousticWaveSolver(model, geometry, dse=dse, dle='noop') rec, u, _ = solver.forward(save=False) return u, rec
def tti_setup(shape=(50, 50, 50), spacing=(20.0, 20.0, 20.0), tn=250.0, space_order=4, nbl=10, preset='layers-tti', **kwargs): nrec = 101 # Two layer model for true velocity model = demo_model(preset, shape=shape, spacing=spacing, nbl=nbl) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) return AnisotropicWaveSolver(model, geometry, space_order=space_order, **kwargs)
def acoustic_setup(shape=(50, 50, 50), spacing=(15.0, 15.0, 15.0), tn=500., kernel='OT2', space_order=4, nbpml=10, constant=False, **kwargs): nrec = shape[0] preset = 'constant-isotropic' if constant else 'layers-isotropic' model = demo_model(preset, space_order=space_order, shape=shape, nbpml=nbpml, dtype=kwargs.pop('dtype', np.float32), spacing=spacing) # Derive timestepping from model spacing dt = model.critical_dt * (1.73 if kernel == 'OT4' else 1.0) t0 = 0.0 time_range = TimeAxis(start=t0, stop=tn, step=dt) # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src.coordinates.data[0, -1] = model.origin[-1] + 2 * spacing[-1] # Define receiver geometry (spread across x, just below surface) rec = Receiver(name='rec', grid=model.grid, time_range=time_range, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, source=src, receiver=rec, kernel=kernel, space_order=space_order, **kwargs) return solver
def tti_setup(shape=(50, 50, 50), spacing=(20.0, 20.0, 20.0), tn=250.0, time_order=2, space_order=4, nbpml=10, **kwargs): nrec = 101 # Two layer model for true velocity model = demo_model('layers-tti', shape=shape, spacing=spacing, nbpml=nbpml) # Derive timestepping from model spacing dt = model.critical_dt t0 = 0.0 nt = int(1 + (tn - t0) / dt) time = np.linspace(t0, tn, nt) # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.015, time=time) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = model.origin[-1] + 2 * spacing[-1] # Define receiver geometry (spread across x, lust below surface) rec = Receiver(name='nrec', grid=model.grid, ntime=nt, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] return AnisotropicWaveSolver(model, source=src, receiver=rec, time_order=time_order, space_order=space_order, **kwargs)
def create_model(grid=None): return demo_model('twolayer-isotropic', origin=(0., 0.), shape=(101, 101), spacing=(10., 10.), nbpml=20, grid=grid, ratio=2)
def create_model(grid=None): return demo_model('layers-isotropic', origin=(0., 0.), shape=(101, 101), spacing=(10., 10.), nbl=20, grid=grid, nlayers=2)
def test_adjoint_born(): tn = 1000. shape = (101, 101) nbl = 40 model = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) model0 = demo_model('layers-isotropic', origin=(0., 0.), shape=shape, spacing=(10., 10.), nbl=nbl, nlayers=2, space_order=8) gaussian_smooth(model0.vp, sigma=(1, 1)) geometry0 = setup_geometry(model0, tn) # Pure Devito solver0 = AcousticWaveSolver(model0, geometry0, space_order=8) dm = model.vp.data**(-2) - model0.vp.data**(-2) grad_devito = np.array(solver0.jacobian(dm)[0].data) # Devito4PyTorch dm = torch.from_numpy(np.array(dm[nbl:-nbl, nbl:-nbl])).to(device) d_est = torch.zeros(geometry0.rec.data.shape, requires_grad=True, device=device) adjoint_born = AdjointBornLayer(model0, geometry0, device) loss = 0.5 * torch.norm(adjoint_born(d_est) - dm)**2 # Negative gradient to be compared with linearized data computed above grad = -torch.autograd.grad(loss, d_est, create_graph=False)[0] # Test rel_err = np.linalg.norm(grad.cpu().numpy() - grad_devito) / np.linalg.norm(grad_devito) assert np.isclose(rel_err, 0., atol=1.e-6)
def model(self): shape = (60, 70, 80) nbpml = 10 return demo_model(spacing=[15, 15, 15], shape=shape, nbpml=nbpml, preset='layers-isotropic', ratio=3)
def model(self, space_order, shape, nbpml, dtype): return demo_model(spacing=[15., 15., 15.], dtype=dtype, space_order=space_order, shape=shape, nbpml=nbpml, preset='layers-isotropic', ratio=3)
def model(self): return demo_model(spacing=[15., 15., 15.], dtype=self.dtype, space_order=self.space_order, shape=self.shape, nbl=self.nbl, preset='layers-isotropic', ratio=3)
def test_acoustic(mkey, shape, kernel, space_order, nbpml): t0 = 0.0 # Start time tn = 500. # Final time nrec = 130 # Number of receivers # Create model from preset model = demo_model(spacing=[15. for _ in shape], dtype=np.float64, space_order=space_order, shape=shape, nbpml=nbpml, **(presets[mkey])) # Derive timestepping from model spacing dt = model.critical_dt * (1.73 if kernel == 'OT4' else 1.0) time_range = TimeAxis(start=t0, stop=tn, step=dt) # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = 30. # Define receiver geometry (same as source, but spread across x) rec = Receiver(name='rec', grid=model.grid, time_range=time_range, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, source=src, receiver=rec, kernel=kernel, space_order=space_order) # Create adjoint receiver symbol srca = Receiver(name='srca', grid=model.grid, time_range=solver.source.time_range, coordinates=solver.source.coordinates.data) # Run forward and adjoint operators rec, _, _ = solver.forward(save=False) solver.adjoint(rec=rec, srca=srca) # Adjoint test: Verify <Ax,y> matches <x, A^Ty> closely term1 = np.dot(srca.data.reshape(-1), solver.source.data) term2 = linalg.norm(rec.data)**2 info('<Ax,y>: %f, <x, A^Ty>: %f, difference: %12.12f, ratio: %f' % (term1, term2, (term1 - term2) / term1, term1 / term2)) assert np.isclose((term1 - term2) / term1, 0., rtol=1.e-10)
def test_position(shape): t0 = 0.0 # Start time tn = 500. # Final time nrec = 130 # Number of receivers # Create model from preset model = demo_model('constant-isotropic', spacing=[15. for _ in shape], shape=shape, nbpml=10) # Derive timestepping from model spacing dt = model.critical_dt nt = int(1 + (tn - t0) / dt) # Number of timesteps time_values = np.linspace(t0, tn, nt) # Discretized time axis # Define source geometry (center of domain, just below surface) src = RickerSource(name='src', grid=model.grid, f0=0.01, time=time_values) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = 30. # Define receiver geometry (same as source, but spread across x) rec = Receiver(name='nrec', grid=model.grid, ntime=nt, npoint=nrec) rec.coordinates.data[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, source=src, receiver=rec, time_order=2, space_order=4) rec, u, _ = solver.forward(save=False) # Define source geometry (center of domain, just below surface) with 100. origin src = RickerSource(name='src', grid=model.grid, f0=0.01, time=time_values) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 + 100. src.coordinates.data[0, -1] = 130. # Define receiver geometry (same as source, but spread across x) rec2 = Receiver(name='rec2', grid=model.grid, ntime=nt, npoint=nrec) rec2.coordinates.data[:, 0] = np.linspace(100., 100. + model.domain_size[0], num=nrec) rec2.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] rec1, u1, _ = solver.forward(save=False, src=src, rec=rec2, o_x=100., o_y=100., o_z=100.) assert (np.allclose(rec.data, rec1.data, atol=1e-5))
def model(self): # TTI layered model for the tti test, no need for a smooth interace bewtween # the two layer as the dse/compiler is tested not the physical prettiness # of the result, saves testing time return demo_model('layers-tti', nlayers=3, nbl=10, space_order=4, shape=(50, 50, 50), spacing=(20., 20., 20.), smooth=False)
def test_resample(): shape = (50, 50, 50) spacing = (10., 10., 10.) nbl = 10 f0 = 0.01 t0 = 0.0 tn = 500 # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=1., vp_bottom=2., spacing=spacing, shape=shape, nbl=nbl) time_range = TimeAxis(start=t0, stop=tn, step=model.critical_dt) src_a = RickerSource(name='src_a', grid=model.grid, f0=f0, time_range=time_range) time_range_f = TimeAxis(start=t0, step=time_range.step / (10 * np.sqrt(2)), stop=time_range.stop) src_b = RickerSource(name='src_b', grid=model.grid, f0=f0, time_range=time_range_f) # Test resampling specifying dt. src_c = src_b.resample(dt=src_a._time_range.step) end = min(src_a.data.shape[0], src_c.data.shape[0]) assert np.allclose(src_a.data[:end], src_c.data[:end]) assert np.allclose(src_a.data[:end], src_c.data[:end]) # Text resampling based on num src_d = RickerSource(name='src_d', grid=model.grid, f0=f0, time_range=TimeAxis(start=time_range_f.start, stop=time_range_f.stop, num=src_a._time_range.num)) src_e = src_b.resample(num=src_d._time_range.num) assert np.isclose(src_d._time_range.step, src_e._time_range.step) assert np.isclose(src_d._time_range.stop, src_e._time_range.stop) assert src_d._time_range.num == src_e._time_range.num assert np.allclose(src_d.data, src_e.data) assert np.allclose(src_d.data, src_e.data)
def test_adjoint_J(self, mkey, shape, kernel, space_order, setup_func): """ Adjoint test for the FWI Jacobian operator. The Jacobian operator J generates a linearized shot record (measurements) from a model perturbation dm while the adjoint of J generates the FWI gradient from an adjoint source (usually data residual). This test uses the conventional dot test: < Jx, y> = <x ,J^T y> """ tn = 500. # Final time nbl = 10 + space_order / 2 spacing = tuple([10.] * len(shape)) # Create solver from preset solver = setup_func(shape=shape, spacing=spacing, vp_bottom=2, kernel=kernel, nbl=nbl, tn=tn, space_order=space_order, **(presets[mkey]), dtype=np.float64) # Create initial model (m0) with a constant velocity throughout model0 = demo_model(**(presets[mkey]), vp_top=1.5, vp_bottom=1.5, spacing=spacing, space_order=space_order, shape=shape, nbl=nbl, dtype=np.float64, grid=solver.model.grid) # Compute initial born perturbation from m - m0 dm = (solver.model.vp.data**(-2) - model0.vp.data**(-2)) du = solver.jacobian(dm, model=model0)[0] # Compute the full bg field(s) & gradient from initial perturbation if setup_func is tti_setup: u0, v0 = solver.forward(save=True, model=model0)[1:-1] im, _ = solver.jacobian_adjoint(du, u0, v0, model=model0) else: u0 = solver.forward(save=True, model=model0)[1] im, _ = solver.jacobian_adjoint(du, u0, model=model0) # Adjoint test: Verify <Ax,y> matches <x, A^Ty> closely term1 = np.dot(im.data.reshape(-1), dm.reshape(-1)) term2 = norm(du)**2 info('<x, J^Ty>: %f, <Jx,y>: %f, difference: %4.4e, ratio: %f' % (term1, term2, (term1 - term2) / term1, term1 / term2)) assert np.isclose((term1 - term2) / term1, 0., atol=1.e-12)
def test_position(shape): t0 = 0.0 # Start time tn = 500. # Final time nrec = 130 # Number of receivers # Create model from preset model = demo_model('constant-isotropic', spacing=[15. for _ in shape], shape=shape, nbpml=10) # Derive timestepping from model spacing dt = model.critical_dt time_range = TimeAxis(start=t0, stop=tn, step=dt) # Source and receiver geometries src_coordinates = np.empty((1, len(shape))) src_coordinates[0, :] = np.array(model.domain_size) * .5 src_coordinates[0, -1] = 30. rec_coordinates = np.empty((nrec, len(shape))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) rec_coordinates[:, 1:] = src_coordinates[0, 1:] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=t0, tn=tn, src_type='Ricker', f0=0.010) # Create solver object to provide relevant operators solver = AcousticWaveSolver(model, geometry, time_order=2, space_order=4) rec, u, _ = solver.forward(save=False) # Define source geometry (center of domain, just below surface) with 100. origin src = RickerSource(name='src', grid=model.grid, f0=0.01, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 + 100. src.coordinates.data[0, -1] = 130. # Define receiver geometry (same as source, but spread across x) rec2 = Receiver(name='rec', grid=model.grid, time_range=time_range, npoint=nrec) rec2.coordinates.data[:, 0] = np.linspace(100., 100. + model.domain_size[0], num=nrec) rec2.coordinates.data[:, 1:] = src.coordinates.data[0, 1:] ox_g, oy_g, oz_g = tuple(o.dtype(o.data+100.) for o in model.grid.origin) rec1, u1, _ = solver.forward(save=False, src=src, rec=rec2, o_x=ox_g, o_y=oy_g, o_z=oz_g) assert(np.allclose(rec.data, rec1.data, atol=1e-5))
def test_resample(): shape = (50, 50, 50) spacing = (10., 10., 10.) nbpml = 10 f0 = 0.01 t0 = 0.0 tn = 500 # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=1., vp_bottom=2., spacing=spacing, shape=shape, nbpml=nbpml) time_range = TimeAxis(start=t0, stop=tn, step=model.critical_dt) src_a = RickerSource(name='src_a', grid=model.grid, f0=f0, time_range=time_range) time_range_f = TimeAxis(start=t0, step=time_range.step/(10*np.sqrt(2)), stop=time_range.stop) src_b = RickerSource(name='src_b', grid=model.grid, f0=f0, time_range=time_range_f) # Test resampling specifying dt. src_c = src_b.resample(dt=src_a._time_range.step) end = min(src_a.data.shape[0], src_c.data.shape[0]) assert np.allclose(src_a.data[:end], src_c.data[:end]) assert np.allclose(src_a.data[:end], src_c.data[:end]) # Text resampling based on num src_d = RickerSource(name='src_d', grid=model.grid, f0=f0, time_range=TimeAxis(start=time_range_f.start, stop=time_range_f.stop, num=src_a._time_range.num)) src_e = src_b.resample(num=src_d._time_range.num) assert np.isclose(src_d._time_range.step, src_e._time_range.step) assert np.isclose(src_d._time_range.stop, src_e._time_range.stop) assert src_d._time_range.num == src_e._time_range.num assert np.allclose(src_d.data, src_e.data) assert np.allclose(src_d.data, src_e.data)
def test_adjoint_J(self, shape, space_order): """ Adjoint test for the FWI Jacobian operator. The Jacobian operator J generates a linearized shot record (measurements) from a model perturbation dm while the adjoint of J generates the FWI gradient from an adjoint source (usually data residual). This test uses the conventional dot test: < Jx, y> = <x ,J^T y> """ tn = 500. # Final time nbpml = 10 + space_order / 2 spacing = tuple([10.]*len(shape)) # Create solver from preset solver = acoustic_setup(shape=shape, spacing=spacing, nbpml=nbpml, tn=tn, space_order=space_order, preset='layers-isotropic', dtype=np.float64) # Create initial model (m0) with a constant velocity throughout model0 = demo_model('layers-isotropic', ratio=3, vp_top=1.5, vp_bottom=1.5, spacing=spacing, space_order=space_order, shape=shape, nbpml=nbpml, dtype=np.float64, grid=solver.model.grid) # Compute the full wavefield u0 _, u0, _ = solver.forward(save=True, m=model0.m) # Compute initial born perturbation from m - m0 dm = (solver.model.m.data - model0.m.data) du, _, _, _ = solver.born(dm, m=model0.m) # Compute gradientfrom initial perturbation im, _ = solver.gradient(du, u0, m=model0.m) # Adjoint test: Verify <Ax,y> matches <x, A^Ty> closely term1 = np.dot(im.data.reshape(-1), dm.reshape(-1)) term2 = linalg.norm(du.data.reshape(-1))**2 info('<Jx,y>: %f, <x, J^Ty>: %f, difference: %4.4e, ratio: %f' % (term1, term2, (term1 - term2)/term1, term1 / term2)) assert np.isclose((term1 - term2)/term1, 0., rtol=1.e-10)
def tti_setup(shape=(50, 50, 50), spacing=(20.0, 20.0, 20.0), tn=250.0, space_order=4, nbpml=10, preset='layers-tti', **kwargs): nrec = 101 # Two layer model for true velocity model = demo_model(preset, shape=shape, spacing=spacing, nbpml=nbpml) # Source and receiver geometries src_coordinates = np.empty((1, len(spacing))) src_coordinates[0, :] = np.array(model.domain_size) * .5 if len(shape) > 1: src_coordinates[0, -1] = model.origin[-1] + 2 * spacing[-1] rec_coordinates = np.empty((nrec, len(spacing))) rec_coordinates[:, 0] = np.linspace(0., model.domain_size[0], num=nrec) if len(shape) > 1: rec_coordinates[:, 1] = np.array(model.domain_size)[1] * .5 rec_coordinates[:, -1] = model.origin[-1] + 2 * spacing[-1] geometry = AcquisitionGeometry(model, rec_coordinates, src_coordinates, t0=0.0, tn=tn, src_type='Ricker', f0=0.010) return AnisotropicWaveSolver(model, geometry, space_order=space_order, **kwargs)
def test_full_model(): shape = (50, 50, 50) spacing = [10. for _ in shape] nbpml = 10 # Create two-layer model from preset model = demo_model(preset='layers-isotropic', vp_top=1., vp_bottom=2., spacing=spacing, shape=shape, nbpml=nbpml) # Test Model pickling pkl_model = pickle.dumps(model) new_model = pickle.loads(pkl_model) assert np.isclose(np.linalg.norm(model.vp-new_model.vp), 0) f0 = .010 dt = model.critical_dt t0 = 0.0 tn = 350.0 time_range = TimeAxis(start=t0, stop=tn, step=dt) # Test TimeAxis pickling pkl_time_range = pickle.dumps(time_range) new_time_range = pickle.loads(pkl_time_range) assert np.isclose(np.linalg.norm(time_range.time_values), np.linalg.norm(new_time_range.time_values)) # Test Class Constant pickling pkl_origin = pickle.dumps(model.grid.origin) new_origin = pickle.loads(pkl_origin) for a, b in zip(model.grid.origin, new_origin): assert a.compare(b) == 0 # Test Class TimeDimension pickling time_dim = TimeDimension(name='time', spacing=Constant(name='dt', dtype=np.float32)) pkl_time_dim = pickle.dumps(time_dim) new_time_dim = pickle.loads(pkl_time_dim) assert time_dim.spacing._value == new_time_dim.spacing._value # Test Class SteppingDimension stepping_dim = SteppingDimension(name='t', parent=time_dim) pkl_stepping_dim = pickle.dumps(stepping_dim) new_stepping_dim = pickle.loads(pkl_stepping_dim) assert stepping_dim.is_Time == new_stepping_dim.is_Time # Test Grid pickling pkl_grid = pickle.dumps(model.grid) new_grid = pickle.loads(pkl_grid) assert model.grid.shape == new_grid.shape assert model.grid.extent == new_grid.extent assert model.grid.shape == new_grid.shape for a, b in zip(model.grid.dimensions, new_grid.dimensions): assert a.compare(b) == 0 ricker = RickerSource(name='src', grid=model.grid, f0=f0, time_range=time_range) pkl_ricker = pickle.dumps(ricker) new_ricker = pickle.loads(pkl_ricker) assert np.isclose(np.linalg.norm(ricker.data), np.linalg.norm(new_ricker.data))
def model(self): return demo_model(spacing=[15., 15., 15.], dtype=self.dtype, space_order=self.space_order, shape=self.shape, nbpml=self.nbpml, preset='layers-isotropic', ratio=3)