Beispiel #1
0
    def test_linearity_adjoint_F(self, shape, dtype, so):
        """
        Test the linearity of the adjoint modeling operator by verifying:
            a F^T(r) = F^T(a r)
        """
        np.random.seed(0)
        solver = acoustic_sa_setup(shape=shape, dtype=dtype, space_order=so)
        src0 = solver.geometry.src
        rec, _, _ = solver.forward(src0)
        a = -1 + 2 * np.random.rand()
        src1, _, _ = solver.adjoint(rec)
        rec.data[:] = a * rec.data[:]
        src2, _, _ = solver.adjoint(rec)
        src1.data[:] *= a

        # Check adjoint source wavefeild linearity
        # Normalize by rms of rec2, to enable using abolute tolerance below
        rms2 = np.sqrt(np.mean(src2.data**2))
        diff = (src1.data - src2.data) / rms2
        info("linearity adjoint F %s (so=%d) rms 1,2,diff; "
             "%+16.10e %+16.10e %+16.10e" %
             (shape, so, np.sqrt(np.mean(src1.data**2)), np.sqrt(np.mean(src2.data**2)),
              np.sqrt(np.mean(diff**2))))
        tol = 1.e-12
        assert np.allclose(diff, 0.0, atol=tol)
Beispiel #2
0
    def test_array_reduction(self, so, dim):
        """
        Test generation of OpenMP reduction clauses involving Function's.
        """
        grid = Grid(shape=(3, 3, 3))
        d = grid.dimensions[dim]

        f = Function(name='f',
                     shape=(3, ),
                     dimensions=(d, ),
                     grid=grid,
                     space_order=so)
        u = TimeFunction(name='u', grid=grid)

        op = Operator(Inc(f, u + 1),
                      opt=('openmp', {
                          'par-collapse-ncores': 1
                      }))

        iterations = FindNodes(Iteration).visit(op)
        assert "reduction(+:f[0:f_vec->size[0]])" in iterations[1].pragmas[
            0].value

        try:
            op(time_M=1)
        except:
            # Older gcc <6.1 don't support reductions on array
            info("Un-supported older gcc version for array reduction")
            assert True
            return

        assert np.allclose(f.data, 18)
Beispiel #3
0
def basic_gradient_test(wave, space_order, v0, v, rec, F0, gradient, dm):

    G = np.dot(mat2vec(gradient.data), 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
        def initializer(data):
            data[:] = np.sqrt(v0**2 * v**2 /
                              ((1 - H[i]) * v**2 + H[i] * v0**2))

        vloc = Function(name='vloc',
                        grid=wave.model.grid,
                        space_order=space_order,
                        initializer=initializer)
        # Data for the new model
        d = wave.forward(vp=vloc, dt=wave.model.critical_dt)[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)

    # 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))
    assert np.isclose(p1[0], 1.0, rtol=0.1)
    assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #4
0
def run(shape=(50, 50, 50),
        spacing=(20.0, 20.0, 20.0),
        tn=250.0,
        autotune=False,
        time_order=2,
        space_order=4,
        nbl=10,
        kernel='centered',
        full_run=False,
        **kwargs):

    solver = tti_setup(shape=shape,
                       spacing=spacing,
                       tn=tn,
                       space_order=space_order,
                       nbl=nbl,
                       kernel=kernel,
                       **kwargs)
    info("Applying Forward")

    rec, u, v, summary = solver.forward(autotune=autotune)

    if not full_run:
        return summary.gflopss, summary.oi, summary.timings, [rec, u, v]

    info("Applying Adjoint")
    solver.adjoint(rec, autotune=autotune)
    return summary.gflopss, summary.oi, summary.timings, [rec, u, v]
    def test_gradientJ(self, shape, kernel, space_order):
        """
        This test ensures that the Jacobian computed with devito
        satisfies the Taylor expansion property:
        .. math::
            F(m0 + h dm) = F(m0) + \O(h) \\
            F(m0 + h dm) = F(m0) + J dm + \O(h^2) \\

        with F the Forward modelling operator.
        :param dimensions: size of the domain in all dimensions
        in number of grid points
        :param time_order: order of the time discretization scheme
        :param space_order: order of the spacial discretization scheme
        :return: assertion that the Taylor properties are satisfied
        """
        spacing = tuple(15. for _ in shape)
        wave = setup(shape=shape, spacing=spacing, dtype=np.float64,
                     kernel=kernel, space_order=space_order,
                     tn=1000., nbpml=10+space_order/2)

        m0 = Function(name='m0', grid=wave.model.grid, space_order=space_order)
        smooth(m0, wave.model.m)
        dm = np.float64(wave.model.m.data - m0.data)
        linrec = Receiver(name='rec', grid=wave.model.grid,
                          time_range=wave.receiver.time_range,
                          coordinates=wave.receiver.coordinates.data)

        # Compute receiver data and full wavefield for the smooth velocity
        rec, u0, _ = wave.forward(m=m0, save=False)

        # Gradient: J dm
        Jdm, _, _, _ = wave.born(dm, rec=linrec, m=m0)
        # 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
            def initializer(data):
                data[:] = m0.data + H[i] * dm
            mloc = Function(name='mloc', grid=wave.model.m.grid, space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(m=mloc)[0]
            delta_d = (d.data - rec.data).reshape(-1)
            # First order error F(m0 + hdm) - F(m0)

            error1[i] = np.linalg.norm(delta_d, 1)
            # Second order term F(m0 + hdm) - F(m0) - J dm
            error2[i] = np.linalg.norm(delta_d - H[i] * Jdm.data.reshape(-1), 1)

        # 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) with slope: %s compared to 1' % (p1[0]))
        info('2nd order error, Phi(m0+dm)-Phi(m0) - <J(m0)^T \delta d, dm>with slope:'
             ' %s comapred to 2' % (p2[0]))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #6
0
    def test_gradientJ(self, shape, kernel, space_order):
        r"""
        This test ensures that the Jacobian computed with devito
        satisfies the Taylor expansion property:
        .. math::
            F(m0 + h dm) = F(m0) + \O(h) \\
            F(m0 + h dm) = F(m0) + J dm + \O(h^2) \\

        with F the Forward modelling operator.
        """
        spacing = tuple(15. for _ in shape)
        wave = setup(shape=shape, spacing=spacing, dtype=np.float64,
                     kernel=kernel, space_order=space_order,
                     tn=1000., nbpml=10+space_order/2)

        m0 = Function(name='m0', grid=wave.model.grid, space_order=space_order)
        smooth(m0, wave.model.m)
        dm = np.float64(wave.model.m.data - m0.data)
        linrec = Receiver(name='rec', grid=wave.model.grid,
                          time_range=wave.geometry.time_axis,
                          coordinates=wave.geometry.rec_positions)

        # Compute receiver data and full wavefield for the smooth velocity
        rec, u0, _ = wave.forward(m=m0, save=False)

        # Gradient: J dm
        Jdm, _, _, _ = wave.born(dm, rec=linrec, m=m0)
        # 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
            def initializer(data):
                data[:] = m0.data + H[i] * dm
            mloc = Function(name='mloc', grid=wave.model.m.grid, space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(m=mloc)[0]
            delta_d = (d.data - rec.data).reshape(-1)
            # First order error F(m0 + hdm) - F(m0)

            error1[i] = np.linalg.norm(delta_d, 1)
            # Second order term F(m0 + hdm) - F(m0) - J dm
            error2[i] = np.linalg.norm(delta_d - H[i] * Jdm.data.reshape(-1), 1)

        # 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) with slope: %s compared to 1' % (p1[0]))
        info(r'2nd order error, Phi(m0+dm)-Phi(m0) - <J(m0)^T \delta d, dm>with slope:'
             ' %s comapred to 2' % (p2[0]))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #7
0
def check_norms(fn_norms, reference):
    with open(fn_norms, 'r') as f:
        norms = eval(f.read())

    assert isinstance(norms, dict)
    assert isinstance(reference, dict)
    assert set(norms) == set(reference)

    for k, v in norms.items():
        norm = float(v)
        info("norm(%s) = %f (expected = %f, delta = %f)"
             % (k, norm, reference[k], abs(norm - reference[k])))
Beispiel #8
0
    def test_gradientJ(self, dtype, space_order, kernel, shape, spacing, time_order,
                       setup_func):
        """
        This test ensures that the Jacobian computed with devito
        satisfies the Taylor expansion property:
        .. math::
            F(m0 + h dm) = F(m0) + \O(h) \\
            F(m0 + h dm) = F(m0) + J dm + \O(h^2) \\
        with F the Forward modelling operator.
        """
        wave = setup_func(shape=shape, spacing=spacing, dtype=dtype,
                          kernel=kernel, space_order=space_order,
                          time_order=time_order, tn=1000., nbl=10+space_order/2)

        v0 = Function(name='v0', grid=wave.model.grid, space_order=space_order)
        smooth(v0, wave.model.vp)
        v = wave.model.vp.data
        dm = dtype(wave.model.vp.data**(-2) - v0.data**(-2))

        # Compute receiver data and full wavefield for the smooth velocity
        rec = wave.forward(vp=v0, save=False)[0]

        # Gradient: J dm
        Jdm = wave.jacobian(dm, vp=v0)[0]
        # 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
            def initializer(data):
                data[:] = np.sqrt(v0.data**2 * v**2 /
                                  ((1 - H[i]) * v**2 + H[i] * v0.data**2))
            vloc = Function(name='vloc', grid=wave.model.grid, space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(vp=vloc)[0]
            delta_d = (d.data - rec.data).reshape(-1)
            # First order error F(m0 + hdm) - F(m0)

            error1[i] = np.linalg.norm(delta_d, 1)
            # Second order term F(m0 + hdm) - F(m0) - J dm
            error2[i] = np.linalg.norm(delta_d - H[i] * Jdm.data.reshape(-1), 1)

        # 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) with slope: %s compared to 1' % (p1[0]))
        info(r'2nd order error, Phi(m0+dm)-Phi(m0) - <J(m0)^T \delta d, dm>with slope:'
             ' %s compared to 2' % (p2[0]))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #9
0
def cli_run_jit_backdoor(problem, **kwargs):
    """`click` interface for the `run_jit_backdoor` mode in `benchmark.py`."""

    # Preset shared parameters
    kwargs['space_order'] = [12]
    kwargs['time_order'] = [2]
    kwargs['nbl'] = 10
    kwargs['spacing'] = (20.0, 20.0, 20.0)

    # Preset problem-specific parameters
    if problem == 'tti':
        kwargs['shape'] = (350, 350, 350)
        kwargs['tn'] = 50  # End time of the simulation in ms
        kwargs['dse'] = 'aggressive'

        # Reference norms for the output fields
        reference = {'rec': 66.417102, 'u': 30.707737, 'v': 30.707728}
    elif problem == 'acoustic':
        kwargs['shape'] = (492, 492, 492)
        kwargs['tn'] = 100  # End time of the simulation in ms
        kwargs['dse'] = 'advanced'

        # Reference norms for the output fields
        reference = {'rec': 184.526400, 'u': 151.545837}
    else:
        assert False

    # Dummy values as they will be unused
    kwargs['block_shape'] = []
    kwargs['autotune'] = 'off'

    retval = run_jit_backdoor(problem, **kwargs)

    if retval is not None:
        for i in retval:
            if isinstance(i, DiscreteFunction):
                v = norm(i)
                info(
                    "norm(%s) = %f (expected = %f, delta = %f)" %
                    (i.name, v, reference[i.name], abs(v - reference[i.name])))

    # Record DEVITO_ environment
    env = [(k, v) for k, v in os.environ.items() if k.startswith('DEVITO_')]
    content = "{%s}" % ", ".join("'%s': '%s'" % (k, v) for k, v in env)
    with open('env.py', 'w') as f:
        f.write(content)
Beispiel #10
0
def save_rec(rec, src_coords, path, nt_new):
    comm = rec.grid.distributor.comm
    rank = comm.Get_rank()

    if rec.data.size != 0:
        rec_save, coords = resample_shot(rec, nt_new)

        info("From rank %s, shot record of size %s, number of rec locations %s" % (rank, rec_save.shape, coords.shape))
        info("From rank %s, writing %s in rec, maximum value is %s" % (rank, rec_save.shape, np.max(rec_save)))
        segy_write(rec_save,
                   [src_coords[0]],
                   [src_coords[-1]],
                   coords[:, 0],
                   coords[:, -1],
                   2.0,  path + "_rank_%s.segy" % (rank),
                   sourceY=[src_coords[1]],
                   groupY=coords[:, 1])
    def test_derivative_skew_symmetry(self, dtype, so):
        """
        We ensure that the first derivatives constructed with calls like
            f.dx(x0=x+0.5*x.spacing)
        Are skew (anti) symmetric. See the notebook ssa_01_iso_implementation.ipynb
        for more details.
        """
        np.random.seed(0)
        n = 101
        d = 1.0
        shape = (n, )
        origin = (0., )
        extent = (d * (n - 1), )

        # Initialize Devito grid and Functions for input(f1,g1) and output(f2,g2)
        grid1d = Grid(shape=shape, extent=extent, origin=origin, dtype=dtype)
        x = grid1d.dimensions[0]
        f1 = Function(name='f1', grid=grid1d, space_order=8)
        f2 = Function(name='f2', grid=grid1d, space_order=8)
        g1 = Function(name='g1', grid=grid1d, space_order=8)
        g2 = Function(name='g2', grid=grid1d, space_order=8)

        # Fill f1 and g1 with random values in [-1,+1]
        f1.data[:] = -1 + 2 * np.random.rand(n, )
        g1.data[:] = -1 + 2 * np.random.rand(n, )

        # Equation defining: [f2 = forward 1/2 cell shift derivative applied to f1]
        equation_f2 = Eq(f2, f1.dx(x0=x + 0.5 * x.spacing))

        # Equation defining: [g2 = backward 1/2 cell shift derivative applied to g1]
        equation_g2 = Eq(g2, g1.dx(x0=x - 0.5 * x.spacing))

        # Define an Operator to implement these equations and execute
        op = Operator([equation_f2, equation_g2])
        op()

        # Compute the dot products and the relative error
        f1g2 = np.dot(f1.data, g2.data)
        g1f2 = np.dot(g1.data, f2.data)
        diff = (f1g2 + g1f2) / (f1g2 - g1f2)

        info(
            "skew symmetry (so=%d) -- f1g2, g1f2, diff; %+16.10e %+16.10e %+16.10e"
            % (so, f1g2, g1f2, diff))
        assert np.isclose(diff, 0., atol=1.e-12)
    def test_adjoint_J(self, shape, dtype, so):
        """
        Test the Jacobian of the forward modeling operator by verifying for
        'random' dm, dr:
            dr . J(dm) = J^T(dr) . dm
        """
        np.random.seed(0)
        solver = acoustic_ssa_setup(shape=shape, dtype=dtype, space_order=so)

        src0 = solver.geometry.src

        m0 = Function(name='m0', grid=solver.model.grid, space_order=so)
        dm1 = Function(name='dm1', grid=solver.model.grid, space_order=so)
        m0.data[:] = 1.5

        # Model perturbation, box of random values centered on middle of model
        dm1.data[:] = 0
        size = 5
        ns = 2 * size + 1
        if len(shape) == 2:
            nx2, nz2 = shape[0] // 2, shape[1] // 2
            dm1.data[nx2-size:nx2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns)
        else:
            nx2, ny2, nz2 = shape[0] // 2, shape[1] // 2, shape[2] // 2
            nx, ny, nz = shape
            dm1.data[nx2-size:nx2+size, ny2-size:ny2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns, ns)

        # Data perturbation
        rec1 = solver.geometry.rec
        nt, nr = rec1.data.shape
        rec1.data[:] = np.random.rand(nt, nr)

        # Linearized modeling
        rec2, u0, _, _ = solver.jacobian_forward(dm1, src0, vp=m0, save=True)
        dm2, _, _, _ = solver.jacobian_adjoint(rec1, u0, vp=m0)

        sum_m = np.dot(dm1.data.reshape(-1), dm2.data.reshape(-1))
        sum_d = np.dot(rec1.data.reshape(-1), rec2.data.reshape(-1))
        diff = (sum_m - sum_d) / (sum_m + sum_d)
        info(
            "adjoint J %s (so=%d) sum_m, sum_d, diff; %16.10e %+16.10e %+16.10e"
            % (shape, so, sum_m, sum_d, diff))
        assert np.isclose(diff, 0., atol=1.e-11)
Beispiel #13
0
    def test_linearity_forward_J(self, shape, dtype, so):
        """
        Test the linearity of the forward Jacobian of the forward modeling operator
        by verifying
            a J(dm) = J(a dm)
        """
        np.random.seed(0)
        solver = acoustic_sa_setup(shape=shape, dtype=dtype, space_order=so)

        src0 = solver.geometry.src

        m0 = Function(name='m0', grid=solver.model.grid, space_order=so)
        m1 = Function(name='m1', grid=solver.model.grid, space_order=so)
        m0.data[:] = 1.5

        # Model perturbation, box of random values centered on middle of model
        m1.data[:] = 0
        size = 5
        ns = 2 * size + 1
        if len(shape) == 2:
            nx2, nz2 = shape[0]//2, shape[1]//2
            m1.data[nx2-size:nx2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns)
        else:
            nx2, ny2, nz2 = shape[0]//2, shape[1]//2, shape[2]//2
            nx, ny, nz = shape
            m1.data[nx2-size:nx2+size, ny2-size:ny2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns, ns)

        a = np.random.rand()
        rec1, _, _, _ = solver.jacobian(m1, src0, vp=m0, save=True)
        rec1.data[:] = a * rec1.data[:]
        m1.data[:] = a * m1.data[:]
        rec2, _, _, _ = solver.jacobian(m1, src0, vp=m0)

        # Normalize by rms of rec2, to enable using abolute tolerance below
        rms2 = np.sqrt(np.mean(rec2.data**2))
        diff = (rec1.data - rec2.data) / rms2
        info("linearity forward J %s (so=%d) rms 1,2,diff; "
             "%+16.10e %+16.10e %+16.10e" %
             (shape, so, np.sqrt(np.mean(rec1.data**2)), np.sqrt(np.mean(rec2.data**2)),
              np.sqrt(np.mean(diff**2))))
        tol = 1.e-12
        assert np.allclose(diff, 0.0, atol=tol)
Beispiel #14
0
    def test_array_reduction(self, so, dim):
        """
        Test generation of OpenMP reduction clauses involving Function's.
        """
        grid = Grid(shape=(3, 3, 3))
        d = grid.dimensions[dim]

        f = Function(name='f',
                     shape=(3, ),
                     dimensions=(d, ),
                     grid=grid,
                     space_order=so)
        u = TimeFunction(name='u', grid=grid)

        op = Operator(Inc(f, u + 1),
                      opt=('openmp', {
                          'par-collapse-ncores': 1
                      }))

        iterations = FindNodes(Iteration).visit(op)
        parallelized = iterations[dim + 1]
        assert parallelized.pragmas
        if parallelized is iterations[-1]:
            # With the `f[z] += u[t0][x + 1][y + 1][z + 1] + 1` expr, the innermost
            # `z` Iteration gets parallelized, nothing is collapsed, hence no
            # reduction is required
            assert "reduction" not in parallelized.pragmas[0].value
        elif Ompizer._support_array_reduction(configuration['compiler']):
            assert "reduction(+:f[0:f_vec->size[0]])" in parallelized.pragmas[
                0].value
        else:
            # E.g. old GCC's
            assert "atomic update" in str(iterations[-1])

        try:
            op(time_M=1)
        except:
            # Older gcc <6.1 don't support reductions on array
            info("Un-supported older gcc version for array reduction")
            assert True
            return

        assert np.allclose(f.data, 18)
Beispiel #15
0
    def test_adjoint_F(self, shape, dtype, so):
        """
        Test the forward modeling operator by verifying for random s, r:
            r . F(s) = F^T(r) . s
        """
        solver = acoustic_sa_setup(shape=shape, dtype=dtype, space_order=so)
        src1 = solver.geometry.src
        rec1 = solver.geometry.rec

        rec2, _, _ = solver.forward(src1)
        # flip sign of receiver data for adjoint to make it interesting
        rec1.data[:] = rec2.data[:]
        src2, _, _ = solver.adjoint(rec1)
        sum_s = np.dot(src1.data.reshape(-1), src2.data.reshape(-1))
        sum_r = np.dot(rec1.data.reshape(-1), rec2.data.reshape(-1))
        diff = (sum_s - sum_r) / (sum_s + sum_r)
        info("adjoint F %s (so=%d) sum_s, sum_r, diff; %+16.10e %+16.10e %+16.10e" %
             (shape, so, sum_s, sum_r, diff))
        assert np.isclose(diff, 0., atol=1.e-12)
Beispiel #16
0
def run_jit_backdoor(problem, **kwargs):
    """
    A single run using the DEVITO_JIT_BACKDOOR to test kernel customization.
    """
    configuration['develop-mode'] = False

    setup = model_type[problem]['setup']

    time_order = kwargs.pop('time_order')[0]
    space_order = kwargs.pop('space_order')[0]
    autotune = kwargs.pop('autotune')

    info("Preparing simulation...")
    solver = setup(space_order=space_order, time_order=time_order, **kwargs)

    # Generate code (but do not JIT yet)
    op = solver.op_fwd()

    # Get the filename in the JIT cache
    cfile = "%s.c" % str(op._compiler.get_jit_dir().joinpath(op._soname))

    if not os.path.exists(cfile):
        # First time we run this problem, let's generate and jit-compile code
        op.cfunction
        info("You may now edit the generated code in `%s`. "
             "Then save the file, and re-run this benchmark." % cfile)
        return

    info("Running wave propagation Operator...")

    @switchconfig(jit_backdoor=True)
    def _run_jit_backdoor():
        return solver.forward(autotune=autotune)

    return _run_jit_backdoor()
Beispiel #17
0
    def test_linearity_forward_F(self, shape, dtype, so):
        """
        Test the linearity of the forward modeling operator by verifying:
            a F(s) = F(a s)
        """
        solver = acoustic_sa_setup(shape=shape, dtype=dtype, space_order=so)
        src = solver.geometry.src

        a = -1 + 2 * np.random.rand()
        rec1, _, _ = solver.forward(src)
        src.data[:] *= a
        rec2, _, _ = solver.forward(src)
        rec1.data[:] *= a

        # Check receiver wavefeild linearity
        # Normalize by rms of rec2, to enable using abolute tolerance below
        rms2 = np.sqrt(np.mean(rec2.data**2))
        diff = (rec1.data - rec2.data) / rms2
        info("linearity forward F %s (so=%d) rms 1,2,diff; "
             "%+16.10e %+16.10e %+16.10e" %
             (shape, so, np.sqrt(np.mean(rec1.data**2)), np.sqrt(np.mean(rec2.data**2)),
              np.sqrt(np.mean(diff**2))))
        tol = 1.e-12
        assert np.allclose(diff, 0.0, atol=tol)
Beispiel #18
0
def run(shape=(50, 50, 50), spacing=(20.0, 20.0, 20.0), tn=250.0,
        autotune=False, space_order=4, nbl=10, preset='layers-tti',
        kernel='centered', full_run=False, checkpointing=False, **kwargs):

    solver = tti_setup(shape=shape, spacing=spacing, tn=tn, space_order=space_order,
                       nbl=nbl, kernel=kernel, preset=preset, **kwargs)

    info("Applying Forward")
    # Whether or not we save the whole time history. We only need the full wavefield
    # with 'save=True' if we compute the gradient without checkpointing, if we use
    # checkpointing, PyRevolve will take care of the time history
    save = full_run and not checkpointing
    # Define receiver geometry (spread across `x, y`` just below surface)
    rec, u, v, summary = solver.forward(save=save, autotune=autotune)

    if preset == 'constant':
        # With  a new m as Constant
        v0 = Constant(name="v", value=2.0, dtype=np.float32)
        solver.forward(save=save, vp=v0)
        # With a new vp as a scalar value
        solver.forward(save=save, vp=2.0)

    if not full_run:
        return summary.gflopss, summary.oi, summary.timings, [rec, u, v]

    # Smooth velocity
    initial_vp = Function(name='v0', grid=solver.model.grid, space_order=space_order)
    smooth(initial_vp, solver.model.vp)
    dm = np.float32(initial_vp.data**(-2) - solver.model.vp.data**(-2))

    info("Applying Adjoint")
    solver.adjoint(rec, autotune=autotune)
    info("Applying Born")
    solver.jacobian(dm, autotune=autotune)
    info("Applying Gradient")
    solver.jacobian_adjoint(rec, u, v, autotune=autotune, checkpointing=checkpointing)

    return summary.gflopss, summary.oi, summary.timings, [rec, u, v]
Beispiel #19
0
def chain_contractions(A, B, C, D, E, F, optimize):
    """``AB + AC = D, DE = F``."""
    op = Operator([Eq(D, A*B + A*C), Eq(F, D*E)], dle=optimize)
    op.apply()
    info('Executed `AB + AC = D, DE = F`')
Beispiel #20
0
def mat_mat_sum(A, B, C, D, optimize):
    """``AB + AC = D``."""
    op = Operator(Eq(D, A*B + A*C), dle=optimize)
    op.apply()
    info('Executed `AB + AC = D`')
Beispiel #21
0
def mat_mat(A, B, C, optimize):
    """``AB = C``."""
    op = Operator(Eq(C, A*B), dle=optimize)
    op.apply()
    info('Executed `AB = C`')
Beispiel #22
0
def transpose_mat_vec(A, x, b, optimize):
    """``A -> A^T, A^Tx = b``."""
    i, j = A.indices
    op = Operator([Eq(b, A.indexed[j, i]*x)], dle=optimize)
    op.apply()
    info('Executed `A^Tx = b`')
Beispiel #23
0
def mat_vec(A, x, b, optimize):
    """``Ax = b``."""
    op = Operator(Eq(b, A*x), dle=optimize)
    op.apply()
    info('Executed `Ax = b`')
Beispiel #24
0
    def test_gradientFWI(self, shape, kernel, space_order, checkpointing):
        """
        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.
        :param dimensions: size of the domain in all dimensions
        in number of grid points
        :param time_order: order of the time discretization scheme
        :param space_order: order of the spacial discretization scheme
        :return: assertion that the Taylor properties are satisfied
        """
        spacing = tuple(10. for _ in shape)
        wave = setup(shape=shape,
                     spacing=spacing,
                     dtype=np.float64,
                     kernel=kernel,
                     space_order=space_order,
                     nbpml=40)

        m0 = Function(name='m0',
                      grid=wave.model.m.grid,
                      space_order=space_order)
        m0.data[:] = smooth10(wave.model.m.data, wave.model.m.shape_domain)
        dm = np.float32(wave.model.m.data - m0.data)

        # Compute receiver data for the true velocity
        rec, u, _ = wave.forward()

        # Compute receiver data and full wavefield for the smooth velocity
        rec0, u0, _ = wave.forward(m=m0, save=True)

        # Objective function value
        F0 = .5 * linalg.norm(rec0.data - rec.data)**2

        # Gradient: <J^T \delta d, dm>
        residual = Receiver(name='rec',
                            grid=wave.model.grid,
                            data=rec0.data - rec.data,
                            time_range=rec.time_range,
                            coordinates=rec0.coordinates.data)

        gradient, _ = wave.gradient(residual,
                                    u0,
                                    m=m0,
                                    checkpointing=checkpointing)
        G = np.dot(gradient.data.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
            def initializer(data):
                data[:] = m0.data + H[i] * dm

            mloc = Function(name='mloc',
                            grid=wave.model.m.grid,
                            space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(m=mloc)[0]
            # First order error Phi(m0+dm) - Phi(m0)
            error1[i] = np.absolute(.5 * linalg.norm(d.data - rec.data)**2 -
                                    F0)
            # Second order term r Phi(m0+dm) - Phi(m0) - <J(m0)^T \delta d, dm>
            error2[i] = np.absolute(.5 * linalg.norm(d.data - rec.data)**2 -
                                    F0 - 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('2nd order error, Phi(m0+dm)-Phi(m0) - <J(m0)^T \delta d, dm>: %s'
             % (p2))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #25
0
    def test_gradientFWI(self, shape, kernel, space_order, checkpointing):
        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.
        """
        spacing = tuple(10. for _ in shape)
        wave = setup(shape=shape, spacing=spacing, dtype=np.float64,
                     kernel=kernel, space_order=space_order,
                     nbpml=40)

        m0 = Function(name='m0', grid=wave.model.grid, space_order=space_order)
        smooth(m0, wave.model.m)
        dm = np.float32(wave.model.m.data[:] - m0.data[:])

        # Compute receiver data for the true velocity
        rec, u, _ = wave.forward()

        # Compute receiver data and full wavefield for the smooth velocity
        rec0, u0, _ = wave.forward(m=m0, save=True)

        # Objective function value
        F0 = .5*linalg.norm(rec0.data - rec.data)**2

        # Gradient: <J^T \delta d, dm>
        residual = Receiver(name='rec', grid=wave.model.grid, data=rec0.data - rec.data,
                            time_range=wave.geometry.time_axis,
                            coordinates=wave.geometry.rec_positions)

        gradient, _ = wave.gradient(residual, u0, m=m0, checkpointing=checkpointing)
        G = np.dot(gradient.data.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
            def initializer(data):
                data[:] = m0.data + H[i] * dm
            mloc = Function(name='mloc', grid=wave.model.m.grid, space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(m=mloc)[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)

        # 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))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #26
0
def run(problem, **kwargs):
    """
    A single run with a specific set of performance parameters.
    """
    setup = model_type[problem]['setup']
    options = {}

    time_order = kwargs.pop('time_order')[0]
    space_order = kwargs.pop('space_order')[0]
    autotune = kwargs.pop('autotune')
    options['autotune'] = autotune
    block_shapes = as_tuple(kwargs.pop('block_shape'))
    operator = kwargs.pop('operator', 'forward')
    warmup = kwargs.pop('warmup')

    # Should a specific block-shape be used? Useful if one wants to skip
    # the autotuning pass as a good block-shape is already known
    # Note: the following piece of code is horribly *hacky*, but it works for now
    for i, block_shape in enumerate(block_shapes):
        for n, level in enumerate(block_shape):
            for d, s in zip(['x', 'y', 'z'], level):
                options['%s%d_blk%d_size' % (d, i, n)] = s

    solver = setup(space_order=space_order, time_order=time_order, **kwargs)
    if warmup:
        info("Performing warm-up run ...")
        set_log_level('ERROR', comm=MPI.COMM_WORLD)
        run_op(solver, operator, **options)
        set_log_level('DEBUG', comm=MPI.COMM_WORLD)
        info("DONE!")
    retval = run_op(solver, operator, **options)

    try:
        rank = MPI.COMM_WORLD.rank
    except AttributeError:
        # MPI not available
        rank = 0

    dumpfile = kwargs.pop('dump_summary')
    if dumpfile:
        if configuration['profiling'] != 'advanced':
            raise RuntimeError(
                "Must set DEVITO_PROFILING=advanced (or, alternatively, "
                "DEVITO_LOGGING=PERF) with --dump-summary")
        if rank == 0:
            with open(dumpfile, 'w') as f:
                summary = retval[-1]
                assert isinstance(summary, PerformanceSummary)
                f.write(str(summary.globals_all))

    dumpfile = kwargs.pop('dump_norms')
    if dumpfile:
        norms = [
            "'%s': %f" % (i.name, norm(i)) for i in retval[:-1]
            if isinstance(i, DiscreteFunction)
        ]
        if rank == 0:
            with open(dumpfile, 'w') as f:
                f.write("{%s}" % ', '.join(norms))

    return retval
Beispiel #27
0
    def test_linearization_F(self, shape, dtype, so):
        """
        Test the linearization of the forward modeling operator by verifying
        for sequence of h decreasing that the error in the linearization E is
        of second order.

            E = 0.5 || F(m + h   dm) - F(m) - h   J(dm) ||^2

        This is done by fitting a 1st order polynomial to the norms
        """
        np.random.seed(0)
        solver = acoustic_sa_setup(shape=shape, dtype=dtype, space_order=so)
        src = solver.geometry.src

        # Create Functions for models and perturbation
        m0 = Function(name='m0', grid=solver.model.grid, space_order=so)
        mm = Function(name='mm', grid=solver.model.grid, space_order=so)
        dm = Function(name='dm', grid=solver.model.grid, space_order=so)

        # Background model
        m0.data[:] = 1.5

        # Model perturbation, box of random values centered on middle of model
        dm.data[:] = 0
        size = 5
        ns = 2 * size + 1
        if len(shape) == 2:
            nx2, nz2 = shape[0]//2, shape[1]//2
            dm.data[nx2-size:nx2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns)
        else:
            nx2, ny2, nz2 = shape[0]//2, shape[1]//2, shape[2]//2
            nx, ny, nz = shape
            dm.data[nx2-size:nx2+size, ny2-size:ny2+size, nz2-size:nz2+size] = \
                -1 + 2 * np.random.rand(ns, ns, ns)

        # Compute F(m + dm)
        rec0, u0, summary0 = solver.forward(src, vp=m0)

        # Compute J(dm)
        rec1, u1, du, summary1 = solver.jacobian(dm, src=src, vp=m0)

        # Linearization test via polyfit (see devito/tests/test_gradient.py)
        # Solve F(m + h dm) for sequence of decreasing h
        dh = np.sqrt(2.0)
        h = 0.1
        nstep = 7
        scale = np.empty(nstep)
        norm1 = np.empty(nstep)
        norm2 = np.empty(nstep)
        for kstep in range(nstep):
            h = h / dh
            mm.data[:] = m0.data + h * dm.data
            rec2, _, _ = solver.forward(src, vp=mm)
            scale[kstep] = h
            norm1[kstep] = 0.5 * np.linalg.norm(rec2.data - rec0.data)**2
            norm2[kstep] = 0.5 * np.linalg.norm(rec2.data - rec0.data - h * rec1.data)**2

        # Fit 1st order polynomials to the error sequences
        #   Assert the 1st order error has slope dh^2
        #   Assert the 2nd order error has slope dh^4
        p1 = np.polyfit(np.log10(scale), np.log10(norm1), 1)
        p2 = np.polyfit(np.log10(scale), np.log10(norm2), 1)
        info("linearization F %s (so=%d) 1st (%.1f) = %.4f, 2nd (%.1f) = %.4f" %
             (shape, so, dh**2, p1[0], dh**4, p2[0]))

        # we only really care the 2nd order err is valid, not so much the 1st order error
        assert np.isclose(p1[0], dh**2, rtol=0.25)
        assert np.isclose(p2[0], dh**4, rtol=0.10)
Beispiel #28
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)
Beispiel #29
0
def mat_vec(A, x, b, optimize):
    """``Ax = b``."""
    op = Operator(Inc(b, A*x), dle=optimize)
    op.apply()
    info('Executed `Ax = b`')
Beispiel #30
0
def transpose_mat_vec(A, x, b, optimize):
    """``A -> A^T, A^Tx = b``."""
    i, j = A.indices
    op = Operator([Inc(b, A[j, i]*x)], dle=optimize)
    op.apply()
    info('Executed `A^Tx = b`')
Beispiel #31
0
def mat_mat(A, B, C, optimize):
    """``AB = C``."""
    op = Operator(Inc(C, A*B), dle=optimize)
    op.apply()
    info('Executed `AB = C`')
Beispiel #32
0
def mat_mat_sum(A, B, C, D, optimize):
    """``AB + AC = D``."""
    op = Operator(Inc(D, A*B + A*C), dle=optimize)
    op.apply()
    info('Executed `AB + AC = D`')
Beispiel #33
0
def chain_contractions(A, B, C, D, E, F, optimize):
    """``AB + AC = D, DE = F``."""
    op = Operator([Inc(D, A*B + A*C), Inc(F, D*E)], dle=optimize)
    op.apply()
    info('Executed `AB + AC = D, DE = F`')
Beispiel #34
0
    def test_gradientFWI(self, dtype, space_order, kernel, shape, ckp,
                         setup_func, time_order):
        """
        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.
        """
        spacing = tuple(10. for _ in shape)
        wave = setup_func(shape=shape,
                          spacing=spacing,
                          dtype=dtype,
                          kernel=kernel,
                          tn=400.0,
                          space_order=space_order,
                          nbl=40,
                          time_order=time_order)

        vel0 = Function(name='vel0',
                        grid=wave.model.grid,
                        space_order=space_order)
        smooth(vel0, wave.model.vp)
        v = wave.model.vp.data
        dm = dtype(wave.model.vp.data**(-2) - vel0.data**(-2))
        # Compute receiver data for the true velocity
        rec = wave.forward()[0]

        # Compute receiver data and full wavefield for the smooth velocity
        if setup_func is tti_setup:
            rec0, u0, v0, _ = wave.forward(vp=vel0, save=True)
        else:
            rec0, u0 = wave.forward(vp=vel0, save=True)[0:2]

        # Objective function value
        F0 = .5 * linalg.norm(rec0.data - rec.data)**2

        # Gradient: <J^T \delta d, dm>
        residual = Receiver(name='rec',
                            grid=wave.model.grid,
                            data=rec0.data - rec.data,
                            time_range=wave.geometry.time_axis,
                            coordinates=wave.geometry.rec_positions)

        if setup_func is tti_setup:
            gradient, _ = wave.jacobian_adjoint(residual,
                                                u0,
                                                v0,
                                                vp=vel0,
                                                checkpointing=ckp)
        else:
            gradient, _ = wave.jacobian_adjoint(residual,
                                                u0,
                                                vp=vel0,
                                                checkpointing=ckp)

        G = np.dot(gradient.data.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
            def initializer(data):
                data[:] = np.sqrt(vel0.data**2 * v**2 /
                                  ((1 - H[i]) * v**2 + H[i] * vel0.data**2))

            vloc = Function(name='vloc',
                            grid=wave.model.grid,
                            space_order=space_order,
                            initializer=initializer)
            # Data for the new model
            d = wave.forward(vp=vloc)[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)

        # 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))
        assert np.isclose(p1[0], 1.0, rtol=0.1)
        assert np.isclose(p2[0], 2.0, rtol=0.1)
Beispiel #35
0
    def test_analytic_comparison_2d(self, dtype, so):
        """
        Wnsure that the farfield response from the propagator matches analytic reponse
        in a wholespace.
        """
        # Setup time / frequency
        nt = 1001
        dt = 0.1
        tmin = 0.0
        tmax = dt * (nt - 1)
        fpeak = 0.090
        t0w = 1.0 / fpeak
        omega = 2.0 * np.pi * fpeak

        # Model
        space_order = 8
        npad = 50
        dx = 0.5
        shape = (801, 801)
        dtype = np.float64
        qmin = 0.1
        qmax = 100000
        v0 = 1.5
        init_damp = lambda fu, nbl: setup_w_over_q(fu, omega, qmin, qmax, nbl, sigma=0)
        o = tuple([0]*len(shape))
        spacing = tuple([dx]*len(shape))
        model = Model(origin=o, shape=shape, vp=v0, b=1.0, spacing=spacing, nbl=npad,
                      space_order=space_order, bcs=init_damp)

        # Source and reciver coordinates
        src_coords = np.empty((1, 2), dtype=dtype)
        rec_coords = np.empty((1, 2), dtype=dtype)
        src_coords[0, :] = np.array(model.domain_size) * .5
        rec_coords[0, :] = np.array(model.domain_size) * .5 + 60
        geometry = AcquisitionGeometry(model, rec_coords, src_coords,
                                       t0=0.0, tn=tmax, src_type='Ricker', f0=fpeak)

        # Solver setup
        solver = SaIsoAcousticWaveSolver(model, geometry, space_order=space_order)

        # Numerical solution
        recNum, uNum, _ = solver.forward()

        # Analytic response
        def analytic_response():
            """
            Computes analytic solution of 2D acoustic wave-equation with Ricker wavelet
            peak frequency fpeak, temporal padding 20x per the accuracy notebook:
            examples/seismic/acoustic/accuracy.ipynb
                u(r,t) = 1/(2 pi) sum[ -i pi H_0^2(k,r) q(w) e^{i w t} dw
                where:
                    r = sqrt{(x_s - x_r)^2 + (z_s - z_r)^2}
                    w = 2 pi f
                    q(w) = Fourier transform of Ricker source wavelet
                    H_0^2(k,r) Hankel function of the second kind
                    k = w/v (wavenumber)
            """
            sx, sz = src_coords[0, :]
            rx, rz = rec_coords[0, :]
            ntpad = 20 * (nt - 1) + 1
            tmaxpad = dt * (ntpad - 1)
            time_axis_pad = TimeAxis(start=tmin, stop=tmaxpad, step=dt)
            srcpad = RickerSource(name='srcpad', grid=model.grid, f0=fpeak, npoint=1,
                                  time_range=time_axis_pad, t0w=t0w)
            nf = int(ntpad / 2 + 1)
            df = 1.0 / tmaxpad
            faxis = df * np.arange(nf)

            # Take the Fourier transform of the source time-function
            R = np.fft.fft(srcpad.wavelet[:])
            R = R[0:nf]
            nf = len(R)

            # Compute the Hankel function and multiply by the source spectrum
            U_a = np.zeros((nf), dtype=complex)
            for a in range(1, nf - 1):
                w = 2 * np.pi * faxis[a]
                r = np.sqrt((rx - sx)**2 + (rz - sz)**2)
                U_a[a] = -1j * np.pi * hankel2(0.0, w * r / v0) * R[a]

            # Do inverse fft on 0:dt:T and you have analytical solution
            U_t = 1.0/(2.0 * np.pi) * np.real(np.fft.ifft(U_a[:], ntpad))

            # Note that the analytic solution is scaled by dx^2 to convert to pressure
            return (np.real(U_t) * (dx**2)), srcpad

        uAnaPad, srcpad = analytic_response()
        uAna = uAnaPad[0:nt]

        # Compute RMS and difference
        diff = (recNum.data - uAna)
        nrms = np.max(np.abs(recNum.data))
        arms = np.max(np.abs(uAna))
        drms = np.max(np.abs(diff))

        info("Maximum absolute numerical,analytic,diff; %+12.6e %+12.6e %+12.6e" %
             (nrms, arms, drms))

        # This isnt a very strict tolerance ...
        tol = 0.1
        assert np.allclose(diff, 0.0, atol=tol)