def grad_fwi(model, recin, rec_coords, u, space_order=8, free_surface=False): """ FWI gradient, i.e adjoint Jacobian on a data residual. Parameters ---------- model: Model Physical model recin: Array Data residual rec_coords: Array Receivers coordinates u: TimeFunction Forward wavefield space_order: Int (optional) Spatial discretization order, defaults to 8 free_surface: Bool (optional) Whether or not to use a free surface Returns ---------- Array FWI gradient """ g = gradient(model, recin, rec_coords, u, space_order=space_order, free_surface=free_surface) return g.data
def J_adjoint_freq(model, src_coords, wavelet, rec_coords, recin, space_order=8, freq_list=[], is_residual=False, return_obj=False, nlind=False, dft_sub=None, isic=False, ws=None, t_sub=1, born_fwd=False): """ Jacobian (adjoint fo born modeling operator) operator on a shot record as a source (i.e data residual). Outputs the gradient with Frequency compression (on-the-fly DFT). Parameters ---------- model: Model Physical model src_coords: Array Coordiantes of the source(s) wavelet: Array Source signature rec_coords: Array Coordiantes of the receiver(s) recin: Array Receiver data space_order: Int (optional) Spatial discretization order, defaults to 8 freq_list: List List of frequencies for on-the-fly DFT dft_sub: Int Subsampling factor for on-the-fly DFT isic : Bool Whether or not to use ISIC imaging condition ws : Array Extended source spatial distribution is_residual: Bool Whether to treat the input as the residual or as the observed data born_fwd: Bool Whether to use the forward or linearized forward modeling operator nlind: Bool Whether to remove the non linear data from the input data. This option is only available in combination with `born_fwd` Returns ---------- Array Adjoint jacobian on the input data (gradient) """ rec, u, _ = op_fwd_J[born_fwd](model, src_coords, rec_coords, wavelet, save=False, space_order=space_order, freq_list=freq_list, ws=ws, dft_sub=dft_sub, nlind=nlind) # Residual and gradient if not is_residual: if nlind: recin[:] = rec[0].data[:] - (recin[:] - rec[1].data) # input is observed data else: recin[:] = rec.data[:] - recin[:] # input is observed data g, _ = gradient(model, recin, rec_coords, u, space_order=space_order, isic=isic, freq=freq_list, dft_sub=dft_sub) if return_obj: return .5*model.critical_dt*np.linalg.norm(recin)**2, g.data return g.data
def wri_func(model, src_coords, wavelet, rec_coords, recin, yin, space_order=8, isic=False, ws=None, t_sub=1, grad="m", grad_corr=False, alpha_op=False, w_fun=None, eps=0): """ Time domain wavefield reconstruction inversion wrapper """ # F(m0) * q if y is not an input and compute y = r(m0) if yin is None or grad_corr: y, u0, _ = forward(model, src_coords, rec_coords, wavelet, save=grad_corr, space_order=space_order, ws=ws) ydat = recin[:] - y.data[:] else: ydat = yin # Compute wavefield vy = adjoint(F(m0))*y and norm on the fly srca, v, norm_v, _ = adjoint(model, ydat, src_coords, rec_coords, norm_v=True, w_fun=w_fun, save=grad is not None) c1 = 1 / (recin.shape[1]) c2 = np.log(np.prod(model.shape)) # <PTy, d-F(m)*f> = <PTy, d>-<adjoint(F(m))*PTy, f> ndt = np.sqrt(model.critical_dt) PTy_dot_r = ndt**2 * (np.dot(ydat.reshape(-1), recin.reshape(-1)) - np.dot(srca.data.reshape(-1), wavelet.reshape(-1))) norm_y = ndt * np.linalg.norm(ydat) # alpha α = compute_optalpha(c2*norm_y, c1*norm_v, eps, comp_alpha=alpha_op) # Lagrangian evaluation fun = -.5 * c1 * α**2 * norm_v + c2 * α * PTy_dot_r - eps * np.abs(α) * norm_y gradm = grady = None if grad is not None: w = weight_fun(w_fun, model, src_coords) w = c1*α/w**2 if w is not None else c1*α Q = wf_as_src(v, w=w) rcv, gradm, _ = forward_grad(model, src_coords, rec_coords, c2*wavelet, q=Q, v=v) # Compute gradient wrt y if grad_corr or grad in ["all", "y"]: grady = c2 * recin - rcv.data[:] if norm_y != 0: grady -= np.abs(eps) * ydat / norm_y # Correcting for reduced gradient if not grad_corr: gradm = gradm.data else: gradm_corr, _ = gradient(model, grady, rec_coords, u0) # Reduced gradient post-processing gradm = gradm.data + gradm_corr.data return fun, α * gradm, grady
def J_adjoint_freq(model, src_coords, wavelet, rec_coords, recin, space_order=8, free_surface=False, freq_list=[], is_residual=False, return_obj=False, dft_sub=None, isic=False, ws=None, t_sub=1): """ Jacobian (adjoint fo born modeling operator) operator on a shot record as a source (i.e data residual). Outputs the gradient with Frequency compression (on-the-fly DFT). Parameters ---------- model: Model Physical model src_coords: Array Coordiantes of the source(s) wavelet: Array Source signature rec_coords: Array Coordiantes of the receiver(s) recin: Array Receiver data space_order: Int (optional) Spatial discretization order, defaults to 8 free_surface: Bool (optional) Whether or not to use a free surface freq_list: List List of frequencies for on-the-fly DFT dft_sub: Int Subsampling factor for on-the-fly DFT isic : Bool Whether or not to use ISIC imaging condition ws : Array Extended source spatial distribution is_residual: Bool Whether to treat the input as the residual or as the observed data Returns ---------- Array Adjoint jacobian on the input data (gradient) """ rec, u = forward(model, src_coords, rec_coords, wavelet, save=False, space_order=space_order, free_surface=free_surface, freq_list=freq_list, dft_sub=dft_sub, ws=ws) # Residual and gradient if not is_residual: recin[:] = rec.data[:] - recin[:] # input is observed data g = gradient(model, recin, rec_coords, u, space_order=space_order, isic=isic, free_surface=free_surface, freq=freq_list, dft_sub=dft_sub) if return_obj: return .5*model.critical_dt*np.linalg.norm(recin)**2, g.data return g.data
def J_adjoint_standard(model, src_coords, wavelet, rec_coords, recin, space_order=8, free_surface=False, is_residual=False, return_obj=False, isic=False, ws=None, t_sub=1): """ Adjoint Jacobian (adjoint fo born modeling operator) operator on a shot record as a source (i.e data residual). Outputs the gradient with standard zero lag cross correlation over time. Parameters ---------- model: Model Physical model src_coords: Array Coordiantes of the source(s) wavelet: Array Source signature rec_coords: Array Coordiantes of the receiver(s) recin: Array Receiver data space_order: Int (optional) Spatial discretization order, defaults to 8 free_surface: Bool (optional) Whether or not to use a free surface isic : Bool Whether or not to use ISIC imaging condition ws : Array Extended source spatial distribution is_residual: Bool Whether to treat the input as the residual or as the observed data Returns ---------- Array Adjoint jacobian on the input data (gradient) """ rec, u = forward(model, src_coords, rec_coords, wavelet, save=True, ws=ws, space_order=space_order, free_surface=free_surface, t_sub=t_sub) # Residual and gradient if not is_residual: recin[:] = rec.data[:] - recin[:] # input is observed data g = gradient(model, recin, rec_coords, u, space_order=space_order, free_surface=free_surface, isic=isic) if return_obj: return .5*model.critical_dt*np.linalg.norm(recin)**2, g.data return g.data
def grad_fwi(model, recin, rec_coords, u, space_order=8): """ FWI gradient, i.e adjoint Jacobian on a data residual. Parameters ---------- model: Model Physical model recin: Array Data residual rec_coords: Array Receivers coordinates u: TimeFunction Forward wavefield space_order: Int (optional) Spatial discretization order, defaults to 8 Returns ---------- Array FWI gradient """ g, _ = gradient(model, recin, rec_coords, u, space_order=space_order) return g.data
dt = new_time_range.step to_interp = np.asarray(rec.data) data = np.zeros((num, to_interp.shape[1])) for i in range(to_interp.shape[1]): tck = interpolate.splrep(time, to_interp[:, i], k=3) data[:, i] = interpolate.splev(new_time_range.time_values, tck) coords_loc = np.asarray(rec.coordinates.data) # Return new object return data, coords_loc # Devito operator d_obs, u0, summary1 = forward(model, src.coordinates.data, rec_coords, src.data, save=True, t_sub=12) grad, summary2 = gradient(model, d_obs, rec_coords, u0, isic=True) grad.data[:, 0:66] = 0 # mute water column # Remove pml and pad rtm = grad.data[model.nbl:-model.nbl, model.nbl:-model.nbl] # remove padding rtm = extent_gradient(shape_full, origin_full, shape, origin, spacing, rtm) plt.figure() plt.imshow(d_obs.data, vmin=-1e-1, vmax=1e-1, cmap='gray', aspect='auto') plt.figure() plt.imshow(np.transpose(rtm), vmin=-2e0, vmax=2e0, cmap='gray', aspect='auto') plt.show()
def J_adjoint_checkpointing(model, src_coords, wavelet, rec_coords, recin, space_order=8, is_residual=False, n_checkpoints=None, maxmem=None, return_obj=False, isic=False, ws=None, t_sub=1): """ Jacobian (adjoint fo born modeling operator) operator on a shot record as a source (i.e data residual). Outputs the gradient with Checkpointing. Parameters ---------- model: Model Physical model src_coords: Array Coordiantes of the source(s) wavelet: Array Source signature rec_coords: Array Coordiantes of the receiver(s) recin: Array Receiver data space_order: Int (optional) Spatial discretization order, defaults to 8 checkpointing: Bool Whether or not to use checkpointing n_checkpoints: Int Number of checkpoints for checkpointing maxmem: Float Maximum memory to use for checkpointing isic : Bool Whether or not to use ISIC imaging condition ws : Array Extended source spatial distribution is_residual: Bool Whether to treat the input as the residual or as the observed data Returns ---------- Array Adjoint jacobian on the input data (gradient) """ # Optimal checkpointing op_f, u, rec_g = forward(model, src_coords, rec_coords, wavelet, space_order=space_order, return_op=True, ws=ws) op, g, v = gradient(model, recin, rec_coords, u, space_order=space_order, return_op=True, isic=isic) nt = wavelet.shape[0] rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords) cp = DevitoCheckpoint([uu for uu in as_tuple(u)]) if maxmem is not None: memsize = (cp.size * u.data.itemsize) n_checkpoints = int(np.floor(maxmem * 10**6 / memsize)) # Op arguments uk = {uu.name: uu for uu in as_tuple(u)} vk = {**uk, **{vv.name: vv for vv in as_tuple(v)}} uk.update({'rcv%s' % as_tuple(u)[0].name: rec_g}) vk.update({'src%s' % as_tuple(v)[0].name: rec}) # Wrapped ops wrap_fw = CheckpointOperator(op_f, vp=model.vp, **uk) wrap_rev = CheckpointOperator(op, vp=model.vp, **vk) # 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.data[:] = recin[:] else: rec.data[:] = rec.data[:] - recin[:] # input is observed data wrp.apply_reverse() if return_obj: return .5 * model.critical_dt * norm(rec)**2, g.data return g.data
src.coordinates.data, rec_t.coordinates.data, src.data, save=True) # Forward print("Forward") _, u0, _ = forward(model, src.coordinates.data, rec_t.coordinates.data, src.data, save=True) # gradient print("Adjoint J") dm_hat, _ = gradient(model, dD_hat, rec_t.coordinates.data, u0) # Adjoint test a = model.critical_dt * inner(dD_hat, dD_hat) b = inner(dm_hat, model.dm) if is_tti: c = np.linalg.norm(u0[0].data.flatten() - u0l[0].data.flatten(), np.inf) else: c = np.linalg.norm(u0.data.flatten() - u0l.data.flatten(), np.inf) print("Difference between saving with forward and born", c) print("Adjoint test J") print("a = %2.2e, b = %2.2e, diff = %2.2e: " % (a, b, a - b)) print("Relative error: ", a / b - 1)
######################################################################################### # Source wavelet tn = 1000. dt_shot = model.critical_dt nt = int(tn / dt_shot) time_s = np.linspace(0, tn, nt) wavelet = Ricker(0.015, time_s) ######################################################################################### # Devito operator d_obs = born(model, src_coords, rec_coords, wavelet, save=False)[0] u0 = forward(model, src_coords, rec_coords, wavelet, save=True, t_sub=8)[1] grad_dist = gradient(model, d_obs, d_obs.coordinates, u0, isic=False)[0] if rank > 0: # Send result to master comm.send(model.m.local_indices, dest=0, tag=10) comm.send(grad_dist.data, dest=0, tag=11) else: # Master # Initialize full array grad = np.empty(shape=model.m.shape_global, dtype='float32') grad[model.m.local_indices] = grad_dist.data # Collect gradients for j in range(1, size): local_indices = comm.recv(source=j, tag=10) glocal = comm.recv(source=j, tag=11)