예제 #1
0
 def callback(final_solution_basename, vec):
     callback.call_count += 1
     fwi_iteration = callback.call_count
     filename = "%s_%d.h5" % (final_solution_basename, fwi_iteration)
     with profiler.get_timer('io', 'write_progress'):
         to_hdf5(vec2mat(vec, model.shape), filename)
     print(profiler.summary())
예제 #2
0
파일: run.py 프로젝트: keshava/daks
    def callback(progress_dir, intermediates_dir, model, exclude_boundaries, vec):
        global plot_model_to_file
        callback.call_count += 1

        if not hasattr(callback, "obj_fn_history"):
            callback.obj_fn_history = []

        callback.obj_fn_history.append(fwi_gradient.obj_fn_cache[vec.tobytes()])

        fwi_iteration = callback.call_count
        filename = os.path.join(intermediates_dir, "solution%d.h5" % fwi_iteration)
        if exclude_boundaries:
            to_hdf5(vec2mat(vec, model.shape), filename)
        else:
            to_hdf5(vec2mat(vec, model.vp.shape), filename)

        progress_filename = os.path.join(progress_dir, "fwi-iter%d.pdf" % (fwi_iteration))
        plot_model_to_file(solver.model, progress_filename)
예제 #3
0
def test_vec2mat():
    shape = (2, 2, 2)
    vec = np.arange(8)
    mat = vec.reshape(shape)

    assert (np.array_equal(mat, vec2mat(vec, shape)))

    back = mat2vec(mat)

    assert (np.array_equal(back, vec))
예제 #4
0
def fwi_gradient(vp_in, model, geometry, nshots, client, solver_params):
    start_time = time.time()
    vp_in = vec2mat(vp_in, model.shape)
    f_vp_in = client.scatter(vp_in)  # Dask enforces this for large arrays
    assert (model.shape == vp_in.shape)

    futures = []

    for i in range(nshots):
        futures.append(
            client.submit(
                fwi_gradient_shot,
                f_vp_in,
                i,
                solver_params,
                resources={
                    'tasks': 1
                }))  # Ensure one task per worker (to run two, tasks=0.5)

    shape = model.shape

    def reduction(*args):
        grad = np.zeros(shape)  # Closured from above
        objective = 0.

        for a in args:
            o, g = a
            objective += o
            grad += g
        return objective, grad

    reduce_future = client.submit(reduction, *futures)
    wait(reduce_future)

    objective, grad = reduce_future.result()
    elapsed_time = time.time() - start_time
    print("Objective function evaluation completed in %f seconds" %
          elapsed_time)

    # Scipy LBFGS misbehaves if type is not float64
    grad = mat2vec(np.array(grad)).astype(np.float64)

    return objective, grad
예제 #5
0
def fwi_gradient_local(vp_in, nshots, solver, shots_container):
    model = solver.model

    vp_in = np.array(vec2mat(vp_in, solver.model.vp.shape),
                     dtype=solver.model.dtype)

    assert (model.vp.shape == vp_in.shape)

    solver.model.update("vp", vp_in)

    objective = 0.

    grad = np.zeros(model.vp.shape)

    for i in range(nshots):
        o, g = process_shot(i,
                            solver,
                            shots_container,
                            exclude_boundaries=False)
        objective += o
        grad += g

    return objective, -mat2vec(grad).astype(np.float64)
예제 #6
0
파일: run.py 프로젝트: keshava/daks
def run(initial_model_filename, results_dir, tn, nshots, shots_container, so, nbl, kernel, scale_gradient, max_iter,
        checkpointing, n_checkpoints, compression, tolerance, reference_solution, dtype):

    if dtype == 'float32':
        dtype = np.float32
    elif dtype == 'float64':
        dtype = np.float64
    else:
        raise ValueError("Invalid dtype")

    water_depth = 20  # Number of points at the top of the domain that correspond to water
    exclude_boundaries = True  # Exclude the boundary regions from the optimisation problem
    mute_water = True  # Mute the gradient in the water region

    initial_model_filename, datakey = initial_model_filename

    model, geometry, bounds = initial_setup(initial_model_filename, tn, dtype, so, nbl,
                                            datakey=datakey, exclude_boundaries=exclude_boundaries, water_depth=water_depth)

    client = setup_dask()

    if not os.path.exists(results_dir):
        os.mkdir(results_dir)

    intermediates_dir = os.path.join(results_dir, "intermediates")

    if not os.path.exists(intermediates_dir):
        os.mkdir(intermediates_dir)

    progress_dir = os.path.join(results_dir, "progress")

    if not os.path.exists(progress_dir):
        os.mkdir(progress_dir)

    auth = default_auth()

    solver_params = {'h5_file': Blob("models", initial_model_filename, auth=auth), 'tn': tn,
                     'space_order': so, 'dtype': dtype, 'datakey': datakey, 'nbl': nbl,
                     'opt': ('noop', {'openmp': True, 'par-dynamic-work': 1000})}

    if kernel in ['OT2', 'OT4']:
        solver_params['kernel'] = kernel
        solver = overthrust_solver_iso(**solver_params)
    elif kernel == "rho":
        solver_params['water_depth'] = water_depth
        solver_params['calculate_density'] = False
        solver = overthrust_solver_density(**solver_params)
    solver._dt = 1.75
    solver.geometry.resample(1.75)

    f_args = [nshots, client, solver, shots_container, auth, scale_gradient, mute_water, exclude_boundaries, water_depth]

    if checkpointing:
        f_args += [checkpointing, {'n_checkpoints': n_checkpoints, 'scheme': compression,
                                   'tolerance': tolerance}]
    if exclude_boundaries:
        v0 = mat2vec(trim_boundary(model.vp, model.nbl)).astype(np.float64)
    else:
        v0 = mat2vec(model.vp).astype(np.float64)

    def callback(progress_dir, intermediates_dir, model, exclude_boundaries, vec):
        global plot_model_to_file
        callback.call_count += 1

        if not hasattr(callback, "obj_fn_history"):
            callback.obj_fn_history = []

        callback.obj_fn_history.append(fwi_gradient.obj_fn_cache[vec.tobytes()])

        fwi_iteration = callback.call_count
        filename = os.path.join(intermediates_dir, "solution%d.h5" % fwi_iteration)
        if exclude_boundaries:
            to_hdf5(vec2mat(vec, model.shape), filename)
        else:
            to_hdf5(vec2mat(vec, model.vp.shape), filename)

        progress_filename = os.path.join(progress_dir, "fwi-iter%d.pdf" % (fwi_iteration))
        plot_model_to_file(solver.model, progress_filename)

    callback.call_count = 0

    partial_callback = partial(callback, progress_dir, intermediates_dir, model, exclude_boundaries)

    fwi_gradient.call_count = 0
    fwd_op = solver.op_fwd(save=False)
    rev_op = solver.op_grad(save=False)
    fwd_op.ccode
    rev_op.ccode

    solution_object = minimize(fwi_gradient,
                               v0,
                               args=tuple(f_args),
                               jac=True, method='L-BFGS-B',
                               callback=partial_callback, bounds=bounds,
                               options={'disp': True, 'maxiter': max_iter})

    if exclude_boundaries:
        final_model = vec2mat(solution_object.x, model.shape)
    else:
        final_model = vec2mat(solution_object.x, model.vp.shape)

    solver.model.update("vp", final_model)

    # Save plot of final model
    final_plot_filename = os.path.join(results_dir, "final_model.pdf")
    plot_model_to_file(solver.model, final_plot_filename)

    # Save objective function values to CSV
    obj_fn_history = callback.obj_fn_history
    obj_fn_vals_filename = os.path.join(results_dir, "objective_function_values.csv")
    with open(obj_fn_vals_filename, "w") as vals_file:
        vals_writer = csv.writer(vals_file)
        for r in obj_fn_history:
            vals_writer.writerow([r])

    # Plot objective function values
    plt.title("FWI convergence")
    plt.xlabel("Iteration number")
    plt.ylabel("Objective function value")
    obj_fun_plt_filename = os.path.join(results_dir, "convergence.tex")
    obj_fun_plt_pdf_filename = os.path.join(results_dir, "convergence.pdf")

    plt.clf()
    if reference_solution is None:
        plt.plot(obj_fn_history)
    else:
        # Load reference solution convergence history
        with open(reference_solution, 'r') as reference_file:
            vals_reader = csv.reader(reference_file)
            reference_solution_values = []
            for r in vals_reader:
                reference_solution_values.append(float(r[0]))
        # Pad with 0s to ensure same size

        # Plot with legends
        plt.plot(obj_fn_history, label="Lossy FWI")
        plt.plot(reference_solution_values, label="Reference FWI")
        # Display legend
        plt.legend()
    plt.savefig(obj_fun_plt_pdf_filename)
    tikzplotlib.save(obj_fun_plt_filename)

    true_model = overthrust_model_iso("overthrust_3D_true_model_2D.h5", datakey="m", dtype=dtype, space_order=so, nbl=nbl)
    true_model_vp = trim_boundary(true_model.vp, true_model.nbl)

    error_norm = np.linalg.norm(true_model_vp - final_model)
    print("L2 norm of final solution vs true solution: %f" % error_norm)

    data = {'error_norm': error_norm,
            'checkpointing': checkpointing,
            'compression': compression,
            'tolerance': tolerance,
            'ncp': n_checkpoints}

    write_results(data, "fwi_experiment.csv")

    # Final solution
    final_solution_filename = os.path.join(results_dir, "final_solution.h5")
    to_hdf5(final_model, final_solution_filename)
예제 #7
0
파일: run.py 프로젝트: keshava/daks
def fwi_gradient(vp_in, nshots, client, solver, shots_container, auth, scale_gradient=None, mute_water=True,
                 exclude_boundaries=True, water_depth=20, checkpointing=False, checkpoint_params=None):
    start_time = time.time()

    reset_cluster(client)

    if not hasattr(fwi_gradient, "obj_fn_cache"):
        fwi_gradient.obj_fn_cache = {}

    if exclude_boundaries:
        vp = np.array(vec2mat(vp_in, solver.model.shape), dtype=solver.model.dtype)
    else:
        vp = np.array(vec2mat(vp_in, solver.model.vp.shape), dtype=solver.model.dtype)

    solver.model.update("vp", vp)

    # Dask enforces this for large objects
    f_solver = client.scatter(solver, broadcast=True)

    futures = []

    for i in range(nshots):
        if checkpointing:
            futures.append(client.submit(process_shot_checkpointed, i, f_solver, shots_container, auth, exclude_boundaries,
                                         checkpoint_params, resources={'tasks': 1}))
        else:
            futures.append(client.submit(process_shot, i, f_solver, shots_container, auth, exclude_boundaries,
                                         resources={'tasks': 1}))  # Ensure one task per worker (to run two, tasks=0.5)

    if exclude_boundaries:
        gradient_shape = solver.model.shape
    else:
        gradient_shape = solver.model.vp.shape

    def reduction(*args):
        grad = np.zeros(gradient_shape)  # Closured from above
        objective = 0.

        for a in args:
            o, g = a
            objective += o
            grad += g
        return objective, grad

    reduce_future = client.submit(reduction, *futures)

    wait(reduce_future)

    objective, grad = reduce_future.result()

    if mute_water:
        if exclude_boundaries:
            muted_depth = water_depth
        else:
            muted_depth = water_depth + solver.model.nbl
        grad[:, 0:muted_depth] = 0

    # Scipy LBFGS misbehaves if type is not float64
    grad = mat2vec(grad).astype(np.float64)

    if scale_gradient is not None:
        if scale_gradient == "W":
            if not hasattr(fwi_gradient, "gradient_scaling_factor"):
                fwi_gradient.gradient_scaling_factor = np.max(np.abs(grad))

            grad /= fwi_gradient.gradient_scaling_factor
        elif scale_gradient == "L":
            grad /= np.max(np.abs(grad))
        else:
            raise ValueError("Invalid value %s for gradient scaling. Allowed: None, L, W" % scale_gradient)

    fwi_gradient.obj_fn_cache[vp_in.tobytes()] = objective

    elapsed_time = time.time() - start_time
    eprint("Objective function evaluation completed in %f seconds. F=%f" % (elapsed_time, objective))

    return objective, -grad
예제 #8
0
def fwi_gradient_checkpointed(vp_in,
                              model,
                              geometry,
                              nshots,
                              client,
                              solver_params,
                              n_checkpoints=1000,
                              compression_params=None):
    # Create symbols to hold the gradient and residual
    grad = Function(name="grad", grid=model.grid)
    vp = Function(name="vp", grid=model.grid)
    smooth_d = Receiver(name='rec',
                        grid=model.grid,
                        time_range=geometry.time_axis,
                        coordinates=geometry.rec_positions)
    residual = Receiver(name='rec',
                        grid=model.grid,
                        time_range=geometry.time_axis,
                        coordinates=geometry.rec_positions)
    objective = 0.
    time_order = 2
    vp_in = vec2mat(vp_in, model.shape)

    assert (model.vp.shape == vp_in.shape)
    vp.data[:] = vp_in[:]
    filename = solver_params['filename']

    solver = overthrust_solver_iso(filename, datakey="m0")
    dt = solver.dt
    nt = smooth_d.data.shape[0] - 2
    u = TimeFunction(name='u',
                     grid=model.grid,
                     time_order=time_order,
                     space_order=4)
    v = TimeFunction(name='v',
                     grid=model.grid,
                     time_order=time_order,
                     space_order=4)
    fwd_op = solver.op_fwd(save=False)
    rev_op = solver.op_grad(save=False)
    cp = DevitoCheckpoint([u])
    for i in range(nshots):
        true_d, source_location = load_shot(i)
        # Update source location
        solver.geometry.src_positions[0, :] = source_location[:]

        # Compute smooth data and full forward wavefield u0
        u.data[:] = 0.
        residual.data[:] = 0.
        v.data[:] = 0.
        smooth_d.data[:] = 0.

        wrap_fw = CheckpointOperator(fwd_op,
                                     src=solver.geometry.src,
                                     u=u,
                                     rec=smooth_d,
                                     vp=vp,
                                     dt=dt)
        wrap_rev = CheckpointOperator(rev_op,
                                      vp=vp,
                                      u=u,
                                      v=v,
                                      rec=residual,
                                      grad=grad,
                                      dt=dt)
        wrp = Revolver(cp,
                       wrap_fw,
                       wrap_rev,
                       n_checkpoints,
                       nt,
                       compression_params=compression_params)
        wrp.apply_forward()

        # Compute gradient from data residual and update objective function
        residual.data[:] = smooth_d.data[:] - true_d[:]

        objective += .5 * np.linalg.norm(residual.data.ravel())**2
        wrp.apply_reverse()
        print(wrp.profiler.summary())

    return objective, -np.ravel(grad.data).astype(np.float64)
예제 #9
0
def run(initial_model_filename, final_solution_basename, tn, nshots,
        shots_container, so, nbl, kernel, checkpointing, n_checkpoints,
        compression, tolerance):
    dtype = np.float32
    model, geometry, bounds = initial_setup(initial_model_filename, tn, dtype,
                                            so, nbl)

    solver_params = {
        'filename': initial_model_filename,
        'tn': tn,
        'space_order': so,
        'dtype': dtype,
        'datakey': 'm0',
        'nbl': nbl,
        'origin': model.origin,
        'spacing': model.spacing,
        'shots_container': shots_container
    }

    client = setup_dask()

    f_args = [model, geometry, nshots, client, solver_params]

    # if checkpointing:
    #    f_g = fwi_gradient_checkpointed
    #    compression_params = {'scheme': compression, 'tolerance': 10**(-tolerance)}
    #    f_args.append(n_checkpoints)
    #    f_args.append(compression_params)
    # else:

    f_g = fwi_gradient

    clipped_vp = mat2vec(clip_boundary_and_numpy(model.vp.data, model.nbl))

    def callback(final_solution_basename, vec):
        callback.call_count += 1
        fwi_iteration = callback.call_count
        filename = "%s_%d.h5" % (final_solution_basename, fwi_iteration)
        with profiler.get_timer('io', 'write_progress'):
            to_hdf5(vec2mat(vec, model.shape), filename)
        print(profiler.summary())

    callback.call_count = 0

    partial_callback = partial(callback, final_solution_basename)

    solution_object = minimize(f_g,
                               clipped_vp,
                               args=tuple(f_args),
                               jac=True,
                               method='L-BFGS-B',
                               callback=partial_callback,
                               bounds=bounds,
                               options={
                                   'disp': True,
                                   'maxiter': 60
                               })

    final_model = vec2mat(solution_object.x, model.shape)

    true_model = overthrust_model_iso("overthrust_3D_true_model_2D.h5",
                                      datakey="m",
                                      dtype=dtype,
                                      space_order=so,
                                      nbl=nbl)
    true_model_vp = clip_boundary_and_numpy(true_model.vp.data, true_model.nbl)

    error_norm = np.linalg.norm(true_model_vp - final_model)
    print(error_norm)

    data = {
        'error_norm': error_norm,
        'checkpointing': checkpointing,
        'compression': compression,
        'tolerance': tolerance,
        'ncp': n_checkpoints
    }

    write_results(data, "fwi_experiment.csv")

    to_hdf5(final_model, '%s_final.h5' % final_solution_basename)
예제 #10
0
    def test_gradientFWI(self):
        r"""
        This test ensures that the FWI gradient computed with devito
        satisfies the Taylor expansion property:
        .. math::
            \Phi(m0 + h dm) = \Phi(m0) + \O(h) \\
            \Phi(m0 + h dm) = \Phi(m0) + h \nabla \Phi(m0) + \O(h^2) \\
            \Phi(m0) = .5* || F(m0 + h dm) - D ||_2^2
        where
        .. math::
            \nabla \Phi(m0) = <J^T \delta d, dm> \\
            \delta d = F(m0+ h dm) - D \\
        with F the Forward modelling operator.
        """
        initial_model_filename = "overthrust_3D_initial_model_2D.h5"
        true_model_filename = "overthrust_3D_true_model_2D.h5"

        tn = 4000

        dtype = np.float32

        so = 6

        nbl = 40

        shots_container = "shots-iso"

        shot_id = 10

        ##########

        model0 = overthrust_model_iso(initial_model_filename,
                                      datakey="m0",
                                      dtype=dtype,
                                      space_order=so,
                                      nbl=nbl)

        model_t = overthrust_model_iso(true_model_filename,
                                       datakey="m",
                                       dtype=dtype,
                                       space_order=so,
                                       nbl=nbl)

        _, geometry, _ = initial_setup(initial_model_filename,
                                       tn,
                                       dtype,
                                       so,
                                       nbl,
                                       datakey="m0")
        # rec, source_location, old_dt = load_shot(shot_id,
        #                                         container=shots_container)
        source_location = geometry.src_positions
        solver_params = {
            'h5_file': initial_model_filename,
            'tn': tn,
            'space_order': so,
            'dtype': dtype,
            'datakey': 'm0',
            'nbl': nbl,
            'origin': model0.origin,
            'spacing': model0.spacing,
            'shots_container': shots_container,
            'src_coordinates': source_location
        }

        solver = overthrust_solver_iso(**solver_params)

        true_solver_params = solver_params.copy()

        true_solver_params['h5_file'] = true_model_filename
        true_solver_params['datakey'] = "m"

        solver_true = overthrust_solver_iso(**true_solver_params)

        rec, _, _ = solver_true.forward()

        v0 = mat2vec(clip_boundary_and_numpy(model0.vp.data, model0.nbl))

        v_t = mat2vec(clip_boundary_and_numpy(model_t.vp.data, model_t.nbl))

        dm = np.float64(v_t**(-2) - v0**(-2))

        print("dm", np.linalg.norm(dm), dm.shape)

        F0, gradient = fwi_gradient_shot(vec2mat(v0, model0.shape), shot_id,
                                         solver_params, source_location)

        G = np.dot(gradient.reshape(-1), dm.reshape(-1))

        # FWI Gradient test
        H = [0.5, 0.25, .125, 0.0625, 0.0312, 0.015625, 0.0078125]
        error1 = np.zeros(7)
        error2 = np.zeros(7)
        for i in range(0, 7):
            # Add the perturbation to the model
            vloc = np.sqrt(v0**2 * v_t**2 /
                           ((1 - H[i]) * v_t**2 + H[i] * v0**2))
            m = Model(vp=vloc,
                      nbl=nbl,
                      space_order=so,
                      dtype=dtype,
                      shape=model0.shape,
                      origin=model0.origin,
                      spacing=model0.spacing,
                      bcs="damp")
            # Data for the new model
            d = solver.forward(vp=m.vp)[0]
            # First order error Phi(m0+dm) - Phi(m0)
            F_i = .5 * linalg.norm((d.data - rec.data).reshape(-1))**2
            error1[i] = np.absolute(F_i - F0)
            # Second order term r Phi(m0+dm) - Phi(m0) - <J(m0)^T \delta d, dm>
            error2[i] = np.absolute(F_i - F0 - H[i] * G)
            print(i, F0, F_i, H[i] * G)

        # Test slope of the  tests
        p1 = np.polyfit(np.log10(H), np.log10(error1), 1)
        p2 = np.polyfit(np.log10(H), np.log10(error2), 1)
        info('1st order error, Phi(m0+dm)-Phi(m0): %s' % (p1))
        info(
            r'2nd order error, Phi(m0+dm)-Phi(m0) - <J(m0)^T \delta d, dm>: %s'
            % (p2))
        print("Error 1:")
        print(error1)
        print("***")
        print("Error 2:")
        print(error2)
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)