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 adjoint_modeling(model, src_coords, rec_coords, rec_data, 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 # Create the adjoint wavefield v = TimeFunction(name="v", grid=model.grid, time_order=2, space_order=space_order) # 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)] # Adjoint source is injected at receiver locations 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) # Data is sampled at source locations src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords) adj_rec = src.interpolate(expr=v, offset=model.nbpml) # Create operator and run set_log_level('ERROR') expression += adj_src + adj_rec op = Operator(expression, subs=model.spacing_map, dse='advanced', dle='advanced', name="Backward%s" % randint(1e5)) op(dt=dt) return src.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_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 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_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 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, 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_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 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