pyTEMlib 0.2025.2.1__tar.gz → 0.2025.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyTEMlib might be problematic. Click here for more details.

Files changed (45) hide show
  1. {pytemlib-0.2025.2.1/pyTEMlib.egg-info → pytemlib-0.2025.3.0}/PKG-INFO +2 -2
  2. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/core_loss_widget.py +2 -4
  3. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/eels_dialog.py +1 -1
  4. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/eels_tools.py +11 -10
  5. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/file_tools.py +14 -18
  6. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/graph_tools.py +85 -35
  7. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/image_tools.py +29 -18
  8. pytemlib-0.2025.3.0/pyTEMlib/version.py +6 -0
  9. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0/pyTEMlib.egg-info}/PKG-INFO +2 -2
  10. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib.egg-info/requires.txt +1 -1
  11. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/setup.py +1 -1
  12. pytemlib-0.2025.2.1/pyTEMlib/version.py +0 -6
  13. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/LICENSE +0 -0
  14. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/MANIFEST.in +0 -0
  15. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/README.rst +0 -0
  16. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/__init__.py +0 -0
  17. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/animation.py +0 -0
  18. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/atom_tools.py +0 -0
  19. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/config_dir.py +0 -0
  20. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/crystal_tools.py +0 -0
  21. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/diffraction_plot.py +0 -0
  22. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/dynamic_scattering.py +0 -0
  23. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/eds_tools.py +0 -0
  24. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/eels_dialog_utilities.py +0 -0
  25. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/file_tools_qt.py +0 -0
  26. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/graph_viz.py +0 -0
  27. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/image_dialog.py +0 -0
  28. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/image_dlg.py +0 -0
  29. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/info_widget.py +0 -0
  30. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/info_widget3.py +0 -0
  31. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/interactive_image.py +0 -0
  32. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/kinematic_scattering.py +0 -0
  33. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/low_loss_widget.py +0 -0
  34. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/microscope.py +0 -0
  35. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/peak_dialog.py +0 -0
  36. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/peak_dlg.py +0 -0
  37. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/probe_tools.py +0 -0
  38. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/sidpy_tools.py +0 -0
  39. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/simulation_tools.py +0 -0
  40. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib/xrpa_x_sections.py +0 -0
  41. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib.egg-info/SOURCES.txt +0 -0
  42. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib.egg-info/dependency_links.txt +0 -0
  43. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib.egg-info/entry_points.txt +0 -0
  44. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/pyTEMlib.egg-info/top_level.txt +0 -0
  45. {pytemlib-0.2025.2.1 → pytemlib-0.2025.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyTEMlib
3
- Version: 0.2025.2.1
3
+ Version: 0.2025.3.0
4
4
  Summary: pyTEM: TEM Data Quantification library through a model-based approach
5
5
  Home-page: https://pycroscopy.github.io/pyTEMlib/about.html
6
6
  Author: Gerd Duscher
@@ -39,7 +39,7 @@ Requires-Dist: spglib
39
39
  Requires-Dist: scikit-image
40
40
  Requires-Dist: scikit-learn
41
41
  Requires-Dist: pyNSID>=0.0.7
42
- Requires-Dist: sidpy>=0.12.1
42
+ Requires-Dist: sidpy>=0.12.7
43
43
  Requires-Dist: SciFiReaders>=0.0.8
44
44
  Dynamic: author
45
45
  Dynamic: author-email
@@ -500,8 +500,7 @@ class CoreLoss(object):
500
500
  self.core_loss_tab[11, 0].value = edge['areal_density']
501
501
  self.core_loss_tab[11, 2].value = 'a.u.'
502
502
  else:
503
- dispersion = self.parent.energy_scale[1] - \
504
- self.parent.energy_scale[0]
503
+ dispersion = self.parent.energy_scale.slope
505
504
  self.core_loss_tab[11, 0].value = np.round(
506
505
  edge['areal_density']/self.dataset.metadata['experiment']['flux_ppm']*1e-6, 2)
507
506
  self.core_loss_tab[11, 2].value = 'atoms/nm²'
@@ -663,8 +662,7 @@ class CoreLoss(object):
663
662
 
664
663
  edge['areal_density'] = self.core_loss_tab[11, 0].value
665
664
  if self.parent.y_scale != 1.0:
666
- dispersion = self.parent.energy_scale[1] - \
667
- self.parent.energy_scale[0]
665
+ dispersion = self.parent.energy_scale.slope
668
666
  edge['areal_density'] = self.core_loss_tab[11, 0].value * \
669
667
  self.dataset.metadata['experiment']['flux_ppm']/1e-6
670
668
  if 'model' in self.edges:
@@ -335,7 +335,7 @@ class CompositionWidget(object):
335
335
  self.dd = (self.energy_scale[0], self.energy_scale[1])
336
336
 
337
337
  self.dataset.metadata['experiment']['offset'] = self.energy_scale[0]
338
- self.dataset.metadata['experiment']['dispersion'] = self.energy_scale[1] - self.energy_scale[0]
338
+ self.dataset.metadata['experiment']['dispersion'] = self.spec_dim.slope
339
339
  if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
340
340
  self.dataset.metadata['edges'] = {'0': {}, 'model': {}, 'use_low_loss': False}
341
341
 
@@ -42,7 +42,6 @@ from pyTEMlib.xrpa_x_sections import x_sections
42
42
 
43
43
  import sidpy
44
44
  from sidpy.proc.fitter import SidFitter
45
- from sidpy.base.num_utils import get_slope
46
45
 
47
46
  # we have a function called find peaks - is it necessary?
48
47
  # or could we just use scipy.signal import find_peaks
@@ -604,7 +603,8 @@ def fit_plasmon(dataset: Union[sidpy.Dataset, np.ndarray], startFitEnergy: float
604
603
  guess_pos = np.argmax(fit_dset)
605
604
  guess_amplitude = fit_dset[guess_pos]
606
605
  guess_width =(endFitEnergy-startFitEnergy)/4
607
- guess_pos = energy[guess_pos]
606
+ guess_pos = energy[start_fit_pixel+guess_pos]
607
+
608
608
  if guess_width >8:
609
609
  guess_width=8
610
610
  try:
@@ -618,7 +618,7 @@ def fit_plasmon(dataset: Union[sidpy.Dataset, np.ndarray], startFitEnergy: float
618
618
  p0=[guess_pos, guess_width, guess_amplitude])
619
619
  except:
620
620
  popt=[0,0,0]
621
-
621
+
622
622
  plasmon = dataset.like_data(energy_loss_function(energy, popt[0], popt[1], popt[2]))
623
623
  plasmon *= anglog
624
624
  start_plasmon = np.searchsorted(energy, 0)+1
@@ -652,16 +652,16 @@ def fit_plasmon(dataset: Union[sidpy.Dataset, np.ndarray], startFitEnergy: float
652
652
  def angle_correction(spectrum):
653
653
 
654
654
  acceleration_voltage = spectrum.metadata['experiment']['acceleration_voltage']
655
- energy_scale = spectrum.get_spectral_dims(return_axis=True)[0].values
655
+ energy_scale = spectrum.get_spectral_dims(return_axis=True)[0]
656
656
  # eff_beta = effective_collection_angle(energy_scale, spectrum.metadata['experiment']['convergence_angle'],
657
657
  # spectrum.metadata['experiment']['collection_angle'],acceleration_voltage)
658
658
 
659
659
 
660
- epc = energy_scale[1] - energy_scale[0] # input('ev per channel : ');
660
+ epc = energy_scale.slope # input('ev per channel : ');
661
661
 
662
662
  alpha = spectrum.metadata['experiment']['convergence_angle'] # input('Alpha (mrad) : ');
663
663
  beta = spectrum.metadata['experiment']['collection_angle']# input('Beta (mrad) : ');
664
- e = energy_scale
664
+ e = energy_scale.values
665
665
  e0 = acceleration_voltage/1000 # input('E0 (keV) : ');
666
666
 
667
667
  T = 1000.0*e0*(1.+e0/1022.12)/(1.0+e0/511.06)**2 # %eV # equ.5.2a or Appendix E p 427
@@ -1261,7 +1261,7 @@ def second_derivative(dataset: sidpy.Dataset, sensitivity: float=2.5) -> None:
1261
1261
  """Calculates second derivative of a sidpy.dataset"""
1262
1262
 
1263
1263
  dim = dataset.get_spectral_dims()
1264
- energy_scale = dataset.get_spectral_dims(return_axis=True)[0].values
1264
+ energy_scale = dataset.get_spectral_dims(return_axis=True)[0]
1265
1265
  if dataset.data_type.name == 'SPECTRAL_IMAGE':
1266
1266
  spectrum = dataset.view.get_spectrum()
1267
1267
  else:
@@ -1269,7 +1269,7 @@ def second_derivative(dataset: sidpy.Dataset, sensitivity: float=2.5) -> None:
1269
1269
 
1270
1270
  spec = scipy.ndimage.gaussian_filter(spectrum, 3)
1271
1271
 
1272
- dispersion = get_slope(energy_scale)
1272
+ dispersion = energy_scale.slope
1273
1273
  second_dif = np.roll(spec, -3) - 2 * spec + np.roll(spec, +3)
1274
1274
  second_dif[:3] = 0
1275
1275
  second_dif[-3:] = 0
@@ -1405,8 +1405,9 @@ def identify_edges(dataset: sidpy.Dataset, noise_level: float=2.0):
1405
1405
 
1406
1406
  """
1407
1407
  dim = dataset.get_spectral_dims()
1408
- energy_scale = dataset.get_spectral_dims(return_axis=True)[0].values
1409
- dispersion = get_slope(energy_scale)
1408
+ energy_scale = dataset.get_spectral_dims(return_axis=True)[0]
1409
+ dispersion = energy_scale.slope
1410
+
1410
1411
  spec = scipy.ndimage.gaussian_filter(dataset, 3/dispersion) # smooth with 3eV wideGaussian
1411
1412
 
1412
1413
  first_derivative = spec - np.roll(spec, +2)
@@ -33,8 +33,6 @@ import pyTEMlib.crystal_tools
33
33
  from pyTEMlib.config_dir import config_path
34
34
  from pyTEMlib.sidpy_tools import *
35
35
 
36
- from pyTEMlib.sidpy_tools import *
37
-
38
36
  Qt_available = True
39
37
  try:
40
38
  from PyQt5 import QtCore, QtWidgets, QtGui
@@ -44,8 +42,6 @@ except ModuleNotFoundError:
44
42
 
45
43
  Dimension = sidpy.Dimension
46
44
 
47
- # Austin commented the line below - it is not used anywhere in the code, and it gives import errors 9-14-2024
48
- # get_slope = sidpy.base.num_utils.get_slopes
49
45
  __version__ = '2024.9.14'
50
46
 
51
47
  from traitlets import Unicode, Bool, validate, TraitError
@@ -116,7 +112,6 @@ class FileWidget2(ipywidgets.DOMWidget):
116
112
  value='None',
117
113
  description='directory:',
118
114
  disabled=False,
119
- button_style='',
120
115
  layout=widgets.Layout(width='90%'))
121
116
 
122
117
 
@@ -203,8 +198,7 @@ class FileWidget3(FileWidget2):
203
198
  self.loaded_datasets = widgets.Dropdown(options=self.dataset_list,
204
199
  value=self.dataset_list[0],
205
200
  description='loaded datasets:',
206
- disabled=False,
207
- button_style='')
201
+ disabled=False)
208
202
 
209
203
  ui = widgets.HBox([select_button, add_button, self.loaded_datasets])
210
204
  display(ui)
@@ -313,14 +307,12 @@ class FileWidget(ipywidgets.DOMWidget):
313
307
  value='None',
314
308
  description='directory:',
315
309
  disabled=False,
316
- button_style='',
317
310
  layout=widgets.Layout(width='90%'))
318
311
  self.dataset_list = ['None']
319
312
  self.loaded_datasets = widgets.Dropdown(options=self.dataset_list,
320
313
  value=self.dataset_list[0],
321
314
  description='loaded datasets:',
322
- disabled=False,
323
- button_style='')
315
+ disabled=False)
324
316
 
325
317
  self.set_options()
326
318
  ui = widgets.VBox([self.path_choice, self.select_files, widgets.HBox([select_button, add_button,
@@ -446,8 +438,7 @@ class ChooseDataset(object):
446
438
  self.select_image = widgets.Dropdown(options=self.dataset_list,
447
439
  value=self.dataset_list[0],
448
440
  description='select dataset:',
449
- disabled=False,
450
- button_style='')
441
+ disabled=False)
451
442
  if show_dialog:
452
443
  display(self.select_image)
453
444
 
@@ -484,7 +475,7 @@ class ChooseDataset(object):
484
475
  self.dataset = self.datasets[self.key]
485
476
  self.dataset.title = self.dataset.title.split('/')[-1]
486
477
  self.dataset.title = self.dataset.title.split('/')[-1]
487
-
478
+
488
479
 
489
480
  def add_to_dict(file_dict, name):
490
481
  full_name = os.path.join(file_dict['directory'], name)
@@ -968,13 +959,18 @@ def open_file(filename=None, h5_group=None, write_hdf_file=False, sum_frames=Fa
968
959
  id = dset[key1].original_metadata[key]['InstrumentId']
969
960
  dset[key1].metadata['experiment']['instrument'] = model + str(id)
970
961
  if key == 'Optics':
971
- dset[key1].metadata['experiment']['current'] = float(dset[key1].original_metadata[key]['LastMeasuredScreenCurrent'])
962
+ if 'LastMeasuredScreenCurrent' in dset[key1].original_metadata[key]:
963
+ dset[key1].metadata['experiment']['current'] = float(dset[key1].original_metadata[key]['LastMeasuredScreenCurrent'])
972
964
  if key == 'Scan':
973
- dset[key1].metadata['experiment']['pixel_time'] = float(dset[key1].original_metadata[key]['DwellTime'])
974
- dset[key1].metadata['experiment']['exposure_time'] = float(dset[key1].original_metadata[key]['FrameTime'])
965
+ if 'DwellTime' in dset[key1].original_metadata[key]:
966
+ dset[key1].metadata['experiment']['pixel_time'] = float(dset[key1].original_metadata[key]['DwellTime'])
967
+ if 'FrameTime' in dset[key1].original_metadata[key]:
968
+ dset[key1].metadata['experiment']['exposure_time'] = float(dset[key1].original_metadata[key]['FrameTime'])
975
969
  if key == 'Sample':
976
- dset[key1].metadata['experiment']['sample'] = dset[key1].original_metadata[key]['SampleDescription']
977
- dset[key1].metadata['experiment']['sample_id'] = dset[key1].original_metadata[key]['SampleId']
970
+ if 'SampleDescription' in dset[key1].original_metadata[key]:
971
+ dset[key1].metadata['experiment']['sample'] = dset[key1].original_metadata[key]['SampleDescription']
972
+ if 'SampleId' in dset[key1].original_metadata[key]:
973
+ dset[key1].metadata['experiment']['sample_id'] = dset[key1].original_metadata[key]['SampleId']
978
974
  if key == 'Detectors':
979
975
  if 'detector' in dset[key1].metadata['experiment']:
980
976
  used_detector = dset[key1].metadata['experiment']['detector']
@@ -5,7 +5,6 @@ import numpy as np
5
5
  # import ase
6
6
  import sys
7
7
 
8
- # from scipy.spatial import cKDTree, Voronoi, ConvexHull
9
8
  import scipy.spatial
10
9
  import scipy.optimize
11
10
  import scipy.interpolate
@@ -20,7 +19,7 @@ import pyTEMlib.crystal_tools
20
19
  from tqdm.auto import tqdm, trange
21
20
 
22
21
  from .graph_viz import *
23
-
22
+ QT_available = False
24
23
 
25
24
  ###########################################################################
26
25
  # utility functions
@@ -212,6 +211,14 @@ def get_voronoi(tetrahedra, atoms, bond_radii=None, optimize=True):
212
211
  """
213
212
 
214
213
  extent = atoms.cell.lengths()
214
+ print('extent', extent)
215
+
216
+ if np.abs(atoms.positions[:, 2]).sum() <= 0.01:
217
+ positions = atoms.positions[:, :2]
218
+ extent = extent[:2]
219
+ else:
220
+ positions = atoms.positions
221
+
215
222
  if atoms.info is None:
216
223
  atoms.info = {}
217
224
 
@@ -232,8 +239,8 @@ def get_voronoi(tetrahedra, atoms, bond_radii=None, optimize=True):
232
239
  r_a = []
233
240
  for vert in vertices:
234
241
  r_a.append(bond_radii[vert])
235
- voronoi, radius = interstitial_sphere_center(atoms.positions[vertices], r_a, optimize=optimize)
236
-
242
+ voronoi, radius = interstitial_sphere_center(positions[vertices], r_a, optimize=optimize)
243
+
237
244
  r_a = np.average(r_a) # np.min(r_a)
238
245
  r_aa.append(r_a)
239
246
 
@@ -247,7 +254,7 @@ def get_voronoi(tetrahedra, atoms, bond_radii=None, optimize=True):
247
254
  def find_overlapping_spheres(voronoi_vertices, r_vv, r_a, cheat=1.):
248
255
  """Find overlapping spheres"""
249
256
 
250
- vertex_tree = scipy.spatial.cKDTree(voronoi_vertices)
257
+ vertex_tree = scipy.spatial.KDTree(voronoi_vertices)
251
258
 
252
259
  pairs = vertex_tree.query_pairs(r=r_a * 2)
253
260
 
@@ -424,7 +431,7 @@ def get_non_periodic_supercell(super_cell):
424
431
  return atoms
425
432
 
426
433
  def get_connectivity_matrix(crystal, atoms, polyhedra):
427
- crystal_tree = scipy.spatial.cKDTree(crystal.positions)
434
+ crystal_tree = scipy.spatial.KDTree(crystal.positions)
428
435
 
429
436
 
430
437
  connectivity_matrix = np.zeros([len(atoms),len(atoms)], dtype=int)
@@ -476,8 +483,8 @@ def get_bonds(crystal, shift= 0., verbose = False, cheat=1.0):
476
483
  other = []
477
484
  super_cell_atoms =[]
478
485
 
479
- atoms_tree = scipy.spatial.cKDTree(atoms.positions-crystal.cell.lengths())
480
- crystal_tree = scipy.spatial.cKDTree(crystal.positions)
486
+ atoms_tree = scipy.spatial.KDTree(atoms.positions-crystal.cell.lengths())
487
+ crystal_tree = scipy.spatial.KDTree(crystal.positions)
481
488
  connectivity_matrix = np.zeros([len(atoms),len(atoms)], dtype=float)
482
489
 
483
490
  for polyhedron in polyhedra.values():
@@ -699,18 +706,21 @@ def find_polyhedra(atoms, optimize=True, cheat=1.0, bond_radii=None):
699
706
  raise TypeError('This function needs an ase.Atoms object')
700
707
 
701
708
  if np.abs(atoms.positions[:, 2]).sum() <= 0.01:
702
- tetrahedra = scipy.spatial.Delaunay(atoms.positions[:, :2])
709
+ positions = atoms.positions[:, :2]
710
+ print('2D')
703
711
  else:
704
- tetrahedra = scipy.spatial.Delaunay(atoms.positions)
712
+ positions = atoms.positions
713
+ tetrahedra = scipy.spatial.Delaunay(positions)
705
714
 
706
715
  voronoi_vertices, voronoi_tetrahedrons, r_vv, r_a = get_voronoi(tetrahedra, atoms, optimize=optimize, bond_radii=bond_radii)
707
- if np.abs(atoms.positions[:, 2]).sum() <= 0.01:
708
- r_vv = np.array(r_vv)*3.
716
+
717
+ if positions.shape[1] < 3:
718
+ r_vv = np.array(r_vv)*1.
709
719
  overlapping_pairs = find_overlapping_spheres(voronoi_vertices, r_vv, r_a, cheat=cheat)
710
720
 
711
721
  clusters, visited_all = find_interstitial_clusters(overlapping_pairs)
712
722
 
713
- if np.abs(atoms.positions[:, 2]).sum() <= 0.01:
723
+ if positions.shape[1] < 3:
714
724
  rings = get_polygons(atoms, clusters, voronoi_tetrahedrons)
715
725
  return rings
716
726
  else:
@@ -770,7 +780,7 @@ def sort_polyhedra_by_vertices(polyhedra, visible=range(4, 100), z_lim=[0, 100],
770
780
  ##########################
771
781
  # New Graph Stuff
772
782
  ##########################
773
- def breadth_first_search(graph, initial, projected_crystal):
783
+ def breadth_first_search2(graph, initial, projected_crystal):
774
784
  """ breadth first search of atoms viewed as a graph
775
785
 
776
786
  the projection dictionary has to contain the following items
@@ -794,15 +804,20 @@ def breadth_first_search(graph, initial, projected_crystal):
794
804
  """
795
805
 
796
806
  projection_tags = projected_crystal.info['projection']
797
-
798
- # get lattice vectors to hopp along through graph
799
- projected_unit_cell = projected_crystal.cell[:2, :2]
800
- a_lattice_vector = projected_unit_cell[0]
801
- b_lattice_vector = projected_unit_cell[1]
802
- main = np.array([a_lattice_vector, -a_lattice_vector, b_lattice_vector, -b_lattice_vector]) # vectors of unit cell
803
- near = np.append(main, projection_tags['near_base'], axis=0) # all nearest atoms
807
+ if 'lattice_vector' in projection_tags:
808
+ a_lattice_vector = projection_tags['lattice_vector']['a']
809
+ b_lattice_vector = projection_tags['lattice_vector']['b']
810
+ main = np.array([a_lattice_vector, -a_lattice_vector, b_lattice_vector, -b_lattice_vector]) # vectors of unit cell
811
+ near = main
812
+ else:
813
+ # get lattice vectors to hopp along through graph
814
+ projected_unit_cell = projected_crystal.cell[:2, :2]
815
+ a_lattice_vector = projected_unit_cell[0]
816
+ b_lattice_vector = projected_unit_cell[1]
817
+ main = np.array([a_lattice_vector, -a_lattice_vector, b_lattice_vector, -b_lattice_vector]) # vectors of unit cell
818
+ near = np.append(main, projection_tags['near_base'], axis=0) # all nearest atoms
804
819
  # get k next nearest neighbours for each node
805
- neighbour_tree = scipy.spatial.cKDTree(graph)
820
+ neighbour_tree = scipy.spatial.KDTree(graph)
806
821
  distances, indices = neighbour_tree.query(graph, # let's get all neighbours
807
822
  k=50) # projection_tags['number_of_nearest_neighbours']*2 + 1)
808
823
  # print(projection_tags['number_of_nearest_neighbours'] * 2 + 1)
@@ -835,6 +850,46 @@ def breadth_first_search(graph, initial, projected_crystal):
835
850
 
836
851
  return graph[visited], ideal
837
852
 
853
+
854
+
855
+ def breath_first_search(graph, initial, lattice_parameter, tolerance=1):
856
+ """ breadth first search of atoms viewed as a graph
857
+ we only
858
+ """
859
+ neighbour_tree = scipy.spatial.KDTree(graph)
860
+ distances, indices = neighbour_tree.query(graph, # let's get all neighbours
861
+ k=50) # projection_tags['number_of_nearest_neighbours']*2 + 1)
862
+ visited = [] # the atoms we visited
863
+ angles = [] # atoms at ideal lattice
864
+ sub_lattice = [] # atoms in base and disregarded
865
+ queue = [initial]
866
+ queue_angles=[0]
867
+
868
+ while queue:
869
+ node = queue.pop(0)
870
+ angle = queue_angles.pop(0)
871
+ if node not in visited:
872
+ visited.append(node)
873
+ angles.append(angle)
874
+ neighbors = indices[node]
875
+ for i, neighbour in enumerate(neighbors):
876
+ if neighbour not in visited:
877
+ hopp = graph[node] - graph[neighbour]
878
+ distance_to_ideal = np.linalg.norm(hopp)
879
+ if np.min(np.abs(distance_to_ideal - lattice_parameter)) < tolerance:
880
+ queue.append(neighbour)
881
+ queue_angles.append(np.arctan2(hopp[1], hopp[0]))
882
+ angles[0] = angles[1]
883
+ out_atoms = np.stack([graph[visited][:, 0], graph[visited][:, 1], angles])
884
+ return out_atoms.T, visited
885
+
886
+ def delete_rim_atoms(atoms, extent, rim_distance):
887
+ rim = np.where(atoms[:, :2] - extent > -rim_distance)[0]
888
+ middle_atoms = np.delete(atoms, rim, axis=0)
889
+ rim = np.where(middle_atoms[:, :2].min(axis=1)<rim_distance)[0]
890
+ middle_atoms = np.delete(middle_atoms, rim, axis=0)
891
+ return middle_atoms
892
+
838
893
  ####################
839
894
  # Distortion Matrix
840
895
  ####################
@@ -992,7 +1047,7 @@ def get_significant_vertices(vertices, distance=3):
992
1047
  list of points that are all a minimum of 3 apart.
993
1048
  """
994
1049
 
995
- tt = scipy.spatial.cKDTree(np.array(vertices))
1050
+ tt = scipy.spatial.KDTree(np.array(vertices))
996
1051
  near = tt.query_ball_point(vertices, distance)
997
1052
  ideal_vertices = []
998
1053
  for indices in near:
@@ -1146,21 +1201,16 @@ def undistort_stack(distortion_matrix, data):
1146
1201
  nimages = data.shape[0]
1147
1202
  done = 0
1148
1203
 
1149
- if QT_available:
1150
- progress = ft.ProgressDialog("Correct Scan Distortions", nimages)
1204
+
1151
1205
  for i in range(nimages):
1152
- if QT_available:
1153
- progress.set_value(i)
1154
- elif done < int((i + 1) / nimages * 50):
1155
- done = int((i + 1) / nimages * 50)
1156
- sys.stdout.write('\r')
1157
- # progress output :
1158
- sys.stdout.write("[%-50s] %d%%" % ('=' * done, 2 * done))
1159
- sys.stdout.flush()
1206
+ done = int((i + 1) / nimages * 50)
1207
+ sys.stdout.write('\r')
1208
+ # progress output :
1209
+ sys.stdout.write("[%-50s] %d%%" % ('=' * done, 2 * done))
1210
+ sys.stdout.flush()
1160
1211
 
1161
1212
  interpolated[i, :, :] = griddata(corrected, intensity_values[i, :], (grid_x, grid_y), method='linear')
1162
- if QT_available:
1163
- progress.set_value(nimages)
1213
+
1164
1214
  print(':-)')
1165
1215
  print('You have successfully completed undistortion of image stack')
1166
1216
  return interpolated
@@ -212,6 +212,7 @@ def fourier_transform(dset: sidpy.Dataset) -> sidpy.Dataset:
212
212
  return
213
213
 
214
214
  new_image = new_image - new_image.min()
215
+
215
216
  fft_transform = (np.fft.fftshift(np.fft.fft2(new_image)))
216
217
 
217
218
  image_dims = pyTEMlib.sidpy_tools.get_image_dims(dset)
@@ -227,12 +228,12 @@ def fourier_transform(dset: sidpy.Dataset) -> sidpy.Dataset:
227
228
  fft_dset.modality = 'fft'
228
229
 
229
230
  fft_dset.set_dimension(0, sidpy.Dimension(np.fft.fftshift(np.fft.fftfreq(new_image.shape[0],
230
- d=ft.get_slope(dset.x.values))),
231
+ d=dset.x[1]-dset.x[0])),
231
232
 
232
233
  name='u', units=units_x, dimension_type='RECIPROCAL',
233
234
  quantity='reciprocal_length'))
234
235
  fft_dset.set_dimension(1, sidpy.Dimension(np.fft.fftshift(np.fft.fftfreq(new_image.shape[1],
235
- d=ft.get_slope(dset.y.values))),
236
+ d=dset.y[1]- dset.y[0])),
236
237
  name='v', units=units_y, dimension_type='RECIPROCAL',
237
238
  quantity='reciprocal_length'))
238
239
 
@@ -319,7 +320,9 @@ def diffractogram_spots(dset, spot_threshold, return_center=True, eps=0.1):
319
320
  print(f'Found {spots_random.shape[0]} reflections')
320
321
 
321
322
  # Needed for conversion from pixel to Reciprocal space
322
- rec_scale = np.array([ft.get_slope(dset.u.values), ft.get_slope(dset.v.values)])
323
+ image_dims = dset.get_image_dims(return_axis=True)
324
+ rec_scale = np.array([image_dims[0].slope, image_dims[1].slope])
325
+
323
326
  spots_random[:, :2] = spots_random[:, :2]*rec_scale+[dset.u.values[0], dset.v.values[0]]
324
327
  # sort reflections
325
328
  spots_random[:, 2] = np.linalg.norm(spots_random[:, 0:2], axis=1)
@@ -516,7 +519,8 @@ def complete_registration(main_dataset, storage_channel=None):
516
519
 
517
520
  rigid_registered_dataset = rigid_registration(main_dataset)
518
521
 
519
-
522
+ print(rigid_registered_dataset)
523
+ rigid_registered_dataset.data_type = 'IMAGE_STACK'
520
524
  print('Non-Rigid_Registration')
521
525
 
522
526
  non_rigid_registered = demon_registration(rigid_registered_dataset)
@@ -580,7 +584,6 @@ def demon_registration(dataset, verbose=False):
580
584
  resampler.SetDefaultPixelValue(0)
581
585
 
582
586
  for i in trange(nimages):
583
-
584
587
  moving = sitk.GetImageFromArray(dataset[i])
585
588
  moving_f = sitk.DiscreteGaussian(moving, 2.0)
586
589
  displacement_field = demons.Execute(fixed, moving_f)
@@ -603,6 +606,7 @@ def demon_registration(dataset, verbose=False):
603
606
  if 'input_shape' in dataset.metadata:
604
607
  demon_registered.metadata['input_shape'] = dataset.metadata['input_shape']
605
608
  demon_registered.metadata['input_dataset'] = dataset.source
609
+ demon_registered.data_type = 'IMAGE_STACK'
606
610
  return demon_registered
607
611
 
608
612
 
@@ -699,6 +703,7 @@ def rigid_registration(dataset, sub_pixel=True):
699
703
  rigid_registered.set_dimension(2, sidpy.Dimension(array_y,
700
704
  'y', units='nm', quantity='Length',
701
705
  dimension_type='spatial'))
706
+ rigid_registered.data_type = 'IMAGE_STACK'
702
707
  return rigid_registered.rechunk({0: 'auto', 1: -1, 2: -1})
703
708
 
704
709
 
@@ -902,9 +907,9 @@ def get_profile(dataset, line, spline_order=-1):
902
907
  """
903
908
  xv, yv = get_line_selection_points(line)
904
909
  if dataset.data_type.name == 'IMAGE':
905
- dataset.get_image_dims()
906
- xv /= (dataset.x[1] - dataset.x[0])
907
- yv /= (dataset.y[1] - dataset.y[0])
910
+ image_dims = dataset.get_image_dims(return_axis=True)
911
+ xv /= image_dims[0].slope
912
+ yv /= image_dims[1].slope
908
913
  profile = scipy.ndimage.map_coordinates(np.array(dataset), [xv, yv])
909
914
 
910
915
  profile_dataset = sidpy.Dataset.from_array(profile.sum(axis=0))
@@ -1101,7 +1106,7 @@ def clean_svd(im, pixel_size=1, source_size=5):
1101
1106
  patch_size = int(source_size/pixel_size)
1102
1107
  if patch_size < 3:
1103
1108
  patch_size = 3
1104
- patches = image.extract_patches_2d(im, (patch_size, patch_size))
1109
+ patches = image.extract_patches_2d(np.array(im), (patch_size, patch_size))
1105
1110
  patches = patches.reshape(patches.shape[0], patches.shape[1]*patches.shape[2])
1106
1111
 
1107
1112
  num_components = 32
@@ -1110,6 +1115,8 @@ def clean_svd(im, pixel_size=1, source_size=5):
1110
1115
  u_im_size = int(np.sqrt(u.shape[0]))
1111
1116
  reduced_image = u[:, 0].reshape(u_im_size, u_im_size)
1112
1117
  reduced_image = reduced_image/reduced_image.sum()*im.sum()
1118
+ if isinstance(im, sidpy.Dataset):
1119
+ reduced_image = im.like_data(reduced_image)
1113
1120
  return reduced_image
1114
1121
 
1115
1122
 
@@ -1402,11 +1409,18 @@ def decon_lr(o_image, probe, verbose=False):
1402
1409
  error = np.ones(o_image.shape, dtype=np.complex64)
1403
1410
  est = np.ones(o_image.shape, dtype=np.complex64)
1404
1411
  source = np.ones(o_image.shape, dtype=np.complex64)
1412
+ o_image = o_image - o_image.min()
1413
+ image_mult = o_image.max()
1414
+ o_image = o_image / o_image.max()
1405
1415
  source.real = o_image
1406
1416
 
1407
1417
  response_ft = fftpack.fft2(probe_c)
1408
1418
 
1409
- ap_angle = o_image.metadata['experiment']['convergence_angle'] / 1000.0 # now in rad
1419
+
1420
+
1421
+ ap_angle = o_image.metadata['experiment']['convergence_angle']
1422
+ if ap_angle > .1:
1423
+ ap_angle /= 1000 # now in rad
1410
1424
 
1411
1425
  e0 = float(o_image.metadata['experiment']['acceleration_voltage'])
1412
1426
 
@@ -1438,19 +1452,16 @@ def decon_lr(o_image, probe, verbose=False):
1438
1452
  # de = 100
1439
1453
  dest = 100
1440
1454
  i = 0
1441
- while abs(dest) > 0.0001: # or abs(de) > .025:
1455
+ while abs(dest) > 0.001: # or abs(de) > .025:
1442
1456
  i += 1
1443
1457
  error_old = np.sum(error.real)
1444
1458
  est_old = est.copy()
1445
1459
  error = source / np.real(fftpack.fftshift(fftpack.ifft2(fftpack.fft2(est) * response_ft)))
1446
1460
  est = est * np.real(fftpack.fftshift(fftpack.ifft2(fftpack.fft2(error) * np.conjugate(response_ft))))
1447
- # est = est_old * est
1448
- # est = np.real(fftpack.fftshift(fftpack.ifft2(fftpack.fft2(est)*fftpack.fftshift(aperture) )))
1449
-
1461
+
1450
1462
  error_new = np.real(np.sum(np.power(error, 2))) - error_old
1451
1463
  dest = np.sum(np.power((est - est_old).real, 2)) / np.sum(est) * 100
1452
- # print(np.sum((est.real - est_old.real)* (est.real - est_old.real) )/np.sum(est.real)*100 )
1453
-
1464
+
1454
1465
  if error_old != 0:
1455
1466
  de = error_new / error_old * 1.0
1456
1467
  else:
@@ -1466,10 +1477,10 @@ def decon_lr(o_image, probe, verbose=False):
1466
1477
  print('terminate')
1467
1478
  progress.update(1)
1468
1479
  progress.write(f"converged in {i} iterations")
1469
- # progress.close()
1470
1480
  print('\n Lucy-Richardson deconvolution converged in ' + str(i) + ' iterations')
1471
- est2 = np.real(fftpack.ifft2(fftpack.fft2(est) * fftpack.fftshift(aperture)))
1481
+ est2 = np.real(fftpack.ifft2(fftpack.fft2(est) * fftpack.fftshift(aperture)))*image_mult
1472
1482
  out_dataset = o_image.like_data(est2)
1473
1483
  out_dataset.title = 'Lucy Richardson deconvolution'
1474
1484
  out_dataset.data_type = 'image'
1475
1485
  return out_dataset
1486
+
@@ -0,0 +1,6 @@
1
+ """
2
+ version
3
+ """
4
+ _version = '0.2025.03.0'
5
+ __version__ = _version
6
+ _time = '2025-02-25 19:58:26'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyTEMlib
3
- Version: 0.2025.2.1
3
+ Version: 0.2025.3.0
4
4
  Summary: pyTEM: TEM Data Quantification library through a model-based approach
5
5
  Home-page: https://pycroscopy.github.io/pyTEMlib/about.html
6
6
  Author: Gerd Duscher
@@ -39,7 +39,7 @@ Requires-Dist: spglib
39
39
  Requires-Dist: scikit-image
40
40
  Requires-Dist: scikit-learn
41
41
  Requires-Dist: pyNSID>=0.0.7
42
- Requires-Dist: sidpy>=0.12.1
42
+ Requires-Dist: sidpy>=0.12.7
43
43
  Requires-Dist: SciFiReaders>=0.0.8
44
44
  Dynamic: author
45
45
  Dynamic: author-email
@@ -12,5 +12,5 @@ spglib
12
12
  scikit-image
13
13
  scikit-learn
14
14
  pyNSID>=0.0.7
15
- sidpy>=0.12.1
15
+ sidpy>=0.12.7
16
16
  SciFiReaders>=0.0.8
@@ -49,7 +49,7 @@ setuptools.setup(
49
49
  author_email="gduscher@utk.edu",
50
50
 
51
51
  install_requires=['scipy', 'numpy', 'pillow', 'ase', 'tqdm', 'plotly', 'pandas', 'requests', 'lxml', 'ipympl',
52
- 'spglib', 'scikit-image', 'scikit-learn', 'pyNSID>=0.0.7', 'sidpy>=0.12.1', 'SciFiReaders>=0.0.8'], # 'PyQt5> 1.0'],#
52
+ 'spglib', 'scikit-image', 'scikit-learn', 'pyNSID>=0.0.7', 'sidpy>=0.12.7', 'SciFiReaders>=0.0.8'], # 'PyQt5> 1.0'],#
53
53
  setup_requires=['pytest-runner'],
54
54
  tests_require=['pytest'],
55
55
  platforms=['Linux', 'Mac OSX', 'Windows 11/10'],
@@ -1,6 +0,0 @@
1
- """
2
- version
3
- """
4
- _version = '0.2025.02.1'
5
- __version__ = _version
6
- _time = '2025-02-23 19:58:26'
File without changes
File without changes
File without changes
File without changes