def test_keep_file_open(self): for fn in self.text_example_file_list: # Text file can be opened as binary or text with open(fn, 'rb') as f: open_topography(f) self.assertFalse(f.closed, msg=fn) with open(fn, 'r') as f: open_topography(f) self.assertFalse(f.closed, msg=fn) for fn in self.binary_example_file_list: with open(fn, 'rb') as f: open_topography(f) self.assertFalse(f.closed, msg=fn) for datastr in self.text_example_memory_list: with io.StringIO(datastr) as f: open_topography(f) self.assertFalse( f.closed, msg="text memory stream for '{}' was closed".format( datastr)) # Doing the same when but only giving a binary stream with io.BytesIO(datastr.encode(encoding='utf-8')) as f: open_topography(f) self.assertFalse( f.closed, msg="binary memory stream for '{}' was closed".format( datastr))
def test_keep_text_file_open(fn): # Text file can be opened as binary or text with open(fn, 'rb') as f: open_topography(f) assert not f.closed, f"Text file {fn} was opened as binary file and is closed, but should not" with open(fn, 'r') as f: open_topography(f) assert not f.closed, f"Text file {fn} was opened as text file and is closed, but should not"
def test_keep_stream_from_memory_open(datastr): with io.StringIO(datastr) as f: open_topography(f) assert not f.closed, "text memory stream for '{}' was closed".format( datastr) # Doing the same when but only giving a binary stream with io.BytesIO(datastr.encode(encoding='utf-8')) as f: open_topography(f) assert not f.closed, "binary memory stream for '{}' was closed".format( datastr)
def test_can_be_pickled(fn): reader = open_topography(fn) physical_sizes = None if reader.default_channel.physical_sizes is None: physical_sizes = (1., ) * reader.default_channel.dim topography = reader.topography(physical_sizes=physical_sizes) topographies = [topography] if hasattr(topography, 'to_uniform'): topographies += [topography.to_uniform(100, 0)] for t in topographies: s = pickle.dumps(t) pickled_t = pickle.loads(s) # # Compare some attributes after unpickling # # sometimes the result is a list of topographies multiple = isinstance(t, list) if not multiple: t = [t] pickled_t = [pickled_t] for x, y in zip(t, pickled_t): for attr in ['dim', 'physical_sizes', 'is_periodic']: assert getattr(x, attr) == getattr(y, attr) if x.physical_sizes is not None: assert_array_equal(x.positions(), y.positions()) assert_array_equal(x.heights(), y.heights())
def test_reader_arguments(fn): """Check whether all readers have channel, physical_sizes and height_scale_factor arguments. Also check whether we can execute `topography` multiple times for all readers""" physical_sizes0 = (1.2, 1.3) # Test open -> topography r = open_topography(fn) physical_sizes = None if r.channels[ 0].physical_sizes is not None else physical_sizes0 t = r.topography(channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: assert t.physical_sizes == physical_sizes # Second call to topography t2 = r.topography(channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: assert t2.physical_sizes == physical_sizes assert_array_equal(t.heights(), t2.heights()) # Test read_topography t = read_topography(fn, channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: assert t.physical_sizes == physical_sizes
def test_reader_topography_same(fn): """ Tests that properties like physical sizes, units and nb_grid_pts are the same in the ChannelInfo and the loaded topography. """ reader = open_topography(fn) for channel in reader.channels: foo_str = reader.format() + "-%d" % (channel.index, ) # unique for each channel topography = channel.topography( physical_sizes=(1, 1) if channel.physical_sizes is None else None, info=dict(foo=foo_str)) assert channel.nb_grid_pts == topography.nb_grid_pts # some checks on info dict in channel and topography assert topography.info['foo'] == foo_str if channel.unit is not None or topography.unit is not None: assert channel.unit == topography.unit assert channel.info['unit'] == topography.unit assert channel.unit == topography.info['unit'] if channel.physical_sizes is not None: assert channel.physical_sizes == topography.physical_sizes if channel.height_scale_factor is not None and hasattr( topography, 'scale_factor'): assert channel.height_scale_factor == topography.scale_factor
def test_reader_arguments(self): """Check whether all readers have channel, physical_sizes and height_scale_factor arguments. Also check whether we can execute `topography` multiple times for all readers""" physical_sizes0 = (1.2, 1.3) for fn in self.text_example_file_list + self.binary_example_file_list: # Test open -> topography r = open_topography(fn) physical_sizes = None if r.channels[0].dim == 1 \ else physical_sizes0 t = r.topography(channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: self.assertEqual(t.physical_sizes, physical_sizes) # Second call to topography t2 = r.topography(channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: self.assertEqual(t2.physical_sizes, physical_sizes) assert_array_equal(t.heights(), t2.heights()) # Test read_topography t = read_topography(fn, channel_index=0, physical_sizes=physical_sizes, height_scale_factor=None) if physical_sizes is not None: self.assertEqual(t.physical_sizes, physical_sizes)
def test_periodic_flag(fn): reader = open_topography(fn) ch = reader.default_channel physical_sizes_arg_if_missing_in_file = (1., ) * ch.dim physical_sizes_arg = physical_sizes_arg_if_missing_in_file if ch.physical_sizes is None else None t = reader.topography(physical_sizes=physical_sizes_arg, periodic=True) assert t.is_periodic, fn t = reader.topography(physical_sizes=physical_sizes_arg, periodic=False) assert not t.is_periodic, fn
def test_nb_grid_pts_and_physical_sizes_are_tuples_or_none(fn): r = open_topography(fn) assert isinstance( r.default_channel.nb_grid_pts, tuple), f'{fn} - {r.__class__}: {r.default_channel.nb_grid_pts}' if r.default_channel.physical_sizes is not None: assert isinstance(r.default_channel.physical_sizes, tuple), \ f'{fn} - {r.__class__}: {r.default_channel.physical_sizes}' # If it is a tuple, it cannot contains None's assert np.all([p is not None for p in r.default_channel.physical_sizes]), \ f'{fn} - {r.__class__}: {r.default_channel.physical_sizes}'
def test_gwyddion_txt_import(lang_filename_infix): fname = os.path.join(DATADIR, 'gwyddion-export-{}.txt'.format(lang_filename_infix)) # # test channel infos # reader = open_topography(fname) assert len(reader.channels) == 1 channel = reader.default_channel assert channel.name == "My Channel Name" assert channel.unit == 'm' assert pytest.approx( channel.physical_sizes[0]) == 12.34 * 1e-6 # was given as µm assert pytest.approx( channel.physical_sizes[1]) == 5678.9 * 1e-9 # was given as nm # # test metadata of topography # topo = reader.topography() assert topo.unit == 'm' assert pytest.approx( topo.physical_sizes[0]) == 12.34 * 1e-6 # was given as µm assert pytest.approx( topo.physical_sizes[1]) == 5678.9 * 1e-9 # was given as nm # # test scaling and order of data # # The order of the lines in the text files mimic the lines as they # are shown in the gwyddion plot. # # In gwyddion's text export: # - first index corresponds to y dimension (rows), second index (columns) # to x dimension # - y coordinates grow from top row to bottom row # - x coordinates grow from left column to column of array # # PyCo's heights() has a different order: # - first index corresponds to x dimension, second index to y dimension # - plot from the heights correspond to same image in gwyddion if plotted # with "pcolormesh(t.heights.T)", but with origin in lower left, i.e. the # image looks flipped vertically when compared to gwyddion # # => heights() must be same array as in file, but transposed # heights_in_file = [[1, 1.5, 3], [-2, -3, -6], [0, 0, 0], [9, 9, 9]] expected_heights = np.array(heights_in_file).T np.testing.assert_allclose(topo.heights(), expected_heights)
def test_periodic_flag(self): file_list = self.text_example_file_list + self.binary_example_file_list for fn in file_list: reader = open_topography(fn) physical_sizes = None if reader.default_channel.dim != 1: physical_sizes = reader.default_channel.physical_sizes \ if reader.default_channel.physical_sizes is not None \ else [1., ] * reader.default_channel.dim t = reader.topography(physical_sizes=physical_sizes, periodic=True) assert t.is_periodic, fn t = reader.topography(physical_sizes=physical_sizes, periodic=False) assert not t.is_periodic, fn
def test_read(self): # All units are nm for (fn, n, s, rmslist) in [ ('di1.di', 512, 500.0, [(9.9459868005603909, "Height"), (114.01328027385664, "Height"), (None, "Phase"), (None, "AmplitudeError")]), ('di2.di', 512, 300.0, [(24.721922008645919, "Height"), (24.807150576054838, "Height"), (0.13002312109876774, "Deflection")]), ('di3.di', 256, 10000.0, [(226.42539668457405, "ZSensor"), (None, "AmplitudeError"), (None, "Phase"), (264.00285276203158, "Height")]), # Height ( 'di4.di', 512, 10000.0, [ (81.622909804184744, "ZSensor"), # ZSensor (0.83011806260022758, "AmplitudeError"), # AmplitudeError (None, "Phase") ]) # Phase ]: reader = open_topography(os.path.join(DATADIR, '{}').format(fn), format="di") for i, (rms, name) in enumerate(rmslist): assert reader.channels[i].name == name surface = reader.topography(channel_index=i) nx, ny = surface.nb_grid_pts self.assertEqual(nx, n) self.assertEqual(ny, n) sx, sy = surface.physical_sizes if type(surface.info['unit']) is tuple: unit, dummy = surface.info['unit'] else: unit = surface.info['unit'] self.assertAlmostEqual( sx * get_unit_conversion_factor(unit, 'nm'), s) self.assertAlmostEqual( sy * get_unit_conversion_factor(unit, 'nm'), s) if rms is not None: self.assertAlmostEqual(surface.rms_height(), rms) self.assertEqual(unit, 'nm') self.assertTrue(surface.is_uniform)
def test_save_and_load_np(comm_self, file_format_examples): # sometimes the surface isn't transposed the same way when topography = open_topography(os.path.join(file_format_examples, 'di4.di'), format="di").topography() with tempfile.TemporaryDirectory() as d: npyfile = os.path.join(d, 'test_save_and_load_np.npy') np.save(npyfile, topography.heights()) loaded_topography = NPYReader( npyfile, communicator=comm_self).topography(physical_sizes=(1., 1.)) np.testing.assert_allclose(loaded_topography.heights(), topography.heights())
def test_reader_height_scale_factor_arg_for_topography(fn): """Test whether height_scale_factor can be given to .topography() and is effective. Also checking whether the reader channels have .height_scale_factor attribute and whether it is equal to the scaling factor known from topography. Also tests that info dict of channel and topography have no height_scale_factor, because this should be a channel property now. """ reader = open_topography(fn) ch = reader.default_channel assert hasattr(ch, 'height_scale_factor') assert 'height_scale_factor' not in ch.info height_scale_factor_if_missing_in_file = 2 # just some number # calculate argument for .topography() height_scale_factor_arg = height_scale_factor_if_missing_in_file if ch.height_scale_factor is None else None # which factor we expect at the end exp_height_scale_factor = height_scale_factor_if_missing_in_file if ch.height_scale_factor is None \ else ch.height_scale_factor # in order to call .topography(), we also need valid physical_sizes physical_sizes_arg_if_missing_in_file = (1., ) * ch.dim physical_sizes_arg = physical_sizes_arg_if_missing_in_file if ch.physical_sizes is None else None # The check whether an exception is raised if meta data like `physical_sizes` # and `height_scale_factor` has already been defined in the file and # one tries to override it, is done in another test. # # (only do this if not an NC file with units, since this is special: height_scale_factor # should only be choosable then.) if reader.format != 'nc' and 'unit' not in ch.info: topography = reader.topography( physical_sizes=physical_sizes_arg, height_scale_factor=height_scale_factor_arg) if hasattr(topography, 'scale_factor'): # sometimes we use height_scale_factor = 1 in the channel info in order # to denote that the height scale factor cannot be changed later. # This does not mean that the topography also really has been scaled, so # we compare the scale factor here only of it is available assert pytest.approx(exp_height_scale_factor) == topography.scale_factor, \ "Difference in height scale factor between channel/argument and resulting topography"
def test_ibw_file_with_one_channel_without_name(): """ After implementing new IBW readers there was an issue https://github.com/pastewka/TopoBank/issues/413 This test should ensure that it's fixed. """ fn = os.path.join(DATADIR, "10x10-one_channel_without_name.ibw") reader = open_topography(fn) assert len(reader.channels) == 1 ch_info = reader.channels[0] # we could use "Default" here, but what if there are multiple no names? assert ch_info.name == 'no name (1)' assert ch_info.dim == 2 assert ch_info.nb_grid_pts == (10, 10)
def test_reader_topography_same(self): """ Tests that properties like physical sizes, units and nb_grid_pts are the same in the ChannelInfo and the loaded topography """ for fn in self.text_example_file_list + self.binary_example_file_list: reader = open_topography(fn) for channel in reader.channels: topography = channel.topography(physical_sizes=( 1, 1) if channel.physical_sizes is None else None) assert channel.nb_grid_pts == topography.nb_grid_pts if "unit" in channel.info.keys() or \ "unit" in topography.info.keys(): assert channel.info["unit"] == topography.info["unit"] if channel.physical_sizes is not None: assert channel.physical_sizes == topography.physical_sizes
def test_save_and_load(comm_self, file_format_examples): # sometimes the surface isn't transposed the same way when topography = open_topography( os.path.join(file_format_examples, 'di4.di'), format="di").topography() npyfile = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_save_and_load.npy") save_npy(npyfile, topography) loaded_topography = NPYReader(npyfile, communicator=comm_self).topography( # nb_subdomain_grid_pts=topography.nb_grid_pts, # subdomain_locations=(0,0), physical_sizes=(1., 1.)) np.testing.assert_allclose(loaded_topography.heights(), topography.heights()) os.remove(npyfile)
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_ibw_kpfm_file(): """ We had an issue with KPFM files, see https://github.com/pastewka/PyCo/pull/231#discussion_r354687995 This test should ensure that it's fixed. """ fn = os.path.join(DATADIR, 'spot_1-1000nm.ibw') reader = open_topography(fn) # # Try to read all channels # for channel_info in reader.channels: assert pytest.approx(channel_info.physical_sizes[0], abs=0.01) == 2e-05 # 20 µm assert pytest.approx(channel_info.physical_sizes[1], abs=0.01) == 2e-05 # 20 µm channel_info.topography()
def test_nb_grid_pts_and_physical_sizes_are_tuples_or_none(self): file_list = self.text_example_file_list + self.binary_example_file_list for fn in file_list: r = open_topography(fn) self.assertTrue( isinstance(r.default_channel.nb_grid_pts, tuple), msg=f'{fn} - {r.__class__}: {r.default_channel.nb_grid_pts}') if r.default_channel.physical_sizes is not None: self.assertTrue( isinstance(r.default_channel.physical_sizes, tuple), msg= f'{fn} - {r.__class__}: {r.default_channel.physical_sizes}' ) # If it is a tuple, it cannot contains None's self.assertTrue( np.all([ p is not None for p in r.default_channel.physical_sizes ]), msg= f'{fn} - {r.__class__}: {r.default_channel.physical_sizes}' )
def plot(fn): r = open_topography(fn) t = r.topography() if 'unit' in t.info: unit = t.info['unit'] else: unit = '?' fig = plt.figure(figsize=(10, 10)) fig.suptitle("{}, channel {}".format(fn, r.default_channel.name)) ax = fig.add_subplot(2, 2, 1) ax.set_title("pcolormesh(t.heights().T)") ax.pcolormesh(t.heights().T) ax = fig.add_subplot(2, 2, 2) ax.set_title("pcolormesh(*t.positions_and_heights())") ax.set_xlabel("x [{}]".format(unit)) ax.set_ylabel("y [{}]".format(unit)) ax.pcolormesh(*t.positions_and_heights()) ax = fig.add_subplot(2, 2, 3) ax.set_title("above is correct, if this is like Gwyddion") ax.pcolormesh(np.flipud(t.heights().T)) ax = fig.add_subplot(2, 2, 4) ax.set_title("imshow(t.heights().T)") extent = (0, t.physical_sizes[0], t.physical_sizes[1], 0) ax.imshow(t.heights().T, extent=extent) fig.subplots_adjust(hspace=0.5) fig.show() h = t.heights() for i, j in [(0, 0), (0, -1), (-1, 0), (-1, -1)]: print("h[{},{}] == {}".format(i, j, h[i, j])) return t
def get_topography_reader(filefield, format=None): """Returns SurfaceTopography.IO.ReaderBase object. Parameters ---------- filefield: models.FileField instance reference to file which should be opened by the reader format: str, optional specify in which format the file should be interpreted; if not given, the format is determined automatically Returns ------- Instance of a `ReaderBase` subclass according to the format. """ # Workaround such that SurfaceTopography module recognizes this a binary stream if not hasattr(filefield, 'mode'): filefield.mode = 'rb' if hasattr(filefield.file, 'seek'): # make sure the file is rewound filefield.file.seek(0) reader = open_topography(filefield, format=format) return reader
def test_reader_args_doesnt_overwrite_data_from_file(fn): """ Tests that if some properties like `physical_sizes and `height_scale_factor` are given in the file, they cannot be overridden by given arguments to the .topography() method. """ reader = open_topography(fn) ch = reader.default_channel physical_sizes_arg_if_missing_in_file = (1., ) * ch.dim physical_sizes_arg = physical_sizes_arg_if_missing_in_file if ch.physical_sizes is None else None if ch.physical_sizes is not None: with pytest.raises(MetadataAlreadyFixedByFile): reader.topography( physical_sizes=physical_sizes_arg_if_missing_in_file) if ch.height_scale_factor is not None: with pytest.raises(MetadataAlreadyFixedByFile): if ch.physical_sizes is None: reader.topography(physical_sizes=physical_sizes_arg, height_scale_factor=10) else: # if an exception happens, we want it because of height scale factor reader.topography(height_scale_factor=10)
def test_example6(self): topography_file = open_topography( os.path.join(DATADIR, 'example6.txt')) surf = topography_file.topography(physical_sizes=(1,)) self.assertTrue(isinstance(surf, UniformLineScan)) np.testing.assert_allclose(surf.heights(), [1, 2, 3, 4, 5, 6, 7, 8, 9])
def test_detect_format_then_read(self): f = open(os.path.join(DATADIR, 'example.ibw'), 'rb') fmt = detect_format(f) self.assertTrue(fmt, 'ibw') open_topography(f, format=fmt).topography() f.close()
type=int, default=None, help='use NBINS bins for radial average', metavar='NBINS') parser.add_argument('--detrend_mode', dest='detrend_mode', type=str, default='center', help='detrend surface; posibilities are ' 'DETREND=center|height|slope|curvature', metavar='DETREND') arguments = parser.parse_args() ### surface = DetrendedTopography(open_topography(arguments.filename), detrend_mode=arguments.detrend_mode) unit = surface.unit nx, ny = surface.shape nbins = arguments.nbins if nbins is None: nbins = (nx + ny) / 2 ### r, A, A_xy = autocorrelation_2D(surface, nbins=nbins, return_map=True) fig = plt.figure() ax = fig.add_subplot(111) ax.loglog(r, A, 'ko') ax.set_xlabel('Distance $r$ ({})'.format(unit))
def test_keep_binary_file_open(fn): with open(fn, 'rb') as f: open_topography(f) assert not f.closed, f"Binary file {fn} was opened as binary file and is closed, but should not"