def test_fourier_derivative_realness(nx, ny): # fourier_derivative internally asserts that the imaginary part is within # numerical tolerance. We check here this error isn't raised for any # configuration of odd and even grid points topography = Topography(np.random.random((nx, ny)), physical_sizes=(2., 3.)) topography.fourier_derivative(imtol=1e-12)
def test_saving_loading_and_sphere(self): # domain physical_sizes (edge length of square) length = 8 + 4 * rand() R = 17 + 6 * rand() # sphere radius res = 2 # nb_grid_pts x_c = length * rand() # coordinates of center y_c = length * rand() x = np.arange(res, dtype=float) * length / res - x_c y = np.arange(res, dtype=float) * length / res - y_c r2 = np.zeros((res, res)) for i in range(res): for j in range(res): r2[i, j] = x[i]**2 + y[j]**2 h = np.sqrt(R**2 - r2) - R # profile of sphere S1 = Topography(h, h.shape) with tmp_dir() as dir: fname = os.path.join(dir, "surface") S1.save(fname) # TODO: datafiles fixture may solve the problem # For some reason, this does not find the file... # S2 = read_asc(fname) S2 = S1 S3 = make_sphere(R, (res, res), (length, length), (x_c, y_c)) self.assertTrue(np.array_equal(S1.heights(), S2.heights())) self.assertTrue(np.array_equal(S1.heights(), S3.heights()))
def test_uniform_brute_force_autocorrelation_from_area(): n = 10 m = 11 for surf in [Topography(np.ones([n, m]), (n, m), periodic=False), Topography(np.random.random([n, m]), (n, m), periodic=False)]: r, A, A_xy = surf.autocorrelation_from_area(nbins=100, return_map=True) nx, ny = surf.nb_grid_pts dir_A_xy = np.zeros([n, m]) dir_A = np.zeros_like(A) dir_n = np.zeros_like(A) for dx in range(n): for dy in range(m): for i in range(nx - dx): for j in range(ny - dy): dir_A_xy[dx, dy] += (surf.heights()[i, j] - surf.heights()[ i + dx, j + dy]) ** 2 / 2 dir_A_xy[dx, dy] /= (nx - dx) * (ny - dy) d = np.sqrt(dx ** 2 + dy ** 2) i = np.argmin(np.abs(r - d)) dir_A[i] += dir_A_xy[dx, dy] dir_n[i] += 1 dir_n[dir_n == 0] = 1 dir_A /= dir_n assert_array_almost_equal(A_xy, dir_A_xy) assert_array_almost_equal(A[:-2], dir_A[:-2])
def test_init_with_lists_calling_scale_and_detrend(): t = Topography(np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]), physical_sizes=(1, 1)) # the following commands should be possible without errors st = t.scale(1) st.detrend(detrend_mode='center')
def test_squeeze(): x = np.linspace(0, 4 * np.pi, 101) y = np.linspace(0, 8 * np.pi, 103) h = np.sin(x.reshape(-1, 1)) + np.cos(y.reshape(1, -1)) surface = Topography(h, (1.2, 3.2)).scale(2.0) surface2 = surface.squeeze() assert isinstance(surface2, Topography) np.testing.assert_allclose(surface.heights(), surface2.heights())
def test_fourier_interpolate_transpose_symmetry(nx, ny, fine_nx, fine_ny): topography = Topography(np.random.random((nx, ny)), physical_sizes=(1., 1.5)) interp = topography.interpolate_fourier((fine_nx, fine_ny)) interp_t = topography.transpose().interpolate_fourier( (fine_ny, fine_nx)).transpose() np.testing.assert_allclose(interp.heights(), interp_t.heights())
def test_power_spectrum_from_profile(): X = np.arange(3).reshape(1, 3) Y = np.arange(4).reshape(4, 1) h = X + Y t = Topography(h, (8, 6)) q1, C1 = t.power_spectrum_from_profile(window='hann')
def test_constrained_conjugate_gradients(): # punch radius: r_s = 20.0 # equivalent Young's modulus E_s = 3.56 for nx, ny in [(256, 256), (256, 255), (255, 256)]: for disp0, normal_force in [(None, 15), (0.1, None)]: sx = sy = 2.5 * r_s substrate = FreeFFTElasticHalfSpace((nx, ny), E_s, (sx, sy)) x_range = np.arange(nx).reshape(-1, 1) y_range = np.arange(ny).reshape(1, -1) r_sq = (sx / nx * (x_range - nx // 2)) ** 2 + \ (sy / ny * (y_range - ny // 2)) ** 2 surface = Topography( np.ma.masked_where(r_sq > r_s ** 2, np.zeros([nx, ny])), (sx, sy) ) system = make_system(substrate, surface) try: result = system.minimize_proxy(offset=disp0, external_force=normal_force, pentol=1e-4) except substrate.FreeBoundaryError as err: if False: import matplotlib.pyplot as plt fig, ax = plt.subplots() # ax.pcolormesh(substrate.force / # surface.area_per_pt,rasterized=True) plt.colorbar(ax.pcolormesh(surface.heights(), rasterized=True)) ax.set_xlabel("") ax.set_ylabel("") ax.legend() fig.tight_layout() plt.show(block=True) raise err offset = result.offset forces = -result.jac converged = result.success # Check that calculation has converged assert converged # Check that target values have been reached if disp0 is not None: np.testing.assert_almost_equal(offset, disp0) if normal_force is not None: np.testing.assert_almost_equal(-forces.sum(), normal_force) # Check contact stiffness np.testing.assert_almost_equal( -forces.sum() / offset / (2 * r_s * E_s), 1.0, decimal=2)
def test_attribute_error(): X = np.arange(3).reshape(1, 3) Y = np.arange(4).reshape(4, 1) h = X + Y t = Topography(h, (8, 6)) # nonsense attributes return attribute error with pytest.raises(AttributeError): t.ababababababababa # # only scaled topographies have coeff # with pytest.raises(AttributeError): t.coeff st = t.scale(1) assert st.height_scale_factor == 1 # # only detrended topographies have detrend_mode # with pytest.raises(AttributeError): st.detrend_mode dm = st.detrend(detrend_mode='height').detrend_mode assert dm == 'height' # # this all should also work after pickling # t2 = pickle.loads(pickle.dumps(t)) with pytest.raises(AttributeError): t2.height_scale_factor st2 = t2.scale(1) assert st2.height_scale_factor == 1 with pytest.raises(AttributeError): st2.detrend_mode dm2 = st2.detrend(detrend_mode='height').detrend_mode assert dm2 == 'height' # # this all should also work after scaled+pickled # t3 = pickle.loads(pickle.dumps(st)) with pytest.raises(AttributeError): t3.detrend_mode dm3 = t3.detrend(detrend_mode='height').detrend_mode assert dm3 == 'height'
def test_checkerboard_detrend_with_no_subdivisions(self): r = 32 x, y = np.mgrid[:r, :r] h = 1.3 * x - 0.3 * y + 0.02 * x * x + 0.03 * y * y - 0.013 * x * y t = Topography(h, (1, 1), periodic=False) # This should be the same as a detrend with detrend_mode='height' ut1 = t.checkerboard_detrend((1, 1)) ut2 = t.detrend().heights() np.testing.assert_allclose(ut1, ut2)
def test_mirror_stitch(): t = Topography(np.array(((0, 1), (0, 0))), (2., 3.)) tp = t.mirror_stitch() assert tp.is_periodic np.testing.assert_allclose(tp.physical_sizes, (4., 6.)) np.testing.assert_allclose( tp.heights(), [[0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0]])
def test_rms_curvature_paraboloid_uniform_2D(): n = 16 X, Y = np.mgrid[slice(0, n), slice(0, n)] curvature = 0.1 heights = 0.5 * curvature * (X**2 + Y**2) surf = Topography(heights, physical_sizes=(n, n), periodic=False) # central finite differences are second order and so exact for the # paraboloid assert abs( (surf.rms_curvature_from_area() - curvature) / curvature) < 1e-15
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_checkerboard_detrend_2d(self): arr = np.zeros([4, 4]) arr[:2, :2] = 1.0 outarr = Topography(arr, arr.shape).checkerboard_detrend((2, 2)) np.testing.assert_allclose(outarr, np.zeros([4, 4])) arr = np.zeros([4, 4]) arr[:2, :2] = 1.0 arr[:2, 1] = 2.0 outarr = Topography(arr, arr.shape).checkerboard_detrend((2, 2)) np.testing.assert_allclose(outarr, np.zeros([4, 4]))
def test_positions_and_heights(): X = np.arange(3).reshape(1, 3) Y = np.arange(4).reshape(4, 1) h = X + Y t = Topography(h, (8, 6)) assert t.nb_grid_pts == (4, 3) assert_array_equal(t.heights(), h) X2, Y2, h2 = t.positions_and_heights() assert_array_equal(X2, [ (0, 0, 0), (2, 2, 2), (4, 4, 4), (6, 6, 6), ]) assert_array_equal(Y2, [ (0, 2, 4), (0, 2, 4), (0, 2, 4), (0, 2, 4), ]) assert_array_equal(h2, [(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5)]) # # After detrending, the position and heights should have again # just 3 arrays and the third array should be the same as .heights() # dt = t.detrend(detrend_mode='slope') np.testing.assert_allclose(dt.heights(), [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], atol=1e-15) X2, Y2, h2 = dt.positions_and_heights() assert h2.shape == (4, 3) assert_array_equal(X2, [ (0, 0, 0), (2, 2, 2), (4, 4, 4), (6, 6, 6), ]) assert_array_equal(Y2, [ (0, 2, 4), (0, 2, 4), (0, 2, 4), (0, 2, 4), ]) np.testing.assert_allclose(h2, [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], atol=1e-15)
def topography(self, channel_index=None, physical_sizes=None, height_scale_factor=None, info={}, periodic=False, subdomain_locations=None, nb_subdomain_grid_pts=None): if channel_index is None: channel_index = self._default_channel_index if subdomain_locations is not None or \ nb_subdomain_grid_pts is not None: raise RuntimeError( 'This reader does not support MPI parallelization.') close_file = False if not hasattr(self._fobj, 'read'): fobj = open(self._fobj, 'rb') close_file = True else: fobj = self._fobj channel = self._channels[channel_index] sx, sy = self._check_physical_sizes(physical_sizes, channel.physical_sizes) nx, ny = channel.nb_grid_pts offset = self._offsets[channel_index] dtype = np.dtype('<i2') ################################### fobj.seek(offset) rawdata = fobj.read(nx * ny * dtype.itemsize) unscaleddata = np.frombuffer(rawdata, count=nx * ny, dtype=dtype).reshape(nx, ny) # internal information from file _info = dict(unit=channel.info["unit"], data_source=channel.name) _info.update(info) if 'acquisition_time' in channel.info: _info['acquisition_time'] = channel.info['acquisition_time'] # the orientation of the heights is modified in order to match # the image of gwyddion when plotted with imshow(t.heights().T) # or pcolormesh(t.heights().T) for origin in lower left and # with inverted y axis (cartesian coordinate system) surface = Topography(np.fliplr(unscaleddata.T), (sx, sy), info=_info, periodic=periodic) if height_scale_factor is None: height_scale_factor = channel.info["height_scale_factor"] surface = surface.scale(height_scale_factor) if close_file: fobj.close() return surface
def test_default_window_2D(): x = np.linspace(0, 1, 200).reshape(-1, 1) heights = np.cos(2 * np.pi * x * 8.3) * np.ones((1, 200)) topography = Topography(heights, physical_sizes=(1, 1), periodic=True) if True: import matplotlib.pyplot as plt fig, ax = plt.subplots() ax.plot(*topography.power_spectrum_from_profile(), label="periodic=True") ax.plot(*topography.power_spectrum_from_area(nbins=20), label="2D, periodic=True") ax.set_xscale("log") ax.set_yscale("log") topography = Topography(heights, physical_sizes=(1, 1), periodic=False) if True: import matplotlib.pyplot as plt ax.plot(*topography.power_spectrum_from_profile(), label="periodic=False") ax.plot(*topography.power_spectrum_from_area(nbins=20), label="2D, periodic=False") ax.set_xscale("log") ax.set_yscale("log") # ax.set_ylim(bottom=1e-6) ax.legend() plt.show(block=True)
def test_checkerboard_detrend_profile_2d(): arr = np.zeros([4, 4]) arr[:2, :2] = 1.0 outarr = Topography(arr, arr.shape).checkerboard_detrend_profile(2) np.testing.assert_allclose(outarr, np.zeros([4, 4]), atol=1e-12) arr = np.zeros([4, 4]) arr[:2, :2] = 1.0 arr[:2, 1] = 2.0 arr[:, 1] += 1 # offsets do not matter since all profile are independently tilt corrected arr[:, 2] += 1.5 arr[:, 3] += 0.7 outarr = Topography(arr, arr.shape).checkerboard_detrend_profile(2) np.testing.assert_allclose(outarr, np.zeros([4, 4]), atol=1e-12)
def test_hardwall_plastic_nonperiodic_disp_control(comm_self): # test just that it works without bug, not accuracy nx, ny = 128, 128 sx = 0.005 # mm sy = 0.005 # mm x = np.arange(0, nx).reshape(-1, 1) * sx / nx - sx / 2 y = np.arange(0, ny).reshape(1, -1) * sy / ny - sy / 2 topography = Topography(-np.sqrt(x**2 + y**2) * 0.05, physical_sizes=(sx, sy)) Es = 230000 # MPa hardness = 6000 # MPa system = make_plastic_system(substrate="free", surface=PlasticTopography( topography=topography, hardness=hardness), young=Es, communicator=comm_self) offsets = [1e-4] disp0 = None for offset in offsets: sol = system.minimize_proxy(offset=offset, initial_displacements=disp0, pentol=1e-10) assert sol.success
def simple_linear_2d_topography(): """Simple 2D topography, which is linear in y""" unit = 'nm' info = dict(unit=unit) y = np.arange(10).reshape((1, -1)) x = np.arange(5).reshape((-1, 1)) arr = -2 * y + 0 * x # only slope in y direction t = Topography(arr, (5, 10), info=info).detrend('center') return t
def test_rms_curvature_sinewave_2D(periodic): precision = 5 n = 256 X, Y = np.mgrid[slice(0, n), slice(0, n)] hm = 0.3 L = float(n) size = (L, L) surf = Topography(np.sin(2 * np.pi / L * X) * hm, physical_sizes=size, periodic=periodic) numerical_lapl = surf.rms_laplacian() analytical_lapl = np.sqrt((2 * np.pi / L)**4 * hm**2 / 2) # print(numerical-analytical) np.testing.assert_almost_equal(numerical_lapl, analytical_lapl, precision) np.testing.assert_almost_equal(surf.rms_curvature_from_area(), analytical_lapl / 2, precision)
def test_hard_wall_bearing_area(comm): # Test that at very low hardness we converge to (almost) the bearing # area geometry pnp = Reduction(comm) fullsurface = open_topography(os.path.join(FIXTURE_DIR, 'surface1.out')) fullsurface = fullsurface.topography( physical_sizes=fullsurface.channels[0].nb_grid_pts) nb_domain_grid_pts = fullsurface.nb_grid_pts substrate = PeriodicFFTElasticHalfSpace(nb_domain_grid_pts, 1.0, fft='mpi', communicator=comm) surface = Topography( fullsurface.heights(), physical_sizes=nb_domain_grid_pts, decomposition='domain', subdomain_locations=substrate.topography_subdomain_locations, nb_subdomain_grid_pts=substrate.topography_nb_subdomain_grid_pts, communicator=substrate.communicator) plastic_surface = PlasticTopography(surface, 1e-12) system = PlasticNonSmoothContactSystem(substrate, plastic_surface) offset = -0.002 if comm.rank == 0: def cb(it, p_r, d): print("{0}: area = {1}".format(it, d["area"])) else: def cb(it, p_r, d): pass result = system.minimize_proxy(offset=offset, callback=cb) assert result.success c = result.jac > 0.0 ncontact = pnp.sum(c) assert plastic_surface.plastic_area == ncontact * surface.area_per_pt bearing_area = bisect( lambda x: pnp.sum((surface.heights() > x)) - ncontact, -0.03, 0.03) cba = surface.heights() > bearing_area # print(comm.Get_rank()) assert pnp.sum(np.logical_not(c == cba)) < 25
def test_fourier_interpolate_nyquist(plot=False): # asserts that the interpolation follows the "minimal-osciallation" # assumption for the nyquist frequency topography = Topography(np.array([[1], [-1]]), physical_sizes=(1., 1.)) interpolated_topography = topography.interpolate_fourier((64, 1)) if plot: import matplotlib.pyplot as plt fig, ax = plt.subplots() x, y = topography.positions() ax.plot(x.flat, topography.heights().flat, "+") x, y = interpolated_topography.positions() ax.plot(x.flat, interpolated_topography.heights().flat, "-") fig.show() x, y = interpolated_topography.positions() np.testing.assert_allclose(interpolated_topography.heights(), np.cos(2 * np.pi * x), atol=1e-14)
def test_heuristic_pentol(): # just checks works without bug nx, ny = (10, 5) topo = Topography(np.resize(np.cos(2 * np.pi * np.arange(nx) / nx), (nx, ny)), physical_sizes=(nx, ny), periodic=True) system = make_system(surface=topo, substrate="periodic", young=1) system.minimize_proxy(offset=-0.5)
def test_checkerboard_detrend_order2_2d(): arr = np.zeros([6, 6]) arr[:3, :3] = 1.0 outarr = Topography(arr, arr.shape).checkerboard_detrend_area((2, 2), order=2) np.testing.assert_allclose(outarr, np.zeros([6, 6]), atol=1e-12) arr = np.zeros([6, 6]) arr[:3, :3] = 1.0 arr[:3, 1] = 2.0 outarr = Topography(arr, arr.shape).checkerboard_detrend_area((2, 2), order=2) np.testing.assert_allclose(outarr, np.zeros([6, 6]), atol=1e-12) arr = np.zeros([6, 6]) arr[:3, :3] = 1.0 arr[:3, 1] = 2.0 arr[:3, 2] = -0.5 outarr = Topography(arr, arr.shape).checkerboard_detrend_area((2, 2), order=2) np.testing.assert_allclose(outarr, np.zeros([6, 6]), atol=1e-12)
def test_saving_loading_and_sphere(self): # domain physical_sizes (edge length of square) length = 8 + 4 * rand() R = 17 + 6 * rand() # sphere radius res = 2 # nb_grid_pts x_c = length * rand() # coordinates of center y_c = length * rand() x = np.arange(res, dtype=float) * length / res - x_c y = np.arange(res, dtype=float) * length / res - y_c r2 = np.zeros((res, res)) for i in range(res): for j in range(res): r2[i, j] = x[i] ** 2 + y[j] ** 2 h = np.sqrt(R ** 2 - r2) - R # profile of sphere S1 = Topography(h, h.shape) with tmp_dir() as dir: fname = os.path.join(dir, "surface") S1.to_matrix(fname) S2 = read_matrix(fname) self.assertTrue(np.allclose(S2.heights(), S1.heights())) S3 = make_sphere(R, (res, res), (length, length), (x_c, y_c)) self.assertTrue(np.array_equal(S1.heights(), S2.heights())) self.assertTrue(np.array_equal(S1.heights(), S3.heights()))
def test_positions(comm): nx, ny = (12 * comm.Get_size(), 10 * comm.Get_size() + 1) sx = 33. sy = 54. fftengine = FFT((nx, ny), fft='mpi', communicator=comm) surf = Topography(np.zeros(fftengine.nb_subdomain_grid_pts), physical_sizes=(sx, sy), decomposition='subdomain', nb_grid_pts=(nx, ny), subdomain_locations=fftengine.subdomain_locations, communicator=comm) x, y = surf.positions() assert x.shape == fftengine.nb_subdomain_grid_pts assert y.shape == fftengine.nb_subdomain_grid_pts assert Reduction(comm).min(x) == 0 assert abs(Reduction(comm).max(x) - sx * (1 - 1. / nx)) \ < 1e-8 * sx / nx, "{}".format(x) assert Reduction(comm).min(y) == 0 assert abs(Reduction(comm).max(y) - sy * (1 - 1. / ny)) < 1e-8
def uniform_2d_topography(request): """Returns a uniform 2D topography, with all combinations of scaled and detrended. Detrended is always executed after scaling, if requested. Returns ------- A uniform 2D topography. """ y = np.arange(10).reshape((1, -1)) x = np.arange(5).reshape((-1, 1)) arr = -2 * y + 0 * x # only slope in y direction topography = Topography(arr, (5, 10)).detrend('center') return apply_param(topography, request.param)
def test_smooth_without_size(self): arr = self._flat_arr surf = Topography(arr, (1, 1)).detrend(detrend_mode='height') self.assertEqual(surf.dim, 2) self.assertTrue(surf.is_uniform) self.assertAlmostEqual(surf.mean(), 0) self.assertAlmostEqual(surf.rms_gradient(), 0) self.assertTrue( surf.rms_height_from_area() < Topography(arr, (1, 1)).rms_height_from_area())
def test_uniform_brute_force_autocorrelation_from_profile(): n = 10 for surf in [UniformLineScan(np.ones(n), n, periodic=False), UniformLineScan(np.arange(n), n, periodic=False), Topography(np.random.random(n).reshape(n, 1), (n, 1), periodic=False)]: r, A = surf.autocorrelation_from_profile() n = len(A) dir_A = np.zeros(n) for d in range(n): for i in range(n - d): dir_A[d] += (surf.heights()[i] - surf.heights()[ i + d]) ** 2 / 2 dir_A[d] /= (n - d) assert_array_almost_equal(A, dir_A)