Beispiel #1
0
def test_fourier_synthesis_1D_input():
    H = 0.7
    c0 = 1.

    n = 512
    s = n * 4.
    ls = 8
    np.random.seed(0)
    fourier_synthesis((n, ), (s, ),
                      H,
                      c0=c0,
                      long_cutoff=s / 2,
                      short_cutoff=ls,
                      amplitude_distribution=lambda n: np.ones(n))
Beispiel #2
0
def test_shortcut_vs_isotropic_filter():
    print(SurfaceTopography.__file__)
    n = 100
    # t = SurfaceTopography(np.zeros(n,n), (2,3))
    np.random.seed(0)
    t = fourier_synthesis((n, n), (13, 13), 0.9, 1.)

    cutoff_wavevector = 2 * np.pi / 13 * 0.4 * n
    hc = t.shortcut(cutoff_wavevector=cutoff_wavevector)
    fhc = t.filter(filter_function=lambda q: q <= cutoff_wavevector)

    assert hc.is_filter_isotropic
    assert fhc.is_filter_isotropic
    if False:
        import matplotlib.pyplot as plt

        fig, ax = plt.subplots()
        ax.loglog(*hc.power_spectrum_2D(), "+", label="shortcut")
        ax.loglog(*fhc.power_spectrum_2D(), "x", label="filter")

        ax.loglog(*t.power_spectrum_2D(), label="original")
        ax.legend()
        fig.show()

    np.testing.assert_allclose(fhc.heights(), hc.heights())
def test_uniform_scaled_topography():
    surf = fourier_synthesis((5, 7), (1.2, 1.1), 0.8, rms_height=1)
    sx, sy = surf.physical_sizes
    for fac in [1.0, 2.0, np.pi]:
        surf2 = surf.scale(fac)
        np.testing.assert_almost_equal(fac * surf.rms_height_from_profile(),
                                       surf2.rms_height_from_profile())
        np.testing.assert_almost_equal(surf.positions(), surf2.positions())

        surf2 = surf.scale(fac, 2 * fac)
        np.testing.assert_almost_equal(fac * surf.rms_height_from_profile(),
                                       surf2.rms_height_from_profile())

        sx2, sy2 = surf2.physical_sizes
        np.testing.assert_almost_equal(2 * fac * sx, sx2)
        np.testing.assert_almost_equal(2 * fac * sy, sy2)

        x, y = surf.positions()
        x2, y2 = surf2.positions()
        np.testing.assert_almost_equal(2 * fac * x, x2)
        np.testing.assert_almost_equal(2 * fac * y, y2)

        x2, y2, h2 = surf2.positions_and_heights()
        np.testing.assert_almost_equal(2 * fac * x, x2)
        np.testing.assert_almost_equal(2 * fac * y, y2)
def test_wrapped_bicubic_vs_fourier(sx, sy):
    # test against fourier interpolation
    # sx and sy are varied to ensure the unit conversions of the slopes are
    # correct

    nx, ny = [35, 42]

    hc = 0.2 * sx
    np.random.seed(0)
    topography = fourier_synthesis(
        (nx, ny),
        (sx, sy),
        0.8,
        rms_height=1.,
        short_cutoff=hc,
        long_cutoff=hc + 1e-9,
    )
    topography = topography.scale(1 / topography.rms_height())
    interp = topography.interpolate_bicubic()

    fine_topography = topography.interpolate_fourier((4 * nx, 4 * ny))

    interp_height, interp_slopex, interp_slopey = interp(
        *fine_topography.positions(), derivative=1)
    np.testing.assert_allclose(interp_height,
                               fine_topography.heights(),
                               atol=1e-2)
    derx, dery = fine_topography.fourier_derivative()
    rms_slope = topography.rms_slope()
    np.testing.assert_allclose(interp_slopex, derx, atol=1e-1 * rms_slope)
    np.testing.assert_allclose(interp_slopey, dery, atol=1e-1 * rms_slope)
def test_rms_slope_from_area():
    r = 2048
    res = [r, r]
    for H in [0.3, 0.8]:
        for s in [(1, 1), (1.4, 3.3)]:
            t = fourier_synthesis(res,
                                  s,
                                  H,
                                  short_cutoff=8 / r * np.mean(s),
                                  rms_slope=0.1,
                                  amplitude_distribution=lambda n: 1.0)
            last_rms_slope = t.rms_gradient()
            np.testing.assert_almost_equal(last_rms_slope, 0.1, decimal=2)
            np.testing.assert_almost_equal(last_rms_slope,
                                           t.scale(1.3).rms_gradient() / 1.3)
            np.testing.assert_almost_equal(last_rms_slope,
                                           t.scale(1.3, 1.3).rms_gradient())
            # rms slope should not depend on filter for these cutoffs...
            for cutoff in [4]:
                rms_slope = t.rms_gradient(short_wavelength_cutoff=s[0] / r *
                                           cutoff)
                np.testing.assert_almost_equal(rms_slope, last_rms_slope)
            # ...but starts being a monotonously decreasing function here
            for cutoff in [16, 32]:
                rms_slope = t.rms_gradient(short_wavelength_cutoff=s[0] / r *
                                           cutoff)
                assert rms_slope < last_rms_slope
                last_rms_slope = rms_slope
def test_load_no_physical_sizes(comm_self):
    nb_grid_pts = (128, 128)
    size = (3, 3)

    np.random.seed(1)
    t = fourier_synthesis(nb_grid_pts, size, 0.8, rms_slope=0.1)

    # Topographies always have physical size information, we need to create a
    # NetCDF file without any manually
    with Dataset('no_physical_sizes.nc', 'w', format='NETCDF3_CLASSIC') as nc:
        nc.createDimension('x', nb_grid_pts[0])
        nc.createDimension('y', nb_grid_pts[1])
        nc.createVariable('heights', 'f8', ('x', 'y'))
        nc.variables['heights'] = t.heights()

    # Attempt to open full file on each process
    # with pytest.raises(ValueError):
    #    # This raises an error because the physical sizes are not present
    #    t2 = read_topography('no_physical_sizes.nc')
    t2 = read_topography('no_physical_sizes.nc', physical_sizes=size)

    assert t.physical_sizes == t2.physical_sizes
    assert 'unit' not in t2.info
    np.testing.assert_array_almost_equal(t.heights(), t2.heights())

    os.remove('no_physical_sizes.nc')
Beispiel #7
0
def test_fourier_synthesis_linescan_c0(n):
    H = 0.7
    c0 = 8.

    s = n * 4.
    ls = 32
    qs = 2 * np.pi / ls
    np.random.seed(0)
    t = fourier_synthesis((n, ), (s, ),
                          c0=c0,
                          hurst=H,
                          long_cutoff=s / 2,
                          short_cutoff=ls,
                          amplitude_distribution=lambda n: np.ones(n))

    if False:
        import matplotlib.pyplot as plt
        q, psd = t.power_spectrum_1D()

        fig, ax = plt.subplots()
        ax.plot(q, psd)
        ax.plot(q, c0 * q**(-1 - 2 * H))

        ax.set_xscale("log")
        ax.set_yscale("log")

        ax.set_ylim(bottom=1)
        fig.show()

    ref_slope = np.sqrt(1 / (2 * np.pi) * c0 / (1 - H) * qs**(2 - 2 * H))
    assert abs(t.rms_slope() - ref_slope) / ref_slope < 1e-1
Beispiel #8
0
def test_fourier_synthesis_rms_height_more_wavevectors(comm_self):
    """
    Set amplitude to 0 (rolloff = 0) outside the self affine region.

    Long cutoff wavelength is smaller then the box size so that we get closer
    to a continuum of wavevectors
    """
    n = 256
    H = 0.74
    rms_height = 7.
    s = 1.

    realised_rms_heights = []
    for i in range(50):
        topography = fourier_synthesis(
            (n, n),
            (s, s),
            H,
            rms_height=rms_height,
            rolloff=0,
            long_cutoff=s / 8,
            short_cutoff=4 * s / n,
            # amplitude_distribution=lambda n: np.ones(n)
        )

        realised_rms_heights.append(topography.rms_height())
    # print(abs(np.mean(realised_rms_heights) - rms_height) / rms_height)
    # TODO: this is not very accurate !
    assert abs(np.mean(realised_rms_heights) - rms_height) / rms_height < 0.1
Beispiel #9
0
def test_fourier_synthesis_linescan_hrms_more_wavevectors():
    """
    Set amplitude to 0 (rolloff = 0) outside the self affine region.

    Long cutoff wavelength is smaller then the box size so that we get closer
    to a continuum of wavevectors
    """
    H = 0.7
    hrms = 4.
    n = 4096
    s = n * 4.
    ls = 8
    np.random.seed(0)
    realised_rms_heights = []
    for i in range(50):
        t = fourier_synthesis(
            (n, ),
            (s, ),
            rms_height=hrms,
            hurst=H,
            rolloff=0,
            long_cutoff=s / 8,
            short_cutoff=ls,
        )
        realised_rms_heights.append(t.rms_height())
    realised_rms_heights = np.array(realised_rms_heights)
    ref_height = hrms
    # print(np.sqrt(np.mean(
    # (realised_rms_heights - np.mean(realised_rms_heights))**2)))
    assert abs(np.mean(realised_rms_heights) -
               ref_height) / ref_height < 0.1  #
def test_delegation():
    t1 = fourier_synthesis((128,), (1,), 0.8, rms_slope=0.1)
    t2 = t1.detrend()
    t3 = t2.to_nonuniform()
    t4 = t3.scale(2.0)

    t4.scale_factor
    with pytest.raises(AttributeError):
        t2.scale_factor
    t2.detrend_mode
    # detrend_mode should not be delegated to the parent class
    with pytest.raises(AttributeError):
        t4.detrend_mode

    # t2 should have 'to_nonuniform'
    t2.to_nonuniform()
    # but it should not have 'to_uniform'
    with pytest.raises(AttributeError):
        t2.to_uniform(100, 10)

    # t4 should have 'to_uniform'
    t5 = t4.to_uniform(100, 10)
    # but it should not have 'to_nonuniform'
    with pytest.raises(AttributeError):
        t4.to_nonuniform()

    # t5 should have 'to_nonuniform'
    t5.to_nonuniform()
    # but it should not have 'to_uniform'
    with pytest.raises(AttributeError):
        t5.to_uniform(100, 10)
def test_uniform_vs_nonuniform():
    t1 = fourier_synthesis([12], [6], 0.8, rms_slope=0.1, periodic=False)
    t2 = t1.to_nonuniform()

    d1 = t1.derivative(1)
    d2 = t2.derivative(1)

    np.testing.assert_allclose(d1, d2)
def test_q0_1D():
    surf = fourier_synthesis([1024, 512], [2.3, 1.5], 0.8, rms_height=0.87)
    rms_height = surf.rms_height_from_profile(
    )  # Need to measure it since it can fluctuate wildly
    q, C = surf.power_spectrum_from_profile()
    ratio = rms_height**2 / (np.trapz(C, q) / np.pi)
    assert ratio > 0.2
    assert ratio < 5
Beispiel #13
0
def test_scale_dependent_rms_slope_from_profile():
    t = fourier_synthesis((1024, 1024), (1, 1), 0.8, rms_slope=0.1)

    x, A = t.autocorrelation_from_profile()

    s = t.scale_dependent_statistical_property(lambda x, y: np.var(x), distance=x[1::20])

    np.testing.assert_allclose(2*A[1::20]/x[1::20]**2, s)
def test_autocompletion():
    t1 = fourier_synthesis((128,), (1,), 0.8, rms_slope=0.1)
    t2 = t1.detrend()
    t3 = t2.to_nonuniform()

    assert 'detrend' in dir(t1)
    assert 'to_nonuniform' in dir(t2)
    assert 'to_uniform' in dir(t3)
Beispiel #15
0
def test_isotropic_1d():
    n = 32

    t = fourier_synthesis((n, ), (13, ), 0.9, 1.)

    cutoff_wavevector = 2 * np.pi / 13 * n / 4
    q, psd = t.filter(
        filter_function=lambda q: q > cutoff_wavevector).power_spectrum_1D()
    assert (psd[q < 0.9 * cutoff_wavevector] < 1e-10).all()
def test_q0_2D():
    surf = fourier_synthesis([1024, 512], [2.3, 1.5], 0.8, rms_height=0.87)
    rms_height = surf.rms_height_from_area(
    )  # Need to measure it since it can fluctuate wildly
    q, C = surf.power_spectrum_from_area(nbins=200, bin_edges='quadratic')
    # This is really not quantitative, it's just checking whether it's the right ballpark.
    # Any bug in normalization would show up here as an order of magnitude
    ratio = rms_height**2 / (np.trapz(q * C, q) / np.pi)
    assert ratio > 0.2
    assert ratio < 5
 def test_noniform_mean_zero(self):
     surface = fourier_synthesis((512,), (1.3,), 0.8,
                                 rms_height=1).to_nonuniform()
     self.assertTrue(not surface.is_uniform)
     x, h = surface.positions_and_heights()
     s, = surface.physical_sizes
     self.assertAlmostEqual(surface.mean(), np.trapz(h, x) / s)
     detrended_surface = surface.detrend(detrend_mode='height')
     self.assertAlmostEqual(detrended_surface.mean(), 0)
     x, h = detrended_surface.positions_and_heights()
     self.assertAlmostEqual(np.trapz(h, x), 0)
 def test_randomly_rough(self):
     surface = fourier_synthesis((511, 511), (1., 1.), 0.8, rms_height=1)
     self.assertTrue(surface.is_uniform)
     cut = Topography(surface[:64, :64], physical_sizes=(64., 64.))
     self.assertTrue(cut.is_uniform)
     untilt1 = cut.detrend(detrend_mode='height')
     untilt2 = cut.detrend(detrend_mode='slope')
     self.assertTrue(untilt1.is_uniform)
     self.assertTrue(untilt2.is_uniform)
     self.assertTrue(untilt1.rms_height_from_area() < untilt2.rms_height_from_area())
     self.assertTrue(untilt1.rms_gradient() > untilt2.rms_gradient())
def test_third_derivatives_fourier_vs_finite_differences(plot=False):
    nx, ny = [512] * 2
    sx, sy = [1.] * 2

    lc = 0.5
    topography = fourier_synthesis((nx, ny), (sx, sy),
                                   0.8,
                                   rms_height=1.,
                                   short_cutoff=lc,
                                   long_cutoff=lc + 1e-9)
    topography = topography.scale(1 / topography.rms_height_from_area())

    # Fourier derivative
    dx3_topography = topography.filter(lambda qx, qy: (1j * qx)**3,
                                       isotropic=False)
    dx3 = dx3_topography.heights()
    dy3 = topography.filter(lambda qx, qy: (1j * qy)**3,
                            isotropic=False).heights()

    # Finite-differences. We use central differences because this produces the
    # derivative at the same point as the Fourier derivative
    dx3_num, dy3_num = topography.derivative(3, operator=third_2d)

    np.testing.assert_allclose(dx3,
                               dx3_num,
                               atol=dx3_topography.rms_height_from_area() *
                               1e-1)
    np.testing.assert_allclose(dy3,
                               dy3_num,
                               atol=dx3_topography.rms_height_from_area() *
                               1e-1)

    if plot:
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots()
        x, y = topography.positions()

        ax.plot(x[:, 0], topography.heights()[:, 0], label="height")
        ax.plot(x[:, 0], dx3[:, 0], label="fourier der")
        ax.plot(x[:, 0], dx3_num[:, 0], label="FD")
        ax.set_title("x")
        ax.legend()

        fig.show()

        fig, ax = plt.subplots()
        ax.set_title("y")
        x, y = topography.positions()
        ax.plot(y[-1, :], topography.heights()[-1, :], label="height")
        ax.plot(y[-1, :], dy3[-1, :], label="fourier der")
        ax.plot(y[-1, :], dy3_num[-1, :], label="FD")
        ax.legend()

        fig.show()
def test_transposed_topography():
    surf = fourier_synthesis([124, 368], [6, 3], 0.8, rms_slope=0.1)
    nx, ny = surf.nb_grid_pts
    sx, sy = surf.physical_sizes
    surf2 = surf.transpose()
    nx2, ny2 = surf2.nb_grid_pts
    sx2, sy2 = surf2.physical_sizes
    assert nx == ny2
    assert ny == nx2
    assert sx == sy2
    assert sy == sx2
    assert (surf.heights() == surf2.heights().T).all()
Beispiel #21
0
 def test_self_affine_topography_2d(self):
     r = 2048
     res = [r, r]
     for H in [0.3, 0.8]:
         t = fourier_synthesis(res, (1, 1), H, rms_slope=0.1,
                               amplitude_distribution=lambda n: 1.0)
         mag, bwidth, rms = t.variable_bandwidth(nb_grid_pts_cutoff=r // 32)
         self.assertAlmostEqual(rms[0], t.detrend().rms_height())
         # Since this is a self-affine surface, rms(mag) ~ mag^-H
         b, a = np.polyfit(np.log(mag[1:]), np.log(rms[1:]), 1)
         # The error is huge...
         self.assertTrue(abs(H + b) < 0.1)
def test_self_affine_uniform_autocorrelation():
    r = 2048
    s = 1
    H = 0.8
    slope = 0.1
    t = fourier_synthesis((r,), (s,), H, rms_slope=slope,
                          amplitude_distribution=lambda n: 1.0)

    r, A = t.autocorrelation_from_profile()

    m = np.logical_and(r > 1e-3, r < 10 ** (-1.5))
    b, a = np.polyfit(np.log(r[m]), np.log(A[m]), 1)
    assert abs(b / 2 - H) < 0.1
def test_nonuniform_rms_height():
    r = 128
    s = 1.3
    H = 0.8
    slope = 0.1
    t = fourier_synthesis((r,), (s,), H, rms_slope=slope,
                          amplitude_distribution=lambda n: 1.0) \
        .to_nonuniform().detrend(detrend_mode='center')
    assert_almost_equal(t.mean(), 0)

    r, A = height_height_autocorrelation(t, distances=[0])
    s, = t.physical_sizes
    assert_almost_equal(t.rms_height_from_profile() ** 2 * s, A[0])
def test_write():
    nx, ny = 1782, 1302
    t = fourier_synthesis((nx, ny), (1, 1), 0.8, rms_slope=0.1)
    with tempfile.TemporaryDirectory() as d:
        t.to_dzi('synthetic', d)
        assert os.path.exists(f'{d}/synthetic_files')
        for i in range(12):
            assert os.path.exists(f'{d}/synthetic_files/{i}')
        root = ET.parse(open(f'{d}/synthetic.xml')).getroot()
        assert root.attrib['TileSize'] == '256'
        assert root.attrib['Overlap'] == '1'
        assert root.attrib['Format'] == 'jpg'
        assert root[0].attrib['Width'] == f'{nx}'
        assert root[0].attrib['Height'] == f'{ny}'
Beispiel #25
0
    def test_self_affine_topography_1d(self):
        r = 16384
        for H in [0.3, 0.8]:
            t0 = fourier_synthesis((r,), (1,), H, rms_slope=0.1,
                                   amplitude_distribution=lambda n: 1.0)

            for t in [t0, t0.to_nonuniform()]:
                mag, bwidth, rms = t.variable_bandwidth(
                    nb_grid_pts_cutoff=r // 32)
                self.assertAlmostEqual(rms[0], t.detrend().rms_height())
                np.testing.assert_allclose(bwidth, t.physical_sizes[0] / mag)
                # Since this is a self-affine surface, rms(mag) ~ mag^-H
                b, a = np.polyfit(np.log(mag[1:]), np.log(rms[1:]), 1)
                # The error is huge...
                self.assertTrue(abs(H + b) < 0.1)
Beispiel #26
0
def test_save_and_load(comm):
    nb_grid_pts = (128, 128)
    size = (3, 3)

    np.random.seed(1)
    t = fourier_synthesis(nb_grid_pts, size, 0.8, rms_slope=0.1, unit='µm')

    fft = FFT(nb_grid_pts, communicator=comm, fft="mpi")
    fft.create_plan(1)
    dt = t.domain_decompose(fft.subdomain_locations,
                            fft.nb_subdomain_grid_pts,
                            communicator=comm)
    assert t.unit == 'µm'
    assert dt.unit == 'µm'
    assert t.info['unit'] == 'µm'
    assert dt.info['unit'] == 'µm'
    if comm.size > 1:
        assert dt.is_domain_decomposed

    # Save file
    dt.to_netcdf('parallel_save_test.nc')

    # Attempt to open full file on each MPI process
    t2 = read_topography('parallel_save_test.nc')

    assert t.physical_sizes == t2.physical_sizes
    assert t.unit == t2.unit
    assert t.info['unit'] == t2.info['unit']
    np.testing.assert_array_almost_equal(t.heights(), t2.heights())

    # Attempt to open file in parallel
    r = NCReader('parallel_save_test.nc', communicator=comm)

    assert r.channels[0].nb_grid_pts == nb_grid_pts

    t3 = r.topography(subdomain_locations=fft.subdomain_locations,
                      nb_subdomain_grid_pts=fft.nb_subdomain_grid_pts)

    assert t.physical_sizes == t3.physical_sizes
    assert t.unit == t3.unit
    assert t.info['unit'] == t3.info['unit']
    np.testing.assert_array_almost_equal(dt.heights(), t3.heights())

    assert t3.is_periodic

    comm.barrier()
    if comm.rank == 0:
        os.remove('parallel_save_test.nc')
def test_c_vs_py_reference():
    from _SurfaceTopography import nonuniform_autocorrelation
    r = 16
    s = 1
    H = 0.8
    slope = 0.1
    t = fourier_synthesis((r,), (s,), H, rms_slope=slope,
                          amplitude_distribution=lambda n: 1.0).to_nonuniform()

    r1, A1 = py_autocorrelation_from_profile(t)

    s, = t.physical_sizes
    r2, A2 = nonuniform_autocorrelation(*t.positions_and_heights(), s)

    assert_array_almost_equal(r1, r2)
    assert_array_almost_equal(A1, A2)
Beispiel #28
0
def test_fourier_synthesis(n):
    H = 0.74
    rms_slope = 1.2
    s = 2e-6

    topography = fourier_synthesis((n, n), (s, s),
                                   H,
                                   rms_slope=rms_slope,
                                   long_cutoff=s / 4,
                                   short_cutoff=4 * s / n)

    qx, psdx = topography.power_spectrum_1D()
    qy, psdy = topography.transpose().power_spectrum_1D()

    assert psdy[-1] < 10 * psdx[-1]  # assert psdy is not much bigger
    assert abs(topography.rms_slope() - rms_slope) / rms_slope < 1e-1
Beispiel #29
0
def test_constrained_conjugate_gradients():
    nb_grid_pts = (512, 512)
    physical_sizes = (1., 1.)
    hurst = 0.8
    rms_slope = 0.1
    modulus = 1

    np.random.seed(999)
    topography = fourier_synthesis(nb_grid_pts,
                                   physical_sizes,
                                   hurst,
                                   rms_slope=rms_slope)

    substrate = PeriodicFFTElasticHalfSpace(nb_grid_pts, modulus,
                                            physical_sizes)
    system = make_system(substrate, topography)
    system.minimize_proxy(offset=0.1)
Beispiel #30
0
def test_save_and_load_no_unit(comm_self):
    nb_grid_pts = (128, 128)
    size = (3, 3)

    np.random.seed(1)
    t = fourier_synthesis(nb_grid_pts, size, 0.8, rms_slope=0.1)

    # Save file
    t.to_netcdf('no_unit.nc')

    t2 = read_topography('no_unit.nc')

    assert t.physical_sizes == t2.physical_sizes
    assert 'unit' not in t2.info
    np.testing.assert_array_almost_equal(t.heights(), t2.heights())

    os.remove('no_unit.nc')