def gy(field, model): """ Rotated first derivative in y Parameters ---------- u: TimeFunction or Expr TTI field model: Model Model structure Returns ---------- Expr du/dy in rotated coordinates """ costheta, sintheta, cosphi, sinphi = angles_to_trig(model) dims = field.dimensions[1:model.dim + 1] o1 = field.space_order // 2 Dy = (-sinphi * first_derivative(field, dim=dims[0], side=centered, fd_order=o1) + cosphi * first_derivative(field, dim=dims[1], side=centered, fd_order=o1)) return Dy
def gx(field, model): """ Rotated first derivative in x Parameters ---------- u: TimeFunction or Expr TTI field model: Model Model structure Returns ---------- Expr du/dx in rotated coordinates """ costheta, sintheta, cosphi, sinphi = angles_to_trig(model) dims = field.dimensions[1:model.dim + 1] order1 = field.space_order // 2 Dx = (costheta * cosphi * first_derivative(field, dim=dims[0], side=left, fd_order=order1) - sintheta * first_derivative(field, dim=dims[-1], side=left, fd_order=order1)) if len(dims) == 3: Dx += costheta * sinphi * first_derivative( field, dim=dims[1], side=left, fd_order=order1) return Dx
def gy_T(field, model): """ Rotated first derivative in y Parameters ---------- u: TimeFunction or Expr TTI field model: Model Model structure Returns ---------- Expr du/dy.T in rotated coordinates """ if field == 0: return 0 costheta, sintheta, cosphi, sinphi = angles_to_trig(model) dims = field.dimensions[1:model.dim + 1] order1 = field.space_order // 2 Dy = (first_derivative(-sinphi * field, dim=dims[0], matvec=transpose, side=centered, fd_order=order1) + first_derivative(cosphi * field, dim=dims[1], matvec=transpose, side=centered, fd_order=order1)) return Dy
def forward_born(model, src_coords, wavelet, rec_coords, space_order=8, nb=40, 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) expression = expression_u + expression_du + src_term + 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) # 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') op() return rec.data
def acoustic_laplacian(v, rho): if rho is None: Lap = v.laplace rho = 1 else: if isinstance(rho, Function): Lap = sum([first_derivative(first_derivative(v, fd_order=int(v.space_order/2), side=left, dim=d) / rho, fd_order=int(v.space_order/2), dim=d, side=right) for d in v.space_dimensions]) else: Lap = 1 / rho * v.laplace return Lap, rho
def gz_T(field, model): """ Rotated first derivative in z Parameters ---------- u: TimeFunction or Expr TTI field model: Model Model structure Returns ---------- Expr du/dz.T in rotated coordinates """ if field == 0: return 0 costheta, sintheta, cosphi, sinphi = angles_to_trig(model) dims = field.dimensions[1:model.dim + 1] order1 = field.space_order // 2 Dz = -(first_derivative(sintheta * cosphi * field, dim=dims[0], side=right, fd_order=order1, matvec=transpose) + first_derivative(costheta * field, dim=dims[-1], side=right, fd_order=order1, matvec=transpose)) if len(dims) == 3: Dz += first_derivative(sintheta * sinphi * field, dim=dims[1], side=right, fd_order=order1, matvec=transpose) return Dz
def Gzz2d(field, costheta, sintheta, irho): """ 3D rotated second order derivative in the direction z Parameters ---------- field: symbolic data whose derivative we are computing costheta: cosine of the tilt angle sintheta: sine of the tilt angle cosphi: cosine of the azymuth angle sinphi: sine of the azymuth angle space_order: discretization order Returns ------- rotated second order derivative wrt ztranspose """ if sintheta == 0: return getattr(field, 'd%s2' % field.grid.dimensions[-1]) order1 = field.space_order // 2 x, z = field.grid.dimensions Gz = -(sintheta * first_derivative( field, dim=x, side=centered, fd_order=order1) + costheta * first_derivative(field, dim=z, side=centered, fd_order=order1)) Gzz = (first_derivative(Gz * sintheta * irho, dim=x, side=centered, fd_order=order1, matvec=transpose) + first_derivative(Gz * costheta * irho, dim=z, side=centered, fd_order=order1, matvec=transpose)) return Gzz
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_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_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 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