pyTEMlib 0.2024.9.0__py3-none-any.whl → 0.2025.2.2__py3-none-any.whl

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.

pyTEMlib/peak_dialog.py CHANGED
@@ -136,13 +136,13 @@ def get_sidebar():
136
136
  return side_bar
137
137
 
138
138
  class PeakFitWidget(object):
139
- def __init__(self, datasets=None):
139
+ def __init__(self, datasets, key):
140
140
  self.datasets = datasets
141
141
  if not isinstance(datasets, dict):
142
142
  raise TypeError('need dictioary of sidpy datasets')
143
143
 
144
144
  self.sidebar = get_sidebar()
145
- self.key = list(self.datasets)[0]
145
+ self.key = key
146
146
  self.dataset = datasets[self.key]
147
147
  if not isinstance(self.dataset, sidpy.Dataset):
148
148
  raise TypeError('dataset or first item inhas to be a sidpy dataset')
@@ -199,16 +199,22 @@ class PeakFitWidget(object):
199
199
  spectrum = self.dataset.view.get_spectrum()
200
200
  else:
201
201
  spectrum = self.dataset
202
+ #if 'features' in self.peaks:
203
+ if 'resolution_function' in self.datasets.keys():
204
+
205
+ zl = self.datasets['resolution_function'] # self.peaks['features']]
206
+ additional_spectra = {}
202
207
  if len(self.model) > 1:
203
208
  additional_spectra = {'model': self.model,
204
- 'difference': spectrum-self.model}
209
+ 'difference': spectrum-self.model,
210
+ 'zero_loss': self.datasets['resolution_function']}
205
211
  else:
206
212
  additional_spectra = {}
207
213
  if 'peaks' in self.peaks:
208
214
  if len(self.peaks)>0:
209
215
  for index, peak in self.peaks['peaks'].items(): # ll
210
216
  p = [peak['position'], peak['amplitude'], peak['width']]
211
- additional_spectra[f'peak {index}']= eels_tools.gauss(self.energy_scale, p)
217
+ additional_spectra[f'peak {index}']= gauss(np.array(self.energy_scale), p)
212
218
  self.view.plot(scale=True, additional_spectra=additional_spectra )
213
219
  self.change_y_scale = 1.
214
220
 
@@ -263,7 +269,9 @@ class PeakFitWidget(object):
263
269
  if self.dataset.data_type.name =='SPECTRAL_IMAGE':
264
270
  self.view = eels_dialog_utilities.SIPlot(self.dataset)
265
271
  else:
266
- self.view = eels_dialog_utilities.SpectrumPlot(self.dataset)
272
+ self.view = eels_dialog_utilities.SpectrumPlot(self.dataset)
273
+ self.dataset.view = self.view
274
+ #self.view.legend(loc='Upper Right')
267
275
  self.y_scale = 1.0
268
276
  self.change_y_scale = 1.0
269
277
 
@@ -309,19 +317,26 @@ class PeakFitWidget(object):
309
317
  self.peaks['peaks'][str(peak_index)]['asymmetry'] = 0.
310
318
  self.sidebar[12, 0].value = self.peaks['peaks'][str(peak_index)]['asymmetry']
311
319
 
312
-
313
- def fit_peaks(self, value = 0):
314
- """Fit spectrum with peaks given in peaks dictionary"""
315
- # print('Fitting peaks...')
320
+
321
+ def get_input(self):
316
322
  p_in = []
317
323
  for key, peak in self.peaks['peaks'].items():
318
324
  if key.isdigit():
319
325
  p_in.append(peak['position'])
320
326
  p_in.append(peak['amplitude'])
321
327
  p_in.append(peak['width'])
328
+ return p_in
322
329
 
323
- spectrum = np.array(self.dataset)
324
-
330
+
331
+ def fit_peaks(self, value=0):
332
+ """Fit spectrum with peaks given in peaks dictionary"""
333
+ # print('Fitting peaks...')
334
+
335
+ if self.dataset.data_type.name == 'SPECTRUM':
336
+ spectrum = np.array(self.dataset)
337
+ else:
338
+ spectrum = self.dataset.view.get_spectrum()
339
+ spectrum -= spectrum.min() - 1
325
340
  # set the energy scale and fit start and end points
326
341
  energy_scale = np.array(self.energy_scale)
327
342
  start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
@@ -335,25 +350,31 @@ class PeakFitWidget(object):
335
350
  # print('Core loss model found. Fitting on top of the model.')
336
351
  model = self.dataset.metadata['edges']['model']['spectrum'][start_channel:end_channel]
337
352
  else:
353
+
338
354
  # print('No core loss model found. Fitting to the full spectrum.')
339
355
  model = np.zeros(end_channel - start_channel)
340
356
 
341
357
  # if we have a core loss model we will only fit the difference between the model and the data.
342
358
  difference = np.array(spectrum[start_channel:end_channel] - model)
343
-
359
+ p_in = self.get_input()
344
360
  # find the optimum fitting parameters
345
- [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals_smooth, np.array(p_in), ftol=1e-3,
346
- args=(energy_scale, difference, False))
361
+ #[self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals_smooth, np.array(p_in), ftol=1e-3,
362
+ # args=(energy_scale, difference, False))
347
363
 
364
+ [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals3, np.array(p_in, dtype=np.float64),
365
+ args=(energy_scale, difference) ) # , False))
348
366
  # construct the fit data from the optimized parameters
349
- self.peak_model = np.zeros(len(self.energy_scale))
350
- self.model = np.zeros(len(self.energy_scale))
351
- self.model[start_channel:end_channel] = model
352
- fit = eels_tools.model_smooth(energy_scale, self.p_out, False)
353
- self.peak_model[start_channel:end_channel] = fit
354
- self.dataset.metadata['peak_fit']['edge_model'] = self.model
355
- self.model = self.model + self.peak_model
356
- self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
367
+ #self.peak_model = np.zeros(len(self.energy_scale))
368
+ #self.model = np.zeros(len(self.energy_scale))
369
+ #self.model[start_channel:end_channel] = model
370
+ #fit = eels_tools.model_smooth(energy_scale, self.p_out, False)
371
+ fit = eels_tools.gmm(energy_scale, self.p_out) # , False)
372
+ self.peak_model = fit
373
+
374
+ #self.peak_model[start_channel:end_channel] = fit
375
+ #self.dataset.metadata['peak_fit']['edge_model'] = self.model
376
+ #self.model = self.model + self.peak_model
377
+ #self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
357
378
 
358
379
  for key, peak in self.peaks['peaks'].items():
359
380
  if key.isdigit():
@@ -410,13 +431,29 @@ class PeakFitWidget(object):
410
431
  self.peak_list = []
411
432
  self.peaks['peaks'] = {}
412
433
  new_number_of_peaks = 0
413
- for i in range(number_of_peaks):
414
- self.peak_list.append((f'Peak {i+1}', i))
415
- p = self.peak_out_list[i]
416
- if p[1]>0:
417
- self.peaks['peaks'][str(new_number_of_peaks)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
418
- 'asymmetry': 0}
419
- new_number_of_peaks += 1
434
+
435
+ peaks, prop = scipy.signal.find_peaks(self.peak_model, width=5)
436
+ print(len(peaks), number_of_peaks, len(peaks)>= number_of_peaks)
437
+ if len(peaks) >= number_of_peaks:
438
+ if self.dataset.data_type.name == 'SPECTRUM':
439
+ spectrum = np.array(self.dataset)
440
+ else:
441
+ spectrum = self.dataset.view.get_spectrum()
442
+ for i in range(number_of_peaks):
443
+ self.peak_list.append((f'Peak {i+1}', i))
444
+ p = [self.energy_scale[peaks[i]], np.float32(spectrum[peaks[i]]), np.sqrt(prop['widths'][i])]
445
+ if p[1]>0:
446
+ self.peaks['peaks'][str(new_number_of_peaks)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
447
+ 'asymmetry': 0}
448
+ new_number_of_peaks += 1
449
+ else:
450
+ for i in range(number_of_peaks):
451
+ self.peak_list.append((f'Peak {i+1}', i))
452
+ p = self.peak_out_list[i]
453
+ if p[1]>0:
454
+ self.peaks['peaks'][str(new_number_of_peaks)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
455
+ 'asymmetry': 0}
456
+ new_number_of_peaks += 1
420
457
  self.sidebar[5, 0].value = str(new_number_of_peaks)
421
458
  self.peak_list.append((f'add peak', -1))
422
459
 
@@ -437,9 +474,13 @@ class PeakFitWidget(object):
437
474
  """
438
475
  iterations = self.sidebar[4, 0].value
439
476
  self.sidebar[5, 0].value = 0
440
- advanced_present=False
477
+
478
+ if self.key == self.datasets['_relationship']['low_loss']:
479
+ if 'resolution_function' in self.datasets['_relationship'].keys():
480
+ self.model = np.array(self.datasets['resolution_function'])
481
+
441
482
 
442
- self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset, iterations, advanced_present)
483
+ self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset-self.model, iterations, advanced_present)
443
484
 
444
485
  spec_dim = ft.get_dimensions_by_type('SPECTRAL', self.dataset)[0]
445
486
  if spec_dim[1][0] > 0:
@@ -454,7 +495,9 @@ class PeakFitWidget(object):
454
495
  self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
455
496
  self.dataset.metadata['peak_fit']['peak_out_list'] = self.peak_out_list
456
497
 
457
- self.sidebar[5, 0].value = str(len(self.peak_out_list))
498
+ peaks, prop = scipy.signal.find_peaks(self.peak_model, width=5)
499
+
500
+ self.sidebar[5, 0].value = str(len(peaks))
458
501
  self.update()
459
502
  self.plot()
460
503
 
@@ -471,15 +514,20 @@ class PeakFitWidget(object):
471
514
  energy_scale = np.array(self.energy_scale)
472
515
  start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
473
516
  end_channel = np.searchsorted(energy_scale, self.peaks['fit_end'])
474
- energy_scale = self.energy_scale[start_channel:end_channel]
517
+ energy_scale = self.energy_scale # [start_channel:end_channel]
475
518
  # select the core loss model if it exists. Otherwise, we will fit to the full spectrum.
476
-
477
- fit = eels_tools.model_smooth(energy_scale, p_peaks, False)
478
- self.peak_model[start_channel:end_channel] = fit
479
- if 'edge_model' in self.dataset.metadata['peak_fit']:
519
+
520
+ p_peaks = np.array(p_peaks, dtype=np.float64)
521
+
522
+ fit = eels_tools.gmm(energy_scale, p_peaks) # , False)
523
+ self.peak_model = fit
524
+ #self.peak_model[start_channel:end_channel] = fit
525
+ """if 'edge_model' in self.dataset.metadata['peak_fit']:
480
526
  self.model = self.dataset.metadata['peak_fit']['edge_model'] + self.peak_model
481
527
  else:
482
528
  self.model = np.zeros(self.dataset.shape)
529
+ """
530
+ self.model = fit
483
531
 
484
532
  def modify_peak_position(self, value=-1):
485
533
  peak_index = self.sidebar[7, 0].value
@@ -683,22 +731,24 @@ if Qt_available:
683
731
  self.axis.clear()
684
732
 
685
733
  self.axis.plot(self.energy_scale, spectrum, label='spectrum')
686
- if 'zero_loss' in self.dataset.metadata:
687
- self.axis.plot(self.energy_scale, spectrum, label=name)
734
+ #if 'features' in self.peaks:
735
+ zl = self.datasets[self.peaks['features']]
736
+ self.axis.plot(self.energy_scale, zl, label='zero_loss')
688
737
 
689
738
  if len(self.model) > 1:
690
739
  self.axis.plot(self.energy_scale, self.model, label='model')
691
740
  self.axis.plot(self.energy_scale, spectrum - self.model, label='difference')
692
741
  #self.axis.plot(self.energy_scale, (spectrum - self.model) / np.sqrt(spectrum), label='Poisson')
693
- self.axis.legend()
742
+
694
743
  self.axis.set_xlim(x_limit)
695
744
  self.axis.set_ylim(y_limit)
696
- self.axis.figure.canvas.draw_idle()
697
-
745
+
698
746
  for index, peak in self.peaks['peaks'].items():
699
747
  p = [peak['position'], peak['amplitude'], peak['width']]
700
748
  self.axis.plot(self.energy_scale, eels_tools.gauss(self.energy_scale, p))
701
-
749
+ self.axis.legend(loc="upper right")
750
+ self.axis.figure.canvas.draw_idle()
751
+
702
752
  def fit_peaks(self):
703
753
  """Fit spectrum with peaks given in peaks dictionary"""
704
754
  print('Fitting peaks...')
@@ -714,10 +764,10 @@ if Qt_available:
714
764
  spectrum = self.dataset.view.get_spectrum()
715
765
  else:
716
766
  spectrum = np.array(self.dataset)
717
-
767
+ spectrum -= spectrum.min()-1
718
768
  # set the energy scale and fit start and end points
719
769
  energy_scale = np.array(self.energy_scale)
720
- start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
770
+ """start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
721
771
  end_channel = np.searchsorted(energy_scale, self.peaks['fit_end'])
722
772
 
723
773
  energy_scale = self.energy_scale[start_channel:end_channel]
@@ -732,19 +782,29 @@ if Qt_available:
732
782
  model = np.zeros(end_channel - start_channel)
733
783
 
734
784
  # if we have a core loss model we will only fit the difference between the model and the data.
785
+
786
+
735
787
  difference = np.array(spectrum[start_channel:end_channel] - model)
788
+ """
789
+ difference = spectrum
790
+ if self.key == self.datasets['_relationships']['low_loss']:
791
+ if 'resolution_function' in self.datasets['_relationships'].keys():
792
+ difference -= np.array(self.datasets['_relationships']['resolution_function'])
793
+ self.peaks['peaks']['features'] = 'resolution_function'
794
+ self.model = np.array(self.datasets['_relationships']['resolution_function'])
736
795
 
737
796
  # find the optimum fitting parameters
738
- [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals_smooth, np.array(p_in), ftol=1e-3,
797
+ [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals3, np.array(p_in), ftol=1e-3,
739
798
  args=(energy_scale, difference, False))
740
799
 
741
800
  # construct the fit data from the optimized parameters
742
- self.peak_model = np.zeros(len(self.energy_scale))
743
- self.model = np.zeros(len(self.energy_scale))
744
- self.model[start_channel:end_channel] = model
745
- fit = eels_tools.model_smooth(energy_scale, self.p_out, False)
746
- self.peak_model[start_channel:end_channel] = fit
747
- self.dataset.metadata['peak_fit']['edge_model'] = self.model
801
+ #self.peak_model = np.zeros(len(self.energy_scale))
802
+ #self.model = np.zeros(len(self.energy_scale))
803
+ #self.model[start_channel:end_channel] = model
804
+ fit = eels_tools.gmm(energy_scale, self.p_out, False)
805
+ self.peak_model = fit
806
+ #self.peak_model[start_channel:end_channel] = fit
807
+ #self.dataset.metadata['peak_fit']['edge_model'] = self.model
748
808
  self.model = self.model + self.peak_model
749
809
  self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
750
810
 
@@ -773,8 +833,13 @@ if Qt_available:
773
833
  if 'resolution_function' in self.datasets:
774
834
  self.dataset.metadata['model'] = np.array(self.datasets['resolution_function'])
775
835
  iterations = int(self.ui.smooth_list.currentIndex())
836
+
837
+ if self.key == self.datasets['_relationships']['low_loss']:
838
+ if 'resolution_function' in self.datasets['_relationships'].keys():
839
+ self.model = np.array(self.datasets['_relationships']['resolution_function'])
840
+
776
841
 
777
- self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset, iterations, advanced_present)
842
+ self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset-self.model, iterations, advanced_present)
778
843
 
779
844
  spec_dim = ft.get_dimensions_by_type('SPECTRAL', self.dataset)[0]
780
845
  if spec_dim[1][0] > 0:
@@ -1015,6 +1080,8 @@ if Qt_available:
1015
1080
 
1016
1081
 
1017
1082
  def smooth(dataset, iterations, advanced_present):
1083
+ from pyTEMlib import advanced_eels_tools
1084
+
1018
1085
  """Gaussian mixture model (non-Bayesian)
1019
1086
 
1020
1087
  Fit lots of Gaussian to spectrum and let the program sort it out
@@ -1023,15 +1090,15 @@ def smooth(dataset, iterations, advanced_present):
1023
1090
  """
1024
1091
 
1025
1092
  # TODO: add sensitivity to dialog and the two functions below
1026
- peaks = dataset.metadata['peak_fit']
1093
+ #peaks = dataset.metadata['peak_fit']
1094
+
1095
+ #peak_model, peak_out_list = eels_tools.find_peaks(dataset, peaks['fit_start'], peaks['fit_end'])
1096
+ peak_model, peak_out_list = eels_tools.gaussian_mixture_model(dataset, p_in=None)
1027
1097
 
1028
- peak_model, peak_out_list = eels_tools.find_peaks(dataset,
1029
- peaks['fit_start'],
1030
- peaks['fit_end'])
1031
1098
  #
1032
- #cif advanced_present and iterations > 1:
1099
+ # if advanced_present and iterations > 1:
1033
1100
  # peak_model, peak_out_list = advanced_eels_tools.smooth(dataset, peaks['fit_start'],
1034
- # peaks['fit_end'], iterations=iterations)
1101
+ # peaks['fit_end'], iterations=iterations)
1035
1102
  # else:
1036
1103
  # peak_model, peak_out_list = eels_tools.find_peaks(dataset, peaks['fit_start'], peaks['fit_end'])
1037
1104
  # peak_out_list = [peak_out_list]
@@ -1045,3 +1112,18 @@ def smooth(dataset, iterations, advanced_present):
1045
1112
  number_of_peaks = np.searchsorted(area * -1, -np.average(area))
1046
1113
 
1047
1114
  return peak_model, peak_out_list, number_of_peaks
1115
+
1116
+
1117
+ def gauss(x, p): # p[0]==mean, p[1]= amplitude p[2]==fwhm,
1118
+ """Gaussian Function
1119
+
1120
+ p[0]==mean, p[1]= amplitude p[2]==fwhm
1121
+ area = np.sqrt(2* np.pi)* p[1] * np.abs(p[2] / 2.3548)
1122
+ FWHM = 2 * np.sqrt(2 np.log(2)) * sigma = 2.3548 * sigma
1123
+ sigma = FWHM/3548
1124
+ """
1125
+ if p[2] == 0:
1126
+ return x * 0.
1127
+ else:
1128
+ return p[1] * np.exp(-(x - p[0]) ** 2 / (2.0 * (p[2] / 2.3548) ** 2))
1129
+
pyTEMlib/probe_tools.py CHANGED
@@ -2,6 +2,10 @@
2
2
  import numpy as np
3
3
  import pyTEMlib.image_tools
4
4
  import scipy.ndimage as ndimage
5
+ import skimage
6
+
7
+ get_wavelength = pyTEMlib.image_tools.get_wavelength
8
+
5
9
 
6
10
 
7
11
  def make_gauss(size_x, size_y, width=1.0, x0=0.0, y0=0.0, intensity=1.0):
@@ -23,6 +27,7 @@ def make_lorentz(size_x, size_y, gamma=1.0, x0=0., y0=0., intensity=1.):
23
27
  x, y = np.mgrid[-size_x:size_x, -size_y:size_y]
24
28
  g = gamma / (2 * np.pi) / np.power(((x - x0) ** 2 + (y - y0) ** 2 + gamma ** 2), 1.5)
25
29
  probe = g / g.sum() * intensity
30
+
26
31
  return probe
27
32
 
28
33
 
@@ -32,6 +37,7 @@ def zero_loss_peak_weight():
32
37
  y = [0.0143, 0.0193, 0.0281, 0.0440, 0.0768, 0.1447, 0.2785, 0.4955, 0.7442, 0.9380, 1.0000, 0.9483, 0.8596,
33
38
  0.7620, 0.6539, 0.5515, 0.4478, 0.3500, 0.2683, 0.1979, 0.1410, 0.1021, 0.0752, 0.0545, 0.0401, 0.0300,
34
39
  0.0229, 0.0176, 0.0139]
40
+
35
41
  return x, y
36
42
 
37
43
 
@@ -92,6 +98,7 @@ def get_chi(ab, size_x, size_y, verbose=False):
92
98
  chi = make_chi(phi, theta, ab)
93
99
 
94
100
  # Aperture function
101
+ print(aperture_angle)
95
102
  mask = theta >= aperture_angle
96
103
 
97
104
  aperture = np.ones((size_x, size_y), dtype=float)
@@ -106,15 +113,15 @@ def print_aberrations(ab):
106
113
  output += f"Aberrations [nm] for acceleration voltage: {ab['acceleration_voltage'] / 1e3:.0f} kV"
107
114
  output += '<table>'
108
115
  output += f"<tr><td> C10 </td><td> {ab['C10']:.1f} </tr>"
109
- output += f"<tr><td> C12a </td><td> {ab['C12a']:20.1f} <td> C12b </td><td> {ab['C12b']:20.1f} </tr>"
110
- output += f"<tr><td> C21a </td><td> {ab['C21a']:.1f} <td> C21b </td><td> {ab['C21b']:.1f} "
111
- output += f" <td> C23a </td><td> {ab['C23a']:.1f} <td> C23b </td><td> {ab['C23b']:.1f} </tr>"
116
+ output += f"<tr><td> C12a (A1) </td><td> {ab['C12a']:20.1f} <td> C12b (A1) </td><td> {ab['C12b']:20.1f} </tr>"
117
+ output += f"<tr><td> C21a (B2) </td><td> {ab['C21a']:.1f} <td> C21b (B2)</td><td> {ab['C21b']:.1f} "
118
+ output += f" <td> C23a (A2) </td><td> {ab['C23a']:.1f} <td> C23b (A2) </td><td> {ab['C23b']:.1f} </tr>"
112
119
  output += f"<tr><td> C30 </td><td> {ab['C30']:.1f} </tr>"
113
- output += f"<tr><td> C32a </td><td> {ab['C32a']:20.1f} <td> C32b </td><td> {ab['C32b']:20.1f} "
114
- output += f"<td> C34a </td><td> {ab['C34a']:20.1f} <td> C34b </td><td> {ab['C34b']:20.1f} </tr>"
115
- output += f"<tr><td> C41a </td><td> {ab['C41a']:.3g} <td> C41b </td><td> {ab['C41b']:.3g} "
116
- output += f" <td> C43a </td><td> {ab['C43a']:.3g} <td> C43b </td><td> {ab['C41b']:.3g} "
117
- output += f" <td> C45a </td><td> {ab['C45a']:.3g} <td> C45b </td><td> {ab['C45b']:.3g} </tr>"
120
+ output += f"<tr><td> C32a (S3) </td><td> {ab['C32a']:20.1f} <td> C32b (S3)</td><td> {ab['C32b']:20.1f} "
121
+ output += f"<td> C34a (A3) </td><td> {ab['C34a']:20.1f} <td> C34b (A3) </td><td> {ab['C34b']:20.1f} </tr>"
122
+ output += f"<tr><td> C41a (B4) </td><td> {ab['C41a']:.3g} <td> C41b (B4) </td><td> {ab['C41b']:.3g} "
123
+ output += f" <td> C43a (D4) </td><td> {ab['C43a']:.3g} <td> C43b (D4) </td><td> {ab['C41b']:.3g} "
124
+ output += f" <td> C45a (A4) </td><td> {ab['C45a']:.3g} <td> C45b (A4)</td><td> {ab['C45b']:.3g} </tr>"
118
125
  output += f"<tr><td> C50 </td><td> {ab['C50']:.3g} </tr>"
119
126
  output += f"<tr><td> C52a </td><td> {ab['C52a']:20.1f} <td> C52b </td><td> {ab['C52b']:20.1f} "
120
127
  output += f"<td> C54a </td><td> {ab['C54a']:20.1f} <td> C54b </td><td> {ab['C54b']:20.1f} "
@@ -158,11 +165,44 @@ def get_ronchigram(size, ab, scale='mrad'):
158
165
  extent = [-fov_mrad, fov_mrad, -fov_mrad, fov_mrad]
159
166
  ylabel = 'reciprocal distance [mrad]'
160
167
 
168
+ ab['chi'] = chi
161
169
  ab['ronchi_extent'] = extent
162
170
  ab['ronchi_label'] = ylabel
163
171
  return ronchigram
164
172
 
165
173
 
174
+ def make_probe (chi, aperture):
175
+ chi2 = np.fft.ifftshift(chi)
176
+ chiT = np.fft.ifftshift (np.vectorize(complex)(np.cos(chi2), -np.sin(chi2)) )
177
+ ## Aply aperture function
178
+ chiT = chiT*aperture
179
+ ## inverse fft of aberration function
180
+ i2 = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift (chiT)))
181
+ ## intensity
182
+ probe = np.real(i2 * np.conjugate(i2))
183
+
184
+ return probe
185
+
186
+
187
+ def get_probe( ab, sizeX, sizeY, scale = 'mrad', verbose= True):
188
+
189
+ chi, A_k = get_chi( ab, sizeX, sizeY, verbose= False)
190
+ probe = make_probe (chi, A_k)
191
+
192
+ return probe, A_k, chi
193
+
194
+
195
+ def get_probe_large(ab):
196
+ ab['FOV'] = 20
197
+ sizeX = 512*2
198
+ probe, A_k, chi = pyTEMlib.probe_tools.get_probe( ab, sizeX, sizeX, scale = 'mrad', verbose= True)
199
+
200
+ res = np.zeros((512, 512))
201
+ res[256-32:256+32, 256-32:256+32 ] = skimage.transform.resize(probe, (64, 64))
202
+
203
+ return res
204
+
205
+
166
206
  def get_chi_2(ab, u, v):
167
207
  chi1 = ab['C10'] * (u ** 2 + v ** 2) / 2 \
168
208
  + ab['C12a'] * (u ** 2 - v ** 2) / 2 \
@@ -400,6 +440,22 @@ def get_target_aberrations(TEM_name, acceleration_voltage):
400
440
  ab['TEM_name'] = TEM_name
401
441
 
402
442
  ab['wavelength'] = pyTEMlib.image_tools.get_wavelength(ab['acceleration_voltage'])
443
+
444
+ if TEM_name == 'Spectra300':
445
+ ab = {'C10': 0, 'C12a': 0, 'C12b': 0.38448128113770325,
446
+ 'C21a': -68.45251255685642, 'C21b': 64.85359774641199, 'C23a': 11.667578600494137, 'C23b': -29.775627778458194,
447
+ 'C30': 123,
448
+ 'C32a': 95.3047364258614, 'C32b': -189.72105710231244, 'C34a': -47.45099594807912, 'C34b': -94.67424667529909,
449
+ 'C41a': -905.31842572806, 'C41b': 981.316128853203, 'C43a': 4021.8433526960034, 'C43b': 131.72716642732158,
450
+ 'C45a': -4702.390968272048, 'C45b': -208.25028574642903, 'C50': -663.1,
451
+ 'C50': 552000., 'C52a': -0., 'C52b': 0.,
452
+ 'C54a': -0., 'C54b': -0., 'C56a': -36663.643489934424, 'C56b': 21356.079837905396,
453
+ 'acceleration_voltage': 200000,
454
+ 'FOV': 34.241659495148205,
455
+ 'Cc': 1* 1e6,
456
+ 'convergence_angle': 30,
457
+ 'wavelength': 0.0025079340450548005}
458
+
403
459
  return ab
404
460
 
405
461
 
@@ -456,6 +512,7 @@ def get_ronchigram_2(size, ab, scale='mrad', threshold=3):
456
512
  extent = [-fov_mrad, fov_mrad, -fov_mrad, fov_mrad]
457
513
  ylabel = 'reciprocal distance [mrad]'
458
514
 
515
+ ab['chi'] = chi
459
516
  ab['ronchi_extent'] = extent
460
517
  ab['ronchi_label'] = ylabel
461
518
 
pyTEMlib/version.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """
2
2
  version
3
3
  """
4
- _version = '0.2024.09.0'
4
+ _version = '0.2025.02.2'
5
5
  __version__ = _version
6
- _time = '2024-09-01 19:58:26'
6
+ _time = '2025-02-25 19:58:26'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: pyTEMlib
3
- Version: 0.2024.9.0
3
+ Version: 0.2025.2.2
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
@@ -38,9 +38,19 @@ Requires-Dist: ipympl
38
38
  Requires-Dist: spglib
39
39
  Requires-Dist: scikit-image
40
40
  Requires-Dist: scikit-learn
41
- Requires-Dist: pyNSID >=0.0.7
42
- Requires-Dist: sidpy >=0.12.1
43
- Requires-Dist: SciFiReaders >=0.0.8
41
+ Requires-Dist: pyNSID>=0.0.7
42
+ Requires-Dist: sidpy>=0.12.1
43
+ Requires-Dist: SciFiReaders>=0.0.8
44
+ Dynamic: author
45
+ Dynamic: author-email
46
+ Dynamic: classifier
47
+ Dynamic: description
48
+ Dynamic: home-page
49
+ Dynamic: keywords
50
+ Dynamic: license
51
+ Dynamic: platform
52
+ Dynamic: requires-dist
53
+ Dynamic: summary
44
54
 
45
55
  pyTEMlib
46
56
  ========
@@ -1,37 +1,38 @@
1
1
  pyTEMlib/__init__.py,sha256=nEN93amIEoZxO7rJgN71ABeCoXrnmaywBbE97l5lPio,178
2
- pyTEMlib/animation.py,sha256=oPxbTuy8LfdH2mOOgm9Q40ArFAJmXM_58UV97ptcNAY,25187
3
- pyTEMlib/atom_tools.py,sha256=ViO4ZZZoCZ_Cp2KijiqKKOiQhGOWnye45T0rsiPhf4I,7314
2
+ pyTEMlib/animation.py,sha256=G9ykYo6yB5jexjKienShO9C2b8xEXKbf7t47apwcwTw,25188
3
+ pyTEMlib/atom_tools.py,sha256=uoyZOs0lZKyBwGH6onKSAKzA6IxseqHpgw7ZTos9Nd0,7335
4
4
  pyTEMlib/config_dir.py,sha256=4evlo9P2Yht-AnqaLI-WweLjDQcislbAP3I7P7EZsPU,2085
5
- pyTEMlib/core_loss_widget.py,sha256=BPGGNcYkdiX3pIfe600ERVAJjUHw5C2BA7idroP1pgU,29746
5
+ pyTEMlib/core_loss_widget.py,sha256=EbCn2imCjzeLAL2h9n87APHPou1G4vvN-kA4_RQs_OE,30991
6
6
  pyTEMlib/crystal_tools.py,sha256=g4OXyvd5NLw7vaXhjDP3P6VZpVV6eiyuPn8MdgR2amI,61652
7
7
  pyTEMlib/diffraction_plot.py,sha256=pM5d3bdBGa8LlPZ5lw8sLT94mlYTXELxPLv-jUP2FWY,27959
8
8
  pyTEMlib/dynamic_scattering.py,sha256=O9MxnxfndWJ2VhQRjksKNQ4yY7y-gN_hitRQ4Qox4ns,9472
9
9
  pyTEMlib/eds_tools.py,sha256=Ilof2Cars-1ILXx5g2RsU2G4BgrPwjOHgQ7-OabmbrU,28000
10
- pyTEMlib/eels_dialog.py,sha256=oWLivCQ96Fq0tj52wbfs-5qKccUSWk2k1iP2TVneXZA,32379
10
+ pyTEMlib/eels_dialog.py,sha256=NmPjO1SVjxzah2cCEK0bR1AqwX7Dl6xwejTZkruqIUA,32619
11
11
  pyTEMlib/eels_dialog_utilities.py,sha256=73W9jFbPx-eeLEiSaBptTgGLr40bIYYfSyzLnZbhfvo,51761
12
- pyTEMlib/eels_tools.py,sha256=O22WENQ04fCfVvI4ktJdx6GfE8ZSNb-E6dAu4ZbfHqw,76041
13
- pyTEMlib/file_tools.py,sha256=UScJenVk73MZUW-laoKymnO27eCUC0vlRxxlQ4Kq2Hg,46923
12
+ pyTEMlib/eels_tools.py,sha256=7gfDmu-CqfatVmtCPYwObJZsP5RMDx3bmFXclZzJINE,88739
13
+ pyTEMlib/file_tools.py,sha256=gdP42-99Pjnl0tri50x8QXc33ye-1bs6Yiof3JKVn7I,59969
14
14
  pyTEMlib/file_tools_qt.py,sha256=tLZACS4JyGH_AOzNR_SGAhjA01y4VJB261opPhGMlm8,7223
15
15
  pyTEMlib/graph_tools.py,sha256=iu0Y2hIPU6CkQHQEh-dI1vKnUHnSNXx4-CXs2M-1Sr8,44097
16
16
  pyTEMlib/graph_viz.py,sha256=m5PwSn6l2r0bsaLWBDSHc9IGR3_PneG2BrZgnEdi07I,13644
17
17
  pyTEMlib/image_dialog.py,sha256=F-ZgKq7UnMtPPd1b9eqb7t8MXDfWN-8hVKwB2Il0x28,6235
18
18
  pyTEMlib/image_dlg.py,sha256=n5gradDiYOFGEQ3k_Wlk9RUYYzl4bl_hKLzNVcYteNE,5694
19
- pyTEMlib/image_tools.py,sha256=B1fLX7PGLrglGuMSavJ5areol8UabyjVUVtkRxYc-oM,49279
20
- pyTEMlib/info_widget.py,sha256=wd1F6UDcLMsWEg1DHHVPa1P7_MRGv8iLOUjRsYkZOQY,46453
19
+ pyTEMlib/image_tools.py,sha256=guHd29VLo2z0KXz1-XxcHYWqOiHGoKZ0A9SE_FdSO2g,52655
20
+ pyTEMlib/info_widget.py,sha256=lkzQOuNVlkaasiZDtc5UtYk541-plYNfnW4DQwQB_iA,53467
21
+ pyTEMlib/info_widget3.py,sha256=QSbdSj6m57KQTir2fNhulVgjOu9EQL31c-9SzTlghnE,55495
21
22
  pyTEMlib/interactive_image.py,sha256=5PwypcA1OjLAD-fi8bmWWFHuOjdIPVY9Dh59V24WuDA,34
22
23
  pyTEMlib/kinematic_scattering.py,sha256=CUdJnclkok7d8qm_jDUF92MVHrmaTeMkKdvxxB6AqvA,43309
23
- pyTEMlib/low_loss_widget.py,sha256=nSU6-pu7gP8ch61w2wpImNNIuo_3bBN1HAB3UVlEJoQ,9043
24
+ pyTEMlib/low_loss_widget.py,sha256=0SxHOAuUnuNjDrJSNS2PeWD6hjyuB5FCYxmVfsDTq5c,25573
24
25
  pyTEMlib/microscope.py,sha256=iigUF1UImHEfmL2wqEBBj3aNRgEYouDbIln8VCo4_KM,1545
25
- pyTEMlib/peak_dialog.py,sha256=-HhgmoscfJMme9N495hDzfniYwuhn7iBzsDwZOOhTd4,48260
26
+ pyTEMlib/peak_dialog.py,sha256=r3mhYvECC9niFFItS1oGa96F2nFthsE5kfpA3yVXQaE,51872
26
27
  pyTEMlib/peak_dlg.py,sha256=qcjcnhwpGa4jBCeXzwQz9sCyX-tHsLLQ67ToqfKOiQY,11550
27
- pyTEMlib/probe_tools.py,sha256=8tPQuANClLsGAKnZo6Vo4gNIGKfyDR6WUMO3dXcm_4k,27177
28
+ pyTEMlib/probe_tools.py,sha256=xVwoThZSSOY6hjUMO53va9R_qI7SL5dfwIigz6sd3DI,29242
28
29
  pyTEMlib/sidpy_tools.py,sha256=0oIx-qMtEmcZmLazQKW19dd-KoxyY3B15aIeMcyHA8E,4878
29
30
  pyTEMlib/simulation_tools.py,sha256=RmegD5TpQMU68uASvzZWVplAqs7bM5KkF6bWDWLjyc0,2799
30
- pyTEMlib/version.py,sha256=fwR9D7D8-iWk_APPU-GLy0E-_x3tnurNS454JfAmdHU,94
31
+ pyTEMlib/version.py,sha256=6GC1KyGj1D_9Hs8_3OJrq7lHdhziwk9qllcxLoWcEns,94
31
32
  pyTEMlib/xrpa_x_sections.py,sha256=m4gaH7gaJiNi-CsIT9aKoH4fB6MQIAe876kxEmzSebI,1825392
32
- pyTEMlib-0.2024.9.0.dist-info/LICENSE,sha256=7HdBF6SXIBd38bHOKkQd4DYR1KV-OYm9mwB16fM-984,1062
33
- pyTEMlib-0.2024.9.0.dist-info/METADATA,sha256=5qc9Ssc7GLKeE5dlv4KErBF7A4_x76dcIM49jJ1aDic,3305
34
- pyTEMlib-0.2024.9.0.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
35
- pyTEMlib-0.2024.9.0.dist-info/entry_points.txt,sha256=zn2yO1IWTutI3c7C9e3GdARCvm43JURoOhqQ8YylV4Y,43
36
- pyTEMlib-0.2024.9.0.dist-info/top_level.txt,sha256=rPLVH0UJxrPSPgSoKScTjL1K_X69JFzsYYnDnYTYIlU,9
37
- pyTEMlib-0.2024.9.0.dist-info/RECORD,,
33
+ pytemlib-0.2025.2.2.dist-info/LICENSE,sha256=7HdBF6SXIBd38bHOKkQd4DYR1KV-OYm9mwB16fM-984,1062
34
+ pytemlib-0.2025.2.2.dist-info/METADATA,sha256=tOVUZqAPzyfc6ZXDHRyz5jp6OGzNJvv9CcyE-1bxtxI,3493
35
+ pytemlib-0.2025.2.2.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
36
+ pytemlib-0.2025.2.2.dist-info/entry_points.txt,sha256=zn2yO1IWTutI3c7C9e3GdARCvm43JURoOhqQ8YylV4Y,43
37
+ pytemlib-0.2025.2.2.dist-info/top_level.txt,sha256=rPLVH0UJxrPSPgSoKScTjL1K_X69JFzsYYnDnYTYIlU,9
38
+ pytemlib-0.2025.2.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (75.8.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5