예제 #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_ssa_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)
예제 #2
0
    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)
예제 #3
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_ssa_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)
예제 #4
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_ssa_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)
예제 #5
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_ssa_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)
예제 #6
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_ssa_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)