pyemaps 2.0.0__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.
- pyemaps/COPYING +798 -0
- pyemaps/CifFile/CifFile_module.py +3117 -0
- pyemaps/CifFile/StarFile.py +2496 -0
- pyemaps/CifFile/TypeContentsParser.py +82 -0
- pyemaps/CifFile/YappsStarParser_1_0.py +289 -0
- pyemaps/CifFile/YappsStarParser_1_1.py +288 -0
- pyemaps/CifFile/YappsStarParser_2_0.py +369 -0
- pyemaps/CifFile/YappsStarParser_STAR2.py +382 -0
- pyemaps/CifFile/__init__.py +7 -0
- pyemaps/CifFile/drel/__init__.py +1 -0
- pyemaps/CifFile/drel/drel_ast_yacc.py +582 -0
- pyemaps/CifFile/drel/drel_lex.py +228 -0
- pyemaps/CifFile/drel/drel_runtime.py +126 -0
- pyemaps/CifFile/drel/parsetab.py +185 -0
- pyemaps/CifFile/drel/py_from_ast.py +628 -0
- pyemaps/CifFile/parsetab.py +185 -0
- pyemaps/CifFile/yapps3_compiled_rt.py +390 -0
- pyemaps/README.md +201 -0
- pyemaps/__config__.py +91 -0
- pyemaps/__init__.py +233 -0
- pyemaps/__main__.py +219 -0
- pyemaps/__version__.py +1 -0
- pyemaps/cdata/Aluminium.xtl +4 -0
- pyemaps/cdata/AluminiumOxide.xtl +5 -0
- pyemaps/cdata/Aluminium_FCC.xtl +4 -0
- pyemaps/cdata/BariumTitanate_180k.xtl +6 -0
- pyemaps/cdata/BariumTitanate_270k.xtl +7 -0
- pyemaps/cdata/BariumTitanate_Tetra.xtl +7 -0
- pyemaps/cdata/BiMnO3.xtl +27 -0
- pyemaps/cdata/Boron_Tetra.xtl +8 -0
- pyemaps/cdata/CadmiumSelenide_Hex.xtl +5 -0
- pyemaps/cdata/CadmiumSulfide_Cubic.xtl +5 -0
- pyemaps/cdata/CadmiumSulfide_Hex.xtl +5 -0
- pyemaps/cdata/Chromium_BCC.xtl +4 -0
- pyemaps/cdata/CoSb3_Skutterudite.xtl +5 -0
- pyemaps/cdata/CopperOxide.xtl +5 -0
- pyemaps/cdata/Copper_FCC.xtl +4 -0
- pyemaps/cdata/Cu2O_Cuprite.xtl +5 -0
- pyemaps/cdata/Diamond.xtl +4 -0
- pyemaps/cdata/ErbiumPyrogermanate.xtl +9 -0
- pyemaps/cdata/FePd_Tetra.xtl +5 -0
- pyemaps/cdata/FeS2_Pyrite.xtl +15 -0
- pyemaps/cdata/GalliumAntimonide.xtl +5 -0
- pyemaps/cdata/GalliumArsenide.xtl +5 -0
- pyemaps/cdata/GalliumNitride.xtl +5 -0
- pyemaps/cdata/Germanium.xtl +4 -0
- pyemaps/cdata/Gold_FCC.xtl +4 -0
- pyemaps/cdata/IndiumArsenide.xtl +5 -0
- pyemaps/cdata/LaMnO3.xtl +7 -0
- pyemaps/cdata/LeadZirconateTitanate.xtl +8 -0
- pyemaps/cdata/Li2MnO3.xtl +13 -0
- pyemaps/cdata/NaFeO2.xtl +6 -0
- pyemaps/cdata/Nb3Sn.xtl +5 -0
- pyemaps/cdata/Pentacene.xtl +39 -0
- pyemaps/cdata/Silicon.xtl +4 -0
- pyemaps/cdata/StrontiumTitanate.xtl +6 -0
- pyemaps/cdata/TelluriumDioxide.xtl +5 -0
- pyemaps/cdata/TinDioxide_RT.xtl +5 -0
- pyemaps/cdata/TitaniumDioxide_Anatase.xtl +5 -0
- pyemaps/cdata/TitaniumDioxide_Rutile.xtl +5 -0
- pyemaps/cdata/TungstenDiselenide.xtl +5 -0
- pyemaps/cdata/VanadiumDioxide_RT.xtl +6 -0
- pyemaps/cdata/ZincOxide.xtl +5 -0
- pyemaps/cdata/Zinc_HCP.xtl +4 -0
- pyemaps/cdata/ZirconiumNitride.xtl +5 -0
- pyemaps/cdata/limno2.xtl +6 -0
- pyemaps/crystals.py +1415 -0
- pyemaps/ddiffs.py +147 -0
- pyemaps/diffract/__init__.py +70 -0
- pyemaps/diffract/bloch_dec.py +779 -0
- pyemaps/diffract/csf_dec.py +242 -0
- pyemaps/diffract/dif_dec.py +519 -0
- pyemaps/diffract/dpgen_dec.py +175 -0
- pyemaps/diffract/mxtal_dec.py +201 -0
- pyemaps/diffract/powder_dec.py +137 -0
- pyemaps/diffract/stereo_dec.py +111 -0
- pyemaps/display.py +791 -0
- pyemaps/emcontrols.py +1017 -0
- pyemaps/errors.py +266 -0
- pyemaps/fileutils.py +1001 -0
- pyemaps/kdiffs.py +1221 -0
- pyemaps/license.txt +42 -0
- pyemaps/samples/adf.py +137 -0
- pyemaps/samples/al.img +0 -0
- pyemaps/samples/al_dpgen.py +57 -0
- pyemaps/samples/al_ediom.py +94 -0
- pyemaps/samples/convert_image.py +88 -0
- pyemaps/samples/dm_diff.py +225 -0
- pyemaps/samples/mask.im3 +0 -0
- pyemaps/samples/powder.py +51 -0
- pyemaps/samples/raw.img +0 -0
- pyemaps/samples/si_bloch.py +120 -0
- pyemaps/samples/si_constructor.py +51 -0
- pyemaps/samples/si_csf.py +59 -0
- pyemaps/samples/si_dif.py +134 -0
- pyemaps/samples/si_lacbed.py +59 -0
- pyemaps/samples/si_pyemaps.py +80 -0
- pyemaps/samples/si_scm.py +156 -0
- pyemaps/samples/si_stereo.py +116 -0
- pyemaps/scattering/__init__.py +26 -0
- pyemaps/scattering/sct_dec.py +31 -0
- pyemaps/spg/__init__.py +25 -0
- pyemaps/spg/spg_dec.py +60 -0
- pyemaps/stackimg.py +1031 -0
- pyemaps/xtal.py +222 -0
- pyemaps-2.0.0.dist-info/METADATA +231 -0
- pyemaps-2.0.0.dist-info/RECORD +112 -0
- pyemaps-2.0.0.dist-info/WHEEL +5 -0
- pyemaps-2.0.0.dist-info/entry_points.txt +2 -0
- pyemaps-2.0.0.dist-info/licenses/COPYING +798 -0
- pyemaps-2.0.0.dist-info/licenses/license.txt +42 -0
- pyemaps-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
'''
|
|
2
|
+
.. This file is part of pyEMAPS
|
|
3
|
+
|
|
4
|
+
.. ----
|
|
5
|
+
|
|
6
|
+
.. pyEMAPS is free software. You can redistribute it and/or modify
|
|
7
|
+
.. it under the terms of the GNU General Public License as published
|
|
8
|
+
.. by the Free Software Foundation, either version 3 of the License,
|
|
9
|
+
.. or (at your option) any later version..
|
|
10
|
+
|
|
11
|
+
.. pyEMAPS is distributed in the hope that it will be useful,
|
|
12
|
+
.. but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
.. GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
.. You should have received a copy of the GNU General Public License
|
|
17
|
+
.. along with pyEMAPS. If not, see `<https://www.gnu.org/licenses/>`_.
|
|
18
|
+
|
|
19
|
+
.. Contact supprort@emlabsoftware.com for any questions and comments.
|
|
20
|
+
|
|
21
|
+
.. ----
|
|
22
|
+
|
|
23
|
+
.. Author: EMLab Solutions, Inc.
|
|
24
|
+
.. Date Created: May 07, 2022
|
|
25
|
+
|
|
26
|
+
'''
|
|
27
|
+
def add_dif(target):
|
|
28
|
+
import numpy as np
|
|
29
|
+
from numpy import asfortranarray as farray
|
|
30
|
+
|
|
31
|
+
from . import dif
|
|
32
|
+
from .. import EMC, DP
|
|
33
|
+
from .. import DEF_MODE, DEF_CBED_DSIZE, DEF_XAXIS
|
|
34
|
+
from .. import EMCError,DPListError,CrystalClassError,DPError
|
|
35
|
+
|
|
36
|
+
def load(self, cty=0):
|
|
37
|
+
'''
|
|
38
|
+
Prepare and load crystal data into backend simulation module.
|
|
39
|
+
|
|
40
|
+
Once loaded into simulation modules, the crystal data will be
|
|
41
|
+
in backend module's memory until unload() method is called or
|
|
42
|
+
another crystal object calls this method.
|
|
43
|
+
|
|
44
|
+
Since all crystal objects use this method to load its data into
|
|
45
|
+
the shared silmulation modules, data races need to be avoided.
|
|
46
|
+
|
|
47
|
+
One way to prevent data races is to guard all simulations for
|
|
48
|
+
one crystal object between its load() and unload() methods.
|
|
49
|
+
|
|
50
|
+
:param cty: 0 - normal crystal loading, 1 - loading for crystal constructor
|
|
51
|
+
:type cty: int, optional
|
|
52
|
+
|
|
53
|
+
.. note::
|
|
54
|
+
|
|
55
|
+
This routine is designed to minimize trips to the backend simulation modules
|
|
56
|
+
and therefore miximizing the performance. Users do not need to handle this calls
|
|
57
|
+
directly.
|
|
58
|
+
|
|
59
|
+
'''
|
|
60
|
+
if self.loaded() and cty == self._ltype:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
diff_cell = self._cell.prepare() #cell constant
|
|
64
|
+
|
|
65
|
+
num_atoms = len(self._atoms)
|
|
66
|
+
atn = farray(np.empty((num_atoms, 10), dtype='c'))
|
|
67
|
+
|
|
68
|
+
atnarr = [at.symb for at in self._atoms]
|
|
69
|
+
for i, an in enumerate(atnarr):
|
|
70
|
+
if len(an) > 10:
|
|
71
|
+
raise CrystalClassError(f"Atomic symbol {an} length cannot exceed 10")
|
|
72
|
+
atn[i] = an.ljust(10)
|
|
73
|
+
|
|
74
|
+
diff_atoms = farray([at.prepare() for at in self._atoms], dtype=float)
|
|
75
|
+
|
|
76
|
+
diff_spg = self._spg.prepare()
|
|
77
|
+
|
|
78
|
+
ret = dif.loadcrystal(diff_cell, diff_atoms, atn, diff_spg, ndw=self._dw, cty=cty)
|
|
79
|
+
|
|
80
|
+
if ret != 0:
|
|
81
|
+
self.unload() #remove any memory from backend module
|
|
82
|
+
raise CrystalClassError('Failed to load crystal')
|
|
83
|
+
|
|
84
|
+
self._loaded = True
|
|
85
|
+
self._ltype = cty
|
|
86
|
+
|
|
87
|
+
def unload(self):
|
|
88
|
+
'''
|
|
89
|
+
Remove crystal data from the memory in the backend simulation modules.
|
|
90
|
+
|
|
91
|
+
'''
|
|
92
|
+
dif.crystaldelete()
|
|
93
|
+
self._loaded = False
|
|
94
|
+
|
|
95
|
+
def generateDP(self, mode = None, dsize = None, em_controls = None):
|
|
96
|
+
"""
|
|
97
|
+
Kinematic diffraction simulation.
|
|
98
|
+
|
|
99
|
+
:param mode: Mode of kinemetic diffraction - normal(1) or CBED(2).
|
|
100
|
+
:type mode: int, optional
|
|
101
|
+
|
|
102
|
+
:param dsize: diffractted beam size, only applied to CBED mode.
|
|
103
|
+
:type dsize: float, optional
|
|
104
|
+
|
|
105
|
+
:param em_controls: `Microscope control <pyemaps.emcontrols.html#module-pyemaps.emcontrols>`_ object.
|
|
106
|
+
:type em_controls: pyemaps.EMC, optional
|
|
107
|
+
|
|
108
|
+
:return: A tuple (emc, dp) where emc is the microscope control and dp is a `diffPattern <pyemaps.kdiffs.html#pyemaps.kdiffs.diffPattern>`_ object .
|
|
109
|
+
:rtype: tuple.
|
|
110
|
+
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
if em_controls is None:
|
|
114
|
+
em_controls =EMC()
|
|
115
|
+
|
|
116
|
+
# if not sim_controls:
|
|
117
|
+
# em_controls =SIMC()
|
|
118
|
+
|
|
119
|
+
tx0, ty0 = em_controls.tilt
|
|
120
|
+
dx0, dy0 = em_controls.defl
|
|
121
|
+
cl, vt = em_controls.cl, em_controls.vt
|
|
122
|
+
zone = em_controls.zone
|
|
123
|
+
sc = em_controls.simc
|
|
124
|
+
if em_controls.xaxis != DEF_XAXIS:
|
|
125
|
+
xa = em_controls.xaxis
|
|
126
|
+
else:
|
|
127
|
+
xa = None
|
|
128
|
+
|
|
129
|
+
if not mode:
|
|
130
|
+
mode = DEF_MODE
|
|
131
|
+
|
|
132
|
+
if mode == 2 and dsize is None:
|
|
133
|
+
dsize = DEF_CBED_DSIZE
|
|
134
|
+
|
|
135
|
+
ret, diffp = self._get_diffraction(zone,mode,tx0,ty0,dx0,dy0,cl,vt,dsize,xa,sc)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if ret != 200:
|
|
139
|
+
raise DPError('failed to generate diffraction patterns')
|
|
140
|
+
|
|
141
|
+
# update the controls
|
|
142
|
+
|
|
143
|
+
em_controls(mode=mode)
|
|
144
|
+
if mode == 2:
|
|
145
|
+
em_controls(dsize=dsize)
|
|
146
|
+
|
|
147
|
+
# @70323 merge
|
|
148
|
+
# update x-axis if it was set to (0,0,0)
|
|
149
|
+
# and new xaxis is calculated by the backend
|
|
150
|
+
|
|
151
|
+
if em_controls.xaxis == DEF_XAXIS:
|
|
152
|
+
xa1 = 0
|
|
153
|
+
xa2 = 2
|
|
154
|
+
xa3 = 0
|
|
155
|
+
xa1, xa2, xa3 = dif.get_xaxis()
|
|
156
|
+
em_controls(xaxis = (xa1,xa2,xa3))
|
|
157
|
+
|
|
158
|
+
return em_controls, DP(diffp)
|
|
159
|
+
|
|
160
|
+
def _get_diffraction(self, zone = None,
|
|
161
|
+
mode = None,
|
|
162
|
+
tx0 = None,
|
|
163
|
+
ty0 = None,
|
|
164
|
+
dx0 = None,
|
|
165
|
+
dy0 = None,
|
|
166
|
+
cl = None,
|
|
167
|
+
vt = None,
|
|
168
|
+
dsize = None,
|
|
169
|
+
xa = None,
|
|
170
|
+
simc = None):
|
|
171
|
+
"""
|
|
172
|
+
This routine returns raw diffraction data from emaps dif extension
|
|
173
|
+
|
|
174
|
+
If none of the parameters are supplied, the routine will
|
|
175
|
+
generate the diffraction patterns in default set in the fortran
|
|
176
|
+
backend indicated below:
|
|
177
|
+
zone = (0,0,1) zone axis
|
|
178
|
+
mode = normal kinematic diffraction mode (CBED is the other)
|
|
179
|
+
(tx0,ty0) = (0.0,0.0) tilt angles
|
|
180
|
+
(dx0,dy0) = (0.0,0.0) deflection move
|
|
181
|
+
cl = 1000 EM length
|
|
182
|
+
vt = 200 voltage
|
|
183
|
+
cl and vt must be set togather
|
|
184
|
+
dsize = 0.05 spot disk size in nm
|
|
185
|
+
If any of the values are set, the following tuples must be set togather
|
|
186
|
+
(tx0,ty0,dx0,dy0)
|
|
187
|
+
(cl,vt)
|
|
188
|
+
if mode == 2 (CBED), then dsize must be set
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
import copy
|
|
192
|
+
|
|
193
|
+
if mode != DEF_MODE and mode != DEF_MODE + 1:
|
|
194
|
+
raise EMCError('Simulation mode is invalid: 1 = normal (default), 2 = CBED')
|
|
195
|
+
|
|
196
|
+
dif.initcontrols()
|
|
197
|
+
# mode defaults to DEF_MODE, in which dsize is not used
|
|
198
|
+
# Electron Microscope controls defaults - DEF_CONTROLS
|
|
199
|
+
|
|
200
|
+
if mode == 2:
|
|
201
|
+
dif.setmode(mode)
|
|
202
|
+
try:
|
|
203
|
+
fd = float(dsize)
|
|
204
|
+
except ValueError:
|
|
205
|
+
raise EMCError('Invalid diffracted beams disk size')
|
|
206
|
+
else:
|
|
207
|
+
dif.setdisksize(fd)
|
|
208
|
+
|
|
209
|
+
if tx0 is not None and \
|
|
210
|
+
ty0 is not None and \
|
|
211
|
+
dx0 is not None and \
|
|
212
|
+
dy0 is not None:
|
|
213
|
+
|
|
214
|
+
dif.setsamplecontrols(tx0, ty0, dx0, dy0)
|
|
215
|
+
else:
|
|
216
|
+
print(f'tilt and deflection values: {tx0},{ty0}, {dx0}, {dy0}')
|
|
217
|
+
raise EMCError('Control parameters invalid: tilt and deflection')
|
|
218
|
+
|
|
219
|
+
if cl is not None and vt is not None:
|
|
220
|
+
dif.setemcontrols(cl, vt)
|
|
221
|
+
else:
|
|
222
|
+
raise EMCError('Control parameters invalid: cl and vt')
|
|
223
|
+
|
|
224
|
+
if zone is not None:
|
|
225
|
+
dif.setzone(zone[0], zone[1], zone[2])
|
|
226
|
+
else:
|
|
227
|
+
raise EMCError('Control parameters invalid: zone')
|
|
228
|
+
|
|
229
|
+
# setting simulation parameters
|
|
230
|
+
self.set_sim_controls(simc)
|
|
231
|
+
if xa:
|
|
232
|
+
dif.set_xaxis(1, xa[0], xa[1], xa[2])
|
|
233
|
+
|
|
234
|
+
self.load()
|
|
235
|
+
|
|
236
|
+
ret = dif.diffract()
|
|
237
|
+
if ret == 0:
|
|
238
|
+
return 500, ({})
|
|
239
|
+
|
|
240
|
+
shiftx, shifty = dif.get_shifts()
|
|
241
|
+
bounds = (shiftx, shifty)
|
|
242
|
+
|
|
243
|
+
# dif.diff_printall()
|
|
244
|
+
#remove module internal global memory
|
|
245
|
+
dif.diff_internaldelete(0)
|
|
246
|
+
|
|
247
|
+
klines=[]
|
|
248
|
+
num_klines = dif.getknum()
|
|
249
|
+
|
|
250
|
+
if (num_klines > 0):
|
|
251
|
+
klines_arr = farray(np.zeros((num_klines, 5)), dtype=np.single)
|
|
252
|
+
|
|
253
|
+
if dif.get_klines(klines_arr) == 0:
|
|
254
|
+
for i in range(num_klines):
|
|
255
|
+
j=i+1
|
|
256
|
+
x1,y1,x2,y2,intensity=klines_arr[i][0:]
|
|
257
|
+
klines.append((x1,y1,x2,y2,intensity))
|
|
258
|
+
else:
|
|
259
|
+
print(f"Error: retrieving klines!")
|
|
260
|
+
return 500, ({})
|
|
261
|
+
|
|
262
|
+
disks=[]
|
|
263
|
+
num_disks = dif.getdnum()
|
|
264
|
+
if (num_disks > 0):
|
|
265
|
+
disks_arr = farray(np.zeros((num_disks, 6)), dtype=np.single)
|
|
266
|
+
if dif.get_disks(disks_arr) == 0:
|
|
267
|
+
# for i in range(num_disks):
|
|
268
|
+
# x1,y1,r,i1,i2,i3=disks_arr[i][0:]
|
|
269
|
+
# disk={}
|
|
270
|
+
# disk['c']=(x1,y1)
|
|
271
|
+
# disk['r']=r
|
|
272
|
+
# disk['idx']=(int(i1),int(i2),int(i3))
|
|
273
|
+
# disks.append(disk)
|
|
274
|
+
for d in disks_arr:
|
|
275
|
+
x1,y1,r,i1,i2,i3=d
|
|
276
|
+
disk={}
|
|
277
|
+
disk['c']=(x1,y1)
|
|
278
|
+
disk['r']=r
|
|
279
|
+
disk['idx']=(int(i1),int(i2),int(i3))
|
|
280
|
+
disks.append(disk)
|
|
281
|
+
|
|
282
|
+
else:
|
|
283
|
+
print(f"Error: retrieving disks!")
|
|
284
|
+
return 500, ({})
|
|
285
|
+
|
|
286
|
+
hlines=[]
|
|
287
|
+
num_hlines = 0
|
|
288
|
+
if (mode == 2):
|
|
289
|
+
num_hlines = dif.gethnum()
|
|
290
|
+
|
|
291
|
+
if (num_hlines > 0):
|
|
292
|
+
hlines_arr = farray(np.zeros((num_hlines, 5)), dtype=np.single)
|
|
293
|
+
if dif.get_hlines(hlines_arr) == 0:
|
|
294
|
+
for i in range(num_hlines):
|
|
295
|
+
x1,y1,x2,y2,intensity = hlines_arr[i][0:]
|
|
296
|
+
hlines.append((x1,y1,x2,y2,intensity))
|
|
297
|
+
else:
|
|
298
|
+
print(f"Info: no hlines detected!")
|
|
299
|
+
return 500, ({})
|
|
300
|
+
|
|
301
|
+
nums = {"nklines" : num_klines, "ndisks" : num_disks, "nhlines" : num_hlines}
|
|
302
|
+
data = {"nums" : copy.deepcopy(nums), "bounds": copy.deepcopy(bounds), \
|
|
303
|
+
"klines": copy.deepcopy(klines), "hlines": copy.deepcopy(hlines), \
|
|
304
|
+
"disks": copy.deepcopy(disks), "name" : self.name}
|
|
305
|
+
|
|
306
|
+
# delete diff pattern memory
|
|
307
|
+
dif.diff_delete()
|
|
308
|
+
return 200, data
|
|
309
|
+
|
|
310
|
+
def generateDif(self, mode = None, dsize = None, em_controls = None):
|
|
311
|
+
"""
|
|
312
|
+
Another kinematic diffraction simulation method to be deprecated in
|
|
313
|
+
stabel production soon. Its replacement is:
|
|
314
|
+
`generateDP <pyemaps.crystals.html#pyemaps.crystals.Crystal.generateDP>`_.
|
|
315
|
+
|
|
316
|
+
:param mode: mode of kinemetic diffraction - normal(1) or CBED(2).
|
|
317
|
+
:type mode: int
|
|
318
|
+
|
|
319
|
+
:param dsize: diffractted beam size, only applied to CBED mode.
|
|
320
|
+
:type dsize: float
|
|
321
|
+
|
|
322
|
+
:param em_controls: electron microscope controls object.
|
|
323
|
+
:type em_controls: pyemaps.EMC
|
|
324
|
+
|
|
325
|
+
:return: myDif.
|
|
326
|
+
:rtype: pyemaps.DPList.
|
|
327
|
+
|
|
328
|
+
"""
|
|
329
|
+
from .. import DPList
|
|
330
|
+
if mode is None:
|
|
331
|
+
mode = 1
|
|
332
|
+
try:
|
|
333
|
+
emc, cdp = self.generateDP(mode = mode, dsize=dsize, em_controls = em_controls)
|
|
334
|
+
myDif = DPList(self._name, mode = mode)
|
|
335
|
+
myDif.add(emc, cdp)
|
|
336
|
+
|
|
337
|
+
except (DPListError, EMCError, DPError) as e:
|
|
338
|
+
raise CrystalClassError('failed to generate diffraction')
|
|
339
|
+
|
|
340
|
+
return myDif
|
|
341
|
+
|
|
342
|
+
def d2r(self, v = (0.0, 0.0, 0.0)):
|
|
343
|
+
'''
|
|
344
|
+
Transform vector from real to recriprocal space
|
|
345
|
+
|
|
346
|
+
:param v: A vector of float coordinates
|
|
347
|
+
:type v: tuple, optional
|
|
348
|
+
|
|
349
|
+
:return: a transformed vector
|
|
350
|
+
:rtype: tuple
|
|
351
|
+
|
|
352
|
+
'''
|
|
353
|
+
|
|
354
|
+
self.load()
|
|
355
|
+
|
|
356
|
+
x, y, z = v
|
|
357
|
+
rx, ry, rz = dif.drtrans(x, y, z, 0)
|
|
358
|
+
|
|
359
|
+
# dif.crystaldelete()
|
|
360
|
+
return rx, ry, rz
|
|
361
|
+
|
|
362
|
+
def r2d(self, v = (0.0, 0.0, 0.0)):
|
|
363
|
+
'''
|
|
364
|
+
Transform vector from recriprocal to real space
|
|
365
|
+
|
|
366
|
+
:param v: A vector of float coordinates
|
|
367
|
+
:type v: tuple, optional
|
|
368
|
+
|
|
369
|
+
:return: Tranformed vector
|
|
370
|
+
:rtype: tuple of floats
|
|
371
|
+
|
|
372
|
+
'''
|
|
373
|
+
|
|
374
|
+
self.load()
|
|
375
|
+
|
|
376
|
+
x, y, z = v
|
|
377
|
+
dx, dy, dz = dif.drtrans(x, y, z, 1)
|
|
378
|
+
|
|
379
|
+
# dif.crystaldelete()
|
|
380
|
+
return dx, dy, dz
|
|
381
|
+
|
|
382
|
+
def angle(self, v1 =(1.0, 0.0, 0.0), \
|
|
383
|
+
v2 = (0.0, 0.0, 1.0),
|
|
384
|
+
ty = 0):
|
|
385
|
+
'''
|
|
386
|
+
Calculates angle between two real space vectors or
|
|
387
|
+
two reciprocal space vectors
|
|
388
|
+
|
|
389
|
+
:param v1: A vector of float coordinates
|
|
390
|
+
:type v1: tuple, optional
|
|
391
|
+
|
|
392
|
+
:param v2: A vector of float coordinates
|
|
393
|
+
:type v2: tuple, optional
|
|
394
|
+
|
|
395
|
+
:param ty: 0 real space, 1 reciprocal space
|
|
396
|
+
:type ty: int, optional
|
|
397
|
+
|
|
398
|
+
:return: an angle between v1 and v2.
|
|
399
|
+
:rtype: float
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
'''
|
|
403
|
+
x1, y1, z1 = v1
|
|
404
|
+
if x1 == 0.0 and y1 == 0.0 and z1 == 0.0:
|
|
405
|
+
raise ValueError("Error: input vector can't be zero")
|
|
406
|
+
|
|
407
|
+
x2, y2, z2 = v2
|
|
408
|
+
if x2 == 0.0 and y2 == 0.0 and z2 == 0.0:
|
|
409
|
+
raise ValueError("Error: input vector can't be zero")
|
|
410
|
+
|
|
411
|
+
self.load()
|
|
412
|
+
|
|
413
|
+
a = dif.ang(x1, y1, z1, x2, y2, z2, ty)
|
|
414
|
+
|
|
415
|
+
# dif.crystaldelete()
|
|
416
|
+
return a
|
|
417
|
+
|
|
418
|
+
def vlen(self, v = (1.0, 0.0, 0.0), ty = 0):
|
|
419
|
+
|
|
420
|
+
'''
|
|
421
|
+
Calculates vector length real space vectors or in reciprocal
|
|
422
|
+
space vectors.
|
|
423
|
+
|
|
424
|
+
:param v: A vector of float coordinates
|
|
425
|
+
:type v: tuple, optional
|
|
426
|
+
|
|
427
|
+
:param ty: 0 real space, 1 reciprocal space
|
|
428
|
+
:type ty: int, optional
|
|
429
|
+
|
|
430
|
+
:return: vector length in reciprical space or in reciprocal space
|
|
431
|
+
:rtype: float
|
|
432
|
+
|
|
433
|
+
'''
|
|
434
|
+
|
|
435
|
+
self.load()
|
|
436
|
+
|
|
437
|
+
x, y, z = v
|
|
438
|
+
ln = dif.vlen(x, y, z, ty)
|
|
439
|
+
|
|
440
|
+
# dif.crystaldelete()
|
|
441
|
+
return ln
|
|
442
|
+
|
|
443
|
+
@staticmethod
|
|
444
|
+
def wavelength(kv = 100):
|
|
445
|
+
'''
|
|
446
|
+
Calculates electron wavelength.
|
|
447
|
+
|
|
448
|
+
:param kv: High voltage
|
|
449
|
+
:type kv: float or int, optional
|
|
450
|
+
|
|
451
|
+
return: wave length
|
|
452
|
+
rtype: float
|
|
453
|
+
|
|
454
|
+
'''
|
|
455
|
+
import math
|
|
456
|
+
|
|
457
|
+
if kv <= 0.0:
|
|
458
|
+
raise ValueError("Error: input kv must be positive number")
|
|
459
|
+
|
|
460
|
+
wlen = 0.3878314/math.sqrt(kv*(1.0+0.97846707e-03*kv))
|
|
461
|
+
return wlen
|
|
462
|
+
|
|
463
|
+
def set_sim_controls(self, simc = None):
|
|
464
|
+
'''
|
|
465
|
+
Sets simulation controls in the backend.
|
|
466
|
+
|
|
467
|
+
This method also tries to minimize the trip to the backend
|
|
468
|
+
simulation module by skipping the call to the backend if
|
|
469
|
+
default values are given.
|
|
470
|
+
|
|
471
|
+
:param simc: `Simulation control <pyemaps.emcontrols.html#pyemaps.emcontrols.SIMControl>`_ objects
|
|
472
|
+
:type simc: pyemaps.SIMC, optional
|
|
473
|
+
|
|
474
|
+
.. note::
|
|
475
|
+
|
|
476
|
+
*pyemaps" assumes that attributes in sim_control class are
|
|
477
|
+
rarely changed.
|
|
478
|
+
|
|
479
|
+
'''
|
|
480
|
+
# from pyemaps import
|
|
481
|
+
if not simc:
|
|
482
|
+
# all defaults set in backend set by dif.initcontrols()
|
|
483
|
+
return
|
|
484
|
+
|
|
485
|
+
if not simc._check_def('excitation'):
|
|
486
|
+
sgmin, sgmax = simc.excitation
|
|
487
|
+
dif.setexcitation(sgmin, sgmax)
|
|
488
|
+
|
|
489
|
+
if not simc._check_def('gmax'):
|
|
490
|
+
dif.setglen(simc.gmax)
|
|
491
|
+
|
|
492
|
+
if not simc._check_def('bmin'):
|
|
493
|
+
dif.setgcutoff(simc.bmin)
|
|
494
|
+
|
|
495
|
+
if not simc._check_def('intensity'):
|
|
496
|
+
intz0, intctl = simc.intensity
|
|
497
|
+
dif.setintensities(intctl, intz0)
|
|
498
|
+
|
|
499
|
+
if simc._check_def('gctl'):
|
|
500
|
+
dif.setgctl(simc.gctl)
|
|
501
|
+
|
|
502
|
+
if simc._check_def('zctl'):
|
|
503
|
+
dif.setzctl(simc.zctl)
|
|
504
|
+
dif.setzctl(simc.zctl)
|
|
505
|
+
|
|
506
|
+
target.generateDP = generateDP
|
|
507
|
+
target._get_diffraction = _get_diffraction
|
|
508
|
+
target.generateDif=generateDif
|
|
509
|
+
target.d2r = d2r
|
|
510
|
+
target.r2d = r2d
|
|
511
|
+
target.angle = angle
|
|
512
|
+
target.vlen = vlen
|
|
513
|
+
target.wavelength = wavelength
|
|
514
|
+
target.set_sim_controls = set_sim_controls
|
|
515
|
+
target.load = load
|
|
516
|
+
target.unload = unload
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
return target
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'''
|
|
2
|
+
.. This file is part of pyEMAPS
|
|
3
|
+
|
|
4
|
+
.. ----
|
|
5
|
+
|
|
6
|
+
.. pyEMAPS is free software. You can redistribute it and/or modify
|
|
7
|
+
.. it under the terms of the GNU General Public License as published
|
|
8
|
+
.. by the Free Software Foundation, either version 3 of the License,
|
|
9
|
+
.. or (at your option) any later version..
|
|
10
|
+
|
|
11
|
+
.. pyEMAPS is distributed in the hope that it will be useful,
|
|
12
|
+
.. but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
.. GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
.. You should have received a copy of the GNU General Public License
|
|
17
|
+
.. along with pyEMAPS. If not, see `<https://www.gnu.org/licenses/>`_.
|
|
18
|
+
|
|
19
|
+
.. Contact supprort@emlabsoftware.com for any questions and comments.
|
|
20
|
+
|
|
21
|
+
.. ----
|
|
22
|
+
|
|
23
|
+
.. Author: EMLab Solutions, Inc.
|
|
24
|
+
.. Date Created: May 07, 2022
|
|
25
|
+
|
|
26
|
+
'''
|
|
27
|
+
def add_dpgen(target):
|
|
28
|
+
try:
|
|
29
|
+
from . import dif, dpgen
|
|
30
|
+
|
|
31
|
+
except ImportError as e:
|
|
32
|
+
# return an empty target if non-extant
|
|
33
|
+
return target
|
|
34
|
+
else:
|
|
35
|
+
LOW_RES = dpgen.get_lowres()
|
|
36
|
+
HIGH_RES = dpgen.get_highres()
|
|
37
|
+
|
|
38
|
+
import numpy as np
|
|
39
|
+
from numpy import asfortranarray as farray
|
|
40
|
+
from .. import DEF_XAXIS, DEF_KV, DEF_ZONE, DEF_CL, \
|
|
41
|
+
SIMC, EMC
|
|
42
|
+
|
|
43
|
+
from .. import DPError
|
|
44
|
+
|
|
45
|
+
DPDB_EXT = 'bin'
|
|
46
|
+
MAX_DPDBFN = 256
|
|
47
|
+
DEF_VERTMAT = [[0,0,1],[1,1,1],[0,1,1]]
|
|
48
|
+
|
|
49
|
+
def _getDPDBFN(self):
|
|
50
|
+
'''
|
|
51
|
+
Constructs a bloch image output file name.
|
|
52
|
+
|
|
53
|
+
Refer to :ref:`Environment Variables <Environment Variables>`
|
|
54
|
+
for how this file name is constructed.
|
|
55
|
+
|
|
56
|
+
'''
|
|
57
|
+
|
|
58
|
+
from ..fileutils import compose_ofn
|
|
59
|
+
|
|
60
|
+
cfn = compose_ofn(None, self.name, ty='dpdb')
|
|
61
|
+
|
|
62
|
+
l = len(cfn)
|
|
63
|
+
if l > MAX_DPDBFN:
|
|
64
|
+
raise DPError('Diffraction database file name must not excced 256')
|
|
65
|
+
|
|
66
|
+
return cfn
|
|
67
|
+
|
|
68
|
+
def generateDPDB(self, emc = EMC(),
|
|
69
|
+
xa = DEF_XAXIS,
|
|
70
|
+
res = LOW_RES,
|
|
71
|
+
vertices = DEF_VERTMAT
|
|
72
|
+
):
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
Generate a list diffraction patterns and save them in proprietory
|
|
76
|
+
binary formatted database file with extension .bin.
|
|
77
|
+
|
|
78
|
+
The database created will be used for diffraction pattern indexing
|
|
79
|
+
and matchig functions in pyemaps STEM4D module.
|
|
80
|
+
|
|
81
|
+
The generated database file is saved to directory pointed by environment variable
|
|
82
|
+
*PYEMAPS_DATA* or in current working directory if *PYEMAPS_DATA* is not set.
|
|
83
|
+
|
|
84
|
+
:param emc: Control parameters
|
|
85
|
+
:type emc: EMControls, optional
|
|
86
|
+
|
|
87
|
+
:param xa: x-axis, optional
|
|
88
|
+
:type xa: three integer tuple.
|
|
89
|
+
|
|
90
|
+
:param res: resolution of stereo projection map, ranging from *LOW_RES*=100 to *HIGH_RES*=300 that is
|
|
91
|
+
the number of sampling points along the radius. The higher the resolution, the more
|
|
92
|
+
diffraction patterns are generated in the database file.
|
|
93
|
+
|
|
94
|
+
:type res: integer, defaults to 100, optional.
|
|
95
|
+
|
|
96
|
+
:param vertices: an array of 3 or 4 zone axis indexes that form an enclosed orientation
|
|
97
|
+
surface area within which the diffraction patterns are generated. See the following
|
|
98
|
+
graphic illustration of the vertices input.
|
|
99
|
+
|
|
100
|
+
:type vertices: three integer tuple, optional
|
|
101
|
+
|
|
102
|
+
:return: a tuple of a status code and database file name
|
|
103
|
+
:rtype: tuple of an integer and a string
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
Input zone axis indexes define the vertices of the stereo projection map. The default
|
|
107
|
+
for a cubic crystal is *DEF_VERTMAT* = [[0,0,1],[1,1,1],[0,1,1]].
|
|
108
|
+
|
|
109
|
+
.. image:: https://github.com/emlab-solutions/imagepypy/raw/main/stereoprojectionmap.png
|
|
110
|
+
:width: 75%
|
|
111
|
+
:align: center
|
|
112
|
+
|
|
113
|
+
The diffraction patterns database file produced will be consumed by pyemaps stem4d module
|
|
114
|
+
for experimental diffraction pattern serach and indexing.
|
|
115
|
+
|
|
116
|
+
"""
|
|
117
|
+
import os
|
|
118
|
+
|
|
119
|
+
if (res > HIGH_RES) or (res < LOW_RES):
|
|
120
|
+
print(f'Resolution input {res} is out of range: ({LOW_RES}, {HIGH_RES})')
|
|
121
|
+
return -1, None
|
|
122
|
+
|
|
123
|
+
self.load()
|
|
124
|
+
dif.initcontrols()
|
|
125
|
+
|
|
126
|
+
vt = emc.vt
|
|
127
|
+
zone = emc.zone
|
|
128
|
+
emc(xaxis=xa)
|
|
129
|
+
simc = emc.simc
|
|
130
|
+
|
|
131
|
+
if vt != DEF_KV:
|
|
132
|
+
dif.setemcontrols(DEF_CL, vt)
|
|
133
|
+
|
|
134
|
+
if zone != DEF_ZONE:
|
|
135
|
+
dif.setzone(zone[0], zone[1], zone[2])
|
|
136
|
+
|
|
137
|
+
if xa != DEF_XAXIS:
|
|
138
|
+
dif.set_xaxis(1, xa[0], xa[1], xa[2])
|
|
139
|
+
|
|
140
|
+
self.set_sim_controls(simc=simc)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# TODO: need to replace hard code of 2 here later
|
|
144
|
+
ret = dif.diffract(2)
|
|
145
|
+
|
|
146
|
+
if ret == 0:
|
|
147
|
+
print('Error running dif module')
|
|
148
|
+
return -1, None
|
|
149
|
+
vert = np.array(vertices).transpose()
|
|
150
|
+
vertices = farray(vert, dtype=int)
|
|
151
|
+
|
|
152
|
+
output_fn = self._getDPDBFN()
|
|
153
|
+
|
|
154
|
+
final_fp= output_fn+'.' + DPDB_EXT
|
|
155
|
+
|
|
156
|
+
ret = dpgen.do_dpgen(res, vertices, output_fn)
|
|
157
|
+
|
|
158
|
+
#release the memory
|
|
159
|
+
dpgen.cleanup()
|
|
160
|
+
|
|
161
|
+
if ret != 0:
|
|
162
|
+
print(f'Error generating diffraction patterns for {self.name}')
|
|
163
|
+
return -1, final_fp
|
|
164
|
+
|
|
165
|
+
print('*******************************************************************************')
|
|
166
|
+
print(f'* The diffraction pattern database for {self.name} has been generated successfully')
|
|
167
|
+
print(f'* and saved in:')
|
|
168
|
+
print(f'* {final_fp}')
|
|
169
|
+
print('*******************************************************************************')
|
|
170
|
+
return 0, final_fp
|
|
171
|
+
|
|
172
|
+
target.generateDPDB = generateDPDB
|
|
173
|
+
target._getDPDBFN = _getDPDBFN
|
|
174
|
+
|
|
175
|
+
return target
|