pyTEMlib 0.2020.11.1__py3-none-any.whl → 0.2024.8.4__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.

Files changed (60) hide show
  1. pyTEMlib/__init__.py +11 -11
  2. pyTEMlib/animation.py +631 -0
  3. pyTEMlib/atom_tools.py +240 -245
  4. pyTEMlib/config_dir.py +57 -33
  5. pyTEMlib/core_loss_widget.py +658 -0
  6. pyTEMlib/crystal_tools.py +1255 -0
  7. pyTEMlib/diffraction_plot.py +756 -0
  8. pyTEMlib/dynamic_scattering.py +293 -0
  9. pyTEMlib/eds_tools.py +609 -0
  10. pyTEMlib/eels_dialog.py +749 -491
  11. pyTEMlib/{interactive_eels.py → eels_dialog_utilities.py} +1199 -1177
  12. pyTEMlib/eels_tools.py +2031 -1698
  13. pyTEMlib/file_tools.py +1276 -560
  14. pyTEMlib/file_tools_qt.py +193 -0
  15. pyTEMlib/graph_tools.py +1166 -450
  16. pyTEMlib/graph_viz.py +449 -0
  17. pyTEMlib/image_dialog.py +158 -0
  18. pyTEMlib/image_dlg.py +146 -232
  19. pyTEMlib/image_tools.py +1399 -1028
  20. pyTEMlib/info_widget.py +933 -0
  21. pyTEMlib/interactive_image.py +1 -226
  22. pyTEMlib/kinematic_scattering.py +1196 -0
  23. pyTEMlib/low_loss_widget.py +176 -0
  24. pyTEMlib/microscope.py +61 -81
  25. pyTEMlib/peak_dialog.py +1047 -410
  26. pyTEMlib/peak_dlg.py +286 -242
  27. pyTEMlib/probe_tools.py +653 -207
  28. pyTEMlib/sidpy_tools.py +153 -136
  29. pyTEMlib/simulation_tools.py +104 -87
  30. pyTEMlib/version.py +6 -3
  31. pyTEMlib/xrpa_x_sections.py +20972 -0
  32. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/LICENSE +21 -21
  33. pyTEMlib-0.2024.8.4.dist-info/METADATA +93 -0
  34. pyTEMlib-0.2024.8.4.dist-info/RECORD +37 -0
  35. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/WHEEL +6 -5
  36. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/entry_points.txt +0 -1
  37. pyTEMlib/KinsCat.py +0 -2758
  38. pyTEMlib/__version__.py +0 -2
  39. pyTEMlib/data/TEMlibrc +0 -68
  40. pyTEMlib/data/edges_db.csv +0 -189
  41. pyTEMlib/data/edges_db.pkl +0 -0
  42. pyTEMlib/data/fparam.txt +0 -103
  43. pyTEMlib/data/microscopes.csv +0 -7
  44. pyTEMlib/data/microscopes.xml +0 -167
  45. pyTEMlib/data/path.txt +0 -1
  46. pyTEMlib/defaults_parser.py +0 -90
  47. pyTEMlib/dm3_reader.py +0 -613
  48. pyTEMlib/edges_db.py +0 -76
  49. pyTEMlib/eels_dlg.py +0 -224
  50. pyTEMlib/hdf_utils.py +0 -483
  51. pyTEMlib/image_tools1.py +0 -2194
  52. pyTEMlib/info_dialog.py +0 -237
  53. pyTEMlib/info_dlg.py +0 -202
  54. pyTEMlib/nion_reader.py +0 -297
  55. pyTEMlib/nsi_reader.py +0 -170
  56. pyTEMlib/structure_tools.py +0 -316
  57. pyTEMlib/test.py +0 -2072
  58. pyTEMlib-0.2020.11.1.dist-info/METADATA +0 -20
  59. pyTEMlib-0.2020.11.1.dist-info/RECORD +0 -45
  60. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/top_level.txt +0 -0
pyTEMlib/KinsCat.py DELETED
@@ -1,2758 +0,0 @@
1
- """
2
- KinsCat
3
- Kinematic Scattering Theory
4
- Copyright by Gerd Duscher
5
-
6
- The University of Tennessee, Knoxville
7
- Department of Materials Science & Engineering
8
-
9
- Sources:
10
- Scattering Theory:
11
- Zuo and Spence, "Advanced TEM", 2017
12
-
13
- Spence and Zuo, Electron Microdiffraction, Plenum 1992
14
-
15
- Atomic Form Factor:
16
- Kirkland: Advanced Computing in Electron Microscopy 2nd edition
17
- Appendix C
18
-
19
- Units:
20
- everything is in SI units, except length is given in nm.
21
-
22
- Usage:
23
- See the notebooks for examples of these routines
24
-
25
- All the input and output is done through a dictionary
26
- """
27
- # numerical packages used
28
- import numpy as np
29
- import scipy.constants as const
30
- import itertools
31
- from scipy import spatial
32
-
33
- import sidpy
34
- # plotting package used
35
- import matplotlib.pylab as plt # basic plotting
36
- # import matplotlib as mpl
37
- # from mpl_toolkits.mplot3d import Axes3D # 3D plotting
38
- from matplotlib.patches import Circle # , Ellipse, Rectangle
39
- from matplotlib.collections import PatchCollection
40
-
41
- from ase.io import read # , write
42
- import pyTEMlib.file_tools as ft
43
- import os
44
-
45
-
46
- _version_ = 0.5
47
-
48
- print('Using KinsCat library version ', _version_, ' by G.Duscher')
49
- _spglib_present = True
50
- try:
51
- import spglib
52
- except ModuleNotFoundError:
53
- _spglib_present = False
54
-
55
- if _spglib_present:
56
- print('Symmetry functions of spglib enabled')
57
- else:
58
- print('spglib not installed; Symmetry functions of spglib disabled')
59
-
60
-
61
- def read_poscar():
62
- """
63
- Open file dialog to select a POSCAR file from VASP
64
- """
65
- file_name = ft.openfile_dialog('POSCAR (POSCAR*.txt);;All files (*)')
66
- # use ase package to read file
67
-
68
- base = os.path.basename(file_name)
69
- base_name = os.path.splitext(base)[0]
70
- crystal = read(file_name, format='vasp', parallel=False)
71
-
72
- # make dictionary and plot structure (not essential for further notebook)
73
- tags = {'unit_cell': crystal.cell * 1e-1, 'elements': crystal.get_chemical_symbols(),
74
- 'base': crystal.get_scaled_positions(), 'max_bond_length': 0.23, 'name': base_name}
75
-
76
- return tags
77
-
78
- # Some Structure Determination Routines
79
-
80
-
81
- def example():
82
- """
83
- same as Zuo_fig_3_18
84
- """
85
- return zuo_fig_3_18()
86
-
87
-
88
- def zuo_fig_3_18():
89
- """
90
- Input for Figure 3.18 in Zuo and Spence \"Advanced TEM\", 2017
91
-
92
- This input acts as an example as well as a reference
93
-
94
- Returns:
95
- dictionary: tags is the dictionary of all input and output paramter needed to reproduce that figure.
96
- """
97
- # INPUT
98
- # Create Silicon structure (Could be produced with Silicon routine)
99
- print('Sample Input for Figure 3.18 in Zuo and Spence \"Advanced TEM\", 2017')
100
- tags = {'crystal_name': 'Silicon'}
101
- print('tags[\'crystal\'] = ', tags['crystal_name'])
102
- a = 0.514 # nm
103
- tags['lattice_parameter_nm'] = a
104
- print('tags[\'lattice_parameter_nm\'] =', tags['lattice_parameter_nm'])
105
- tags['unit_cell'] = [[a, 0, 0], [0, a, 0], [0, 0, a]]
106
- print('tags[\'unit_cell\'] =', tags['unit_cell'])
107
- tags['elements'] = list(itertools.repeat('Si', 8))
108
- print('tags[\'elements\'] =', tags['elements'])
109
- base = [(0., 0., 0.), (0.5, 0.0, 0.5), (0.5, 0.5, 0.), (0., 0.5, 0.5)]
110
- tags['base'] = np.array(base + (np.array(base) + (.25, .25, .25)).tolist())
111
- print('tags[\'base\'] =', tags['base'])
112
-
113
- # Define Experimental Conditions
114
- tags['convergence_angle_mrad'] = 7
115
-
116
- tags['acceleration_voltage_V'] = 101.6*1000.0 # V
117
- print('tags[\'acceleration_voltage_V\'] =', tags['acceleration_voltage_V'])
118
-
119
- tags['convergence_angle_mrad'] = 7.1 # mrad; 0 is parallel illumination
120
- print('tags[\'convergence_angle_mrad\'] =', tags['convergence_angle_mrad'])
121
-
122
- tags['zone_hkl'] = np.array([-2, 2, 1]) # incident neares zone axis: defines Laue Zones!!!!
123
- print('tags[\'zone_hkl\'] =', tags['zone_hkl'])
124
- tags['mistilt'] = np.array([0, 0, 0]) # mistilt in degrees
125
- print('tags[\'mistilt\'] =', tags['mistilt'])
126
-
127
- # Define Simulation Parameters
128
-
129
- tags['Sg_max'] = .2 # 1/nm maximum allowed excitation error
130
- print('tags[\'Sg_max\'] =', tags['Sg_max'])
131
-
132
- tags['hkl_max'] = 9 # Highest evaluated Miller indices
133
- print('tags[\'hkl_max\'] =', tags['hkl_max'])
134
-
135
- print('##################')
136
- print('# Output Options #')
137
- print('##################')
138
-
139
- # Output options
140
-
141
- tags['background'] = 'black' # 'white' 'grey'
142
- print('tags[\'background\'] =', tags['background'], '# \'white\', \'grey\' ')
143
- tags['color map'] = 'plasma'
144
- print('tags[\'color map\'] =', tags['color map'], '#,\'cubehelix\',\'Greys\',\'jet\' ')
145
-
146
- tags['plot HOLZ'] = 1
147
- print('tags[\'plot HOLZ\'] =', tags['plot HOLZ'])
148
- tags['plot HOLZ excess'] = 1
149
- print('tags[\'plot HOLZ excess\'] =', tags['plot HOLZ excess'])
150
- tags['plot Kikuchi'] = 1
151
- print('tags[\'plot Kikuchi\'] =', tags['plot Kikuchi'])
152
- tags['plot reflections'] = 1
153
- print('tags[\'plot reflections\'] =', tags['plot reflections'])
154
-
155
- tags['label HOLZ'] = 0
156
- print('tags[\'label HOLZ\'] =', tags['label HOLZ'])
157
- tags['label Kikuchi'] = 0
158
- print('tags[\'label Kikuchi\'] =', tags['label Kikuchi'])
159
- tags['label reflections'] = 0
160
- print('tags[\'label reflections\'] =', tags['label reflections'])
161
-
162
- tags['label color'] = 'black'
163
- print('tags[\'label color\'] =', tags['label color'])
164
- tags['label size'] = 10
165
- print('tags[\'label size\'] =', tags['label size'])
166
-
167
- tags['color Laue Zones'] = ['red', 'blue', 'green', 'blue', 'green'] # , 'green', 'red'] #for OLZ give a sequence
168
- print('tags[\'color Laue Zones\'] =', tags['color Laue Zones'], ' #[\'red\', \'blue\', \'lightblue\']')
169
-
170
- tags['color Kikuchi'] = 'green'
171
- print('tags[\'color Kikuchi\'] =', tags['color Kikuchi'])
172
- tags['linewidth HOLZ'] = -1 # -1: linewidth according to intensity (structure factor F^2
173
- print('tags[\'linewidth HOLZ\'] =', tags['linewidth HOLZ'], '# -1: linewidth according to intensity '
174
- '(structure factor F^2')
175
- tags['linewidth Kikuchi'] = -1 # -1: linewidth according to intensity (structure factor F^2
176
- print('tags[\'linewidth Kikuchi\'] =', tags['linewidth Kikuchi'], '# -1: linewidth according to intensity '
177
- '(structure factor F^2')
178
-
179
- tags['color reflections'] = 'intensity' # 'Laue Zone'
180
- print('tags[\'color reflections\'] =', tags['color reflections'], '#\'Laue Zone\' ')
181
- tags['color zero'] = 'white' # 'None', 'white', 'blue'
182
- print('tags[\'color zero\'] =', tags['color zero'], '#\'None\', \'white\', \'blue\' ')
183
- tags['color ring zero'] = 'None' # 'Red' #'white' #, 'None'
184
- print('tags[\'color ring zero\'] =', tags['color ring zero'], '#\'None\', \'white\', \'Red\' ')
185
-
186
- print('########################')
187
- print('# End of Example Input #')
188
- print('########################\n\n')
189
-
190
- return tags
191
-
192
-
193
- def h5_add_crystal_structure(h5_file, crystal_tags):
194
- """
195
- Adds the basic crystal information to a pyNSID style hdf5 file.
196
-
197
- example usage:
198
- >> crystal_tags = ks.structure_by_name(h5_file, 'Graphite')
199
- >> ks.add_crystal_structure(h5_file, crystal_tags)
200
- """
201
- structure_group = sidpy.hdf.prov_utils.create_indexed_group(h5_file, 'Structure')
202
-
203
- structure_group['unit_cell'] = crystal_tags['unit_cell']
204
- structure_group['relative_positions'] = crystal_tags['base']
205
- structure_group['title'] = str(crystal_tags['crystal_name'])
206
- structure_group['_'+crystal_tags['crystal_name']] = str(crystal_tags['crystal_name'])
207
- structure_group['elements'] = np.array(crystal_tags['elements'], dtype='S')
208
- if 'zone_axis' in structure_group:
209
- structure_group['zone_axis'] = np.array(crystal_tags['zone_axis'], dtype=float)
210
- else:
211
- structure_group['zone_axis'] = np.array([1., 1., 1.], dtype=float)
212
-
213
- h5_file.flush()
214
-
215
- return structure_group
216
-
217
-
218
- def h5_add_to_structure(structure_group, crystal_tags):
219
- for key in crystal_tags:
220
- if key in structure_group.keys():
221
- print(key, ' not written; use new name')
222
- else:
223
- structure_group[key] = crystal_tags[key]
224
-
225
-
226
- def cubic(a):
227
- """ Cubic lattice of dimensions a x a x a. """
228
- return np.identity(3)*a
229
-
230
-
231
- def from_parameters(a, b, c, alpha, beta, gamma):
232
- """
233
- Create a unit cell using lengths and angles (in degrees).
234
- """
235
-
236
- alpha_r = np.radians(alpha)
237
- beta_r = np.radians(beta)
238
- gamma_r = np.radians(gamma)
239
- val = (np.cos(alpha_r) * np.cos(beta_r) - np.cos(gamma_r)) / (np.sin(alpha_r) * np.sin(beta_r))
240
-
241
- # Sometimes rounding errors result in values slightly > 1.
242
- if val > 1.:
243
- val = 1.
244
- if val < -1.:
245
- val = -1.
246
-
247
- gamma_star = np.arccos(val)
248
- vector_a = [a * np.sin(beta_r), 0.0, a * np.cos(beta_r)]
249
- vector_b = [-b * np.sin(alpha_r) * np.cos(gamma_star),
250
- b * np.sin(alpha_r) * np.sin(gamma_star),
251
- b * np.cos(alpha_r)]
252
- vector_c = [0.0, 0.0, float(c)]
253
- return np.array([vector_a, vector_b, vector_c])
254
-
255
-
256
- def tetragonal(a, c):
257
- """
258
- Tetragonal unit cell of dimensions a x a x c.
259
- """
260
- return from_parameters(a, a, c, 90, 90, 90)
261
-
262
-
263
- def bcc(lattice_parameter, elements):
264
- """
265
- BCC structure
266
-
267
- Input:
268
- lattice parameter in nm and
269
- elements as a list or a string of a single element
270
-
271
- Returns:
272
- unit cell , base and relative atom positions
273
- """
274
- unit_cell = cubic(lattice_parameter)
275
- base = np.array([(0., 0., 0.), (0.5, 0.5, 0.5)])
276
- if len(elements) > 1:
277
- atoms = [elements[0], elements[1]]
278
- else:
279
- atoms = [elements[0], elements[0]]
280
- return unit_cell, base, atoms
281
-
282
-
283
- def fcc(lattice_parameter, elements):
284
- """
285
- FCC structure
286
-
287
- Input:
288
- lattice parameter in nm and
289
- elements as a list or a string of a single element
290
-
291
- Returns:
292
- unit cell , base and relative atom positions
293
- """
294
- unit_cell = cubic(lattice_parameter)
295
- base = np.array([(0., 0., 0.), (0.5, 0.0, 0.5), (0.5, 0.5, 0.0), (0., 0.5, 0.5)])
296
- if len(elements) > 3:
297
- atoms = [elements[0], elements[1], elements[2], elements[3]]
298
- elif len(elements) > 1:
299
- atoms = [elements[0], elements[1], elements[1], elements[1]]
300
- else:
301
- atoms = [elements[0]]*4
302
- return unit_cell, base, atoms
303
-
304
-
305
- def dichalcogenide(a, c, u, elements):
306
- """
307
- Dichalcogenide structure
308
-
309
- Input:
310
- a, c: floats - lattice parameters
311
- u: float - relative shift parameter
312
- elements: string of element or list of strings of elements
313
-
314
- Returns:
315
- unit_cell, base, atoms
316
- """
317
- unit_cell = from_parameters(a, a, c, 90., 90., 120.)
318
- base = [(1/3., 2/3., 1/4.), (2/3., 1/3., 3/4.),
319
- (2/3., 1/3., 1/4.+u), (2/3., 1/3., 1/4.-u),
320
- (1/3., 2/3., 3/4.+u), (1/3., 2/3., 3/4.-u)]
321
-
322
- if len(elements) > 1:
323
- atoms = [elements[0]]*2 + [elements[1]]*4
324
- else:
325
- atoms = elements[0]*6
326
- return unit_cell, base, atoms
327
-
328
-
329
- def wurzite(a, c, u, elements):
330
- """
331
- Wurzite structure
332
-
333
- Input:
334
- a, c: floats - lattice parameters in nm
335
- elements: string of element or list of strings of elements
336
-
337
- Returns:
338
- unit_cell, base, atoms
339
- """
340
- unit_cell = from_parameters(a, a, c, 90., 90., 120.)
341
- base = [(2./3., 1./3., .500), (1./3., 2./3., 0.000), (2./3., 1./3., 0.5+u), (1./3., 2./3., u)]
342
- if len(elements) > 1:
343
- atoms = [elements[0]]*2 + [elements[1]]*2
344
- else:
345
- atoms = [elements[0]]*4
346
- return unit_cell, base, atoms
347
-
348
-
349
- def rocksalt(lattice_parameter, elements):
350
- """
351
- Rocksalt structure
352
-
353
- Input:
354
- lattice_parameter: float in nm
355
- elements: string of element or list of strings of elements
356
- Returns:
357
- unit_cell, base, atoms
358
- """
359
- unit_cell = np.identity(3) * lattice_parameter
360
- base = [(0., 0., 0.), (0.5, 0.0, 0.5), (0.5, 0.5, 0.), (0., 0.5, 0.5)]
361
- base2 = np.array(base)+(0.5, 0.5, 0.5)
362
- base2 = np.where(base2 == 1., 0, base2)
363
- base = base + base2.tolist()
364
- if len(elements) > 1:
365
- atoms = [elements[0]]*4 + [elements[1]]*4
366
- else:
367
- atoms = [elements[0]]*8
368
- return unit_cell, base, atoms
369
-
370
-
371
- def zinc_blende(lattice_parameter, elements):
372
- """
373
- Zinc blende structure
374
-
375
- Input:
376
- lattice_parameter: float in nm
377
- elements: string of element or list of strings of elements
378
-
379
- Returns:
380
- unit_cell, base, atoms
381
- """
382
- unit_cell = np.identity(3) * lattice_parameter
383
- base = [(0., 0., 0.), (0.5, 0.0, 0.5), (0.5, 0.5, 0.), (0., 0.5, 0.5)]
384
- base = base + (np.array(base) + (.25, .25, .25)).tolist()
385
- if len(elements) > 3:
386
- atoms = [elements[0], elements[0], elements[1], elements[1], elements[2], elements[2], elements[3], elements[3]]
387
- # Z = [electronFF[elements[0]][Z],
388
- elif len(elements) > 1:
389
- atoms = [elements[0]]*4 + [elements[1]]*4
390
- else:
391
- atoms = [elements[0]]*8
392
- return unit_cell, base, atoms
393
-
394
-
395
- def perovskite(lattice_parameter, elements):
396
- """
397
- Perovskite structure
398
-
399
- Input:
400
- lattice_parameter: float in nm
401
- elements: string of element or list of strings of elements
402
-
403
- Returns:
404
- unit_cell, base, atoms
405
- """
406
- unit_cell = cubic(lattice_parameter)
407
- base = np.array([(0., 0., 0.), (0.5, 0.5, 0.5), (0.5, 0.0, 0.5), (0.5, 0.5, 0.), (0., 0.5, 0.5)])
408
- if len(elements) > 2:
409
- atoms = [elements[0], elements[1]] + [elements[2]]*3
410
- elif len(elements) > 1:
411
- atoms = [elements[0]] + [elements[1]]*4
412
- else:
413
- atoms = [elements[0]]*5
414
- return unit_cell, base, atoms
415
-
416
-
417
- def zone_mistilt(zone, angles):
418
- """
419
- Rotation of zone axis by mistilt
420
-
421
- Input:
422
- zone: zone axis in Miller indices
423
- angles: list of mistilt angles in degree
424
-
425
- Returns:
426
- rotation matrix (3x3)
427
-
428
- """
429
- alpha, beta, gamma = np.radians(angles)
430
-
431
- # first we rotate alpha about x axis
432
- c, s = np.cos(alpha), np.sin(alpha)
433
- rotx = np.array([[1, 0, 0], [0, c, -s], [0, s, c]])
434
-
435
- # second we rotate beta about y axis
436
- c, s = np.cos(beta), np.sin(beta)
437
- roty = np.array([[c, 0, s], [0, 1, 0], [-s, 0, c]])
438
-
439
- # third we rotate gamma about z-axis
440
- c, s = np.cos(gamma), np.sin(gamma)
441
- rotz = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
442
-
443
- return np.dot(np.dot(np.dot(zone, rotx), roty), rotz)
444
-
445
-
446
- def structure_by_name(crystal):
447
- """
448
- Provides unit cell as a structure matrix, the list of elements and the atom base
449
-
450
- Input:
451
- ------
452
- crystal name as string:
453
- type "print(ks.crystal_data_base.keys())" for a list of pre-defined crystal structures
454
-
455
- Please note that the chemical expressions are case sensitive.
456
-
457
- Output:
458
- ------
459
- new dictionary with the following keys:
460
-
461
- ['unit_cell']: the structure matrix
462
- ['base']: relative coordinates of atoms
463
- ['elements']: name of elements in same order as base
464
-
465
- an empty dictionary will be returned if the name is not recognized.
466
- """
467
-
468
- # Check whether name is in the crystal_data_base
469
-
470
- if crystal in cdb:
471
- tags = cdb[crystal].copy()
472
- else:
473
- print('Crystal name not defined')
474
- return {}
475
- print(tags['elements'])
476
- unit_cell = np.identity(3)
477
- atoms = ''
478
- base = []
479
- # Make crystal structure dictionary based on symmetry
480
- if 'symmetry' in tags:
481
- if tags['symmetry'] == 'BCC':
482
- unit_cell, base, atoms = bcc(tags['a'], tags['elements'])
483
-
484
- elif tags['symmetry'] == 'FCC':
485
- unit_cell, base, atoms = fcc(tags['a'], tags['elements'])
486
-
487
- elif tags['symmetry'] == 'perovskite':
488
- unit_cell, base, atoms = perovskite(tags['a'], tags['elements'])
489
-
490
- elif tags['symmetry'] == 'zinc_blende':
491
- unit_cell, base, atoms = zinc_blende(tags['a'], tags['elements'])
492
-
493
- elif tags['symmetry'] == 'wurzite':
494
- unit_cell, base, atoms = wurzite(tags['a'], tags['c'], tags['u'], tags['elements'])
495
-
496
- elif tags['symmetry'] == 'rocksalt':
497
- unit_cell, base, atoms = rocksalt(tags['a'], tags['elements'])
498
-
499
- elif tags['symmetry'] == 'dichalcogenide':
500
- unit_cell, base, atoms = dichalcogenide(tags['a'], tags['c'], tags['u'], tags['elements'])
501
-
502
- tags['unit_cell'] = unit_cell
503
- tags['elements'] = atoms
504
- tags['base'] = base
505
-
506
- return tags
507
-
508
-
509
- def get_symmetry(unit_cell, base, atoms):
510
- """
511
- Symmetry analysis with spglib
512
-
513
- spglib must be installed
514
- """
515
- if _spglib_present:
516
-
517
- print('#####################')
518
- print('# Symmetry Analysis #')
519
- print('#####################')
520
-
521
- atomic_number = []
522
- for i in range(len(atoms)):
523
- a = atoms[i]
524
- atomic_number.append(electronFF[a]['Z'])
525
- print(f'{i+1}: {atomic_number[i]} = {2} : [{base[i][0]:.2f}, {base[i][1]:.2f}, {base[i][2]:.2f}]')
526
-
527
- lattice = (unit_cell, base, atomic_number)
528
- spgroup = spglib.get_spacegroup(lattice)
529
- sym = spglib.get_symmetry(lattice)
530
-
531
- print(" Spacegroup is %s." % spgroup)
532
- print(' Crystal has {0} symmetry operation'.format(sym['rotations'].shape[0]))
533
-
534
- p_lattice, p_positions, p_numbers = spglib.find_primitive(lattice, symprec=1e-5)
535
- print("\n########################\n #Basis vectors of primitive Cell:")
536
- for i in range(3):
537
- print('[{0:.4f}, {1:.4f}, {2:.4f}]'.format(p_lattice[i][0], p_lattice[i][1], p_lattice[i][2]))
538
-
539
- print('There {0} atoms and {1} species in primitive unit cell:'.format(len(p_positions), p_numbers))
540
- else:
541
- print('spglib is not installed')
542
-
543
-
544
- def ball_and_stick(tags, extend=1, max_bond_length=0.):
545
-
546
- """
547
- Calculates the data to plot a ball and stick model
548
-
549
- Input:
550
- tags: dictionary containing the 'unit_cell', 'base' and 'elements' tags.
551
-
552
- extend: 1 or 3 integers
553
- The *extend* argument scales the effective cell in which atoms
554
- will be included. It must either be a list of three integers or a single
555
- integer scaling all 3 directions. By setting this value to one,
556
- all corner and edge atoms will be included in the returned cell.
557
- This will of cause make the returned cell non-repeatable, but this is
558
- very useful for visualisation.
559
-
560
- max_bond_length: 1 float
561
- The max_bond_length argument defines the distance for which a bond will be shown.
562
- If max_bond_length is zero, the tabulated atom radii will be used.
563
-
564
- Output:
565
-
566
- corners,balls, Z, bonds: lists
567
- These lists can be used to plot the
568
- unit cell:
569
- for x, y, z in corners:
570
- l=mlab.plot3d( x,y,z, tube_radius=0.002)
571
- bonds:
572
- for x, y, z in bonds:
573
- mlab.plot3d( x,y,z, tube_radius=0.02)
574
- and atoms:
575
- for i,atom in enumerate(balls):
576
- mlab.points3d(atom[0],atom[1],atom[2],
577
- scale_factor=0.1,##ks.vdw_radii[Z[i]]/5,
578
- resolution=20,
579
- color=tuple(ks.jmol_colors [Z[i]]),
580
- scale_mode='none')
581
-
582
- Please note that you'll need the *Z* list for coloring, or for radii that depend on elements
583
-
584
- """
585
- # Check in which form extend is given
586
- if isinstance(extend, int):
587
- extend = [extend]*3
588
-
589
- extend = np.array(extend, dtype=int)
590
-
591
- # Make the x,y, and z multiplicators
592
- if len(extend) == 3:
593
- x = np.linspace(0, extend[0], extend[0]+1)
594
- y = np.linspace(0, extend[1], extend[1]+1)
595
- z = np.linspace(0, extend[2], extend[2]+1)
596
- else:
597
- print('wrong extend parameter')
598
- return
599
-
600
- # Check whether this is the right kind of dictionary
601
- if 'unit_cell' not in tags:
602
- return
603
- cell = tags['unit_cell']
604
-
605
- # Corners and Outline of unit cell
606
- h = (0, 1)
607
- corner_vectors = np.dot(np.array(list(itertools.product(h, h, h))), cell)
608
- trace = [[0, 1], [1, 3], [3, 2], [2, 0], [0, 4], [4, 5], [5, 7], [6, 7], [6, 4], [1, 5], [2, 6], [3, 7]]
609
- corners = []
610
- for s, e in trace:
611
- corners.append([*zip(corner_vectors[s], corner_vectors[e])])
612
-
613
- # ball position and elements in supercell
614
- super_cell = np.array(list(itertools.product(x, y, z))) # all evaluated Miller indices
615
-
616
- pos = np.add(super_cell, np.array(tags['base'])[:, np.newaxis])
617
-
618
- atomic_number = []
619
- for i in range(len(tags['elements'])):
620
- atomic_number.append(electronFF[tags['elements'][i]]['Z'])
621
-
622
- # List of bond lengths taken from electronFF database below
623
- bond_lengths = []
624
- for atom in tags['elements']:
625
- bond_lengths.append(electronFF[atom]['bond_length'][0])
626
-
627
- # extend list of atomic numbers
628
- zpp = []
629
- for z in atomic_number:
630
- zpp.append([z]*pos.shape[1])
631
- zpp = np.array(zpp).flatten()
632
-
633
- # reshape supercell atom positions
634
- pos = pos.reshape((pos.shape[0]*pos.shape[1], pos.shape[2]))
635
-
636
- # Make a mask that excludes all atoms outside of super cell
637
- maskz = pos[:, 2] <= extend[2]
638
- masky = pos[:, 1] <= extend[1]
639
- maskx = pos[:, 0] <= extend[0]
640
- mask = np.logical_and(maskx, np.logical_and(masky, maskz)) # , axis=1)
641
-
642
- # Only use balls and elements inside super cell
643
- balls = np.dot(pos[mask], cell)
644
- atomic_number = zpp[mask]
645
-
646
- # Get maximum bond length from list of bond -lengths taken from electronFF database
647
- if max_bond_length == 0:
648
- max_bond_length = np.median(bond_lengths)/5
649
- # Check nearest neighbours within max_bond_length
650
- tree = spatial.KDTree(balls)
651
- nearest_neighbours = np.array(tree.query(balls, k=8, distance_upper_bound=max_bond_length))
652
-
653
- # Calculate bonds
654
- bonds = []
655
- bond_indices = []
656
- for i in range(nearest_neighbours.shape[1]):
657
- for j in range(nearest_neighbours.shape[2]):
658
- if nearest_neighbours[0, i, j] < max_bond_length:
659
- if nearest_neighbours[0, i, j] > 0:
660
- # print(atoms[i],atoms[int(bonds[1,i,j])],bonds[:,i,j])
661
- bonds.append([*zip(balls[i], balls[int(nearest_neighbours[1, i, j])])])
662
- bond_indices.append([i, int(nearest_neighbours[1, i, j])])
663
-
664
- return corners, balls, atomic_number, bonds
665
-
666
-
667
- def plot_unitcell_mayavi(tags):
668
- """
669
- Makes a 3D plot of crystal structure
670
-
671
- Input:
672
-
673
- Dictionary with tags: 'unit_cell, 'elements', 'base'
674
-
675
- Output:
676
-
677
- 3D plot
678
-
679
- Dependencies:
680
-
681
- ball_and_stick function of KinsCat
682
- mlab of mayavi
683
- """
684
- from mayavi import mlab
685
-
686
- # Make sure "max_bond_length" and "extend" variables are initialized
687
- if 'max_bond_length' not in tags:
688
- max_bond_length = 0.
689
- else:
690
- max_bond_length = tags['max_bond_length']
691
-
692
- if 'extend' not in tags:
693
- extend = 1
694
- else:
695
- extend = tags['extend']
696
-
697
- # get balls, sticks and atomic numbers for colors and sizes
698
- corners, balls, atomic_number, bonds = ball_and_stick(tags, extend=extend, max_bond_length=max_bond_length)
699
-
700
- print('Now plotting')
701
- fig = mlab.figure(1, bgcolor=(0, 0, 0), size=(350, 350))
702
-
703
- mlab.clf() # clear figure
704
-
705
- # parallel projection
706
- mlab.gcf().scene.parallel_projection = True
707
- mlab.gcf().scene.camera.parallel_scale = 5
708
-
709
- # plot unit cell
710
- for x, y, z in corners:
711
- ll = mlab.plot3d(x, y, z, tube_radius=0.002)
712
-
713
- # plot bonds as sticks
714
- for x, y, z in bonds:
715
- mlab.plot3d(x, y, z, tube_radius=0.02)
716
-
717
- # plot atoms
718
- for i, atom in enumerate(balls):
719
- mlab.points3d(atom[0], atom[1], atom[2],
720
- scale_factor=0.1, # ks.vdw_radii[Z[i]]/50,
721
- resolution=20,
722
- color=tuple(jmol_colors[atomic_number[i]]),
723
- scale_mode='none')
724
-
725
- # parallel projection
726
- mlab.gcf().scene.parallel_projection = True
727
- mlab.gcf().scene.camera.parallel_scale = 5
728
- # show plot
729
- mlab.show()
730
-
731
-
732
- def plot_unitcell(tags):
733
- """
734
- Simple plot of unit cell
735
- """
736
-
737
- if 'max_bond_length' not in tags:
738
- max_bond_length = 0.
739
- else:
740
- max_bond_length = tags['max_bond_length']
741
-
742
- if 'extend' not in tags:
743
- extend = 1
744
- else:
745
- extend = tags['extend']
746
-
747
- corners, balls, atomic_number, bonds = ball_and_stick(tags, extend=extend, max_bond_length=max_bond_length)
748
-
749
- maximum_position = balls.max()*1.05
750
- maximum_x = balls[:, 0].max()
751
- maximum_y = balls[:, 1].max()
752
- maximum_z = balls[:, 2].max()
753
-
754
- balls = balls - [maximum_x/2, maximum_y/2, maximum_z/2]
755
-
756
- fig = plt.figure()
757
- ax = fig.add_subplot(111, projection='3d')
758
- # draw unit_cell
759
- for x, y, z in corners:
760
- ax.plot3D(x-maximum_x/2, y-maximum_y/2, z-maximum_z/2, color="blue")
761
-
762
- # draw bonds
763
- for x, y, z in bonds:
764
- ax.plot3D(x-maximum_x/2, y-maximum_y/2, z-maximum_z/2, color="black", linewidth=4) # , tube_radius=0.02)
765
-
766
- # draw atoms
767
- for i, atom in enumerate(balls):
768
- ax.scatter(atom[0], atom[1], atom[2],
769
- color=tuple(jmol_colors[atomic_number[i]]),
770
- alpha=1.0, s=50)
771
- maximum_position = balls.max()*1.05
772
- ax.set_proj_type('ortho')
773
-
774
- ax.set_zlim(-maximum_position/2, maximum_position/2)
775
- ax.set_ylim(-maximum_position/2, maximum_position/2)
776
- ax.set_xlim(-maximum_position/2, maximum_position/2)
777
-
778
- if 'name' in tags:
779
- ax.set_title(tags['name'])
780
-
781
- ax.set_xlabel('x [nm]')
782
- ax.set_ylabel('y [nm]')
783
- ax.set_zlabel('z [nm]')
784
-
785
-
786
- # The metric tensor of the lattice.
787
- def metric_tensor(matrix):
788
- """
789
- The metric tensor of the lattice.
790
-
791
- Usage:
792
- metric_tensor(unit_cell)
793
- """
794
- metric_tensor2 = np.dot(matrix, matrix.T)
795
- return metric_tensor2
796
-
797
-
798
- def vector_norm(g):
799
- """
800
- Length of vector
801
- """
802
- return np.sqrt(g[:, 0]**2+g[:, 1]**2+g[:, 2]**2)
803
-
804
-
805
- def make_pretty_labels(hkls, hex_label=False):
806
- """
807
- Make pretty labels
808
-
809
- Input:
810
- hkls: a numpy array with all the Miller indices to be labeled
811
-
812
- Optional:
813
- hex_label: if True this will make for Miller indices.
814
-
815
- Output:
816
- list of labels in Latex format
817
- """
818
- hkl_label = []
819
- for i in range(len(hkls)):
820
- h, k, l = np.array(hkls)[i]
821
-
822
- if h < 0:
823
- h_string = r'[$\bar {'+str(int(-h))+'},'
824
- else:
825
- h_string = r'[$\bar {'+str(int(h))+'},'
826
- if k < 0:
827
- k_string = r'\bar {'+str(int(-k))+'},'
828
- else:
829
- k_string = str(int(k))+','
830
- if hex_label:
831
- ii = -(h+k)
832
- if ii < 0:
833
- k_string = k_string + r'\bar {'+str(int(-ii))+'},'
834
- else:
835
- k_string = k_string + str(int(ii))+','
836
- if l < 0:
837
- l_string = r'\bar {'+str(int(-l))+'} $]'
838
- else:
839
- l_string = str(int(l))+'} $]'
840
- label = h_string+k_string+l_string
841
- hkl_label.append(label)
842
- return hkl_label
843
-
844
-
845
- # Wavelength in 1/nm
846
- def get_wavelength(e0):
847
- """
848
- Calculates the relativistic corrected de Broglie wave length of an electron
849
-
850
- Input:
851
- ------
852
- acceleration voltage in volt
853
- Output:
854
- -------
855
- wave length in nm
856
- """
857
-
858
- eV = const.e * e0
859
- return const.h/np.sqrt(2*const.m_e*eV*(1+eV/(2*const.m_e*const.c**2)))*10**9
860
-
861
-
862
- # Determine rotation matrix to tilt zone axis onto z-axis
863
- # We determine spherical coordinates to do that
864
- def get_rotation_matrix(zone, verbose=False):
865
- """
866
- Calculates the rotation matrix to rotate the zone axis parallel to the cartasian z-axis.
867
-
868
- We use spherical coordinates to first rotate around the z-axis and then around the y-axis.
869
- This makes it easier to apply additional tilts, than to use the cross product to determine a single rotation
870
- axis (Rodrigues Formula)
871
-
872
- INPUT:
873
- ------
874
- - zone axis has to be in cartesian coordinates also.
875
- The dot product of zone axis and unit cell will accomplish that.
876
-
877
- Output:
878
- -------
879
- - rotation_matrix
880
- - theta (degrees)
881
- - phi (degrees)
882
- """
883
- # spherical coordinates of zone
884
- r = np.sqrt((zone*zone).sum())
885
- theta = np.arccos(zone[2]/r)
886
- if zone[0] < 0:
887
- theta = -theta
888
- if zone[0] == 0:
889
- phi = np.pi/2
890
- else:
891
- phi = (np.arctan(zone[1]/zone[0]))
892
-
893
- if verbose:
894
- print('Rotation theta ', np.degrees(theta), ' phi ', np.degrees(phi))
895
- # unit = np.array([[1, 0, 0],[0,1, 0],[0, 0,1]])
896
-
897
- # first we rotate phi about z-axis
898
- c, s = np.cos(phi), np.sin(phi)
899
- rotz = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
900
-
901
- # second we rotate theta about y axis
902
- c, s = np.cos(theta), np.sin(theta)
903
- roty = np.array([[c, 0, s], [0, 1, 0], [-s, 0, c]])
904
-
905
- # the rotation now makes zone-axis coincide with plane normal
906
- return np.dot(rotz, roty), np.degrees(theta), np.degrees(phi)
907
-
908
-
909
- def check_sanity(tags):
910
- """
911
- Check sanity of input parameters
912
- """
913
- stop = False
914
- if 'unit_cell' not in tags:
915
- print(' No unit_cell defined')
916
- stop = True
917
- if 'base' not in tags:
918
- print(' No base defined')
919
- stop = True
920
- if 'elements' not in tags:
921
- print(' No atoms defined')
922
- stop = True
923
- if 'acceleration_voltage_V' not in tags:
924
- print(' No acceleration_voltage_V defined')
925
- stop = True
926
- if 'zone_hkl' not in tags:
927
- print(' No zone_hkl defined')
928
- stop = True
929
- if 'Sg_max' not in tags:
930
- print(' No Sg_max defined')
931
- stop = True
932
- if 'hkl_max' not in tags:
933
- print(' No hkl_max defined')
934
- stop = True
935
-
936
- if 'crystal_name' not in tags:
937
- tags['crystal_name'] = 'undefined'
938
- print('tags[\'crystal\'] = \'undefined\'')
939
- if 'mistilt' not in tags:
940
- tags['mistilt'] = [0., 0., 0.]
941
- print('tags[\'mistilt\'] = [0., 0., 0.]')
942
- if 'convergence_angle_mrad' not in tags:
943
- tags['convergence_angle_mrad'] = 0.
944
- print('tags[\'convergence_angle_mrad\'] = 0')
945
-
946
- return stop
947
-
948
-
949
- def ring_pattern_calculation(tags, verbose=False):
950
- """
951
- Calculate the ring diffraction pattern of a crystal structure
952
-
953
- Input:
954
- tags: dictionary of crystal structure
955
- Output:
956
- tags: dictionary with diffraction information added
957
-
958
- """
959
- # Reciprocal Lattice
960
- # We use the linear algebra package of numpy to invert the unit_cell "matrix"
961
- reciprocal_unit_cell = np.linalg.inv(tags['unit_cell']).T # transposed of inverted unit_cell
962
-
963
- # INPUT
964
- hkl_max = 7 # maximum allowed Miller index
965
-
966
- acceleration_voltage = 200.0*1000.0 # V
967
- wave_length = get_wavelength(acceleration_voltage)
968
-
969
- h = np.linspace(-hkl_max, hkl_max, 2*hkl_max+1) # all to be evaluated single Miller Index
970
- hkl = np.array(list(itertools.product(h, h, h))) # all to be evaluated Miller indices
971
- g_hkl = np.dot(hkl, reciprocal_unit_cell)
972
-
973
- # Calculate Structure Factors
974
-
975
- structure_factors = []
976
-
977
- base = np.dot(tags['base'], tags['unit_cell']) # transformation from relative to Cartesian coordinates
978
- for j in range(len(g_hkl)):
979
- F = 0
980
- for b in range(len(base)):
981
- # Atomic formfactor for element and momentum change (g vector)
982
- f = feq(tags['elements'][b], np.linalg.norm(g_hkl[j]))
983
- F += f * np.exp(-2*np.pi*1j*(g_hkl[j]*base[b]).sum())
984
- structure_factors.append(F)
985
- F = structure_factors = np.array(structure_factors)
986
-
987
- # Allowed reflections have a non zero structure factor F (with a bit of numerical error)
988
- allowed = np.absolute(structure_factors) > 0.001
989
-
990
- distances = np.linalg.norm(g_hkl, axis=1)
991
-
992
- if verbose:
993
- print(f' Of the evaluated {hkl.shape[0]} Miller indices {allowed.sum()} are allowed. ')
994
- # We select now all the
995
- zero = distances == 0.
996
- allowed = np.logical_and(allowed, np.logical_not(zero))
997
-
998
- F = F[allowed]
999
- g_hkl = g_hkl[allowed]
1000
- hkl = hkl[allowed]
1001
- distances = distances[allowed]
1002
-
1003
- sorted_allowed = np.argsort(distances)
1004
-
1005
- distances = distances[sorted_allowed]
1006
- hkl = hkl[sorted_allowed]
1007
- F = F[sorted_allowed]
1008
-
1009
- # How many have unique distances and what is their multiplicity
1010
-
1011
- unique, indices = np.unique(distances, return_index=True)
1012
-
1013
- if verbose:
1014
- print(f' Of the {allowed.sum()} allowed Bragg reflections there are {len(unique)} families of reflections.')
1015
-
1016
- intensity = np.absolute(F[indices]**2*(np.roll(indices, -1)-indices))
1017
- if verbose:
1018
- print('\n index \t hkl \t 1/d [1/nm] d [pm] F multip. intensity')
1019
- family = []
1020
- out_tags = {}
1021
- for j in range(len(unique)-1):
1022
- i = indices[j]
1023
- i2 = indices[j+1]
1024
- family.append(hkl[i+np.argmax(hkl[i:i2].sum(axis=1))])
1025
- index = '{'+f'{family[j][0]:.0f} {family[j][1]:.0f} {family[j][2]:.0f}'+'}'
1026
- if verbose:
1027
- print(f'{i:3g}\t {index} \t {distances[i]:.2f} \t {1/distances[i]*1000:.0f} \t {np.absolute(F[i]):.2f},'
1028
- f' \t {indices[j+1]-indices[j]:3g} \t {intensity[j]:.2f}')
1029
- out_tags[index] = {}
1030
- out_tags[index]['reciprocal_distance'] = distances[i]
1031
- out_tags[index]['real_distance'] = 1/distances[i]
1032
- out_tags[index]['F'] = np.absolute(F[i])
1033
- out_tags[index]['multiplicity'] = indices[j+1]-indices[j]
1034
- out_tags[index]['intensity'] = intensity[j]
1035
- return out_tags
1036
-
1037
-
1038
- def kinematic_scattering(tags, verbose=False):
1039
- """
1040
- All kinematic scattering calculation
1041
-
1042
- Calculates Bragg spots, Kikuchi lines, excess, and deficient HOLZ lines
1043
-
1044
- Input:
1045
- a dictionary with crystal structure:
1046
- 'unit_cell', 'base' 'elements'
1047
- and with experimental parameters:
1048
- 'acceleration_voltage_V', 'zone_hkl', 'Sg_max', 'hkl_max'
1049
- Optional parameters are:
1050
- 'mistilt', convergence_angle_mrad', and 'crystal_name'
1051
- vebose = True will give extended output of the calculation
1052
- Output to dictionary:
1053
- There are three sub_dictionaries:
1054
- ['allowed'], ['forbidden'], and ['HOLZ']
1055
- ['allowed'] and ['forbidden'] dictionaries contain:
1056
- ['Sg'], ['hkl'], ['g'], ['structure factor'], ['intensities'],
1057
- ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], ['HHOLZ'], ['label'], and ['Laue_zone']
1058
- the ['HOLZ'] dictionary contains:
1059
- ['slope'], ['distance'], ['theta'], ['g deficient'], ['g excess'], ['hkl'], ['intensities'],
1060
- ['ZOLZ'], ['FOLZ'], ['SOLZ'], ['HOLZ'], and ['HHOLZ']
1061
- Please note that the Kikuchi lines are the HOLZ lines of ZOLZ
1062
-
1063
- There are also a few parameters stored in the main dictionary:
1064
- ['wave_length_nm'], ['reciprocal_unit_cell'], ['inner_potential_V'], ['incident_wave_vector'],
1065
- ['volume'], ['theta'], ['phi'], and ['incident_wave_vector_vacuum']
1066
- """
1067
-
1068
- if check_sanity(tags):
1069
- print('Input is not complete, stopping')
1070
- print('Try \'example()\' for example input')
1071
- return
1072
-
1073
- tags['wave_length_nm'] = get_wavelength(tags['acceleration_voltage_V'])
1074
-
1075
- # ###########################################
1076
- # reciprocal_unit_cell
1077
- # ###########################################
1078
- unit_cell = np.array(tags['unit_cell'])
1079
- # We use the linear algebra package of numpy to invert the unit_cell "matrix"
1080
- reciprocal_unit_cell = np.linalg.inv(unit_cell).T # transposed of inverted unit_cell
1081
- tags['reciprocal_unit_cell'] = reciprocal_unit_cell
1082
-
1083
- if verbose:
1084
- print('reciprocal_unit_cell')
1085
- print(np.round(reciprocal_unit_cell, 3))
1086
-
1087
- # ###########################################
1088
- # Incident wave vector K0 in vacuum and material
1089
- # ###########################################
1090
-
1091
- # Incident wave vector K0 in vacuum and material
1092
- u0 = 0
1093
- for i in range(len(tags['elements'])):
1094
- a = tags['elements'][i]
1095
- u0 += feq(a, 0)*0.023933754
1096
-
1097
- tags['volume'] = float(np.linalg.det(tags['unit_cell']))
1098
- volume = tags['volume']*1000.0 # Needs to be in Angstrom for form factors
1099
- angstrom_conversion = 1.0e10 # So [1A (in m)] * angstrom_conversion = 1
1100
- # NanometerConversion = 1.0e9
1101
-
1102
- scatt_factor_to_volts = (const.h**2)*(angstrom_conversion**2)/(2*np.pi*const.m_e*const.e)*float(volume)
1103
- u0 = u0*scatt_factor_to_volts
1104
- tags['inner_potential_A'] = u0
1105
- tags['inner_potential_V'] = u0*scatt_factor_to_volts
1106
- if verbose:
1107
- print('The inner potential is {0:.3f}kV'.format(tags['inner_potential_V']/1000))
1108
-
1109
- # Calculating incident wave vector magnitude 'K0' in material
1110
- wl = tags['wave_length_nm']
1111
- tags['incident_wave_vector_vacuum'] = 1/wl
1112
-
1113
- k_0 = tags['incident_wave_vector'] = np.sqrt(1/wl**2 - (u0/volume*100.)) # 1/nm
1114
-
1115
- tags['convergence_angle_nm-1'] = k_0*np.sin(tags['convergence_angle_mrad']/1000.)
1116
-
1117
- if verbose:
1118
- print('Magnitude of incident wave vector in material {0:.1f} 1/nm and vacuum {1:.1f} 1/nm'.format(k_0, 1/wl))
1119
- print('The convergence angle of {0}mrad = {1:.2f} 1/nm'.format(tags['convergence_angle_mrad'],
1120
- tags['convergence_angle_nm-1']))
1121
-
1122
- # ############
1123
- # Rotate
1124
- # ############
1125
-
1126
- # first we take care of mistilt: zone axis is then in fractional Miller indices
1127
- zone = tags['zone'] = zone_mistilt(tags['zone_hkl'], tags['mistilt'])
1128
-
1129
- # zone axis in global coordinate system
1130
- zone_vector = np.dot(zone, reciprocal_unit_cell)
1131
-
1132
- rotation_matrix, theta, phi = get_rotation_matrix(zone_vector, verbose=False)
1133
-
1134
- if verbose:
1135
- print('Rotation angles are {0:.1f} deg and {1:.1f} deg'.format(theta, phi))
1136
- tags['theta'] = theta
1137
- tags['phi'] = phi
1138
-
1139
- # rotate incident wave vector
1140
- w_vector = np.dot(zone_vector, rotation_matrix)
1141
- k0_unit_vector = w_vector / np.linalg.norm(w_vector) # incident unit wave vector
1142
- k0_vector = k0_unit_vector*k_0 # incident wave vector
1143
-
1144
- if verbose:
1145
- print('Center of Ewald sphere ', k0_vector)
1146
-
1147
- # #######################
1148
- # Find all Miller indices whose reciprocal point lays near the Ewald sphere with radius k_0
1149
- # within a maximum excitation error Sg
1150
- # #######################
1151
-
1152
- hkl_max = tags['hkl_max']
1153
- Sg_max = tags['Sg_max'] # 1/nm maximum allowed excitation error
1154
-
1155
- h = np.linspace(-hkl_max, hkl_max, 2*hkl_max+1) # all evaluated single Miller Indices
1156
- hkl = np.array(list(itertools.product(h, h, h))) # all evaluated Miller indices
1157
- g = np.dot(hkl, reciprocal_unit_cell) # all evaluated reciprocal_unit_cell points
1158
- g_norm = np.linalg.norm(g, axis=1) # length of all vectors
1159
- not_zero = g_norm > 0
1160
- g = g[not_zero] # zero reflection will make problems further on, so we exclude it.
1161
- g_norm = g_norm[not_zero]
1162
- hkl = hkl[not_zero]
1163
- g_non_rot = g
1164
- g = np.dot(g, rotation_matrix)
1165
-
1166
- # #######################
1167
- # Calculate excitation errors for all reciprocal_unit_cell points
1168
- # #######################
1169
-
1170
- # Zuo and Spence, 'Adv TEM', 2017 -- Eq 3:14
1171
- # S=(k_0**2-np.linalg.norm(g - k0_vector, axis=1)**2)/(2*k_0)
1172
- g_mz = g - k0_vector
1173
-
1174
- in_sqrt = g_mz[:, 2]**2 + np.linalg.norm(g_mz, axis=1)**2 - k_0**2
1175
- in_sqrt[in_sqrt < 0] = 0.
1176
- S = -g_mz[:, 2] - np.sqrt(in_sqrt)
1177
-
1178
- # #######################
1179
- # Determine reciprocal_unit_cell points with excitation error less than the maximum allowed one: Sg_max
1180
- # #######################
1181
-
1182
- reflections = abs(S) < Sg_max # This is now a boolean array with True for all possible reflections
1183
-
1184
- Sg = S[reflections]
1185
- g_hkl = g[reflections]
1186
- g_hkl_non_rot = g_non_rot[reflections]
1187
- hkl = hkl[reflections]
1188
- g_norm = g_norm[reflections]
1189
-
1190
- if verbose:
1191
- print('Of the {0} tested reciprocal_unit_cell points, {1} have an excitation error less than {2:.2f} 1/nm'.
1192
- format(len(g), len(g_hkl), Sg_max))
1193
-
1194
- # #################################
1195
- # Calculate Structure Factors
1196
- # ################################
1197
-
1198
- structure_factors = []
1199
- """for j in range(len(g_hkl)):
1200
- F = 0
1201
- for b in range(len(tags['base'])):
1202
- f = feq(tags['elements'][b],np.linalg.norm(g_hkl[j]))
1203
- #F += f * np.exp(-2*np.pi*1j*(hkl*tags['base'][b]).sum()) # may only work for cubic Gerd
1204
- F += f * np.exp(-2*np.pi*1j*(g_hkl_non_rot*np.dot(tags['base'][b],unit_cell)).sum())
1205
-
1206
-
1207
- structure_factors.append(F)
1208
-
1209
- F = structure_factors = np.array(structure_factors)
1210
- """
1211
- base = np.dot(tags['base'], tags['unit_cell']) # transformation from relative to Cartesian coordinates
1212
- for j in range(len(g_hkl)):
1213
- F = 0
1214
- for b in range(len(base)):
1215
- f = feq(tags['elements'][b], g_norm[j]) # Atomic form factor for element and momentum change (g vector)
1216
- F += f * np.exp(-2*np.pi*1j*(g_hkl_non_rot[j]*base[b]).sum())
1217
- structure_factors.append(F)
1218
- F = structure_factors = np.array(structure_factors)
1219
-
1220
- # ###########################################
1221
- # Sort reflection in allowed and forbidden #
1222
- # ###########################################
1223
-
1224
- allowed = np.absolute(F) > 0.000001 # allowed within numerical error
1225
-
1226
- if verbose:
1227
- print('Of the {0} possible reflection {1} are allowed.'.format(hkl.shape[0], allowed.sum()))
1228
-
1229
- # information of allowed reflections
1230
- Sg_allowed = Sg[allowed]
1231
- hkl_allowed = hkl[allowed][:]
1232
- g_allowed = g_hkl[allowed, :]
1233
- F_allowed = F[allowed]
1234
- g_norm_allowed = g_norm[allowed]
1235
-
1236
- tags['allowed'] = {}
1237
- tags['allowed']['Sg'] = Sg_allowed
1238
- tags['allowed']['hkl'] = hkl_allowed
1239
- tags['allowed']['g'] = g_allowed
1240
- tags['allowed']['structure factor'] = F_allowed
1241
-
1242
- # information of forbidden reflections
1243
- forbidden = np.logical_not(allowed)
1244
- Sg_forbidden = Sg[forbidden]
1245
- hkl_forbidden = hkl[forbidden]
1246
- g_forbidden = g_hkl[forbidden]
1247
-
1248
- tags['forbidden'] = {}
1249
- tags['forbidden']['Sg'] = Sg_forbidden
1250
- tags['forbidden']['hkl'] = hkl_forbidden
1251
- tags['forbidden']['g'] = g_forbidden
1252
-
1253
- # ##########################
1254
- # Make pretty labels
1255
- # ##########################
1256
- hkl_label = make_pretty_labels(hkl_allowed)
1257
- tags['allowed']['label'] = hkl_label
1258
-
1259
- # hkl_label = make_pretty_labels(hkl_forbidden)
1260
- # tags['forbidden']['label'] = hkl_label
1261
-
1262
- # ###########################
1263
- # Calculate Intensities (of allowed reflections)
1264
- # ###########################
1265
-
1266
- intensities = np.absolute(F_allowed)**2
1267
-
1268
- tags['allowed']['intensities'] = intensities
1269
-
1270
- # ###########################
1271
- # Calculate Laue Zones (of allowed reflections)
1272
- # ###########################
1273
- # Below is the expression given in most books.
1274
- # However, that would only work for orthogonal crystal systems
1275
- # Laue_Zone = abs(np.dot(hkl_allowed,tags['zone_hkl'])) # works only for orthogonal systems
1276
-
1277
- # This expression works for all crystal systems
1278
- # Remember we have already tilted, and so the dot product is trivial and gives only the z-component.
1279
- length_zone_axis = np.linalg.norm(np.dot(tags['zone_hkl'], tags['unit_cell']))
1280
- laue_zone = abs(np.floor(g_allowed[:, 2]*length_zone_axis+0.5))
1281
-
1282
- tags['allowed']['Laue_Zone'] = laue_zone
1283
-
1284
- ZOLZ_forbidden = abs(np.floor(g_forbidden[:, 2]*length_zone_axis+0.5)) == 0
1285
-
1286
- tags['forbidden']['Laue_Zone'] = ZOLZ_forbidden
1287
- ZOLZ = laue_zone == 0
1288
- FOLZ = laue_zone == 1
1289
- SOLZ = laue_zone == 2
1290
- HOLZ = laue_zone > 0
1291
- HOLZp = laue_zone > 2
1292
-
1293
- tags['allowed']['ZOLZ'] = ZOLZ
1294
- tags['allowed']['FOLZ'] = FOLZ
1295
- tags['allowed']['SOLZ'] = SOLZ
1296
- tags['allowed']['HOLZ'] = HOLZ
1297
- tags['allowed']['HOLZ_plus'] = tags['allowed']['HHOLZ'] = HOLZp
1298
-
1299
- if verbose:
1300
- print(' There are {0} allowed reflections in the zero order Laue Zone'.format(ZOLZ.sum()))
1301
- print(' There are {0} allowed reflections in the first order Laue Zone'.format((laue_zone == 1).sum()))
1302
- print(' There are {0} allowed reflections in the second order Laue Zone'.format((laue_zone == 2).sum()))
1303
- print(' There are {0} allowed reflections in the other higher order Laue Zones'.format((laue_zone > 2).sum()))
1304
-
1305
- if verbose == 2:
1306
- print(' hkl \t Laue zone \t Intensity (*1 and \t log) \t length \n')
1307
- for i in range(len(hkl_allowed)):
1308
- print(' {0} \t {1} \t {2:.3f} \t {3:.3f} \t {4:.3f} '.format(hkl_allowed[i], g_allowed[i],
1309
- intensities[i], np.log(intensities[i]+1),
1310
- g_norm_allowed[i]))
1311
-
1312
- # ##########################
1313
- # Dynamically Activated forbidden reflections
1314
- # ##########################
1315
-
1316
- double_diffraction = (np.sum(np.array(list(itertools.combinations(hkl_allowed[ZOLZ], 2))), axis=1))
1317
-
1318
- dynamical_allowed = []
1319
- still_forbidden = []
1320
- for i, hkl in enumerate(hkl_forbidden):
1321
- if ZOLZ_forbidden[i]:
1322
- if hkl.tolist() in double_diffraction.tolist():
1323
- dynamical_allowed.append(i)
1324
- else:
1325
- still_forbidden.append(i)
1326
- tags['forbidden']['dynamically_activated'] = dynamical_allowed
1327
- tags['forbidden']['forbidden'] = dynamical_allowed
1328
- if verbose:
1329
- print('Length of zone axis vector in real space {0} nm'.format(np.round(length_zone_axis, 3)))
1330
- print(f'There are {len(dynamical_allowed)} forbidden but dynamical activated diffraction spots:')
1331
- # print(tags['forbidden']['hkl'][dynamical_allowed])
1332
-
1333
- # ###################################
1334
- # Calculate HOLZ and Kikuchi Lines #
1335
- # ###################################
1336
-
1337
- # Dynamic Correction
1338
-
1339
- # Equation Spence+Zuo 3.86a
1340
- gamma_1 = - 1./(2.*k_0) * (intensities / (2.*k_0*Sg_allowed)).sum()
1341
- # print('gamma_1',gamma_1)
1342
-
1343
- # Equation Spence+Zuo 3.84
1344
- Kg = k_0 - k_0*gamma_1/(g_allowed[:, 2]+1e-15)
1345
- Kg[ZOLZ] = k_0
1346
-
1347
- # print(Kg, Kg.shape)
1348
-
1349
- # Calculate angle between K0 and deficient cone vector
1350
- # For dynamic calculations K0 is replaced by Kg
1351
- Kg[:] = k_0
1352
- d_theta = np.arcsin(g_norm_allowed/Kg/2.)-np.arcsin(np.abs(g_allowed[:, 2])/g_norm_allowed)
1353
-
1354
- # calculate length of distance of deficient cone to K0 in ZOLZ plane
1355
- gd_length = 2*np.sin(d_theta/2)*k_0
1356
-
1357
- # Calculate nearest point of HOLZ and Kikuchi lines
1358
- g_closest = g_allowed.copy()
1359
- g_closest = g_closest*(gd_length/np.linalg.norm(g_closest, axis=1))[:, np.newaxis]
1360
-
1361
- g_closest[:, 2] = 0.
1362
-
1363
- # calculate and save line in Hough space coordinates (distance and theta)
1364
- slope = g_closest[:, 0]/(g_closest[:, 1]+1e-10)
1365
- distance = gd_length
1366
- theta = np.arctan2(g_allowed[:, 0], g_allowed[:, 1])
1367
-
1368
- tags['HOLZ'] = {}
1369
- tags['HOLZ']['slope'] = slope
1370
- # a line is now given by
1371
-
1372
- tags['HOLZ']['distance'] = distance
1373
- tags['HOLZ']['theta'] = theta
1374
-
1375
- tags['HOLZ']['g deficient'] = g_closest
1376
- tags['HOLZ']['g excess'] = g_closest+g_allowed
1377
-
1378
- tags['HOLZ']['ZOLZ'] = ZOLZ
1379
- tags['HOLZ']['HOLZ'] = HOLZ
1380
- tags['HOLZ']['FOLZ'] = FOLZ
1381
- tags['HOLZ']['SOLZ'] = SOLZ
1382
- tags['HOLZ']['HHOLZ'] = HOLZp # even higher HOLZ
1383
-
1384
- tags['HOLZ']['hkl'] = tags['allowed']['hkl']
1385
- tags['HOLZ']['intensities'] = intensities
1386
-
1387
- if verbose:
1388
- print('KinsCat\'s \"Kinematic_Scattering\" finished')
1389
-
1390
-
1391
- def plotSAED(tags, gray=False):
1392
- """
1393
- Plot SAED Pattern of single crystal
1394
- """
1395
-
1396
- saed = tags.copy()
1397
- saed['convergence_angle_nm-1'] = 0
1398
-
1399
- saed['background'] = 'white' # 'white' 'grey'
1400
- saed['color map'] = 'plasma' # ,'cubehelix'#'Greys'#'plasma'
1401
- saed['color reflections'] = 'ZOLZ'
1402
-
1403
- if gray:
1404
- saed['color map'] = 'gray'
1405
- saed['background'] = '#303030' # 'darkgray'
1406
- saed['color reflections'] = 'intensity'
1407
- saed['plot HOLZ'] = 0
1408
- saed['plot HOLZ excess'] = 0
1409
- saed['plot Kikuchi'] = 0
1410
- saed['plot reflections'] = 1
1411
-
1412
- saed['label HOLZ'] = 0
1413
- saed['label Kikuchi'] = 0
1414
- saed['label reflections'] = 0
1415
-
1416
- saed['label color'] = 'white'
1417
- saed['label size'] = 10
1418
-
1419
- saed['color Laue Zones'] = ['red', 'blue', 'green', 'blue', 'green'] # , 'green', 'red'] #for OLZ give a sequence
1420
- saed['color zero'] = 'red' # 'None' #'white'
1421
- saed['color ring zero'] = 'None' # 'Red' #'white' #, 'None'
1422
- saed['width ring zero'] = 2
1423
-
1424
- plot_diffraction_pattern(saed, True)
1425
-
1426
-
1427
- def plotKikuchi(tags, grey=False):
1428
- """
1429
- Plot Kikuchi Pattern
1430
- """
1431
- Kikuchi = tags.copy()
1432
-
1433
- Kikuchi['background'] = 'black' # 'white' 'grey'
1434
- Kikuchi['color map'] = 'plasma' # ,'cubehelix'#'Greys'#'plasma'
1435
- Kikuchi['color reflections'] = 'intensity'
1436
-
1437
- Kikuchi['plot HOLZ'] = 0
1438
- Kikuchi['plot HOLZ excess'] = 0
1439
- Kikuchi['plot Kikuchi'] = 1
1440
- Kikuchi['plot reflections'] = 1
1441
-
1442
- Kikuchi['label HOLZ'] = 0
1443
- Kikuchi['label Kikuchi'] = 0
1444
- Kikuchi['label reflections'] = 0
1445
-
1446
- Kikuchi['label color'] = 'white'
1447
- Kikuchi['label size'] = 10
1448
-
1449
- Kikuchi['color Kikuchi'] = 'green'
1450
- Kikuchi['linewidth HOLZ'] = -1 # -1: linewidth according to intensity (structure factor F^2
1451
- Kikuchi['linewidth Kikuchi'] = -1 # -1: linewidth according to intensity (structure factor F^2
1452
-
1453
- Kikuchi['color Laue Zones'] = ['red', 'blue', 'green', 'blue', 'green'] # , 'green', 'red']
1454
- # #for OLZ give a sequence
1455
- Kikuchi['color zero'] = 'white' # 'None' #'white'
1456
- Kikuchi['color ring zero'] = 'None' # 'Red' #'white' #, 'None'
1457
- Kikuchi['width ring zero'] = 2
1458
-
1459
- plot_diffraction_pattern(Kikuchi, True)
1460
-
1461
-
1462
- def plotHOLZ(tags, grey=False):
1463
- """
1464
- Plot HOLZ Pattern
1465
- """
1466
- holz = tags.copy()
1467
-
1468
- holz['background'] = 'black' # 'white' 'grey'
1469
- holz['color map'] = 'plasma' # ,'cubehelix'#'Greys'#'plasma'
1470
- holz['color reflections'] = 'intensity'
1471
-
1472
- holz['plot HOLZ'] = 1
1473
- holz['plot HOLZ excess'] = 0
1474
- holz['plot Kikuchi'] = 1
1475
- holz['plot reflections'] = 0
1476
-
1477
- holz['label HOLZ'] = 0
1478
- holz['label Kikuchi'] = 0
1479
- holz['label reflections'] = 0
1480
-
1481
- holz['label color'] = 'white'
1482
- holz['label size'] = 10
1483
-
1484
- holz['color Kikuchi'] = 'green'
1485
- holz['linewidth HOLZ'] = -1 # -1: linewidth according to intensity (structure factor F^2
1486
- holz['linewidth Kikuchi'] = -1 # -1: linewidth according to intensity (structure factor F^2
1487
-
1488
- holz['color Laue Zones'] = ['red', 'blue', 'green'] # , 'green', 'red'] #for OLZ give a sequence
1489
- holz['color zero'] = 'white' # 'None' #'white'
1490
- holz['color ring zero'] = 'Red' # 'Red' #'white' #, 'None'
1491
- holz['width ring zero'] = 2
1492
-
1493
- plot_diffraction_pattern(holz, True)
1494
-
1495
-
1496
- def plotCBED(tags, grey=False):
1497
- """
1498
- Plot CBED Pattern
1499
- """
1500
- cbed = tags.copy()
1501
-
1502
- cbed['background'] = 'black' # 'white' 'grey'
1503
- cbed['color map'] = 'plasma' # ,'cubehelix'#'Greys'#'plasma'
1504
- cbed['color reflections'] = 'intensity'
1505
-
1506
- cbed['plot HOLZ'] = 1
1507
- cbed['plot HOLZ excess'] = 1
1508
- cbed['plot Kikuchi'] = 1
1509
- cbed['plot reflections'] = 1
1510
-
1511
- cbed['label HOLZ'] = 0
1512
- cbed['label Kikuchi'] = 0
1513
- cbed['label reflections'] = 0
1514
-
1515
- cbed['label color'] = 'white'
1516
- cbed['label size'] = 10
1517
-
1518
- cbed['color Kikuchi'] = 'green'
1519
- cbed['linewidth HOLZ'] = -1 # -1: linewidth according to intensity (structure factor F^2
1520
- cbed['linewidth Kikuchi'] = -1 # -1: linewidth according to intensity (structure factor F^2
1521
-
1522
- cbed['color reflections'] = 'intensity'
1523
-
1524
- cbed['color Laue Zones'] = ['red', 'blue', 'green'] # , 'green', 'red'] #for OLZ give a sequence
1525
- cbed['color zero'] = 'white' # 'None' #'white'
1526
- cbed['color ring zero'] = 'Red' # 'Red' #'white' #, 'None'
1527
- cbed['width ring zero'] = 2
1528
-
1529
- plot_diffraction_pattern(cbed, True)
1530
-
1531
-
1532
- # #######################
1533
- # Plot HOLZ Pattern #
1534
- # #######################
1535
- def circles(x, y, s, c='b', v_min=None, v_max=None, **kwargs):
1536
- """
1537
- Make a scatter plot of circles.
1538
-
1539
- Similar to plt.scatter, but the size of circles are in data scale.
1540
-
1541
- Parameters
1542
-
1543
- x, y : scalar or array_like, shape (n, )
1544
- Input data
1545
- s : scalar or array_like, shape (n, )
1546
- Radius of circles.
1547
- c : color or sequence of color, optional, default : 'b'
1548
- `c` can be a single color format string, or a sequence of color
1549
- specifications of length `N`, or a sequence of `N` numbers to be
1550
- mapped to colors using the `cmap` and `norm` specified via kwargs.
1551
- Note that `c` should not be a single numeric RGB or RGBA sequence
1552
- because that is indistinguishable from an array of values
1553
- to be colormapped. (If you insist, use `color` instead.)
1554
- `c` can be a 2-D array in which the rows are RGB or RGBA, however.
1555
- v_min, v_max : scalar, optional, default: None
1556
- `v_min` and `v_max` are used in conjunction with `norm` to normalize
1557
- luminance data. If either are `None`, the min and max of the
1558
- color array is used.
1559
- kwargs : `~matplotlib.collections.Collection` properties
1560
- Eg. alpha, edgecolor(ec), facecolor(fc), linewidth(lw), linestyle(ls),
1561
- norm, cmap, transform, etc.
1562
- Returns
1563
-
1564
- paths : `~matplotlib.collections.PathCollection`
1565
- Examples
1566
- a = np.arange(11)
1567
- circles(a, a, s=a*0.2, c=a, alpha=0.5, ec='none')
1568
- plt.colorbar()
1569
- License
1570
- This code is under [The BSD 3-Clause License]
1571
- (http://opensource.org/licenses/BSD-3-Clause)
1572
- """
1573
-
1574
- if np.isscalar(c):
1575
- kwargs.setdefault('color', c)
1576
- c = None
1577
-
1578
- if 'fc' in kwargs:
1579
- kwargs.setdefault('facecolor', kwargs.pop('fc'))
1580
- if 'ec' in kwargs:
1581
- kwargs.setdefault('edgecolor', kwargs.pop('ec'))
1582
- if 'ls' in kwargs:
1583
- kwargs.setdefault('linestyle', kwargs.pop('ls'))
1584
- if 'lw' in kwargs:
1585
- kwargs.setdefault('linewidth', kwargs.pop('lw'))
1586
- # You can set `facecolor` with an array for each patch,
1587
- # while you can only set `facecolors` with a value for all.
1588
-
1589
- zipped = np.broadcast(x, y, s)
1590
- patches = [Circle((x_, y_), s_)
1591
- for x_, y_, s_ in zipped]
1592
- collection = PatchCollection(patches, **kwargs)
1593
- if c is not None:
1594
- c = np.broadcast_to(c, zipped.shape).ravel()
1595
- collection.set_array(c)
1596
- collection.set_clim(v_min, v_max)
1597
-
1598
- ax = plt.gca()
1599
- ax.add_collection(collection)
1600
- ax.autoscale_view()
1601
- plt.draw_if_interactive()
1602
- if c is not None:
1603
- plt.sci(collection)
1604
- return collection
1605
-
1606
-
1607
- def plot_diffraction_pattern(tags, grey=False):
1608
- """
1609
- Plot any diffraction pattern based on content in dictionary
1610
- """
1611
- if 'plot_rotation' not in tags:
1612
- tags['plot_rotation'] = 0.
1613
-
1614
- if 'new_plot' not in tags:
1615
- tags['new_plot'] = True
1616
-
1617
- if tags['new_plot']:
1618
- fig = plt.figure()
1619
- ax = fig.add_subplot(111, facecolor=tags['background'])
1620
-
1621
- diffraction_pattern(tags, grey)
1622
-
1623
- plt.axis('equal')
1624
- if 'plot FOV' in tags:
1625
- x = tags['plot FOV'] # in 1/nm
1626
- plt.xlim(-x, x)
1627
- plt.ylim(-x, x)
1628
- plt.title(tags['crystal_name'])
1629
- plt.show()
1630
- else:
1631
- diffraction_pattern(tags, grey)
1632
-
1633
-
1634
- def diffraction_pattern(tags, grey=False):
1635
- """
1636
- Determines how to plot diffraction pattern from kinematic scattering data.
1637
-
1638
- Input:
1639
- tags : dictionary of kinematic scattering data
1640
-
1641
- Returns:
1642
- tags: dictionary that now contains all information of how to plot any diffraction pattern
1643
- plot
1644
- """
1645
-
1646
- # Get information from dictionary
1647
- HOLZ = tags['allowed']['HOLZ']
1648
- ZOLZ = tags['allowed']['ZOLZ']
1649
-
1650
- laue_zone = tags['allowed']['Laue_Zone']
1651
-
1652
- if 'label' in tags['allowed']:
1653
- label = tags['allowed']['label']
1654
-
1655
- angle = np.radians(tags['plot_rotation']) # mrad
1656
- c = np.cos(angle)
1657
- s = np.sin(angle)
1658
- r_mat = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
1659
-
1660
- # HOLZ and Kikuchi lines coordinates in Hough space
1661
- gd = np.dot(tags['HOLZ']['g deficient'], r_mat)
1662
- ge = np.dot(tags['HOLZ']['g excess'], r_mat)
1663
-
1664
- points = np.dot(tags['allowed']['g'], r_mat)
1665
-
1666
- theta = tags['HOLZ']['theta']+angle
1667
-
1668
- intensity = tags['allowed']['intensities']
1669
- radius = tags['convergence_angle_nm-1']
1670
- tags['Bragg'] = {}
1671
- tags['Bragg']['points'] = points
1672
- tags['Bragg']['intensity'] = intensity
1673
- tags['Bragg']['radius'] = radius
1674
-
1675
- if radius < 0.1:
1676
- radius_i = 2
1677
- else:
1678
- radius_i = radius
1679
- # Beginning and ends of HOLZ lines
1680
- max_length = radius_i * 1.3
1681
- h_xp = gd[:, 0] + max_length * np.cos(np.pi-theta)
1682
- h_yp = gd[:, 1] + max_length * np.sin(np.pi-theta)
1683
- h_xm = gd[:, 0] - max_length * np.cos(np.pi-theta)
1684
- h_ym = gd[:, 1] - max_length * np.sin(np.pi-theta)
1685
- tags['HOLZ lines'] = {}
1686
- tags['HOLZ lines']['Hxp'] = h_xp
1687
- tags['HOLZ lines']['Hyp'] = h_yp
1688
- tags['HOLZ lines']['Hxm'] = h_xm
1689
- tags['HOLZ lines']['Hym'] = h_ym
1690
-
1691
- # Beginning and ends of excess HOLZ lines
1692
- max_length = radius_i * 0.8
1693
- e_xp = ge[:, 0] + max_length * np.cos(np.pi-theta)
1694
- e_yp = ge[:, 1] + max_length * np.sin(np.pi-theta)
1695
- e_xm = ge[:, 0] - max_length * np.cos(np.pi-theta)
1696
- e_ym = ge[:, 1] - max_length * np.sin(np.pi-theta)
1697
- tags['excess HOLZ lines'] = {}
1698
- tags['excess HOLZ lines']['Exp'] = e_xp
1699
- tags['excess HOLZ lines']['Eyp'] = e_yp
1700
- tags['excess HOLZ lines']['Exm'] = e_xm
1701
- tags['excess HOLZ lines']['Eym'] = e_ym
1702
-
1703
- # Beginning and ends of HOLZ lines
1704
- max_length = 20
1705
- k_xp = gd[:, 0] + max_length * np.cos(np.pi-theta)
1706
- k_yp = gd[:, 1] + max_length * np.sin(np.pi-theta)
1707
- k_xm = gd[:, 0] - max_length * np.cos(np.pi-theta)
1708
- k_ym = gd[:, 1] - max_length * np.sin(np.pi-theta)
1709
- tags['Kikuchi lines'] = {}
1710
- tags['Kikuchi lines']['Kxp'] = k_xp
1711
- tags['Kikuchi lines']['Kyp'] = k_yp
1712
- tags['Kikuchi lines']['Kxm'] = k_xm
1713
- tags['Kikuchi lines']['Kym'] = k_ym
1714
-
1715
- intensity_Kikuchi = intensity*4./intensity[ZOLZ].max()
1716
- if len(intensity[tags['HOLZ']['HOLZ']]) > 1:
1717
- intensity_HOLZ = intensity*4./intensity[tags['HOLZ']['HOLZ']].max()*.75
1718
- tags['HOLZ lines']['intensity_HOLZ'] = intensity_HOLZ
1719
- tags['Kikuchi lines']['intensity_Kikuchi'] = intensity_Kikuchi
1720
- # #######
1721
- # Plot #
1722
- # #######
1723
- # cms = mpl.cm
1724
- # cm = cms.plasma#jet#, cms.gray, cms.autumn]
1725
- cm = plt.get_cmap(tags['color map'])
1726
-
1727
- fig = plt.gcf()
1728
-
1729
- ax = plt.gca()
1730
-
1731
- if 'plot image' in tags:
1732
- l = -tags['plot image FOV']/2+tags['plot shift x']
1733
- r = tags['plot image FOV']/2+tags['plot shift x']
1734
- t = -tags['plot image FOV']/2+tags['plot shift y']
1735
- b = tags['plot image FOV']/2+tags['plot shift y']
1736
- ax.imshow(tags['plot image'], extent=(l, r, t, b))
1737
- print('image')
1738
-
1739
- ix = np.argsort((points**2).sum(axis=1))
1740
- # print(tags['allowed']['hkl'][ix])
1741
- p = points[ix]
1742
- inten = intensity[ix]
1743
- tags['Bragg']['points'] = p
1744
- tags['Bragg']['intensity'] = inten
1745
-
1746
- laue_color = []
1747
- for i in range(int(laue_zone.max())+1):
1748
- if i < len(tags['color Laue Zones']):
1749
- laue_color.append(tags['color Laue Zones'][i])
1750
- else:
1751
- laue_color.append(tags['color Laue Zones'][-1])
1752
-
1753
- if tags['plot reflections']:
1754
- if radius < 0.1:
1755
- if tags['color reflections'] == 'intensity':
1756
- ax.scatter(points[:, 0], points[:, 1], c=np.log(intensity), cmap=cm, s=20)
1757
- else:
1758
- for i in range(len(laue_zone)):
1759
- color = laue_color[int(laue_zone[i])]
1760
- ax.scatter(points[i, 0], points[i, 1], c=color, cmap=cm, s=20)
1761
-
1762
- ax.scatter(0, 0, c=tags['color zero'], s=100)
1763
- radius = 2
1764
- else:
1765
- ix = np.argsort((points**2).sum(axis=1))
1766
- p = points[ix]
1767
- inten = intensity[ix]
1768
- if tags['color reflections'] == 'intensity':
1769
- circles(p[:, 0], p[:, 1], s=radius, c=np.log(inten+1), cmap=cm, alpha=0.9, edgecolor='')
1770
- else:
1771
- for i in range(len(laue_zone)):
1772
- color = laue_color[int(laue_zone[i])]
1773
- circles(p[i, 0], p[i, 1], s=radius, c=color, cmap=cm, alpha=0.9, edgecolor='')
1774
-
1775
- if not tags['color zero'] == 'None':
1776
- circle = plt.Circle((0, 0), radius, color=tags['color zero'])
1777
- ax.add_artist(circle)
1778
-
1779
- for i in range(len(h_xp)):
1780
- if tags['HOLZ']['HOLZ'][i]:
1781
- color = laue_color[int(laue_zone[i])]
1782
- if tags['plot HOLZ']:
1783
- # plot HOLZ lines
1784
- ax.plot((h_xp[i], h_xm[i]), (h_yp[i], h_ym[i]), c=color, linewidth=intensity_HOLZ[i])
1785
- if tags['plot HOLZ excess']:
1786
- ax.plot((e_xp[i], e_xm[i]), (e_yp[i], e_ym[i]), c=color, linewidth=intensity_HOLZ[i])
1787
-
1788
- if tags['label HOLZ']: # Add indices
1789
- ax.text(h_xp[i], h_yp[i], label[i], fontsize=10)
1790
- ax.text(e_xp[i], e_yp[i], label[i], fontsize=10)
1791
- else:
1792
- # Plot Kikuchi lines
1793
- if tags['plot Kikuchi']:
1794
- ax.plot((k_xp[i], k_xm[i]), (k_yp[i], k_ym[i]), c=tags['color Kikuchi'], linewidth=intensity_Kikuchi[i])
1795
- if tags['label Kikuchi']: # Add indices
1796
- ax.text(k_xp[i], k_yp[i], label[i], fontsize=tags['label size'], color=tags['label color'])
1797
- # tags['Kikuchi lines']
1798
-
1799
- if not (tags['color ring zero'] == 'None'):
1800
- ring = plt.Circle((0, 0), radius, color=tags['color ring zero'], fill=False, linewidth=2)
1801
- ax.add_artist(ring)
1802
- print(ring)
1803
-
1804
- return tags
1805
-
1806
-
1807
- electronFF = {
1808
- # form factor coefficients
1809
- # Z= 6, chisq= 0.143335
1810
- # a1 b1 a2 b2
1811
- # a3 b3 c1 d1
1812
- # c2 d2 c3 d3
1813
-
1814
- # name of the file: feKirkland.txt
1815
- # converted with program sortFF.py
1816
- # form factor parametrized in 1/Angstrom
1817
- # bond_length as a list of atom Sizes, bond radii, angle radii, H-bond radii
1818
-
1819
- 'H': {'Z': 1, 'chisq': 0.170190,
1820
- 'bond_length': [0.98, 0.78, 1.20, 0],
1821
- 'fa': [4.20298324e-003, 6.27762505e-002, 3.00907347e-002],
1822
- 'fb': [2.25350888e-001, 2.25366950e-001, 2.25331756e-001],
1823
- 'fc': [6.77756695e-002, 3.56609237e-003, 2.76135815e-002],
1824
- 'fd': [4.38854001e+000, 4.03884823e-001, 1.44490166e+000]},
1825
- 'He': {'Z': 2, 'chisq': 0.396634,
1826
- 'bond_length': [1.45, 1.25, 1.40, 0],
1827
- 'fa': [1.87543704e-005, 4.10595800e-004, 1.96300059e-001],
1828
- 'fb': [2.12427997e-001, 3.32212279e-001, 5.17325152e-001],
1829
- 'fc': [8.36015738e-003, 2.95102022e-002, 4.65928982e-007],
1830
- 'fd': [3.66668239e-001, 1.37171827e+000, 3.75768025e+004]},
1831
- 'Li': {'Z': 3, 'chisq': 0.286232,
1832
- 'bond_length': [1.76, 1.56, 1.82, 0],
1833
- 'fa': [7.45843816e-002, 7.15382250e-002, 1.45315229e-001],
1834
- 'fb': [8.81151424e-001, 4.59142904e-002, 8.81301714e-001],
1835
- 'fc': [1.12125769e+000, 2.51736525e-003, 3.58434971e-001],
1836
- 'fd': [1.88483665e+001, 1.59189995e-001, 6.12371000e+000]},
1837
- 'Be': {'Z': 4, 'chisq': 0.195442,
1838
- 'bond_length': [1.33, 1.13, 1.70, 0],
1839
- 'fa': [6.11642897e-002, 1.25755034e-001, 2.00831548e-001],
1840
- 'fb': [9.90182132e-002, 9.90272412e-002, 1.87392509e+000],
1841
- 'fc': [7.87242876e-001, 1.58847850e-003, 2.73962031e-001],
1842
- 'fd': [9.32794929e+000, 8.91900236e-002, 3.20687658e+000]},
1843
- 'B': {'Z': 5, 'chisq': 0.146989,
1844
- 'bond_length': [1.18, 0.98, 2.08, 0],
1845
- 'fa': [1.25716066e-001, 1.73314452e-001, 1.84774811e-001],
1846
- 'fb': [1.48258830e-001, 1.48257216e-001, 3.34227311e+000],
1847
- 'fc': [1.95250221e-001, 5.29642075e-001, 1.08230500e-003],
1848
- 'fd': [1.97339463e+000, 5.70035553e+000, 5.64857237e-002]},
1849
- 'C': {'Z': 6, 'chisq': 0.102440,
1850
- 'bond_length': [1.12, 0.92, 1.95, 0],
1851
- 'fa': [2.12080767e-001, 1.99811865e-001, 1.68254385e-001],
1852
- 'fb': [2.08605417e-001, 2.08610186e-001, 5.57870773e+000],
1853
- 'fc': [1.42048360e-001, 3.63830672e-001, 8.35012044e-004],
1854
- 'fd': [1.33311887e+000, 3.80800263e+000, 4.03982620e-002]},
1855
- 'N': {'Z': 7, 'chisq': 0.060249,
1856
- 'bond_length': [1.08, 0.88, 1.85, 1.30],
1857
- 'fa': [5.33015554e-001, 5.29008883e-002, 9.24159648e-002],
1858
- 'fb': [2.90952515e-001, 1.03547896e+001, 1.03540028e+001],
1859
- 'fc': [2.61799101e-001, 8.80262108e-004, 1.10166555e-001],
1860
- 'fd': [2.76252723e+000, 3.47681236e-002, 9.93421736e-001]},
1861
- 'O': {'Z': 8, 'chisq': 0.039944,
1862
- 'bond_length': [1.09, 0.89, 1.70, 1.40],
1863
- 'fa': [3.39969204e-001, 3.07570172e-001, 1.30369072e-001],
1864
- 'fb': [3.81570280e-001, 3.81571436e-001, 1.91919745e+001],
1865
- 'fc': [8.83326058e-002, 1.96586700e-001, 9.96220028e-004],
1866
- 'fd': [7.60635525e-001, 2.07401094e+000, 3.03266869e-002]},
1867
- 'F': {'Z': 9, 'chisq': 0.027866,
1868
- 'bond_length': [1.30, 1.10, 1.73, 0],
1869
- 'fa': [2.30560593e-001, 5.26889648e-001, 1.24346755e-001],
1870
- 'fb': [4.80754213e-001, 4.80763895e-001, 3.95306720e+001],
1871
- 'fc': [1.24616894e-003, 7.20452555e-002, 1.53075777e-001],
1872
- 'fd': [2.62181803e-002, 5.92495593e-001, 1.59127671e+000]},
1873
- 'Ne': {'Z': 10, 'chisq': 0.021836,
1874
- 'bond_length': [1.50, 1.30, 1.54, 0],
1875
- 'fa': [4.08371771e-001, 4.54418858e-001, 1.44564923e-001],
1876
- 'fb': [5.88228627e-001, 5.88288655e-001, 1.21246013e+002],
1877
- 'fc': [5.91531395e-002, 1.24003718e-001, 1.64986037e-003],
1878
- 'fd': [4.63963540e-001, 1.23413025e+000, 2.05869217e-002]},
1879
- 'Na': {'Z': 11, 'chisq': 0.064136,
1880
- 'bond_length': [2.10, 1.91, 2.27, 0],
1881
- 'fa': [1.36471662e-001, 7.70677865e-001, 1.56862014e-001],
1882
- 'fb': [4.99965301e-002, 8.81899664e-001, 1.61768579e+001],
1883
- 'fc': [9.96821513e-001, 3.80304670e-002, 1.27685089e-001],
1884
- 'fd': [2.00132610e+001, 2.60516254e-001, 6.99559329e-001]},
1885
- 'Mg': {'Z': 12, 'chisq': 0.051303,
1886
- 'bond_length': [1.80, 1.60, 1.73, 0],
1887
- 'fa': [3.04384121e-001, 7.56270563e-001, 1.01164809e-001],
1888
- 'fb': [8.42014377e-002, 1.64065598e+000, 2.97142975e+001],
1889
- 'fc': [3.45203403e-002, 9.71751327e-001, 1.20593012e-001],
1890
- 'fd': [2.16596094e-001, 1.21236852e+001, 5.60865838e-001]},
1891
- 'Al': {'Z': 13, 'chisq': 0.049529,
1892
- 'bond_length': [1.60, 1.43, 2.05, 0],
1893
- 'fa': [7.77419424e-001, 5.78312036e-002, 4.26386499e-001],
1894
- 'fb': [2.71058227e+000, 7.17532098e+001, 9.13331555e-002],
1895
- 'fc': [1.13407220e-001, 7.90114035e-001, 3.23293496e-002],
1896
- 'fd': [4.48867451e-001, 8.66366718e+000, 1.78503463e-001]},
1897
- 'Si': {'Z': 14, 'chisq': 0.071667,
1898
- 'bond_length': [1.52, 1.32, 2.10, 0],
1899
- 'fa': [1.06543892e+000, 1.20143691e-001, 1.80915263e-001],
1900
- 'fb': [1.04118455e+000, 6.87113368e+001, 8.87533926e-002],
1901
- 'fc': [1.12065620e+000, 3.05452816e-002, 1.59963502e+000],
1902
- 'fd': [3.70062619e+000, 2.14097897e-001, 9.99096638e+000]},
1903
- 'P': {'Z': 15, 'chisq': 0.047673,
1904
- 'bond_length': [1.48, 1.28, 2.08, 0],
1905
- 'fa': [1.05284447e+000, 2.99440284e-001, 1.17460748e-001],
1906
- 'fb': [1.31962590e+000, 1.28460520e-001, 1.02190163e+002],
1907
- 'fc': [9.60643452e-001, 2.63555748e-002, 1.38059330e+000],
1908
- 'fd': [2.87477555e+000, 1.82076844e-001, 7.49165526e+000]},
1909
- 'S': {'Z': 16, 'chisq': 0.033482,
1910
- 'bond_length': [1.47, 1.27, 2.00, 0],
1911
- 'fa': [1.01646916e+000, 4.41766748e-001, 1.21503863e-001],
1912
- 'fb': [1.69181965e+000, 1.74180288e-001, 1.67011091e+002],
1913
- 'fc': [8.27966670e-001, 2.33022533e-002, 1.18302846e+000],
1914
- 'fd': [2.30342810e+000, 1.56954150e-001, 5.85782891e+000]},
1915
- 'Cl': {'Z': 17, 'chisq': 0.206186,
1916
- 'bond_length': [1.70, 1.50, 1.97, 0],
1917
- 'fa': [9.44221116e-001, 4.37322049e-001, 2.54547926e-001],
1918
- 'fb': [2.40052374e-001, 9.30510439e+000, 9.30486346e+000],
1919
- 'fc': [5.47763323e-002, 8.00087488e-001, 1.07488641e-002],
1920
- 'fd': [1.68655688e-001, 2.97849774e+000, 6.84240646e-002]},
1921
- 'Ar': {'Z': 18, 'chisq': 0.263904,
1922
- 'bond_length': [2.00, 1.80, 1.88, 0],
1923
- 'fa': [1.06983288e+000, 4.24631786e-001, 2.43897949e-001],
1924
- 'fb': [2.87791022e-001, 1.24156957e+001, 1.24158868e+001],
1925
- 'fc': [4.79446296e-002, 7.64958952e-001, 8.23128431e-003],
1926
- 'fd': [1.36979796e-001, 2.43940729e+000, 5.27258749e-002]},
1927
- 'K': {'Z': 19, 'chisq': 0.161900,
1928
- 'bond_length': [2.58, 2.38, 2.75, 0],
1929
- 'fa': [6.92717865e-001, 9.65161085e-001, 1.48466588e-001],
1930
- 'fb': [7.10849990e+000, 3.57532901e-001, 3.93763275e-002],
1931
- 'fc': [2.64645027e-002, 1.80883768e+000, 5.43900018e-001],
1932
- 'fd': [1.03591321e-001, 3.22845199e+001, 1.67791374e+000]},
1933
- 'Ca': {'Z': 20, 'chisq': 0.085209,
1934
- 'bond_length': [2.17, 1.97, 1.97, 0],
1935
- 'fa': [3.66902871e-001, 8.66378999e-001, 6.67203300e-001],
1936
- 'fb': [6.14274129e-002, 5.70881727e-001, 7.82965639e+000],
1937
- 'fc': [4.87743636e-001, 1.82406314e+000, 2.20248453e-002],
1938
- 'fd': [1.32531318e+000, 2.10056032e+001, 9.11853450e-002]},
1939
- 'Sc': {'Z': 21, 'chisq': 0.052352,
1940
- 'bond_length': [1.84, 1.64, 1.70, 0],
1941
- 'fa': [3.78871777e-001, 9.00022505e-001, 7.15288914e-001],
1942
- 'fb': [6.98910162e-002, 5.21061541e-001, 7.87707920e+000],
1943
- 'fc': [1.88640973e-002, 4.07945949e-001, 1.61786540e+000],
1944
- 'fd': [8.17512708e-002, 1.11141388e+000, 1.80840759e+001]},
1945
- 'Ti': {'Z': 22, 'chisq': 0.035298,
1946
- 'bond_length': [1.66, 1.46, 1.70, 0],
1947
- 'fa': [3.62383267e-001, 9.84232966e-001, 7.41715642e-001],
1948
- 'fb': [7.54707114e-002, 4.97757309e-001, 8.17659391e+000],
1949
- 'fc': [3.62555269e-001, 1.49159390e+000, 1.61659509e-002],
1950
- 'fd': [9.55524906e-001, 1.62221677e+001, 7.33140839e-002]},
1951
- 'V': {'Z': 23, 'chisq': 0.030745,
1952
- 'bond_length': [1.55, 1.35, 1.70, 0],
1953
- 'fa': [3.52961378e-001, 7.46791014e-001, 1.08364068e+000],
1954
- 'fb': [8.19204103e-002, 8.81189511e+000, 5.10646075e-001],
1955
- 'fc': [1.39013610e+000, 3.31273356e-001, 1.40422612e-002],
1956
- 'fd': [1.48901841e+001, 8.38543079e-001, 6.57432678e-002]},
1957
- 'Cr': {'Z': 24, 'chisq': 0.015287,
1958
- 'bond_length': [1.56, 1.36, 1.70, 0],
1959
- 'fa': [1.34348379e+000, 5.07040328e-001, 4.26358955e-001],
1960
- 'fb': [1.25814353e+000, 1.15042811e+001, 8.53660389e-002],
1961
- 'fc': [1.17241826e-002, 5.11966516e-001, 3.38285828e-001],
1962
- 'fd': [6.00177061e-002, 1.53772451e+000, 6.62418319e-001]},
1963
- 'Mn': {'Z': 25, 'chisq': 0.031274,
1964
- 'bond_length': [1.54, 1.30, 1.70, 0],
1965
- 'fa': [3.26697613e-001, 7.17297000e-001, 1.33212464e+000],
1966
- 'fb': [8.88813083e-002, 1.11300198e+001, 5.82141104e-001],
1967
- 'fc': [2.80801702e-001, 1.15499241e+000, 1.11984488e-002],
1968
- 'fd': [6.71583145e-001, 1.26825395e+001, 5.32334467e-002]},
1969
- 'Fe': {'Z': 26, 'chisq': 0.031315,
1970
- 'bond_length': [1.47, 1.27, 1.70, 0],
1971
- 'fa': [3.13454847e-001, 6.89290016e-001, 1.47141531e+000],
1972
- 'fb': [8.99325756e-002, 1.30366038e+001, 6.33345291e-001],
1973
- 'fc': [1.03298688e+000, 2.58280285e-001, 1.03460690e-002],
1974
- 'fd': [1.16783425e+001, 6.09116446e-001, 4.81610627e-002]},
1975
- 'Co': {'Z': 27, 'chisq': 0.031643,
1976
- 'bond_length': [1.45, 1.25, 1.70, 0],
1977
- 'fa': [3.15878278e-001, 1.60139005e+000, 6.56394338e-001],
1978
- 'fb': [9.46683246e-002, 6.99436449e-001, 1.56954403e+001],
1979
- 'fc': [9.36746624e-001, 9.77562646e-003, 2.38378578e-001],
1980
- 'fd': [1.09392410e+001, 4.37446816e-002, 5.56286483e-001]},
1981
- 'Ni': {'Z': 28, 'chisq': 0.032245,
1982
- 'bond_length': [1.45, 1.25, 1.63, 0],
1983
- 'fa': [1.72254630e+000, 3.29543044e-001, 6.23007200e-001],
1984
- 'fb': [7.76606908e-001, 1.02262360e-001, 1.94156207e+001],
1985
- 'fc': [9.43496513e-003, 8.54063515e-001, 2.21073515e-001],
1986
- 'fd': [3.98684596e-002, 1.04078166e+001, 5.10869330e-001]},
1987
- 'Cu': {'Z': 29, 'chisq': 0.010467,
1988
- 'bond_length': [1.48, 1.28, 1.40, 0],
1989
- 'fa': [3.58774531e-001, 1.76181348e+000, 6.36905053e-001],
1990
- 'fb': [1.06153463e-001, 1.01640995e+000, 1.53659093e+001],
1991
- 'fc': [7.44930667e-003, 1.89002347e-001, 2.29619589e-001],
1992
- 'fd': [3.85345989e-002, 3.98427790e-001, 9.01419843e-001]},
1993
- 'Zn': {'Z': 30, 'chisq': 0.026698,
1994
- 'bond_length': [1.59, 1.39, 1.39, 0],
1995
- 'fa': [5.70893973e-001, 1.98908856e+000, 3.06060585e-001],
1996
- 'fb': [1.26534614e-001, 2.17781965e+000, 3.78619003e+001],
1997
- 'fc': [2.35600223e-001, 3.97061102e-001, 6.85657228e-003],
1998
- 'fd': [3.67019041e-001, 8.66419596e-001, 3.35778823e-002]},
1999
- 'Ga': {'Z': 31, 'chisq': 0.008110,
2000
- 'bond_length': [1.61, 1.41, 1.87, 0],
2001
- 'fa': [6.25528464e-001, 2.05302901e+000, 2.89608120e-001],
2002
- 'fb': [1.10005650e-001, 2.41095786e+000, 4.78685736e+001],
2003
- 'fc': [2.07910594e-001, 3.45079617e-001, 6.55634298e-003],
2004
- 'fd': [3.27807224e-001, 7.43139061e-001, 3.09411369e-002]},
2005
- 'Ge': {'Z': 32, 'chisq': 0.032198,
2006
- 'bond_length': [1.57, 1.37, 1.70, 0],
2007
- 'fa': [5.90952690e-001, 5.39980660e-001, 2.00626188e+000],
2008
- 'fb': [1.18375976e-001, 7.18937433e+001, 1.39304889e+000],
2009
- 'fc': [7.49705041e-001, 1.83581347e-001, 9.52190743e-003],
2010
- 'fd': [6.89943350e+000, 3.64667232e-001, 2.69888650e-002]},
2011
- 'As': {'Z': 33, 'chisq': 0.034014,
2012
- 'bond_length': [1.59, 1.39, 1.85, 0],
2013
- 'fa': [7.77875218e-001, 5.93848150e-001, 1.95918751e+000],
2014
- 'fb': [1.50733157e-001, 1.42882209e+002, 1.74750339e+000],
2015
- 'fc': [1.79880226e-001, 8.63267222e-001, 9.59053427e-003],
2016
- 'fd': [3.31800852e-001, 5.85490274e+000, 2.33777569e-002]},
2017
- 'Se': {'Z': 34, 'chisq': 0.035703,
2018
- 'bond_length': [1.60, 1.40, 1.90, 0],
2019
- 'fa': [9.58390681e-001, 6.03851342e-001, 1.90828931e+000],
2020
- 'fb': [1.83775557e-001, 1.96819224e+002, 2.15082053e+000],
2021
- 'fc': [1.73885956e-001, 9.35265145e-001, 8.62254658e-003],
2022
- 'fd': [3.00006024e-001, 4.92471215e+000, 2.12308108e-002]},
2023
- 'Br': {'Z': 35, 'chisq': 0.039250,
2024
- 'bond_length': [1.80, 1.60, 2.10, 0],
2025
- 'fa': [1.14136170e+000, 5.18118737e-001, 1.85731975e+000],
2026
- 'fb': [2.18708710e-001, 1.93916682e+002, 2.65755396e+000],
2027
- 'fc': [1.68217399e-001, 9.75705606e-001, 7.24187871e-003],
2028
- 'fd': [2.71719918e-001, 4.19482500e+000, 1.99325718e-002]},
2029
- 'Kr': {'Z': 36, 'chisq': 0.045421,
2030
- 'bond_length': [2.10, 1.90, 2.02, 0],
2031
- 'fa': [3.24386970e-001, 1.31732163e+000, 1.79912614e+000],
2032
- 'fb': [6.31317973e+001, 2.54706036e-001, 3.23668394e+000],
2033
- 'fc': [4.29961425e-003, 1.00429433e+000, 1.62188197e-001],
2034
- 'fd': [1.98965610e-002, 3.61094513e+000, 2.45583672e-001]},
2035
- 'Rb': {'Z': 37, 'chisq': 0.130044,
2036
- 'bond_length': [2.75, 2.55, 1.70, 0],
2037
- 'fa': [2.90445351e-001, 2.44201329e+000, 7.69435449e-001],
2038
- 'fb': [3.68420227e-002, 1.16013332e+000, 1.69591472e+001],
2039
- 'fc': [1.58687000e+000, 2.81617593e-003, 1.28663830e-001],
2040
- 'fd': [2.53082574e+000, 1.88577417e-002, 2.10753969e-001]},
2041
- 'Sr': {'Z': 38, 'chisq': 0.188055,
2042
- 'bond_length': [2.35, 2.15, 1.70, 0],
2043
- 'fa': [1.37373086e-002, 1.97548672e+000, 1.59261029e+000],
2044
- 'fb': [1.87469061e-002, 6.36079230e+000, 2.21992482e-001],
2045
- 'fc': [1.73263882e-001, 4.66280378e+000, 1.61265063e-003],
2046
- 'fd': [2.01624958e-001, 2.53027803e+001, 1.53610568e-002]},
2047
- 'Y': {'Z': 39, 'chisq': 0.174927,
2048
- 'bond_length': [2.00, 1.80, 1.70, 0],
2049
- 'fa': [6.75302747e-001, 4.70286720e-001, 2.63497677e+000],
2050
- 'fb': [6.54331847e-002, 1.06108709e+002, 2.06643540e+000],
2051
- 'fc': [1.09621746e-001, 9.60348773e-001, 5.28921555e-003],
2052
- 'fd': [1.93131925e-001, 1.63310938e+000, 1.66083821e-002]},
2053
- 'Zr': {'Z': 40, 'chisq': 0.072078,
2054
- 'bond_length': [1.80, 1.60, 1.70, 0],
2055
- 'fa': [2.64365505e+000, 5.54225147e-001, 7.61376625e-001],
2056
- 'fb': [2.20202699e+000, 1.78260107e+002, 7.67218745e-002],
2057
- 'fc': [6.02946891e-003, 9.91630530e-002, 9.56782020e-001],
2058
- 'fd': [1.55143296e-002, 1.76175995e-001, 1.54330682e+000]},
2059
- 'Nb': {'Z': 41, 'chisq': 0.011800,
2060
- 'bond_length': [1.67, 1.47, 1.70, 0],
2061
- 'fa': [6.59532875e-001, 1.84545854e+000, 1.25584405e+000],
2062
- 'fb': [8.66145490e-002, 5.94774398e+000, 6.40851475e-001],
2063
- 'fc': [1.22253422e-001, 7.06638328e-001, 2.62381591e-003],
2064
- 'fd': [1.66646050e-001, 1.62853268e+000, 8.26257859e-003]},
2065
- 'Mo': {'Z': 42, 'chisq': 0.008976,
2066
- 'bond_length': [1.60, 1.40, 1.70, 0],
2067
- 'fa': [6.10160120e-001, 1.26544000e+000, 1.97428762e+000],
2068
- 'fb': [9.11628054e-002, 5.06776025e-001, 5.89590381e+000],
2069
- 'fc': [6.48028962e-001, 2.60380817e-003, 1.13887493e-001],
2070
- 'fd': [1.46634108e+000, 7.84336311e-003, 1.55114340e-001]},
2071
- 'Tc': {'Z': 43, 'chisq': 0.023771,
2072
- 'bond_length': [1.56, 1.36, 1.70, 0],
2073
- 'fa': [8.55189183e-001, 1.66219641e+000, 1.45575475e+000],
2074
- 'fb': [1.02962151e-001, 7.64907000e+000, 1.01639987e+000],
2075
- 'fc': [1.05445664e-001, 7.71657112e-001, 2.20992635e-003],
2076
- 'fd': [1.42303338e-001, 1.34659349e+000, 7.90358976e-003]},
2077
- 'Ru': {'Z': 44, 'chisq': 0.010613,
2078
- 'bond_length': [1.54, 1.34, 1.70, 0],
2079
- 'fa': [4.70847093e-001, 1.58180781e+000, 2.02419818e+000],
2080
- 'fb': [9.33029874e-002, 4.52831347e-001, 7.11489023e+000],
2081
- 'fc': [1.97036257e-003, 6.26912639e-001, 1.02641320e-001],
2082
- 'fd': [7.56181595e-003, 1.25399858e+000, 1.33786087e-001]},
2083
- 'Rh': {'Z': 45, 'chisq': 0.012895,
2084
- 'bond_length': [1.54, 1.34, 1.70, 0],
2085
- 'fa': [4.20051553e-001, 1.76266507e+000, 2.02735641e+000],
2086
- 'fb': [9.38882628e-002, 4.64441687e-001, 8.19346046e+000],
2087
- 'fc': [1.45487176e-003, 6.22809600e-001, 9.91529915e-002],
2088
- 'fd': [7.82704517e-003, 1.17194153e+000, 1.24532839e-001]},
2089
- 'Pd': {'Z': 46, 'chisq': 0.009172,
2090
- 'bond_length': [1.58, 1.38, 1.63, 0],
2091
- 'fa': [2.10475155e+000, 2.03884487e+000, 1.82067264e-001],
2092
- 'fb': [8.68606470e+000, 3.78924449e-001, 1.42921634e-001],
2093
- 'fc': [9.52040948e-002, 5.91445248e-001, 1.13328676e-003],
2094
- 'fd': [1.17125900e-001, 1.07843808e+000, 7.80252092e-003]},
2095
- 'Ag': {'Z': 47, 'chisq': 0.006648,
2096
- 'bond_length': [1.64, 1.44, 1.72, 0],
2097
- 'fa': [2.07981390e+000, 4.43170726e-001, 1.96515215e+000],
2098
- 'fb': [9.92540297e+000, 1.04920104e-001, 6.40103839e-001],
2099
- 'fc': [5.96130591e-001, 4.78016333e-001, 9.46458470e-002],
2100
- 'fd': [8.89594790e-001, 1.98509407e+000, 1.12744464e-001]},
2101
- 'Cd': {'Z': 48, 'chisq': 0.005588,
2102
- 'bond_length': [1.77, 1.57, 1.58, 0],
2103
- 'fa': [1.63657549e+000, 2.17927989e+000, 7.71300690e-001],
2104
- 'fb': [1.24540381e+001, 1.45134660e+000, 1.26695757e-001],
2105
- 'fc': [6.64193880e-001, 7.64563285e-001, 8.61126689e-002],
2106
- 'fd': [7.77659202e-001, 1.66075210e+000, 1.05728357e-001]},
2107
- 'In': {'Z': 49, 'chisq': 0.002569,
2108
- 'bond_length': [1.86, 1.66, 1.93, 0],
2109
- 'fa': [2.24820632e+000, 1.64706864e+000, 7.88679265e-001],
2110
- 'fb': [1.51913507e+000, 1.30113424e+001, 1.06128184e-001],
2111
- 'fc': [8.12579069e-002, 6.68280346e-001, 6.38467475e-001],
2112
- 'fd': [9.94045620e-002, 1.49742063e+000, 7.18422635e-001]},
2113
- 'Sn': {'Z': 50, 'chisq': 0.005051,
2114
- 'bond_length': [1.82, 1.62, 2.17, 0],
2115
- 'fa': [2.16644620e+000, 6.88691021e-001, 1.92431751e+000],
2116
- 'fb': [1.13174909e+001, 1.10131285e-001, 6.74464853e-001],
2117
- 'fc': [5.65359888e-001, 9.18683861e-001, 7.80542213e-002],
2118
- 'fd': [7.33564610e-001, 1.02310312e+001, 9.31104308e-002]},
2119
- 'Sb': {'Z': 51, 'chisq': 0.004383,
2120
- 'bond_length': [1.79, 1.59, 2.20, 0],
2121
- 'fa': [1.73662114e+000, 9.99871380e-001, 2.13972409e+000],
2122
- 'fb': [8.84334719e-001, 1.38462121e-001, 1.19666432e+001],
2123
- 'fc': [5.60566526e-001, 9.93772747e-001, 7.37374982e-002],
2124
- 'fd': [6.72672880e-001, 8.72330411e+000, 8.78577715e-002]},
2125
- 'Te': {'Z': 52, 'chisq': 0.004105,
2126
- 'bond_length': [1.80, 1.60, 2.06, 0],
2127
- 'fa': [2.09383882e+000, 1.56940519e+000, 1.30941993e+000],
2128
- 'fb': [1.26856869e+001, 1.21236537e+000, 1.66633292e-001],
2129
- 'fc': [6.98067804e-002, 1.04969537e+000, 5.55594354e-001],
2130
- 'fd': [8.30817576e-002, 7.43147857e+000, 6.17487676e-001]},
2131
- 'I': {'Z': 53, 'chisq': 0.004068,
2132
- 'bond_length': [1.90, 1.70, 2.15, 0],
2133
- 'fa': [1.60186925e+000, 1.98510264e+000, 1.48226200e+000],
2134
- 'fb': [1.95031538e-001, 1.36976183e+001, 1.80304795e+000],
2135
- 'fc': [5.53807199e-001, 1.11728722e+000, 6.60720847e-002],
2136
- 'fd': [5.67912340e-001, 6.40879878e+000, 7.86615429e-002]},
2137
- 'Xe': {'Z': 54, 'chisq': 0.004381,
2138
- 'bond_length': [2.30, 2.10, 2.16, 0],
2139
- 'fa': [1.60015487e+000, 1.71644581e+000, 1.84968351e+000],
2140
- 'fb': [2.92913354e+000, 1.55882990e+001, 2.22525983e-001],
2141
- 'fc': [6.23813648e-002, 1.21387555e+000, 5.54051946e-001],
2142
- 'fd': [7.45581223e-002, 5.56013271e+000, 5.21994521e-001]},
2143
- 'Cs': {'Z': 55, 'chisq': 0.042676,
2144
- 'bond_length': [2.93, 2.73, 1.70, 0],
2145
- 'fa': [2.95236854e+000, 4.28105721e-001, 1.89599233e+000],
2146
- 'fb': [6.01461952e+000, 4.64151246e+001, 1.80109756e-001],
2147
- 'fc': [5.48012938e-002, 4.70838600e+000, 5.90356719e-001],
2148
- 'fd': [7.12799633e-002, 4.56702799e+001, 4.70236310e-001]},
2149
- 'Ba': {'Z': 56, 'chisq': 0.043267,
2150
- 'bond_length': [2.44, 2.24, 1.70, 0],
2151
- 'fa': [3.19434243e+000, 1.98289586e+000, 1.55121052e-001],
2152
- 'fb': [9.27352241e+000, 2.28741632e-001, 3.82000231e-002],
2153
- 'fc': [6.73222354e-002, 4.48474211e+000, 5.42674414e-001],
2154
- 'fd': [7.30961745e-002, 2.95703565e+001, 4.08647015e-001]},
2155
- 'La': {'Z': 57, 'chisq': 0.033249,
2156
- 'bond_length': [2.08, 1.88, 1.70, 0],
2157
- 'fa': [2.05036425e+000, 1.42114311e-001, 3.23538151e+000],
2158
- 'fb': [2.20348417e-001, 3.96438056e-002, 9.56979169e+000],
2159
- 'fc': [6.34683429e-002, 3.97960586e+000, 5.20116711e-001],
2160
- 'fd': [6.92443091e-002, 2.53178406e+001, 3.83614098e-001]},
2161
- 'Ce': {'Z': 58, 'chisq': 0.029355,
2162
- 'bond_length': [2.02, 1.82, 1.70, 0],
2163
- 'fa': [3.22990759e+000, 1.57618307e-001, 2.13477838e+000],
2164
- 'fb': [9.94660135e+000, 4.15378676e-002, 2.40480572e-001],
2165
- 'fc': [5.01907609e-001, 3.80889010e+000, 5.96625028e-002],
2166
- 'fd': [3.66252019e-001, 2.43275968e+001, 6.59653503e-002]},
2167
- 'Pr': {'Z': 59, 'chisq': 0.029725,
2168
- 'bond_length': [2.03, 1.83, 1.70, 0],
2169
- 'fa': [1.58189324e-001, 3.18141995e+000, 2.27622140e+000],
2170
- 'fb': [3.91309056e-002, 1.04139545e+001, 2.81671757e-001],
2171
- 'fc': [3.97705472e+000, 5.58448277e-002, 4.85207954e-001],
2172
- 'fd': [2.61872978e+001, 6.30921695e-002, 3.54234369e-001]},
2173
- 'Nd': {'Z': 60, 'chisq': 0.027597,
2174
- 'bond_length': [2.02, 1.82, 1.70, 0],
2175
- 'fa': [1.81379417e-001, 3.17616396e+000, 2.35221519e+000],
2176
- 'fb': [4.37324793e-002, 1.07842572e+001, 3.05571833e-001],
2177
- 'fc': [3.83125763e+000, 5.25889976e-002, 4.70090742e-001],
2178
- 'fd': [2.54745408e+001, 6.02676073e-002, 3.39017003e-001]},
2179
- 'Pm': {'Z': 61, 'chisq': 0.025208,
2180
- 'bond_length': [2.01, 1.81, 1.70, 0],
2181
- 'fa': [1.92986811e-001, 2.43756023e+000, 3.17248504e+000],
2182
- 'fb': [4.37785970e-002, 3.29336996e-001, 1.11259996e+001],
2183
- 'fc': [3.58105414e+000, 4.56529394e-001, 4.94812177e-002],
2184
- 'fd': [2.46709586e+001, 3.24990282e-001, 5.76553100e-002]},
2185
- 'Sm': {'Z': 62, 'chisq': 0.023540,
2186
- 'bond_length': [2.00, 1.80, 1.70, 0],
2187
- 'fa': [2.12002595e-001, 3.16891754e+000, 2.51503494e+000],
2188
- 'fb': [4.57703608e-002, 1.14536599e+001, 3.55561054e-001],
2189
- 'fc': [4.44080845e-001, 3.36742101e+000, 4.65652543e-002],
2190
- 'fd': [3.11953363e-001, 2.40291435e+001, 5.52266819e-002]},
2191
- 'Eu': {'Z': 63, 'chisq': 0.022204,
2192
- 'bond_length': [2.24, 2.04, 1.70, 0],
2193
- 'fa': [2.59355002e+000, 3.16557522e+000, 2.29402652e-001],
2194
- 'fb': [3.82452612e-001, 1.17675155e+001, 4.76642249e-002],
2195
- 'fc': [4.32257780e-001, 3.17261920e+000, 4.37958317e-002],
2196
- 'fd': [2.99719833e-001, 2.34462738e+001, 5.29440680e-002]},
2197
- 'Gd': {'Z': 64, 'chisq': 0.017492,
2198
- 'bond_length': [2.00, 1.80, 1.70, 0],
2199
- 'fa': [3.19144939e+000, 2.55766431e+000, 3.32681934e-001],
2200
- 'fb': [1.20224655e+001, 4.08338876e-001, 5.85819814e-002],
2201
- 'fc': [4.14243130e-002, 2.61036728e+000, 4.20526863e-001],
2202
- 'fd': [5.06771477e-002, 1.99344244e+001, 2.85686240e-001]},
2203
- 'Tb': {'Z': 65, 'chisq': 0.020036,
2204
- 'bond_length': [1.98, 1.78, 1.70, 0],
2205
- 'fa': [2.59407462e-001, 3.16177855e+000, 2.75095751e+000],
2206
- 'fb': [5.04689354e-002, 1.23140183e+001, 4.38337626e-001],
2207
- 'fc': [2.79247686e+000, 3.85931001e-002, 4.10881708e-001],
2208
- 'fd': [2.23797309e+001, 4.87920992e-002, 2.77622892e-001]},
2209
- 'Dy': {'Z': 66, 'chisq': 0.019351,
2210
- 'bond_length': [1.97, 1.77, 1.70, 0],
2211
- 'fa': [3.16055396e+000, 2.82751709e+000, 2.75140255e-001],
2212
- 'fb': [1.25470414e+001, 4.67899094e-001, 5.23226982e-002],
2213
- 'fc': [4.00967160e-001, 2.63110834e+000, 3.61333817e-002],
2214
- 'fd': [2.67614884e-001, 2.19498166e+001, 4.68871497e-002]},
2215
- 'Ho': {'Z': 67, 'chisq': 0.018720,
2216
- 'bond_length': [1.98, 1.78, 1.70, 0],
2217
- 'fa': [2.88642467e-001, 2.90567296e+000, 3.15960159e+000],
2218
- 'fb': [5.40507687e-002, 4.97581077e-001, 1.27599505e+001],
2219
- 'fc': [3.91280259e-001, 2.48596038e+000, 3.37664478e-002],
2220
- 'fd': [2.58151831e-001, 2.15400972e+001, 4.50664323e-002]},
2221
- 'Er': {'Z': 68, 'chisq': 0.018677,
2222
- 'bond_length': [1.96, 1.76, 1.70, 0],
2223
- 'fa': [3.15573213e+000, 3.11519560e-001, 2.97722406e+000],
2224
- 'fb': [1.29729009e+001, 5.81399387e-002, 5.31213394e-001],
2225
- 'fc': [3.81563854e-001, 2.40247532e+000, 3.15224214e-002],
2226
- 'fd': [2.49195776e-001, 2.13627616e+001, 4.33253257e-002]},
2227
- 'Tm': {'Z': 69, 'chisq': 0.018176,
2228
- 'bond_length': [1.95, 1.75, 1.70, 0],
2229
- 'fa': [3.15591970e+000, 3.22544710e-001, 3.05569053e+000],
2230
- 'fb': [1.31232407e+001, 5.97223323e-002, 5.61876773e-001],
2231
- 'fc': [2.92845100e-002, 3.72487205e-001, 2.27833695e+000],
2232
- 'fd': [4.16534255e-002, 2.40821967e-001, 2.10034185e+001]},
2233
- 'Yb': {'Z': 70, 'chisq': 0.018460,
2234
- 'bond_length': [2.10, 1.90, 1.70, 0],
2235
- 'fa': [3.10794704e+000, 3.14091221e+000, 3.75660454e-001],
2236
- 'fb': [6.06347847e-001, 1.33705269e+001, 7.29814740e-002],
2237
- 'fc': [3.61901097e-001, 2.45409082e+000, 2.72383990e-002],
2238
- 'fd': [2.32652051e-001, 2.12695209e+001, 3.99969597e-002]},
2239
- 'Lu': {'Z': 71, 'chisq': 0.015021,
2240
- 'bond_length': [1.93, 1.73, 1.70, 0],
2241
- 'fa': [3.11446863e+000, 5.39634353e-001, 3.06460915e+000],
2242
- 'fb': [1.38968881e+001, 8.91708508e-002, 6.79919563e-001],
2243
- 'fc': [2.58563745e-002, 2.13983556e+000, 3.47788231e-001],
2244
- 'fd': [3.82808522e-002, 1.80078788e+001, 2.22706591e-001]},
2245
- 'Hf': {'Z': 72, 'chisq': 0.012070,
2246
- 'bond_length': [1.78, 1.58, 1.70, 0],
2247
- 'fa': [3.01166899e+000, 3.16284788e+000, 6.33421771e-001],
2248
- 'fb': [7.10401889e-001, 1.38262192e+001, 9.48486572e-002],
2249
- 'fc': [3.41417198e-001, 1.53566013e+000, 2.40723773e-002],
2250
- 'fd': [2.14129678e-001, 1.55298698e+001, 3.67833690e-002]},
2251
- 'Ta': {'Z': 73, 'chisq': 0.010775,
2252
- 'bond_length': [1.67, 1.47, 1.70, 0],
2253
- 'fa': [3.20236821e+000, 8.30098413e-001, 2.86552297e+000],
2254
- 'fb': [1.38446369e+001, 1.18381581e-001, 7.66369118e-001],
2255
- 'fc': [2.24813887e-002, 1.40165263e+000, 3.33740596e-001],
2256
- 'fd': [3.52934622e-002, 1.46148877e+001, 2.05704486e-001]},
2257
- 'W': {'Z': 74, 'chisq': 0.009479,
2258
- 'bond_length': [1.61, 1.41, 1.70, 0],
2259
- 'fa': [9.24906855e-001, 2.75554557e+000, 3.30440060e+000],
2260
- 'fb': [1.28663377e-001, 7.65826479e-001, 1.34471170e+001],
2261
- 'fc': [3.29973862e-001, 1.09916444e+000, 2.06498883e-002],
2262
- 'fd': [1.98218895e-001, 1.35087534e+001, 3.38918459e-002]},
2263
- 'Re': {'Z': 75, 'chisq': 0.004620,
2264
- 'bond_length': [1.58, 1.38, 1.70, 0],
2265
- 'fa': [1.96952105e+000, 1.21726619e+000, 4.10391685e+000],
2266
- 'fb': [4.98830620e+001, 1.33243809e-001, 1.84396916e+000],
2267
- 'fc': [2.90791978e-002, 2.30696669e-001, 6.08840299e-001],
2268
- 'fd': [2.84192813e-002, 1.90968784e-001, 1.37090356e+000]},
2269
- 'Os': {'Z': 76, 'chisq': 0.003085,
2270
- 'bond_length': [1.55, 1.35, 1.70, 0],
2271
- 'fa': [2.06385867e+000, 1.29603406e+000, 3.96920673e+000],
2272
- 'fb': [4.05671697e+001, 1.46559047e-001, 1.82561596e+000],
2273
- 'fc': [2.69835487e-002, 2.31083999e-001, 6.30466774e-001],
2274
- 'fd': [2.84172045e-002, 1.79765184e-001, 1.38911543e+000]},
2275
- 'Ir': {'Z': 77, 'chisq': 0.003924,
2276
- 'bond_length': [1.56, 1.36, 1.70, 0],
2277
- 'fa': [2.21522726e+000, 1.37573155e+000, 3.78244405e+000],
2278
- 'fb': [3.24464090e+001, 1.60920048e-001, 1.78756553e+000],
2279
- 'fc': [2.44643240e-002, 2.36932016e-001, 6.48471412e-001],
2280
- 'fd': [2.82909938e-002, 1.70692368e-001, 1.37928390e+000]},
2281
- 'Pt': {'Z': 78, 'chisq': 0.003817,
2282
- 'bond_length': [1.59, 1.39, 1.72, 0],
2283
- 'fa': [9.84697940e-001, 2.73987079e+000, 3.61696715e+000],
2284
- 'fb': [1.60910839e-001, 7.18971667e-001, 1.29281016e+001],
2285
- 'fc': [3.02885602e-001, 2.78370726e-001, 1.52124129e-002],
2286
- 'fd': [1.70134854e-001, 1.49862703e+000, 2.83510822e-002]},
2287
- 'Au': {'Z': 79, 'chisq': 0.003143,
2288
- 'bond_length': [1.64, 1.44, 1.66, 0],
2289
- 'fa': [9.61263398e-001, 3.69581030e+000, 2.77567491e+000],
2290
- 'fb': [1.70932277e-001, 1.29335319e+001, 6.89997070e-001],
2291
- 'fc': [2.95414176e-001, 3.11475743e-001, 1.43237267e-002],
2292
- 'fd': [1.63525510e-001, 1.39200901e+000, 2.71265337e-002]},
2293
- 'Hg': {'Z': 80, 'chisq': 0.002717,
2294
- 'bond_length': [1.77, 1.57, 1.55, 0],
2295
- 'fa': [1.29200491e+000, 2.75161478e+000, 3.49387949e+000],
2296
- 'fb': [1.83432865e-001, 9.42368371e-001, 1.46235654e+001],
2297
- 'fc': [2.77304636e-001, 4.30232810e-001, 1.48294351e-002],
2298
- 'fd': [1.55110144e-001, 1.28871670e+000, 2.61903834e-002]},
2299
- 'Tl': {'Z': 81, 'chisq': 0.003492,
2300
- 'bond_length': [1.92, 1.72, 1.96, 0],
2301
- 'fa': [3.75964730e+000, 3.21195904e+000, 6.47767825e-001],
2302
- 'fb': [1.35041513e+001, 6.66330993e-001, 9.22518234e-002],
2303
- 'fc': [2.76123274e-001, 3.18838810e-001, 1.31668419e-002],
2304
- 'fd': [1.50312897e-001, 1.12565588e+000, 2.48879842e-002]},
2305
- 'Pb': {'Z': 82, 'chisq': 0.001158,
2306
- 'bond_length': [1.95, 1.75, 2.02, 0],
2307
- 'fa': [1.00795975e+000, 3.09796153e+000, 3.61296864e+000],
2308
- 'fb': [1.17268427e-001, 8.80453235e-001, 1.47325812e+001],
2309
- 'fc': [2.62401476e-001, 4.05621995e-001, 1.31812509e-002],
2310
- 'fd': [1.43491014e-001, 1.04103506e+000, 2.39575415e-002]},
2311
- 'Bi': {'Z': 83, 'chisq': 0.026436,
2312
- 'bond_length': [1.90, 1.70, 1.70, 0],
2313
- 'fa': [1.59826875e+000, 4.38233925e+000, 2.06074719e+000],
2314
- 'fb': [1.56897471e-001, 2.47094692e+000, 5.72438972e+001],
2315
- 'fc': [1.94426023e-001, 8.22704978e-001, 2.33226953e-002],
2316
- 'fd': [1.32979109e-001, 9.56532528e-001, 2.23038435e-002]},
2317
- 'Po': {'Z': 84, 'chisq': 0.008962,
2318
- 'bond_length': [1.96, 1.76, 1.70, 0],
2319
- 'fa': [1.71463223e+000, 2.14115960e+000, 4.37512413e+000],
2320
- 'fb': [9.79262841e+001, 2.10193717e-001, 3.66948812e+000],
2321
- 'fc': [2.16216680e-002, 1.97843837e-001, 6.52047920e-001],
2322
- 'fd': [1.98456144e-002, 1.33758807e-001, 7.80432104e-001]},
2323
- 'At': {'Z': 85, 'chisq': 0.033776,
2324
- 'bond_length': [2.00, 1.80, 1.70, 0],
2325
- 'fa': [1.48047794e+000, 2.09174630e+000, 4.75246033e+000],
2326
- 'fb': [1.25943919e+002, 1.83803008e-001, 4.19890596e+000],
2327
- 'fc': [1.85643958e-002, 2.05859375e-001, 7.13540948e-001],
2328
- 'fd': [1.81383503e-002, 1.33035404e-001, 7.03031938e-001]},
2329
- 'Rn': {'Z': 86, 'chisq': 0.050132,
2330
- 'bond_length': [2.40, 2.20, 1.70, 0],
2331
- 'fa': [6.30022295e-001, 3.80962881e+000, 3.89756067e+000],
2332
- 'fb': [1.40909762e-001, 3.08515540e+001, 6.51559763e-001],
2333
- 'fc': [2.40755100e-001, 2.62868577e+000, 3.14285931e-002],
2334
- 'fd': [1.08899672e-001, 6.42383261e+000, 2.42346699e-002]},
2335
- 'Fr': {'Z': 87, 'chisq': 0.056720,
2336
- 'bond_length': [3.00, 2.80, 1.70, 0],
2337
- 'fa': [5.23288135e+000, 2.48604205e+000, 3.23431354e-001],
2338
- 'fb': [8.60599536e+000, 3.04543982e-001, 3.87759096e-002],
2339
- 'fc': [2.55403596e-001, 5.53607228e-001, 5.75278889e-003],
2340
- 'fd': [1.28717724e-001, 5.36977452e-001, 1.29417790e-002]},
2341
- 'Ra': {'Z': 88, 'chisq': 0.081498,
2342
- 'bond_length': [2.46, 2.26, 1.70, 0],
2343
- 'fa': [1.44192685e+000, 3.55291725e+000, 3.91259586e+000],
2344
- 'fb': [1.18740873e-001, 1.01739750e+000, 6.31814783e+001],
2345
- 'fc': [2.16173519e-001, 3.94191605e+000, 4.60422605e-002],
2346
- 'fd': [9.55806441e-002, 3.50602732e+001, 2.20850385e-002]},
2347
- 'Ac': {'Z': 89, 'chisq': 0.077643,
2348
- 'bond_length': [2.09, 1.88, 1.70, 0],
2349
- 'fa': [1.45864127e+000, 4.18945405e+000, 3.65866182e+000],
2350
- 'fb': [1.07760494e-001, 8.89090649e+001, 1.05088931e+000],
2351
- 'fc': [2.08479229e-001, 3.16528117e+000, 5.23892556e-002],
2352
- 'fd': [9.09335557e-002, 3.13297788e+001, 2.08807697e-002]},
2353
- 'Th': {'Z': 90, 'chisq': 0.048096,
2354
- 'bond_length': [2.00, 1.80, 1.70, 0],
2355
- 'fa': [1.19014064e+000, 2.55380607e+000, 4.68110181e+000],
2356
- 'fb': [7.73468729e-002, 6.59693681e-001, 1.28013896e+001],
2357
- 'fc': [2.26121303e-001, 3.58250545e-001, 7.82263950e-003],
2358
- 'fd': [1.08632194e-001, 4.56765664e-001, 1.62623474e-002]},
2359
- 'Pa': {'Z': 91, 'chisq': 0.070186,
2360
- 'bond_length': [1.83, 1.63, 1.70, 0],
2361
- 'fa': [4.68537504e+000, 2.98413708e+000, 8.91988061e-001],
2362
- 'fb': [1.44503632e+001, 5.56438592e-001, 6.69512914e-002],
2363
- 'fc': [2.24825384e-001, 3.04444846e-001, 9.48162708e-003],
2364
- 'fd': [1.03235396e-001, 4.27255647e-001, 1.77730611e-002]},
2365
- 'U': {'Z': 92, 'chisq': 0.072478,
2366
- 'bond_length': [1.76, 1.56, 1.86, 0],
2367
- 'fa': [4.63343606e+000, 3.18157056e+000, 8.76455075e-001],
2368
- 'fb': [1.63377267e+001, 5.69517868e-001, 6.88860012e-002],
2369
- 'fc': [2.21685477e-001, 2.72917100e-001, 1.11737298e-002],
2370
- 'fd': [9.84254550e-002, 4.09470917e-001, 1.86215410e-002]},
2371
- 'Np': {'Z': 93, 'chisq': 0.074792,
2372
- 'bond_length': [1.80, 1.60, 1.70, 0],
2373
- 'fa': [4.56773888e+000, 3.40325179e+000, 8.61841923e-001],
2374
- 'fb': [1.90992795e+001, 5.90099634e-001, 7.03204851e-002],
2375
- 'fc': [2.19728870e-001, 2.38176903e-001, 1.38306499e-002],
2376
- 'fd': [9.36334280e-002, 3.93554882e-001, 1.94437286e-002]},
2377
- 'Pu': {'Z': 94, 'chisq': 0.071877,
2378
- 'bond_length': [1.84, 1.64, 1.70, 0],
2379
- 'fa': [5.45671123e+000, 1.11687906e-001, 3.30260343e+000],
2380
- 'fb': [1.01892720e+001, 3.98131313e-002, 3.14622212e-001],
2381
- 'fc': [1.84568319e-001, 4.93644263e-001, 3.57484743e+000],
2382
- 'fd': [1.04220860e-001, 4.63080540e-001, 2.19369542e+001]},
2383
- 'Am': {'Z': 95, 'chisq': 0.062156,
2384
- 'bond_length': [2.01, 1.81, 1.70, 0],
2385
- 'fa': [5.38321999e+000, 1.23343236e-001, 3.46469090e+000],
2386
- 'fb': [1.07289857e+001, 4.15137806e-002, 3.39326208e-001],
2387
- 'fc': [1.75437132e-001, 3.39800073e+000, 4.69459519e-001],
2388
- 'fd': [9.98932346e-002, 2.11601535e+001, 4.51996970e-001]},
2389
- 'Cm': {'Z': 96, 'chisq': 0.050111,
2390
- 'bond_length': [2.20, 2.00, 1.70, 0],
2391
- 'fa': [5.38402377e+000, 3.49861264e+000, 1.88039547e-001],
2392
- 'fb': [1.11211419e+001, 3.56750210e-001, 5.39853583e-002],
2393
- 'fc': [1.69143137e-001, 3.19595016e+000, 4.64393059e-001],
2394
- 'fd': [9.60082633e-002, 1.80694389e+001, 4.36318197e-001]},
2395
- 'Bk': {'Z': 97, 'chisq': 0.044081,
2396
- 'bond_length': [2.20, 2.00, 1.70, 0],
2397
- 'fa': [3.66090688e+000, 2.03054678e-001, 5.30697515e+000],
2398
- 'fb': [3.84420906e-001, 5.48547131e-002, 1.17150262e+001],
2399
- 'fc': [1.60934046e-001, 3.04808401e+000, 4.43610295e-001],
2400
- 'fd': [9.21020329e-002, 1.73525367e+001, 4.27132359e-001]},
2401
- 'Cf': {'Z': 98, 'chisq': 0.041053,
2402
- 'bond_length': [2.20, 2.00, 1.70, 0],
2403
- 'fa': [3.94150390e+000, 5.16915345e+000, 1.61941074e-001],
2404
- 'fb': [4.18246722e-001, 1.25201788e+001, 4.81540117e-002],
2405
- 'fc': [4.15299561e-001, 2.91761325e+000, 1.51474927e-001],
2406
- 'fd': [4.24913856e-001, 1.90899693e+001, 8.81568925e-002]}
2407
- }
2408
-
2409
-
2410
- # From Appendix C of Kirkland, "Advanced Computing in Electron Microscopy", 2nd ed.
2411
- # Calculation of electron form factor for specific q:
2412
- # Using equation Kirkland C.15
2413
-
2414
- def feq(element, q):
2415
- """
2416
- Atomic form factor parametrized in 1/Angstrom but converted to 1/nm
2417
-
2418
- The atomic form factor is from Kirkland: Advanced Computing in Electron Microscopy 2nd edition, Appendix C.
2419
-
2420
- Input:
2421
- element: string of element name
2422
- q: now magnitude of scattering vector in 1/nm -- (=> exp(-i*g.r), physics negative convention)
2423
-
2424
-
2425
- """
2426
-
2427
- q = q/10
2428
- # q is now magnitude of scattering vector in 1/A -- (=> exp(-i*g.r), physics negative convention)
2429
- param = electronFF[element]
2430
- f_l = 0
2431
- f_g = 0
2432
- for i in range(3):
2433
- f_l += param['fa'][i]/(q**2 + param['fb'][i])
2434
- f_g += param['fc'][i]*np.exp(-q**2 * param['fd'][i])
2435
-
2436
- # Conversion factor from scattering factors to volts. h^2/(2pi*m0*e), see e.g. Kirkland eqn. C.5
2437
- # !NB RVolume is already in A unlike RPlanckConstant
2438
- # scatt_factor_to_volts=(PlanckConstant**2)*(angstrom_conversion**2)/(2*np.pi*ElectronMass*ElectronCharge)
2439
- return f_l+f_g # * scatt_factor_to_volts
2440
-
2441
-
2442
- # Jmol colors. See: http://jmol.sourceforge.net/jscolors/#color_U
2443
- jmol_colors = np.array([
2444
- (1.000, 0.000, 0.000), # None1.000,1.000,1.000), # H
2445
- (0.851, 1.000, 1.000), # He
2446
- (0.800, 0.502, 1.000), # Li
2447
- (0.761, 1.000, 0.000), # Be
2448
- (1.000, 0.710, 0.710), # B
2449
- (0.565, 0.565, 0.565), # C
2450
- (0.188, 0.314, 0.973), # N
2451
- (1.000, 0.051, 0.051), # O
2452
- (0.565, 0.878, 0.314), # F
2453
- (0.702, 0.890, 0.961), # Ne
2454
- (0.671, 0.361, 0.949), # Na
2455
- (0.541, 1.000, 0.000), # Mg
2456
- (0.749, 0.651, 0.651), # Al
2457
- (0.941, 0.784, 0.627), # Si
2458
- (1.000, 0.502, 0.000), # P
2459
- (1.000, 1.000, 0.188), # S
2460
- (0.122, 0.941, 0.122), # Cl
2461
- (0.502, 0.820, 0.890), # Ar
2462
- (0.561, 0.251, 0.831), # K
2463
- (0.239, 1.000, 0.000), # Ca
2464
- (0.902, 0.902, 0.902), # Sc
2465
- (0.749, 0.761, 0.780), # Ti
2466
- (0.651, 0.651, 0.671), # V
2467
- (0.541, 0.600, 0.780), # Cr
2468
- (0.612, 0.478, 0.780), # Mn
2469
- (0.878, 0.400, 0.200), # Fe
2470
- (0.941, 0.565, 0.627), # Co
2471
- (0.314, 0.816, 0.314), # Ni
2472
- (0.784, 0.502, 0.200), # Cu
2473
- (0.490, 0.502, 0.690), # Zn
2474
- (0.761, 0.561, 0.561), # Ga
2475
- (0.400, 0.561, 0.561), # Ge
2476
- (0.741, 0.502, 0.890), # As
2477
- (1.000, 0.631, 0.000), # Se
2478
- (0.651, 0.161, 0.161), # Br
2479
- (0.361, 0.722, 0.820), # Kr
2480
- (0.439, 0.180, 0.690), # Rb
2481
- (0.000, 1.000, 0.000), # Sr
2482
- (0.580, 1.000, 1.000), # Y
2483
- (0.580, 0.878, 0.878), # Zr
2484
- (0.451, 0.761, 0.788), # Nb
2485
- (0.329, 0.710, 0.710), # Mo
2486
- (0.231, 0.620, 0.620), # Tc
2487
- (0.141, 0.561, 0.561), # Ru
2488
- (0.039, 0.490, 0.549), # Rh
2489
- (0.000, 0.412, 0.522), # Pd
2490
- (0.753, 0.753, 0.753), # Ag
2491
- (1.000, 0.851, 0.561), # Cd
2492
- (0.651, 0.459, 0.451), # In
2493
- (0.400, 0.502, 0.502), # Sn
2494
- (0.620, 0.388, 0.710), # Sb
2495
- (0.831, 0.478, 0.000), # Te
2496
- (0.580, 0.000, 0.580), # I
2497
- (0.259, 0.620, 0.690), # Xe
2498
- (0.341, 0.090, 0.561), # Cs
2499
- (0.000, 0.788, 0.000), # Ba
2500
- (0.439, 0.831, 1.000), # La
2501
- (1.000, 1.000, 0.780), # Ce
2502
- (0.851, 1.000, 0.780), # Pr
2503
- (0.780, 1.000, 0.780), # Nd
2504
- (0.639, 1.000, 0.780), # Pm
2505
- (0.561, 1.000, 0.780), # Sm
2506
- (0.380, 1.000, 0.780), # Eu
2507
- (0.271, 1.000, 0.780), # Gd
2508
- (0.188, 1.000, 0.780), # Tb
2509
- (0.122, 1.000, 0.780), # Dy
2510
- (0.000, 1.000, 0.612), # Ho
2511
- (0.000, 0.902, 0.459), # Er
2512
- (0.000, 0.831, 0.322), # Tm
2513
- (0.000, 0.749, 0.220), # Yb
2514
- (0.000, 0.671, 0.141), # Lu
2515
- (0.302, 0.761, 1.000), # Hf
2516
- (0.302, 0.651, 1.000), # Ta
2517
- (0.129, 0.580, 0.839), # W
2518
- (0.149, 0.490, 0.671), # Re
2519
- (0.149, 0.400, 0.588), # Os
2520
- (0.090, 0.329, 0.529), # Ir
2521
- (0.816, 0.816, 0.878), # Pt
2522
- (1.000, 0.820, 0.137), # Au
2523
- (0.722, 0.722, 0.816), # Hg
2524
- (0.651, 0.329, 0.302), # Tl
2525
- (0.341, 0.349, 0.380), # Pb
2526
- (0.620, 0.310, 0.710), # Bi
2527
- (0.671, 0.361, 0.000), # Po
2528
- (0.459, 0.310, 0.271), # At
2529
- (0.259, 0.510, 0.588), # Rn
2530
- (0.259, 0.000, 0.400), # Fr
2531
- (0.000, 0.490, 0.000), # Ra
2532
- (0.439, 0.671, 0.980), # Ac
2533
- (0.000, 0.729, 1.000), # Th
2534
- (0.000, 0.631, 1.000), # Pa
2535
- (0.000, 0.561, 1.000), # U
2536
- (0.000, 0.502, 1.000), # Np
2537
- (0.000, 0.420, 1.000), # Pu
2538
- (0.329, 0.361, 0.949), # Am
2539
- (0.471, 0.361, 0.890), # Cm
2540
- (0.541, 0.310, 0.890), # Bk
2541
- (0.631, 0.212, 0.831), # Cf
2542
- (0.702, 0.122, 0.831), # Es
2543
- (0.702, 0.122, 0.729), # Fm
2544
- (0.702, 0.051, 0.651), # Md
2545
- (0.741, 0.051, 0.529), # No
2546
- (0.780, 0.000, 0.400), # Lr
2547
- (0.800, 0.000, 0.349), # Rf
2548
- (0.820, 0.000, 0.310), # Db
2549
- (0.851, 0.000, 0.271), # Sg
2550
- (0.878, 0.000, 0.220), # Bh
2551
- (0.902, 0.000, 0.180), # Hs
2552
- (0.922, 0.000, 0.149), # Mt
2553
- ])
2554
-
2555
- # encoding: utf-8
2556
- # crystal data base cbd
2557
- cdb = {'aluminum': {'crystal_name': 'aluminum',
2558
- 'symmetry': 'FCC',
2559
- 'elements': ['Al'],
2560
- 'a': 0.405, # nm
2561
- 'reference': 'W. Witt, Z. Naturforsch. A, 1967, 22A, 92',
2562
- 'link': 'http://doi.org/10.1515/zna-1967-0115'}}
2563
- cdb['Al'] = cdb['Aluminum'] = cdb['aluminum']
2564
-
2565
- cdb['gold'] = {'crystal_name': 'gold',
2566
- 'symmetry': 'FCC',
2567
- 'elements': ['Au'],
2568
- 'a': 0.40782, # nm
2569
- 'reference': '',
2570
- 'link': ''}
2571
- cdb['Au'] = cdb['Gold'] = cdb['gold']
2572
-
2573
- cdb['silver'] = {'crystal_name': 'silver',
2574
- 'symmetry': 'FCC',
2575
- 'elements': ['Ag'],
2576
- 'a': 0.40853, # nm
2577
- 'reference': '', 'link': ''}
2578
- cdb['Ag'] = cdb['Silver'] = cdb['silver']
2579
-
2580
- cdb['diamond'] = {'crystal_name': 'diamond',
2581
- 'symmetry': 'zinc_blende',
2582
- 'elements': ['C'],
2583
- 'a': 0.35668, # nm
2584
- 'reference': '', 'link': ''}
2585
- cdb['Diamond'] = cdb['diamond']
2586
-
2587
- cdb['germanium'] = {'crystal_name': 'germanium',
2588
- 'symmetry': 'zinc_blende',
2589
- 'elements': ['Ge'],
2590
- 'a': 0.566806348, # nm for 300K
2591
- 'reference': 'H. P. Singh, Acta Crystallogr., 1968, 24A, 469',
2592
- 'link': 'https://doi.org/10.1107/S056773946800094X'}
2593
- cdb['Ge'] = cdb['Germanium'] = cdb['germanium']
2594
-
2595
- cdb['silicon'] = {'crystal_name': 'silicon',
2596
- 'symmetry': 'zinc_blende',
2597
- 'elements': ['Si'],
2598
- 'a': 0.566806348, # nm for 300K
2599
- 'reference': 'C. R. Hubbard, H. E. Swanson, and F. A. Mauer, J. Appl. Crystallogr., 1975, 8, 45',
2600
- 'link': 'https://doi.org/10.1107/S0021889875009508'}
2601
- cdb['Si'] = cdb['Silicon'] = cdb['silicon']
2602
-
2603
- cdb['GaAs'] = {'crystal_name': 'GaAs',
2604
- 'symmetry': 'zinc_blende',
2605
- 'elements': ['Ga', 'As'],
2606
- 'a': 0.565325, # nm for 300K
2607
- 'reference': 'J.F.C. Baker, M. Hart, M.A.G. Halliwell, R. Heckingbottom, Solid-State Electronics, 19, '
2608
- '1976, 331-334,',
2609
- 'link': 'https://doi.org/10.1016/0038-1101(76)90031-9'}
2610
-
2611
- cdb['FCC Fe'] = {'crystal_name': 'FCC Fe',
2612
- 'symmetry': 'FCC',
2613
- 'elements': ['Fe'],
2614
- 'a': 0.3571, # nm
2615
- 'reference': 'R. Kohlhaas, P. Donner, and N. Schmitz-Pranghe, Z. Angew. Phys., 1967, 23, 245',
2616
- 'link': ''}
2617
- cdb['fcc fe'] = cdb['FCC Fe']
2618
-
2619
-
2620
- cdb['BCC Fe'] = {'crystal_name': 'BCC Fe',
2621
- 'symmetry': 'BCC',
2622
- 'elements': ['Fe'],
2623
- 'a': 0.2866, # nm
2624
- 'reference': 'Z. S. Basinski, W. Hume-Rothery and A. L. Sutton, Proceedings of the Royal Society of '
2625
- 'London. Series A, Mathematical and Physical Sciences Vol. 229, No. 1179 '
2626
- '(May 24, 1955), pp. 459-467',
2627
- 'link': 'http://www.jstor.org/stable/99693'}
2628
- cdb['bcc fe'] = cdb['BCC Fe']
2629
-
2630
- cdb['SrTiO3'] = {'crystal_name': 'SrTiO3',
2631
- 'symmetry': 'perovskite',
2632
- 'elements': ['Sr', 'Ti', 'O'],
2633
- 'a': 0.3905268, # nm
2634
- 'reference': 'M. Schmidbauer, A. Kwasniewski and J. Schwarzkopf, Acta Cryst. (2012). B68, 8-14',
2635
- 'link': 'http://doi.org/10.1107/S0108768111046738'}
2636
-
2637
- cdb['ZnO Wurzite'] = {'crystal_name': 'ZnO Wurzite',
2638
- 'symmetry': 'wurzite',
2639
- 'elements': ['Zn', 'O'],
2640
- 'a': 0.3278, # nm
2641
- 'c': 0.5292, # nm
2642
- 'u': 0.382, # nm
2643
- 'reference': '', 'link': ''}
2644
- cdb['ZnO'] = cdb['ZnO wurzite'] = cdb['wZnO'] = cdb['ZnO Wurzite']
2645
-
2646
- cdb['GaN'] = {'crystal_name': 'GaN Wurzite',
2647
- 'symmetry': 'wurzite',
2648
- 'elements': ['Ga', 'N'],
2649
- 'a': 0.3186, # nm
2650
- 'c': 0.5186, # nm
2651
- 'u': 0.376393, # nm
2652
- 'reference': '', 'link': ''}
2653
- cdb['GaN wurzite'] = cdb['wGaN'] = cdb['GaN Wurzite'] = cdb['GaN']
2654
-
2655
- cdb['MgO'] = {'crystal_name': 'MgO',
2656
- 'symmetry': 'rocksalt',
2657
- 'elements': ['Mg', 'O'],
2658
- 'a': 0.4256483, # nm
2659
- 'reference': '', 'link': ''}
2660
-
2661
- cdb['TiN'] = {'crystal_name': 'TiN',
2662
- 'symmetry': 'rocksalt',
2663
- 'elements': ['Ti', 'N'],
2664
- 'a': 0.425353445, # nm
2665
- 'reference': '', 'link': '',
2666
- 'space_group': 225,
2667
- 'symmetry_name': 'Fm-3m'}
2668
-
2669
- cdb['MoS2'] = {'crystal_name': 'MoS2',
2670
- 'symmetry': 'dichalcogenide',
2671
- 'elements': ['Mo', 'S'],
2672
- 'a': 0.319031573, # nm
2673
- 'c': 1.487900430, # nm
2674
- 'u': 0.105174, # nm
2675
- 'reference': '', 'link': ''}
2676
-
2677
- cdb['WS2'] = {'crystal_name': 'WS2',
2678
- 'symmetry': 'dichalcogenide',
2679
- 'elements': ['W', 'S'],
2680
- 'a': 0.319073051, # nm
2681
- 'c': 1.420240204, # nm
2682
- 'u': 0.110759, # nm
2683
- 'reference': '', 'link': ''}
2684
-
2685
- cdb['WSe2'] = {'crystal_name': 'WSe2',
2686
- 'symmetry': 'dichalcogenide',
2687
- 'elements': ['W', 'Se'],
2688
- 'a': 0.332706918, # nm
2689
- 'c': 1.506895072, # nm
2690
- 'u': 0.111569 , # nm
2691
- 'reference': '', 'link': ''}
2692
-
2693
- cdb['MoSe2'] = {'crystal_name': 'MoSe2',
2694
- 'elements': ['Mo', 'Se'],
2695
- 'a': 0.332694913, # nm
2696
- 'c': 1.545142322, # nm
2697
- 'u': 0.108249, # nm
2698
- 'reference': '', 'link': ''}
2699
- a_l = 0.3336
2700
- c_l = 0.4754
2701
- cdb['ZnO hexagonal'] = {'crystal_name': 'ZnO hexagonal',
2702
- 'symmetry': 'hexagonal',
2703
- 'a': a_l, # nm
2704
- 'c': c_l, # not np.sqrt(8/3)*1
2705
- 'elements': ['Zn', 'Zn', 'O', 'O'],
2706
- 'unit_cell': [[a_l, 0., 0.],
2707
- [np.cos(120/180*np.pi)*a_l, np.sin(120/180*np.pi)*a_l, 0.],
2708
- [0., 0., c_l]]}
2709
-
2710
- base_l = [(2./3., 1./3., .5), (1./3., 2./3., 0.), (2./3., 1./3., 0.), (1./3., 2./3., .5)]
2711
- cdb['ZnO hexagonal']['base'] = np.array(base_l)
2712
-
2713
- a_l = b_l = 0.2464 # nm
2714
- c_l = 0.6711 # nm
2715
- cdb['Graphite'] = {'crystal_name': 'Graphite',
2716
- 'symmetry': 'hexagonal',
2717
- 'a': a_l,
2718
- 'c': c_l}
2719
- gamma_l = 60
2720
- alpha_l = beta_l = 90
2721
- cdb['Graphite']['unit_cell'] = from_parameters(a_l, b_l, c_l, alpha_l, beta_l, gamma_l)
2722
-
2723
- # ### Create graphite atom base
2724
- # Elements of base
2725
- cdb['Graphite']['elements'] = ['C']*4
2726
- # atom positions in relative coordinates
2727
- base_l = np.array([(.0, .0, .0), (.0, .0, 0.5), (1./3., 1./3., .0), (2./3., 2./3., 0.5)])
2728
- cdb['Graphite']['base'] = np.array(base_l)
2729
- cdb['Graphite']['reference'] = 'P. Trucano and R. Chen, Nature, 1975, 258, 136'
2730
- cdb['Graphite']['link'] = 'https://doi.org/10.1038/258136a0'
2731
-
2732
- cdb['graphite'] = cdb['Graphite']
2733
-
2734
- # Create CsCl structure
2735
- a_l = 0.4209
2736
- cdb['CsCl'] = {'crystal_name': 'CsCl',
2737
- 'a': a_l, # nm
2738
- 'unit_cell': np.identity(3)*a_l,
2739
- 'elements': ['Cs', 'Cl'],
2740
- 'base': np.array([[0, 0, 0], [0.5, 0.5, 0.5]]),
2741
- 'reference': '', 'link': ''}
2742
-
2743
- cdb['PdSe2'] = {'crystal_name': 'PdSe2',
2744
- 'unit_cell': (np.identity(3)*(.579441832, 0.594542204, 0.858506072)),
2745
- 'elements': ['Pd']*4 + ['Se']*8,
2746
- 'base': np.array([[.5, .0, .0], [.0, 0.5, 0.0],
2747
- [.5, 0.5, 0.5], [.0, 0.5, 0.5],
2748
- [0.611300, 0.119356, 0.585891],
2749
- [0.111300, 0.380644, 0.414109],
2750
- [0.388700, 0.619356, 0.914109],
2751
- [0.888700, 0.880644, 0.085891],
2752
- [0.111300, 0.119356, 0.914109],
2753
- [0.611300, 0.380644, 0.085891],
2754
- [0.888700, 0.619356, 0.585891],
2755
- [0.388700, 0.880644, 0.414109]]),
2756
- 'reference': '', 'link': ''}
2757
-
2758
- crystal_data_base = cdb