def interpolate_line(self, start, end, gpts=None, sampling=None): from abtem.scan import LineScan if not (self.dimensions == 2): raise RuntimeError() if (self.calibrations[0] is None) or (self.calibrations[1] is None): raise RuntimeError() if self.calibrations[0].units != self.calibrations[1].units: raise RuntimeError() if (gpts is None) & (sampling is None): sampling = (self.calibrations[0].sampling + self.calibrations[1].sampling) / 2. x = np.linspace(self.calibrations[0].offset, self.shape[0] * self.calibrations[0].sampling, self.shape[0]) y = np.linspace(self.calibrations[1].offset, self.shape[1] * self.calibrations[1].sampling, self.shape[1]) scan = LineScan(start=start, end=end, gpts=gpts, sampling=sampling) interpolated_array = interpn((x, y), self.array, scan.get_positions()) calibration = Calibration(offset=0, sampling=scan.sampling[0], units=self.calibrations[0].units, name=self.calibrations[0].name) return Measurement(interpolated_array, calibration)
def test_linescan_to_file(tmp_path): d = tmp_path / 'sub' d.mkdir() path = d / 'measurement2.hdf5' atoms = read(_set_path('orthogonal_graphene.cif')) potential = Potential(atoms=atoms, sampling=.05) probe = Probe(energy=200e3, semiangle_cutoff=30) probe.grid.match(potential) scan = LineScan(start=[0, 0], end=[0, potential.extent[1]], gpts=20) detector = PixelatedDetector() export_detector = PixelatedDetector(save_file=path) measurements = probe.scan(scan, [detector, export_detector], potential, pbar=False) measurement = measurements[0] imported_measurement = Measurement.read(measurements[1]) assert np.allclose(measurement.array, imported_measurement.array) assert measurement.calibrations[0] == imported_measurement.calibrations[0] assert measurement.calibrations[1] == imported_measurement.calibrations[1]
def test_probe_waves_line_scan(): probe = Probe(energy=60e3) detector = DummyDetector() potential = DummyPotential(extent=5, sampling=.1) scan = LineScan((0, 0), (1, 1), gpts=10) measurement = probe.scan(scan, detector, potential, max_batch=1, pbar=False) assert detector._detect_count == 10 assert np.all(measurement.array == 1.) measurement = probe.scan(scan, [detector], potential, pbar=False) assert detector._detect_count == 11 assert np.all(measurement.array == 1.) measurement = probe.scan(scan, detector, potential, max_batch=3, pbar=False) assert detector._detect_count == 15 assert np.all(measurement.array == 1.)
def test_fig(): atoms = Atoms('CSiCuAuU', positions=[(x, 25, 4) for x in np.linspace(5, 45, 5)], cell=(50, 50, 8)) gpts = 2048 potential = Potential(atoms=atoms, gpts=gpts, parametrization='kirkland', slice_thickness=8) probe = Probe(energy=200e3, defocus=700, Cs=1.3e7, semiangle_cutoff=10.37) probe.grid.match(potential) scan = LineScan(start=[5, 25], end=[45, 25], gpts=5) detector = AnnularDetector(inner=40, outer=200) measurements = probe.scan(scan, [detector], potential, pbar=False) #assert np.allclose(measurements[detector].array, [0.00010976, 0.00054356, 0.00198158, 0.00997221, 0.01098883]) assert np.allclose( measurements[detector].array, [0.0001168, 0.00059303, 0.00214667, 0.00977803, 0.01167613], atol=1e-5)
def test_interpolation_scan(): atoms = Atoms('C', positions=[(2.5, 2.5, 2)], cell=(5, 5, 4)) potential = Potential(atoms) linescan = LineScan(start=[0, 0], end=[2.5, 2.5], gpts=10) detector = AnnularDetector(inner=80, outer=200) probe = Probe(semiangle_cutoff=30, energy=80e3, gpts=250) measurements = probe.scan(linescan, [detector], potential, max_batch=50, pbar=False) S_builder = SMatrix(semiangle_cutoff=30., energy=80e3, interpolation=2, gpts=500) atoms = Atoms('C', positions=[(2.5, 2.5, 2)], cell=(5, 5, 4)) atoms *= (2, 2, 1) potential = Potential(atoms) S = S_builder.multislice(potential, pbar=False) prism_measurements = S.scan(linescan, detector, max_batch_probes=10, pbar=False) assert np.allclose(measurements.array, prism_measurements.array, atol=1e-6)
def test_probe_waves_line_scan(): atoms = Atoms('CO', positions=[(2.5, 2.5, 2), (2.5, 2.5, 3)], cell=(5, 5, 4)) frozen_phonons = FrozenPhonons(atoms, 2, sigmas={'C': 0, 'O': 0.}) potential = Potential(atoms, sampling=.05) tds_potential = Potential(frozen_phonons, sampling=.05) linescan = LineScan(start=[0, 0], end=[2.5, 2.5], gpts=10) detector = AnnularDetector(inner=80, outer=200) probe = Probe(semiangle_cutoff=30, energy=80e3, gpts=500) measurements = probe.scan(linescan, [detector], potential, max_batch=50, pbar=False) tds_measurements = probe.scan(linescan, [detector], tds_potential, max_batch=50, pbar=False) assert np.allclose(measurements[detector].array, tds_measurements[detector].array, atol=1e-6) frozen_phonons = FrozenPhonons(atoms, 2, sigmas={'C': 0, 'O': 0.1}) tds_potential = Potential(frozen_phonons, sampling=.05) tds_measurements = probe.scan(linescan, [detector], tds_potential, max_batch=50, pbar=False) assert not np.allclose(measurements[detector].array, tds_measurements[detector].array, atol=1e-6)
def interpolate_line(measurement: Measurement, start: Sequence[float], end: Sequence[float], sampling: Sequence[float] = None): from abtem.scan import LineScan array = np.squeeze(measurement.array) if not (len(array.shape) == 2): raise RuntimeError() if (measurement.calibrations[-1] is None) or (measurement.calibrations[-2] is None): raise RuntimeError() if measurement.calibrations[-2].units != measurement.calibrations[-1].units: raise RuntimeError() if (sampling is None): sampling = (measurement.calibrations[-2].sampling + measurement.calibrations[-1].sampling) / 2. x = np.linspace( measurement.calibrations[-2].offset, measurement.shape[-2] * measurement.calibrations[-2].sampling, measurement.shape[-2]) y = np.linspace( measurement.calibrations[1].offset, measurement.shape[-1] * measurement.calibrations[-1].sampling, measurement.shape[-1]) line_scan = LineScan(start=start, end=end, sampling=sampling) interpolated_array = interpn((x, y), array, line_scan.get_positions()) return Measurement( interpolated_array, Calibration(offset=0, sampling=line_scan.sampling[0], units=measurement.calibrations[-2].units, name=measurement.calibrations[-2].name))
def interpolate_line(self, start, end, gpts=None, sampling=None, width=None, interpolation='splinef2d'): from abtem.scan import LineScan self = self.squeeze() if (self.calibrations[0] is None) or (self.calibrations[1] is None): raise RuntimeError() if self.calibrations[0].units != self.calibrations[1].units: raise RuntimeError() if (gpts is None) & (sampling is None): sampling = (self.calibrations[0].sampling + self.calibrations[1].sampling) / 2. x = np.linspace(self.calibrations[0].offset, self.shape[0] * self.calibrations[0].sampling, self.shape[0]) y = np.linspace(self.calibrations[1].offset, self.shape[1] * self.calibrations[1].sampling, self.shape[1]) scan = LineScan(start=start, end=end, gpts=gpts, sampling=sampling) if width is not None: direction = scan.direction perpendicular_direction = np.array([-direction[1], direction[0]]) n = int(np.ceil(width / scan.sampling[0])) perpendicular_positions = np.linspace(-width, width, n)[:, None] * perpendicular_direction[None] positions = scan.get_positions()[None] + perpendicular_positions[:, None] positions = positions.reshape((-1, 2)) interpolated_array = interpn((x, y), self.array, positions, method=interpolation, bounds_error=False, fill_value=0) interpolated_array = interpolated_array.reshape((n, -1)).mean(0) else: interpolated_array = interpn((x, y), self.array, scan.get_positions(), method=interpolation, bounds_error=False, fill_value=0) calibration = Calibration(offset=0, sampling=scan.sampling[0], units=self.calibrations[0].units, name=self.calibrations[0].name) return Measurement(interpolated_array, calibration)
def test_probe_waves_line_scan(): potential = Potential(Atoms('C', positions=[(2.5, 2.5, 2)], cell=(5, 5, 4))) linescan = LineScan(start=[0, 0], end=[2.5, 2.5], gpts=10) detector = AnnularDetector(inner=80, outer=200) S = SMatrix(30, 80e3, 1, gpts=500).multislice(potential, pbar=False) probe = Probe(semiangle_cutoff=30, energy=80e3, gpts=500) prism_measurement = S.scan(linescan, detector, max_batch_probes=10, pbar=False) measurement = probe.scan(linescan, detector, potential, max_batch=50, pbar=False) assert np.allclose(measurement.array, prism_measurement.array, atol=1e-6)
def test_line_scan(): start = (0, 0) end = (1, 1) scan = LineScan(start, end, gpts=5) positions = scan.get_positions() assert np.allclose(positions[0], start) assert np.allclose(positions[-1], end) assert np.allclose(positions[2], np.mean([start, end], axis=0)) assert np.allclose(np.linalg.norm(np.diff(positions, axis=0), axis=1), scan.sampling[0]) scan = LineScan(start, end, gpts=5, endpoint=False) positions = scan.get_positions() assert np.allclose(positions[0], start) assert np.allclose(positions[-1], (end[0] - (end[0] - start[0]) / 5, end[1] - (end[1] - start[1]) / 5))
def test_fig_5_22(): atoms = Atoms('CSiCuAuU', positions=[(x, 25, 4) for x in np.linspace(5, 45, 5)], cell=(50, 50, 8)) gpts = 2048 potential = Potential(atoms=atoms, gpts=gpts, parametrization='kirkland', slice_thickness=8) #probe = Probe(energy=200e3, defocus=700, Cs=1.3e7, semiangle_cutoff=10.37, rolloff=.1) probe = Probe(energy=200e3, defocus=700, Cs=1.3e7, semiangle_cutoff=10.37) probe.grid.match(potential) scan = LineScan(start=[5, 25], end=[45, 25], gpts=5) detector = AnnularDetector(inner=40, outer=200) measurement = probe.scan(scan, detector, potential, pbar=False) #correct_values = np.array([0.0001168, 0.00059303, 0.00214667, 0.00977803, 0.01167613]) correct_values = np.array( [0.00010675, 0.00055145, 0.00199743, 0.00911063, 0.01087296]) assert np.allclose(measurement.array, correct_values, atol=1e-5)
def test_linescan_raises(): with pytest.raises(ValueError) as e: LineScan(start=0, end=1) assert str(e.value) == 'Scan start/end has incorrect shape'
def interpolate_line( self, start: Tuple[float, float], end: Tuple[float, float], gpts: int = None, sampling: float = None, width: float = None, interpolation_method: str = 'splinef2d') -> 'Measurement': """ Interpolate 2d measurement along a line. Parameters ---------- start : two float Start point on line [Å]. end : two float End point on line [Å]. gpts : int Number of grid points along line. sampling : float Sampling rate of grid points along line [1 / Å]. width : float The interpolation will be averaged across interpolation_method : str Returns ------- Measurement Line profile measurement. """ from abtem.scan import LineScan measurement = self.squeeze() if measurement.dimensions != 2: raise RuntimeError('measurement must be 2d') if measurement.calibrations[0].units != measurement.calibrations[ 1].units: raise RuntimeError( 'the units of the interpolation dimensions must match') if (gpts is None) & (sampling is None): sampling = (measurement.calibrations[0].sampling + measurement.calibrations[1].sampling) / 2. x = np.linspace( measurement.calibrations[0].offset, measurement.shape[0] * measurement.calibrations[0].sampling + measurement.calibrations[0].offset, measurement.shape[0]) y = np.linspace( measurement.calibrations[1].offset, measurement.shape[1] * measurement.calibrations[1].sampling + measurement.calibrations[1].offset, measurement.shape[1]) scan = LineScan(start=start, end=end, gpts=gpts, sampling=sampling) if width is not None: direction = scan.direction perpendicular_direction = np.array([-direction[1], direction[0]]) n = int(np.ceil(width / scan.sampling[0])) perpendicular_positions = np.linspace( -width, width, n)[:, None] * perpendicular_direction[None] positions = scan.get_positions( )[None] + perpendicular_positions[:, None] positions = positions.reshape((-1, 2)) interpolated_array = interpn((x, y), measurement.array, positions, method=interpolation_method, bounds_error=False, fill_value=0) # import matplotlib.pyplot as plt # plt.plot(*positions.T,'ro') # plt.show() interpolated_array = interpolated_array.reshape((n, -1)).mean(0) else: interpolated_array = interpn((x, y), measurement.array, scan.get_positions(), method=interpolation_method, bounds_error=False, fill_value=0) calibration = Calibration(offset=0, sampling=scan.sampling[0], units=measurement.calibrations[0].units, name=measurement.calibrations[0].name) return Measurement(interpolated_array, calibration)