ChessAnalysisPipeline 0.0.2__py3-none-any.whl → 0.0.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 ChessAnalysisPipeline might be problematic. Click here for more details.

Files changed (47) hide show
  1. CHAP/__init__.py +3 -0
  2. CHAP/common/__init__.py +19 -0
  3. CHAP/common/models/__init__.py +2 -0
  4. CHAP/common/models/integration.py +515 -0
  5. CHAP/common/models/map.py +535 -0
  6. CHAP/common/processor.py +644 -0
  7. CHAP/common/reader.py +119 -0
  8. CHAP/common/utils/__init__.py +37 -0
  9. CHAP/common/utils/fit.py +2613 -0
  10. CHAP/common/utils/general.py +1225 -0
  11. CHAP/common/utils/material.py +231 -0
  12. CHAP/common/utils/scanparsers.py +785 -0
  13. CHAP/common/writer.py +96 -0
  14. CHAP/edd/__init__.py +7 -0
  15. CHAP/edd/models.py +215 -0
  16. CHAP/edd/processor.py +321 -0
  17. CHAP/edd/reader.py +5 -0
  18. CHAP/edd/writer.py +5 -0
  19. CHAP/inference/__init__.py +3 -0
  20. CHAP/inference/processor.py +68 -0
  21. CHAP/inference/reader.py +5 -0
  22. CHAP/inference/writer.py +5 -0
  23. CHAP/pipeline.py +1 -1
  24. CHAP/processor.py +11 -818
  25. CHAP/reader.py +18 -113
  26. CHAP/saxswaxs/__init__.py +6 -0
  27. CHAP/saxswaxs/processor.py +5 -0
  28. CHAP/saxswaxs/reader.py +5 -0
  29. CHAP/saxswaxs/writer.py +5 -0
  30. CHAP/sin2psi/__init__.py +7 -0
  31. CHAP/sin2psi/processor.py +5 -0
  32. CHAP/sin2psi/reader.py +5 -0
  33. CHAP/sin2psi/writer.py +5 -0
  34. CHAP/tomo/__init__.py +5 -0
  35. CHAP/tomo/models.py +125 -0
  36. CHAP/tomo/processor.py +2009 -0
  37. CHAP/tomo/reader.py +5 -0
  38. CHAP/tomo/writer.py +5 -0
  39. CHAP/writer.py +17 -167
  40. {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/METADATA +1 -1
  41. ChessAnalysisPipeline-0.0.4.dist-info/RECORD +50 -0
  42. CHAP/async.py +0 -56
  43. ChessAnalysisPipeline-0.0.2.dist-info/RECORD +0 -17
  44. {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/LICENSE +0 -0
  45. {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/WHEEL +0 -0
  46. {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/entry_points.txt +0 -0
  47. {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # -*- coding: utf-8 -*-
4
+ """
5
+ Created on Fri May 27 12:21:25 2022
6
+
7
+ @author: rv43
8
+ """
9
+
10
+ import logging
11
+
12
+ import os
13
+ import numpy as np
14
+ try:
15
+ import xrayutilities as xu
16
+ have_xu = True
17
+ except:
18
+ have_xu = False
19
+ pass
20
+ try:
21
+ from hexrd import material
22
+ have_hexrd = True
23
+ except:
24
+ have_hexrd = False
25
+ pass
26
+ if have_hexrd:
27
+ try:
28
+ from hexrd.valunits import valWUnit
29
+ except:
30
+ have_hexrd = False
31
+ pass
32
+
33
+ powder_intensity_cutoff = 1.e-8
34
+
35
+ class Material:
36
+ """Base class for materials in an sin2psi or EDD analysis.
37
+ Right now it assumes a single material
38
+ extend its ability to do differently when test data is available
39
+ """
40
+
41
+ def __init__(self, material_name=None, material_file=None, sgnum=None,
42
+ lattice_parameters_angstroms=None, atoms=None, pos=None, enrgy=None):
43
+ self._enrgy = enrgy
44
+ self._materials = []
45
+ self._ds_min = []
46
+ self._ds_unique = None
47
+ self._hkls_unique = None
48
+ if material_name is not None:
49
+ self.add_material(material_name, material_file, sgnum, lattice_parameters_angstroms,
50
+ atoms, pos)
51
+
52
+ @property
53
+ #FIX passing arguments to a property isn't correct?
54
+ def lattice_parameters(self, index=0):
55
+ """Convert from internal nm units to angstrom
56
+ """
57
+ matl = self._materials[index]
58
+ if isinstance(matl, xu.materials.material.Crystal):
59
+ return [matl.a, matl.b, matl.c]
60
+ elif isinstance(matl, material.Material):
61
+ return [l.getVal("angstrom") for l in self._materials[index].latticeParameters[0:3]]
62
+ else:
63
+ raise ValueError('Illegal material class type')
64
+ return None
65
+
66
+ @property
67
+ def ds_unique(self, tth_tol=None, tth_max=None, round_sig=8):
68
+ if self._ds_unique is None:
69
+ self.get_unique_ds(tth_tol, tth_max, round_sig)
70
+ return self._ds_unique
71
+
72
+ @property
73
+ def hkls_unique(self, tth_tol=None, tth_max=None, round_sig=8):
74
+ if self._hkls_unique is None:
75
+ self.get_unique_ds(tth_tol, tth_max, round_sig)
76
+ return self._hkls_unique
77
+
78
+ def add_material(self, material_name, material_file=None, sgnum=None,
79
+ lattice_parameters_angstroms=None, atoms=None, pos=None, dmin_angstroms=0.6):
80
+ # At this point only for a single material
81
+ # Unique energies works for more, but fitting with different materials is not implemented
82
+ if len(self._materials) == 1:
83
+ exit('Multiple materials not implemented yet')
84
+ self._ds_min.append(dmin_angstroms)
85
+ self._materials.append(Material.make_material(material_name, material_file, sgnum,
86
+ lattice_parameters_angstroms, atoms, pos, dmin_angstroms))
87
+
88
+ def get_unique_ds(self, tth_tol=None, tth_max=None, round_sig=8):
89
+ """Get the list of unique lattice spacings from material HKLs
90
+
91
+ Parameters
92
+ ----------
93
+ tth_tol : two theta tolerance (in degrees)
94
+ tth_max : maximum two theta value (in degrees)
95
+ round_sig : significant digits, passed to round() function
96
+
97
+ Returns
98
+ -------
99
+ hkls : list of hkl's corresponding to the unique lattice spacings
100
+ ds : list of the unique lattice spacings
101
+ """
102
+ hkls = np.empty((0,3))
103
+ ds = np.empty((0))
104
+ ids = np.empty((0))
105
+ for i,m in enumerate(self._materials):
106
+ material_class_valid = False
107
+ if have_xu:
108
+ if isinstance(m, xu.materials.material.Crystal):
109
+ powder = xu.simpack.PowderDiffraction(m, en=self._enrgy)
110
+ hklsi = [hkl for hkl in powder.data if powder.data[hkl]['active']]
111
+ dsi = [m.planeDistance(hkl) for hkl in powder.data if powder.data[hkl]['active']]
112
+ mask = [True if d > self._ds_min[i] else False for d in dsi]
113
+ hkls = np.vstack((hkls, np.array(hklsi)[mask,:]))
114
+ dsi = np.array(dsi)[mask]
115
+ material_class_valid = True
116
+ if have_hexrd:
117
+ if isinstance(m, material.Material):
118
+ pd = m.planeData
119
+ if tth_tol is not None:
120
+ pd.tThWidth = np.radians(tth_tol)
121
+ if tth_max is not None:
122
+ pd.exclusions = None
123
+ pd.tThMax = np.radians(tth_max)
124
+ hkls = np.vstack((hkls, pd.hkls.T))
125
+ dsi = pd.getPlaneSpacings()
126
+ material_class_valid = True
127
+ if not material_class_valid:
128
+ raise ValueError('Illegal material class type')
129
+ ds = np.hstack((ds, dsi))
130
+ ids = np.hstack((ids, i*np.ones(len(dsi))))
131
+
132
+ # Sort lattice spacings in reverse order (use -)
133
+ ds_unique, ids_unique, _ = np.unique(-ds.round(round_sig), return_index=True,
134
+ return_counts=True)
135
+ ds_unique = np.abs(ds_unique)
136
+
137
+ # Limit the list to unique lattice spacings
138
+ self._hkls_unique = hkls[ids_unique,:].astype(int)
139
+ self._ds_unique = ds[ids_unique]
140
+ hkl_list = np.vstack((np.arange(self._ds_unique.shape[0]), ids[ids_unique],
141
+ self._hkls_unique.T, self._ds_unique)).T
142
+ logging.info("Unique d's:")
143
+ for hkl in hkl_list:
144
+ logging.info(f'{hkl[0]:4.0f} {hkl[1]:.0f} {hkl[2]:.0f} {hkl[3]:.0f} {hkl[4]:.0f} '+
145
+ f'{hkl[5]:.6f}')
146
+
147
+ return self._hkls_unique, self._ds_unique
148
+
149
+ @staticmethod
150
+ def make_material(material_name, material_file=None, sgnum=None,
151
+ lattice_parameters_angstroms=None, atoms=None, pos=None, dmin_angstroms=0.6):
152
+ """ Use HeXRD to get material properties when a materials file is provided
153
+ Use xrayutilities otherwise
154
+ """
155
+ if not isinstance(material_name, str):
156
+ raise ValueError(f'Illegal material_name: {material_name} {type(material_name)}')
157
+ if lattice_parameters_angstroms is not None:
158
+ if material_file is not None:
159
+ logging.warning('Overwrite lattice_parameters of material_file with input values '+
160
+ f'({lattice_parameters_angstroms})')
161
+ if isinstance(lattice_parameters_angstroms, (int, float)):
162
+ lattice_parameters = [lattice_parameters_angstroms]
163
+ elif isinstance(lattice_parameters_angstroms, (tuple, list, np.ndarray)):
164
+ lattice_parameters = list(lattice_parameters_angstroms)
165
+ else:
166
+ raise ValueError(f'Illegal lattice_parameters_angstroms: '+
167
+ f'{lattice_parameters_angstroms} {type(lattice_parameters_angstroms)}')
168
+ if material_file is None:
169
+ if not isinstance(sgnum, int):
170
+ raise ValueError(f'Illegal sgnum: {sgnum} {type(sgnum)}')
171
+ if sgnum is None or lattice_parameters_angstroms is None or pos is None:
172
+ raise ValueError('Valid inputs for sgnum and lattice_parameters_angstroms and '+
173
+ 'pos are required if materials file is not specified')
174
+ if isinstance(pos, str):
175
+ pos = [pos]
176
+ use_xu = True
177
+ if (np.array(pos).ndim == 1 and isinstance(pos[0], (int, float)) and
178
+ np.array(pos).size == 3):
179
+ if have_hexrd:
180
+ pos = np.array([pos])
181
+ use_xu = False
182
+ elif (np.array(pos).ndim == 2 and np.array(pos).shape[0] > 0 and
183
+ np.array(pos).shape[1] == 3):
184
+ if have_hexrd:
185
+ pos = np.array(pos)
186
+ use_xu = False
187
+ elif not (np.array(pos).ndim == 1 and isinstance(pos[0], str) and
188
+ np.array(pos).size > 0 and have_xu):
189
+ raise ValueError(f'Illegal pos (have_xu = {have_xu}): {pos} {type(pos)}')
190
+ if use_xu:
191
+ if atoms is None:
192
+ atoms = [material_name]
193
+ matl = xu.materials.Crystal(material_name, xu.materials.SGLattice(sgnum,
194
+ *lattice_parameters, atoms=atoms, pos=[p for p in np.array(pos)]))
195
+ else:
196
+ matl = material.Material(material_name)
197
+ matl.sgnum = sgnum
198
+ matl.atominfo = np.vstack((pos.T, np.ones(pos.shape[0]))).T
199
+ matl.latticeParameters = lattice_parameters
200
+ matl.dmin = valWUnit('lp', 'length', dmin_angstroms, 'angstrom')
201
+ exclusions = matl.planeData.get_exclusions()
202
+ powder_intensity = matl.planeData.powder_intensity
203
+ exclusions = [True if exclusion or i >= len(powder_intensity) or
204
+ powder_intensity[i] < powder_intensity_cutoff else False
205
+ for i, exclusion in enumerate(exclusions)]
206
+ matl.planeData.set_exclusions(exclusions)
207
+ logging.debug(f'powder_intensity = {matl.planeData.powder_intensity}')
208
+ logging.debug(f'exclusions = {matl.planeData.exclusions}')
209
+ else:
210
+ if not have_hexrd:
211
+ raise ValueError('Illegal inputs: must provide detailed material info when '+
212
+ 'hexrd package is unavailable')
213
+ if sgnum is not None:
214
+ logging.warning('Ignore sgnum input when material_file is specified')
215
+ if not (os.path.splitext(material_file)[1] in ('.h5', '.hdf5', '.xtal', '.cif')):
216
+ raise ValueError(f'Illegal material file {material_file}')
217
+ matl = material.Material(material_name, material_file,
218
+ dmin=valWUnit('lp', 'length', dmin_angstroms, 'angstrom'))
219
+ if lattice_parameters_angstroms is not None:
220
+ matl.latticeParameters = lattice_parameters
221
+ exclusions = matl.planeData.get_exclusions()
222
+ powder_intensity = matl.planeData.powder_intensity
223
+ exclusions = [True if exclusion or i >= len(powder_intensity) or
224
+ powder_intensity[i] < powder_intensity_cutoff else False
225
+ for i, exclusion in enumerate(exclusions)]
226
+ matl.planeData.set_exclusions(exclusions)
227
+ logging.debug(f'powder_intensity = {matl.planeData.powder_intensity}')
228
+ logging.debug(f'exclusions = {matl.planeData.exclusions}')
229
+
230
+ return matl
231
+