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.
Files changed (112) hide show
  1. pyemaps/COPYING +798 -0
  2. pyemaps/CifFile/CifFile_module.py +3117 -0
  3. pyemaps/CifFile/StarFile.py +2496 -0
  4. pyemaps/CifFile/TypeContentsParser.py +82 -0
  5. pyemaps/CifFile/YappsStarParser_1_0.py +289 -0
  6. pyemaps/CifFile/YappsStarParser_1_1.py +288 -0
  7. pyemaps/CifFile/YappsStarParser_2_0.py +369 -0
  8. pyemaps/CifFile/YappsStarParser_STAR2.py +382 -0
  9. pyemaps/CifFile/__init__.py +7 -0
  10. pyemaps/CifFile/drel/__init__.py +1 -0
  11. pyemaps/CifFile/drel/drel_ast_yacc.py +582 -0
  12. pyemaps/CifFile/drel/drel_lex.py +228 -0
  13. pyemaps/CifFile/drel/drel_runtime.py +126 -0
  14. pyemaps/CifFile/drel/parsetab.py +185 -0
  15. pyemaps/CifFile/drel/py_from_ast.py +628 -0
  16. pyemaps/CifFile/parsetab.py +185 -0
  17. pyemaps/CifFile/yapps3_compiled_rt.py +390 -0
  18. pyemaps/README.md +201 -0
  19. pyemaps/__config__.py +91 -0
  20. pyemaps/__init__.py +233 -0
  21. pyemaps/__main__.py +219 -0
  22. pyemaps/__version__.py +1 -0
  23. pyemaps/cdata/Aluminium.xtl +4 -0
  24. pyemaps/cdata/AluminiumOxide.xtl +5 -0
  25. pyemaps/cdata/Aluminium_FCC.xtl +4 -0
  26. pyemaps/cdata/BariumTitanate_180k.xtl +6 -0
  27. pyemaps/cdata/BariumTitanate_270k.xtl +7 -0
  28. pyemaps/cdata/BariumTitanate_Tetra.xtl +7 -0
  29. pyemaps/cdata/BiMnO3.xtl +27 -0
  30. pyemaps/cdata/Boron_Tetra.xtl +8 -0
  31. pyemaps/cdata/CadmiumSelenide_Hex.xtl +5 -0
  32. pyemaps/cdata/CadmiumSulfide_Cubic.xtl +5 -0
  33. pyemaps/cdata/CadmiumSulfide_Hex.xtl +5 -0
  34. pyemaps/cdata/Chromium_BCC.xtl +4 -0
  35. pyemaps/cdata/CoSb3_Skutterudite.xtl +5 -0
  36. pyemaps/cdata/CopperOxide.xtl +5 -0
  37. pyemaps/cdata/Copper_FCC.xtl +4 -0
  38. pyemaps/cdata/Cu2O_Cuprite.xtl +5 -0
  39. pyemaps/cdata/Diamond.xtl +4 -0
  40. pyemaps/cdata/ErbiumPyrogermanate.xtl +9 -0
  41. pyemaps/cdata/FePd_Tetra.xtl +5 -0
  42. pyemaps/cdata/FeS2_Pyrite.xtl +15 -0
  43. pyemaps/cdata/GalliumAntimonide.xtl +5 -0
  44. pyemaps/cdata/GalliumArsenide.xtl +5 -0
  45. pyemaps/cdata/GalliumNitride.xtl +5 -0
  46. pyemaps/cdata/Germanium.xtl +4 -0
  47. pyemaps/cdata/Gold_FCC.xtl +4 -0
  48. pyemaps/cdata/IndiumArsenide.xtl +5 -0
  49. pyemaps/cdata/LaMnO3.xtl +7 -0
  50. pyemaps/cdata/LeadZirconateTitanate.xtl +8 -0
  51. pyemaps/cdata/Li2MnO3.xtl +13 -0
  52. pyemaps/cdata/NaFeO2.xtl +6 -0
  53. pyemaps/cdata/Nb3Sn.xtl +5 -0
  54. pyemaps/cdata/Pentacene.xtl +39 -0
  55. pyemaps/cdata/Silicon.xtl +4 -0
  56. pyemaps/cdata/StrontiumTitanate.xtl +6 -0
  57. pyemaps/cdata/TelluriumDioxide.xtl +5 -0
  58. pyemaps/cdata/TinDioxide_RT.xtl +5 -0
  59. pyemaps/cdata/TitaniumDioxide_Anatase.xtl +5 -0
  60. pyemaps/cdata/TitaniumDioxide_Rutile.xtl +5 -0
  61. pyemaps/cdata/TungstenDiselenide.xtl +5 -0
  62. pyemaps/cdata/VanadiumDioxide_RT.xtl +6 -0
  63. pyemaps/cdata/ZincOxide.xtl +5 -0
  64. pyemaps/cdata/Zinc_HCP.xtl +4 -0
  65. pyemaps/cdata/ZirconiumNitride.xtl +5 -0
  66. pyemaps/cdata/limno2.xtl +6 -0
  67. pyemaps/crystals.py +1415 -0
  68. pyemaps/ddiffs.py +147 -0
  69. pyemaps/diffract/__init__.py +70 -0
  70. pyemaps/diffract/bloch_dec.py +779 -0
  71. pyemaps/diffract/csf_dec.py +242 -0
  72. pyemaps/diffract/dif_dec.py +519 -0
  73. pyemaps/diffract/dpgen_dec.py +175 -0
  74. pyemaps/diffract/mxtal_dec.py +201 -0
  75. pyemaps/diffract/powder_dec.py +137 -0
  76. pyemaps/diffract/stereo_dec.py +111 -0
  77. pyemaps/display.py +791 -0
  78. pyemaps/emcontrols.py +1017 -0
  79. pyemaps/errors.py +266 -0
  80. pyemaps/fileutils.py +1001 -0
  81. pyemaps/kdiffs.py +1221 -0
  82. pyemaps/license.txt +42 -0
  83. pyemaps/samples/adf.py +137 -0
  84. pyemaps/samples/al.img +0 -0
  85. pyemaps/samples/al_dpgen.py +57 -0
  86. pyemaps/samples/al_ediom.py +94 -0
  87. pyemaps/samples/convert_image.py +88 -0
  88. pyemaps/samples/dm_diff.py +225 -0
  89. pyemaps/samples/mask.im3 +0 -0
  90. pyemaps/samples/powder.py +51 -0
  91. pyemaps/samples/raw.img +0 -0
  92. pyemaps/samples/si_bloch.py +120 -0
  93. pyemaps/samples/si_constructor.py +51 -0
  94. pyemaps/samples/si_csf.py +59 -0
  95. pyemaps/samples/si_dif.py +134 -0
  96. pyemaps/samples/si_lacbed.py +59 -0
  97. pyemaps/samples/si_pyemaps.py +80 -0
  98. pyemaps/samples/si_scm.py +156 -0
  99. pyemaps/samples/si_stereo.py +116 -0
  100. pyemaps/scattering/__init__.py +26 -0
  101. pyemaps/scattering/sct_dec.py +31 -0
  102. pyemaps/spg/__init__.py +25 -0
  103. pyemaps/spg/spg_dec.py +60 -0
  104. pyemaps/stackimg.py +1031 -0
  105. pyemaps/xtal.py +222 -0
  106. pyemaps-2.0.0.dist-info/METADATA +231 -0
  107. pyemaps-2.0.0.dist-info/RECORD +112 -0
  108. pyemaps-2.0.0.dist-info/WHEEL +5 -0
  109. pyemaps-2.0.0.dist-info/entry_points.txt +2 -0
  110. pyemaps-2.0.0.dist-info/licenses/COPYING +798 -0
  111. pyemaps-2.0.0.dist-info/licenses/license.txt +42 -0
  112. pyemaps-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,390 @@
1
+ #
2
+ # Yapps 2 Runtime, part of Yapps 2 - yet another python parser system
3
+ # Copyright 1999-2003 by Amit J. Patel <amitp@cs.stanford.edu>
4
+ #
5
+ # This version of the Yapps 2 Runtime can be distributed under the
6
+ # terms of the MIT open source license, either found in the LICENSE file
7
+ # included with the Yapps distribution
8
+ # <http://theory.stanford.edu/~amitp/yapps/> or at
9
+ # <http://www.opensource.org/licenses/mit-license.php>
10
+ #
11
+ # Modified for PyCIFRW by JRH to allow external scanner
12
+ #
13
+ # To maximize python3/python2 compatibility
14
+ from __future__ import print_function
15
+ from __future__ import unicode_literals
16
+ from __future__ import division
17
+ from __future__ import absolute_import
18
+
19
+ """ Detail of JRH modifications.
20
+
21
+ The compiled module handles all token administration by itself, but
22
+ does not deal with restrictions. It also effectively removes the
23
+ context-sensitivity of Yapps, as it ignores restrictions, but
24
+ these restrictions turn out to be unnecessary for CIF.
25
+
26
+ Interestingly, the module scan function is never called directly
27
+ from python.
28
+
29
+ """
30
+
31
+ """Run time libraries needed to run parsers generated by Yapps.
32
+
33
+ This module defines parse-time exception classes, a scanner class, a
34
+ base class for parsers produced by Yapps, and a context class that
35
+ keeps track of the parse stack.
36
+
37
+ """
38
+
39
+ # TODO: it should be possible to embed yappsrt into the generated
40
+ # grammar to make a standalone module.
41
+
42
+ import sys, re
43
+
44
+
45
+ # For normal installation this module is "emapsCifFile.yapps3_compiled_rt"
46
+ # and StarScan is an extension module within the parent CifFile module.
47
+ if __name__.startswith('pyemaps.CifFile.'):
48
+ try:
49
+ from . import StarScan
50
+ have_star_scan = True
51
+ except ImportError:
52
+ have_star_scan = False
53
+ # Otherwise assume this is imported from the yapps3/yapps2.py script
54
+ # that is executed from Makefile to generate YappsStarParser sources.
55
+ else:
56
+ assert __name__ == 'yapps3_compiled_rt', "Unexpected module name."
57
+ assert sys.argv[0].endswith('yapps2.py'), (
58
+ "This should be reached only when running yapps2.py in Makefile.")
59
+ have_star_scan = False
60
+
61
+ class YappsSyntaxError(Exception):
62
+ """When we run into an unexpected token, this is the exception to use"""
63
+ def __init__(self, charpos=-1, msg="Bad Token", context=None):
64
+ Exception.__init__(self)
65
+ self.charpos = charpos
66
+ self.msg = msg
67
+ self.context = context
68
+
69
+ def __str__(self):
70
+ if self.charpos < 0: return 'SyntaxError'
71
+ else: return 'SyntaxError@char%s(%s)' % (repr(self.charpos), self.msg)
72
+
73
+ class NoMoreTokens(Exception):
74
+ """Another exception object, for when we run out of tokens"""
75
+ pass
76
+
77
+ class Scanner:
78
+ """Yapps scanner.
79
+
80
+ The Yapps scanner can work in context sensitive or context
81
+ insensitive modes. The token(i) method is used to retrieve the
82
+ i-th token. It takes a restrict set that limits the set of tokens
83
+ it is allowed to return. In context sensitive mode, this restrict
84
+ set guides the scanner. In context insensitive mode, there is no
85
+ restriction (the set is always the full set of tokens).
86
+
87
+ """
88
+
89
+ def __init__(self, patterns, ignore, input, scantype="standard"):
90
+ """Initialize the scanner.
91
+
92
+ Parameters:
93
+ patterns : [(terminal, uncompiled regex), ...] or None
94
+ ignore : [terminal,...]
95
+ input : string
96
+
97
+ If patterns is None, we assume that the subclass has
98
+ defined self.patterns : [(terminal, compiled regex), ...].
99
+ Note that the patterns parameter expects uncompiled regexes,
100
+ whereas the self.patterns field expects compiled regexes.
101
+ """
102
+ self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...]
103
+ self.restrictions = []
104
+ self.input = input
105
+ self.pos = 0
106
+ self.ignore = ignore
107
+ self.scantype = scantype
108
+ self.first_line_number = 1
109
+ if self.scantype == "flex" and have_star_scan:
110
+ StarScan.prepare(input)
111
+ self.scan = self.compiled_scan
112
+ self.token = self.compiled_token
113
+ self.__del__ = StarScan.cleanup
114
+ elif self.scantype == "flex":
115
+ print("WARNING: using Python scanner although C scanner requested")
116
+ self.scantype = "standard"
117
+ if self.scantype != "flex":
118
+ self.scan = self.interp_scan
119
+ self.token = self.interp_token
120
+
121
+ if patterns is not None:
122
+ # Compile the regex strings into regex objects
123
+ self.patterns = []
124
+ for terminal, regex in patterns:
125
+ self.patterns.append( (terminal, re.compile(regex)) )
126
+
127
+ def get_token_pos(self):
128
+ """Get the current token position in the input text."""
129
+ return len(self.tokens)
130
+
131
+ def get_char_pos(self):
132
+ """Get the current char position in the input text."""
133
+ return self.pos
134
+
135
+ def get_prev_char_pos(self, i=None):
136
+ """Get the previous position (one token back) in the input text."""
137
+ if self.pos == 0: return 0
138
+ if i is None: i = -1
139
+ return self.tokens[i][0]
140
+
141
+ def get_line_number(self):
142
+ """Get the line number of the current position in the input text."""
143
+ # TODO: make this work at any token/char position
144
+ return self.first_line_number + self.get_input_scanned().count('\n')
145
+
146
+ def get_column_number(self):
147
+ """Get the column number of the current position in the input text."""
148
+ s = self.get_input_scanned()
149
+ i = s.rfind('\n') # may be -1, but that's okay in this case
150
+ return len(s) - (i+1)
151
+
152
+ def get_input_scanned(self):
153
+ """Get the portion of the input that has been tokenized."""
154
+ return self.input[:self.pos]
155
+
156
+ def get_input_unscanned(self):
157
+ """Get the portion of the input that has not yet been tokenized."""
158
+ return self.input[self.pos:]
159
+
160
+ def interp_token(self, i, restrict=None):
161
+ """Get the i'th token in the input.
162
+
163
+ If i is one past the end, then scan for another token.
164
+
165
+ Args:
166
+
167
+ restrict : [token, ...] or None; if restrict is None, then any
168
+ token is allowed. You may call token(i) more than once.
169
+ However, the restrict set may never be larger than what was
170
+ passed in on the first call to token(i).
171
+
172
+ """
173
+ if i == len(self.tokens):
174
+ self.scan(restrict)
175
+ if i < len(self.tokens):
176
+ # Make sure the restriction is more restricted. This
177
+ # invariant is needed to avoid ruining tokenization at
178
+ # position i+1 and higher.
179
+ if restrict and self.restrictions[i]:
180
+ for r in restrict:
181
+ if r not in self.restrictions[i]:
182
+ raise NotImplementedError("Unimplemented: restriction set changed")
183
+ return self.tokens[i]
184
+ raise NoMoreTokens()
185
+
186
+ def compiled_token(self,i,restrict=0):
187
+ try:
188
+ return StarScan.token(i)
189
+ except IndexError:
190
+ raise NoMoreTokens()
191
+
192
+ def __repr__(self):
193
+ """Print the last 10 tokens that have been scanned in"""
194
+ output = ''
195
+ if self.scantype != "flex":
196
+ for t in self.tokens[-10:]:
197
+ output = '%s\n (@%s) %s = %s' % (output,t[0],t[2],repr(t[3]))
198
+ else:
199
+ out_tokens = StarScan.last_ten()
200
+ for t in out_tokens:
201
+ output = '%s\n (~line %s) %s = %s' % (output,t[0],t[2],repr(t[3]))
202
+ return output
203
+
204
+ def interp_scan(self, restrict):
205
+ """Should scan another token and add it to the list, self.tokens,
206
+ and add the restriction to self.restrictions"""
207
+ # Prepare accepted pattern list
208
+ if restrict:
209
+ # only patterns in the 'restrict' parameter or in self.ignore
210
+ # are accepted
211
+ accepted_patterns=[]
212
+ for p_name, p_regexp in self.patterns:
213
+ if p_name not in restrict and p_name not in self.ignore:
214
+ pass
215
+ else:
216
+ accepted_patterns.append((p_name,p_regexp))
217
+ else:
218
+ # every pattern is good
219
+ accepted_patterns=self.patterns
220
+ # Keep looking for a token, ignoring any in self.ignore
221
+ while 1:
222
+ # Search the patterns for the longest match, with earlier
223
+ # tokens in the list having preference
224
+ best_match = -1
225
+ best_pat = '(error)'
226
+ for p,regexp in accepted_patterns:
227
+ m = regexp.match(self.input, self.pos)
228
+ if m and len(m.group(0)) > best_match:
229
+ # We got a match that's better than the previous one
230
+ best_pat = p
231
+ best_match = len(m.group(0))
232
+
233
+ # If we didn't find anything, raise an error
234
+ if best_pat == '(error)' and best_match < 0:
235
+ msg = 'Bad Token'
236
+ if restrict:
237
+ msg = 'Trying to find one of '+', '.join(restrict)
238
+ raise YappsSyntaxError(self.pos, msg)
239
+
240
+ # If we found something that isn't to be ignored, return it
241
+ if best_pat not in self.ignore:
242
+ # Create a token with this data
243
+ token = (self.pos, self.pos+best_match, best_pat,
244
+ self.input[self.pos:self.pos+best_match])
245
+ self.pos = self.pos + best_match
246
+ # Only add this token if it's not in the list
247
+ # (to prevent looping)
248
+ if not self.tokens or token != self.tokens[-1]:
249
+ self.tokens.append(token)
250
+ self.restrictions.append(restrict)
251
+ return
252
+ else:
253
+ # This token should be ignored ..
254
+ self.pos = self.pos + best_match
255
+
256
+ def compiled_scan(self,restrict):
257
+ token = StarScan.scan()
258
+ print("Calling compiled scan, got %s" % repr(token))
259
+ if token[2] not in restrict:
260
+ msg = "Bad Token"
261
+ if restrict:
262
+ msg = "Trying to find one of " + ", ".join(restrict)
263
+ raise YappsSyntaxError(self.pos,msg)
264
+ self.tokens.append(token)
265
+ self.restrictions.append(restrict)
266
+ return
267
+
268
+ class Parser:
269
+ """Base class for Yapps-generated parsers.
270
+
271
+ """
272
+
273
+ def __init__(self, scanner):
274
+ self._scanner = scanner
275
+ self._pos = 0
276
+
277
+ def _peek(self, *types):
278
+ """Returns the token type for lookahead; if there are any args
279
+ then the list of args is the set of token types to allow"""
280
+ tok = self._scanner.token(self._pos, types)
281
+ return tok[2]
282
+
283
+ def _scan(self, type):
284
+ """Returns the matched text, and moves to the next token"""
285
+ tok = self._scanner.token(self._pos, [type])
286
+ if tok[2] != type:
287
+ raise YappsSyntaxError(tok[0], 'Trying to find '+type+' :'+ ' ,')
288
+ self._pos = 1 + self._pos
289
+ return tok[3]
290
+
291
+ class Context:
292
+ """Class to represent the parser's call stack.
293
+
294
+ Every rule creates a Context that links to its parent rule. The
295
+ contexts can be used for debugging.
296
+
297
+ """
298
+
299
+ def __init__(self, parent, scanner, tokenpos, rule, args=()):
300
+ """Create a new context.
301
+
302
+ Args:
303
+ parent: Context object or None
304
+ scanner: Scanner object
305
+ pos: integer (scanner token position)
306
+ rule: string (name of the rule)
307
+ args: tuple listing parameters to the rule
308
+
309
+ """
310
+ self.parent = parent
311
+ self.scanner = scanner
312
+ self.tokenpos = tokenpos
313
+ self.rule = rule
314
+ self.args = args
315
+
316
+ def __str__(self):
317
+ output = ''
318
+ if self.parent: output = str(self.parent) + ' > '
319
+ output += self.rule
320
+ return output
321
+
322
+ #
323
+ # Note that this sort of error printout is useless with the
324
+ # compiled scanner
325
+ #
326
+
327
+ def print_line_with_pointer(text, p):
328
+ """Print the line of 'text' that includes position 'p',
329
+ along with a second line with a single caret (^) at position p"""
330
+
331
+ # TODO: separate out the logic for determining the line/character
332
+ # location from the logic for determining how to display an
333
+ # 80-column line to stderr.
334
+
335
+ # Now try printing part of the line
336
+ text = text[max(p-80, 0):p+80]
337
+ p = p - max(p-80, 0)
338
+
339
+ # Strip to the left
340
+ i = text[:p].rfind('\n')
341
+ j = text[:p].rfind('\r')
342
+ if i < 0 or (0 <= j < i): i = j
343
+ if 0 <= i < p:
344
+ p = p - i - 1
345
+ text = text[i+1:]
346
+
347
+ # Strip to the right
348
+ i = text.find('\n', p)
349
+ j = text.find('\r', p)
350
+ if i < 0 or (0 <= j < i): i = j
351
+ if i >= 0:
352
+ text = text[:i]
353
+
354
+ # Now shorten the text
355
+ while len(text) > 70 and p > 60:
356
+ # Cut off 10 chars
357
+ text = "..." + text[10:]
358
+ p = p - 7
359
+
360
+ # Now print the string, along with an indicator
361
+ print('> ',text,file=sys.stderr)
362
+ print('> ',' '*p + '^',file=sys.stderr)
363
+
364
+ def print_error(input, err, scanner):
365
+ """Print error messages, the parser stack, and the input text -- for human-readable error messages."""
366
+ # NOTE: this function assumes 80 columns :-(
367
+ # Figure out the line number
368
+ line_number = scanner.get_line_number()
369
+ column_number = scanner.get_column_number()
370
+ print('%d:%d: %s' % (line_number, column_number, err.msg),file=sys.stderr)
371
+
372
+ context = err.context
373
+ if not context:
374
+ print_line_with_pointer(input, err.charpos)
375
+
376
+ while context:
377
+ # TODO: add line number
378
+ print('while parsing %s%s:' % (context.rule, tuple(context.args)),file=sys.stderr)
379
+ print_line_with_pointer(input, context.scanner.get_prev_char_pos(context.tokenpos))
380
+ context = context.parent
381
+
382
+ def wrap_error_reporter(parser, rule):
383
+ try:
384
+ return getattr(parser, rule)()
385
+ except YappsSyntaxError as e:
386
+ input = parser._scanner.input
387
+ print_error(input, e, parser._scanner)
388
+ except NoMoreTokens:
389
+ print('Could not complete parsing; stopped around here:',file=sys.stderr)
390
+ print(parser._scanner,file=sys.stderr)
pyemaps/README.md ADDED
@@ -0,0 +1,201 @@
1
+ <!-- # Open Source __pyEMAPS__ Development Guidelines -->
2
+
3
+ 1. <a id="contents"></a>[What's in pyEMAPS](#overview)
4
+ 2. <a id="contents"></a>[Build pyEMAPS](#build)
5
+ 3. <a id="contents"></a>[Installation](#installation)
6
+ 4. <a id="contents"></a>[Testing](#test)
7
+ 5. <a id="contents"></a>[Development Guidelines](#process)
8
+ 5. <a id="contents"></a>[pyEMAPS Contributor License Agreement](#CLA)
9
+ 5. <a id="contents"></a>[Code of Conduct](#COC)
10
+
11
+ ## What's in pyEMAPS [`↩`](#contents) <a id="overview"></a>
12
+ **pyEMAPS** package is a collection of python modules and libraries designed
13
+ for transmission electron diffraction simulations and crystallographic calculations
14
+ for all crystal systems. The simulation is based on the theories of kinematical and
15
+ dynamical electron diffraction, as described by Spence and Zuo in the book of Electron Microdiffraction (Plenum, New York, 1992).
16
+
17
+ The base version is free for personal and commercial use, while additional licensed features in 4DSTEM are available for enhanced functionality.
18
+
19
+ ### Features:
20
+ Free base features:
21
+ - Crystallography
22
+ - Crystal constructor
23
+ - Loading from a built-in crystal library
24
+ - CIF import
25
+ - Crystallographic transformations
26
+ - Real and reciprocal vector calculations
27
+ - Stereodiagram plotting
28
+ - Crystal Structure Factors Calculations
29
+
30
+ - Electron diffraction pattern, dynamical
31
+ - Convergent beam electron diffraction
32
+ - Electron scattering Matrix
33
+ - Electron dispersion
34
+
35
+ - Electron diffraction pattern, kinematical
36
+ - Selected area diffraction
37
+ - Kikuchi and high order Laue zone line geometry
38
+ - Convergent beam electron diffraction
39
+ - Electron powder diffraction simulations
40
+
41
+ **Extended features** (requires license):
42
+ - Electron diffraction patterns database builder and explore
43
+ - Electron diffraction pattern indexing
44
+ - Annular bright and dark field
45
+ - Masked images
46
+
47
+ Check our full [pyemaps documentation](https://emlab-solutions.github.io/pyemaps) for details of __pyEMAPS__ python classes designs and their interfaces.
48
+
49
+ We are looking for experts in electron microscope and crystallography, and/or python enthusiasts to join pyEMAPS project as contributors, please contact us at support@emlabsoftware.com if you are interested.
50
+
51
+ We greatly appreciate your contributions to pyEMAPS and look forward to making it a tool for the communty to accelaerate microscopy and crystallography education and research. If you benefit from __pyEMAPS__ in your microscopy and crystallography research and education, go to [PayPal](https://www.paypal.com/paypalme/pyemaps22) to donate. Your generous donations keep us in the business of providing software tools to the education and research communities.
52
+
53
+ See instructions below for contributor:
54
+
55
+ ## Build pyEMAPS [`↩`](#content) <a id="build"></a>
56
+
57
+ Requirements and recommendations:
58
+ * __Python__: Version 3.12, 3.13, 3.14 or 3.15
59
+ * __Operating Systems__: Windows
60
+ * __VSCode__: code editing (recommended, for contributors only)
61
+
62
+ Building __pyEMAPS__ itself needs no compiler, because it is pure Python. Its compiled backend, __emaps__, supports Windows with Python 3.12 to 3.15, so __pyEMAPS__ does too. pyEMAPS 1.1.x remains available for Python 3.7. We are also looking for contributors to extend it to other platforms.
63
+
64
+ Like many python development, a virtual python environment is recommended to isolate your pyEMAPS development environment from your other python development projects.
65
+
66
+ Below are steps to establish __pyEMAPS__ build environment with python 3.12 as an example:
67
+
68
+ * Download the Python 3.12 Windows installer (64-bit) from [python.org](https://www.python.org/downloads/windows/).
69
+ * Run the installer, choose the following in installer GUI:
70
+
71
+ * Select Customize Installation
72
+ * Check and select pip
73
+ * Install for all users/specific users
74
+ * Create a virtual environment called "pyemaps_build" for the build
75
+ * Create a dev directory:
76
+ ```
77
+ mkdir pyemaps-dev
78
+ ```
79
+ (or choose your own directory name)
80
+ * Create pyemaps_build virtual environemnt:
81
+ ```
82
+ py -3.12 -m venv pyemaps_build
83
+ ```
84
+ * Activate pyemaps_build vitual environment:
85
+ ```
86
+ .\pyemaps_build\Scripts\activate
87
+ ```
88
+ * Update pip:
89
+ ```
90
+ python -m pip install pip --upgrade
91
+ ```
92
+ * Install other python packages required for building pyemaps, using pip:
93
+ ```
94
+ pip install setuptools wheel build
95
+ ```
96
+ * Build directory structure:
97
+
98
+ <pre>
99
+ 📦pyemaps
100
+ ┣━ 📂.git <----Source repository configurations
101
+ ┣━ 📂build <----Intermediate build folder
102
+ ┣━ 📂dist <----Build package files
103
+ ┣━ 📂cdata <----Built-in crystal data in proprietory format
104
+ ┣━ 📂CifFile <----CIF crystal data reader
105
+ ┣━ 📂diffract <----Diffraction modules python interfaces
106
+ ┣━ 📂docs <----Documentation using Sphinx. Document your changes!
107
+ ┣━ 📂samples <----Sample code. Offical sample code for guiding pyemaps usages
108
+ ┣━ 📂scattering <----Scattering data module
109
+ ┣━ 📂spg <----Space group data module
110
+ ┗━ 📂test <----Test cases including sanity, unit and stree tests. Keep adding them!
111
+ </pre>
112
+ where _docs_ for creation of documents requires Sphinx python package:
113
+ - Sphinx for documentation can be installed:
114
+ ```
115
+ pip install Sphinx=5.3.0
116
+ ```
117
+
118
+ * Build pyEMAPS package, run:
119
+ ```
120
+ python build_pyemaps -t -v 1.0.0
121
+ ```
122
+ Here the option "-t" indicates build is for local testing purposes.
123
+ You can replace the version number '1.0.0' with the one you desire.
124
+
125
+ When the option _-v_ is not specified. The build script will figure out the version
126
+ from pypi.org repository.
127
+
128
+ Note: there will be two additional diretcories:
129
+ - _build_. folder holding intermediate build files.
130
+ - _dist_. folder for final package that includes .whl and .tgz. The former is the package file and the latter is the current source code used to build the pacage in compressed format.
131
+
132
+ ## Installation [`↩`](#contents) <a id="installation"></a>
133
+
134
+ * Install the new pyEMAPS package:
135
+ ```
136
+ pip install .\dist\pyemaps-1.0.0-py3-none-any.whl
137
+ ```
138
+ This will install new pyEMAPS just built in current python virtual environment
139
+ along with all of its dependent packages.
140
+
141
+ If you have a previous _pyemaps_ with versiual or larger than current package version.
142
+ In that case, you need to uninstall previous version before installing the new package:
143
+ ```
144
+ pip uninstall pyemaps
145
+ ```
146
+
147
+ ## Testing [`↩`](#contents) <a id="test"></a>
148
+
149
+ Current pyEMAPS development comes with a set of basic testing suites, including
150
+ * sanity checks
151
+ * unit tests
152
+ * stress tests.
153
+
154
+ To run these test suites, call:
155
+ ```
156
+ .\test\sanity\sanity.bat
157
+ ```
158
+ We are looking for your tests contributions to make the development to keep high quality standards for _pyEMAPS_.
159
+
160
+ ## Development Guidelines [`↩`](#contents) <a id="process"></a>
161
+
162
+ As any open source development project, we strongly recommend contributors to adhere to the following guidelines:
163
+
164
+ * __Issues creation__. Before making changes for bug fix or feature implementation, create an issue in the pyEMAPS' repository. Your concise description of the issue(s) serves well not only in laying good foundations for your design and implementations, but also in communicating to your fellow contributors.
165
+
166
+ * __Development Branch__. Create your own branch from 'main' where you work on your changes. The main branch is kept as production base.
167
+
168
+ * __Backwards Compatibilities Tests__. Existing test suites designed for testing most of the features are to ensure that no existing implementations are unintentionally broken after new changes are introduced.
169
+
170
+ * __New Tests Additions__. Writing new test cases for the new implementations are strongly encouraged.
171
+
172
+ * __Pull Requests__. Before merging your changes into production branch "main", a pull request is required. The request should also accompany a list of code reviewers from the contributors.
173
+
174
+ * __Code Review__. We took code review seriously, whether you are reviewing code or your code is being reviewed. This process provides important step of making sound implementations and preventing new bugs.
175
+
176
+ * __Documentation__. You are the author of the new implementations, so please take the pride by documenting them!
177
+ We use sphinx tool for documentation generation. To install sphinx, run:
178
+ ```
179
+ pip install -U sphinx
180
+ ```
181
+ in your python build virtual environment (pyemaps_build in our example).
182
+
183
+ Most of the documentations files are in "docs" directory. After making documentation changes to record your changes, compile them with sphinx:
184
+ ```
185
+ sphinx-build -b html source .
186
+ ```
187
+ The changes resulted from the above can be previewed by opening index.html with avaliable browser.
188
+
189
+ ## pyEMAPS Contributor License Agreement [`↩`](#contents) <a id="CLA"></a>
190
+
191
+ Please read and agree to our [Contributor License Agreement](CONTRIBUTING.md) before contributing to this project.
192
+
193
+ ## Code of Conduct [`↩`](#contents) <a id="COC"></a>
194
+
195
+ pyEMAPS is committed to providing a welcoming and inclusive environment for all contributors. We follow the [Contributor Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct/) as our code of conduct. Please make sure to review it before contributing.
196
+
197
+ **[Read the Contributor Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct/)**
198
+
199
+ Any instances of unacceptable behavior can be reported to support@emlabsoftware.com.
200
+
201
+
pyemaps/__config__.py ADDED
@@ -0,0 +1,91 @@
1
+ # This file is generated by numpy's setup.py
2
+ # It contains system_info results at the time of building this package.
3
+ __all__ = ["get_info","show"]
4
+
5
+
6
+ import os
7
+ import sys
8
+
9
+ extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs')
10
+
11
+ if sys.platform == 'win32' and os.path.isdir(extra_dll_dir):
12
+ if sys.version_info >= (3, 8):
13
+ os.add_dll_directory(extra_dll_dir)
14
+ else:
15
+ os.environ.setdefault('PATH', '')
16
+ os.environ['PATH'] += os.pathsep + extra_dll_dir
17
+
18
+
19
+ def get_info(name):
20
+ g = globals()
21
+ return g.get(name, g.get(name + "_info", {}))
22
+
23
+ def show():
24
+ """
25
+ Show libraries in the system on which NumPy was built.
26
+
27
+ Print information about various resources (libraries, library
28
+ directories, include directories, etc.) in the system on which
29
+ NumPy was built.
30
+
31
+ See Also
32
+ --------
33
+ get_include : Returns the directory containing NumPy C
34
+ header files.
35
+
36
+ Notes
37
+ -----
38
+ Classes specifying the information to be printed are defined
39
+ in the `numpy.distutils.system_info` module.
40
+
41
+ Information may include:
42
+
43
+ * ``language``: language used to write the libraries (mostly
44
+ C or f77)
45
+ * ``libraries``: names of libraries found in the system
46
+ * ``library_dirs``: directories containing the libraries
47
+ * ``include_dirs``: directories containing library header files
48
+ * ``src_dirs``: directories containing library source files
49
+ * ``define_macros``: preprocessor macros used by
50
+ ``distutils.setup``
51
+ * ``baseline``: minimum CPU features required
52
+ * ``found``: dispatched features supported in the system
53
+ * ``not found``: dispatched features that are not supported
54
+ in the system
55
+
56
+ Examples
57
+ --------
58
+ >>> import numpy as np
59
+ >>> np.show_config()
60
+ blas_opt_info:
61
+ language = c
62
+ define_macros = [('HAVE_CBLAS', None)]
63
+ libraries = ['openblas', 'openblas']
64
+ library_dirs = ['/usr/local/lib']
65
+ """
66
+ from numpy.core._multiarray_umath import (
67
+ __cpu_features__, __cpu_baseline__, __cpu_dispatch__
68
+ )
69
+ for name,info_dict in globals().items():
70
+ if name[0] == "_" or type(info_dict) is not type({}): continue
71
+ print(name + ":")
72
+ if not info_dict:
73
+ print(" NOT AVAILABLE")
74
+ for k,v in info_dict.items():
75
+ v = str(v)
76
+ if k == "sources" and len(v) > 200:
77
+ v = v[:60] + " ...\n... " + v[-60:]
78
+ print(" %s = %s" % (k,v))
79
+
80
+ features_found, features_not_found = [], []
81
+ for feature in __cpu_dispatch__:
82
+ if __cpu_features__[feature]:
83
+ features_found.append(feature)
84
+ else:
85
+ features_not_found.append(feature)
86
+
87
+ print("Supported SIMD extensions in this NumPy install:")
88
+ print(" baseline = %s" % (','.join(__cpu_baseline__)))
89
+ print(" found = %s" % (','.join(features_found)))
90
+ print(" not found = %s" % (','.join(features_not_found)))
91
+