de-ebsd 0.2.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.
- de_ebsd/__init__.py +76 -0
- de_ebsd/core/__init__.py +23 -0
- de_ebsd/core/constants.py +81 -0
- de_ebsd/core/device.py +12 -0
- de_ebsd/core/geometry.py +67 -0
- de_ebsd/core/lambert.py +148 -0
- de_ebsd/core/rotation.py +139 -0
- de_ebsd/crystal/__init__.py +22 -0
- de_ebsd/crystal/data/__init__.py +0 -0
- de_ebsd/crystal/data/element_properties.py +29 -0
- de_ebsd/crystal/data/scattering_tables.py +414 -0
- de_ebsd/crystal/lattice.py +517 -0
- de_ebsd/crystal/scattering.py +339 -0
- de_ebsd/crystal/scattering_torch.py +233 -0
- de_ebsd/crystal/structure_factors.py +291 -0
- de_ebsd/diffraction/__init__.py +45 -0
- de_ebsd/diffraction/backends.py +318 -0
- de_ebsd/diffraction/bethe.py +28 -0
- de_ebsd/diffraction/kinematic.py +389 -0
- de_ebsd/diffraction/kvectors.py +120 -0
- de_ebsd/diffraction/prism.py +204 -0
- de_ebsd/diffraction/reflections.py +234 -0
- de_ebsd/index/__init__.py +61 -0
- de_ebsd/index/_kernels.py +222 -0
- de_ebsd/index/backproject.py +171 -0
- de_ebsd/index/crosscorr.py +654 -0
- de_ebsd/index/dictionary.py +362 -0
- de_ebsd/index/io.py +324 -0
- de_ebsd/index/live/__init__.py +5 -0
- de_ebsd/index/live/background.py +103 -0
- de_ebsd/index/live/calibration.py +70 -0
- de_ebsd/index/live/common.py +44 -0
- de_ebsd/index/live/deformation.py +289 -0
- de_ebsd/index/live/indexer.py +386 -0
- de_ebsd/index/preprocess.py +195 -0
- de_ebsd/index/refine/__init__.py +7 -0
- de_ebsd/index/refine/highres.py +479 -0
- de_ebsd/index/refine/levenberg.py +33 -0
- de_ebsd/index/refine/orientation.py +367 -0
- de_ebsd/index/refine/pattern_center.py +356 -0
- de_ebsd/index/spherical/__init__.py +41 -0
- de_ebsd/index/spherical/correlation.py +106 -0
- de_ebsd/index/spherical/harmonics.py +311 -0
- de_ebsd/index/spherical/indexer.py +345 -0
- de_ebsd/index/spherical/wigner.py +190 -0
- de_ebsd/sim/__init__.py +20 -0
- de_ebsd/sim/detector.py +145 -0
- de_ebsd/sim/masterpattern.py +231 -0
- de_ebsd/sim/microscope.py +93 -0
- de_ebsd/sim/montecarlo/__init__.py +19 -0
- de_ebsd/sim/montecarlo/depth.py +167 -0
- de_ebsd/sim/montecarlo/transport.py +532 -0
- de_ebsd/sim/simulator.py +291 -0
- de_ebsd/viz/__init__.py +53 -0
- de_ebsd/viz/camera.py +56 -0
- de_ebsd/viz/depth_widget.js +76 -0
- de_ebsd/viz/explorer.py +647 -0
- de_ebsd/viz/figures.py +67 -0
- de_ebsd/viz/maps.py +277 -0
- de_ebsd/viz/patterns.py +164 -0
- de_ebsd/viz/setup_widget.js +171 -0
- de_ebsd/viz/views.py +125 -0
- de_ebsd/viz/widgets.py +191 -0
- de_ebsd-0.2.0.dist-info/METADATA +251 -0
- de_ebsd-0.2.0.dist-info/RECORD +69 -0
- de_ebsd-0.2.0.dist-info/WHEEL +5 -0
- de_ebsd-0.2.0.dist-info/licenses/LICENSE +674 -0
- de_ebsd-0.2.0.dist-info/licenses/NOTICE +44 -0
- de_ebsd-0.2.0.dist-info/top_level.txt +1 -0
de_ebsd/viz/views.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Host-neutral compositions of de_ebsd display objects.
|
|
2
|
+
|
|
3
|
+
Scientific panels remain real :class:`anyplotlib.Figure` instances. This
|
|
4
|
+
module only groups figures with small JSON-compatible metadata so Jupyter and
|
|
5
|
+
SpyDE can choose their own layout and lifecycle without nested HTML/iframes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from functools import cached_property
|
|
12
|
+
from html import escape
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from de_ebsd.crystal.lattice import Crystal
|
|
17
|
+
from de_ebsd.sim.masterpattern import MasterPattern
|
|
18
|
+
|
|
19
|
+
__all__ = ["PhaseOverview"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class PhaseOverview:
|
|
24
|
+
"""A phase's metadata and native anyplotlib panels.
|
|
25
|
+
|
|
26
|
+
``figures`` is the integration boundary for application hosts. SpyDE can
|
|
27
|
+
register each value with its existing anyplotlib Electron bridge; Jupyter
|
|
28
|
+
displays this object directly through :meth:`_ipython_display_`.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
crystal: Crystal
|
|
32
|
+
master_pattern: MasterPattern | None = None
|
|
33
|
+
name: str | None = None
|
|
34
|
+
texture_height: int = 128
|
|
35
|
+
n_grid: int = 96
|
|
36
|
+
|
|
37
|
+
def __post_init__(self) -> None:
|
|
38
|
+
if self.texture_height < 8:
|
|
39
|
+
raise ValueError("texture_height must be >= 8")
|
|
40
|
+
if self.n_grid < 8:
|
|
41
|
+
raise ValueError("n_grid must be >= 8")
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def metadata(self) -> dict[str, str | int | float | None]:
|
|
45
|
+
"""Compact, JSON-compatible phase metadata for a sidebar/popover."""
|
|
46
|
+
return {
|
|
47
|
+
"name": self.name or _phase_name(self.crystal),
|
|
48
|
+
"space_group": self.crystal.space_group,
|
|
49
|
+
"space_group_symbol": str(self.crystal._spacegroup.short_name),
|
|
50
|
+
"a_nm": self.crystal.a,
|
|
51
|
+
"b_nm": self.crystal.b,
|
|
52
|
+
"c_nm": self.crystal.c,
|
|
53
|
+
"alpha_deg": self.crystal.alpha,
|
|
54
|
+
"beta_deg": self.crystal.beta,
|
|
55
|
+
"gamma_deg": self.crystal.gamma,
|
|
56
|
+
"volume_nm3": self.crystal.volume,
|
|
57
|
+
"density_g_cm3": self.crystal.density,
|
|
58
|
+
"atom_count": sum(self.crystal.multiplicities),
|
|
59
|
+
"simulation_backend": (
|
|
60
|
+
str(self.master_pattern.metadata.get("backend", "computed"))
|
|
61
|
+
if self.master_pattern is not None
|
|
62
|
+
else None
|
|
63
|
+
),
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@cached_property
|
|
67
|
+
def figure(self):
|
|
68
|
+
"""The single native figure mounted by Jupyter or SpyDE."""
|
|
69
|
+
if self.master_pattern is None:
|
|
70
|
+
return self.crystal.show(title=f"{self.metadata['name']} structure")
|
|
71
|
+
|
|
72
|
+
from de_ebsd.viz.patterns import phase_overview_figure
|
|
73
|
+
|
|
74
|
+
texture = self.master_pattern.to_equirectangular(height=self.texture_height)
|
|
75
|
+
return phase_overview_figure(
|
|
76
|
+
self.crystal,
|
|
77
|
+
texture.detach().cpu().numpy(),
|
|
78
|
+
name=str(self.metadata["name"]),
|
|
79
|
+
n_grid=self.n_grid,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def figures(self) -> dict[str, object]:
|
|
84
|
+
"""Named native figures for notebook or application host mounting."""
|
|
85
|
+
return {"phase_overview": self.figure}
|
|
86
|
+
|
|
87
|
+
def _ipython_display_(self) -> None:
|
|
88
|
+
from IPython.display import HTML, display
|
|
89
|
+
|
|
90
|
+
display(HTML(_metadata_card(self.metadata)))
|
|
91
|
+
for figure in self.figures.values():
|
|
92
|
+
display(figure)
|
|
93
|
+
|
|
94
|
+
def __repr__(self) -> str:
|
|
95
|
+
metadata = self.metadata
|
|
96
|
+
return (
|
|
97
|
+
f"PhaseOverview(name={metadata['name']!r}, "
|
|
98
|
+
f"space_group={metadata['space_group']}, "
|
|
99
|
+
f"master_pattern={self.master_pattern is not None})"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _phase_name(crystal: Crystal) -> str:
|
|
104
|
+
elements = "+".join(dict.fromkeys(site.element for site in crystal.sites))
|
|
105
|
+
return elements or "phase"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _metadata_card(metadata: dict[str, str | int | float | None]) -> str:
|
|
109
|
+
name = escape(str(metadata["name"]))
|
|
110
|
+
symbol = escape(str(metadata["space_group_symbol"]))
|
|
111
|
+
backend = metadata["simulation_backend"] or "not computed"
|
|
112
|
+
cell = " × ".join(f"{float(metadata[key]):.4f}" for key in ("a_nm", "b_nm", "c_nm"))
|
|
113
|
+
return f"""
|
|
114
|
+
<div style="font:12px var(--jp-ui-font-family,system-ui,sans-serif);
|
|
115
|
+
color:var(--jp-ui-font-color1,#d8dee9);background:var(--jp-layout-color1,#20242d);
|
|
116
|
+
border:1px solid var(--jp-border-color2,#3b4252);border-radius:6px;
|
|
117
|
+
padding:8px 10px;max-width:940px;display:flex;gap:18px;align-items:baseline;flex-wrap:wrap">
|
|
118
|
+
<strong style="font-size:13px">{name}</strong>
|
|
119
|
+
<span>{symbol} ({int(metadata["space_group"])})</span>
|
|
120
|
+
<span>cell {cell} nm</span>
|
|
121
|
+
<span>{int(metadata["atom_count"])} atoms</span>
|
|
122
|
+
<span>ρ {float(metadata["density_g_cm3"]):.2f} g/cm³</span>
|
|
123
|
+
<span>{escape(str(backend))}</span>
|
|
124
|
+
</div>
|
|
125
|
+
"""
|
de_ebsd/viz/widgets.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Portable experiment inspectors; one renderer for Jupyter, HTML, and SpyDE.
|
|
2
|
+
|
|
3
|
+
HTML controls edit a local snapshot; notebook controls synchronize via traitlets.
|
|
4
|
+
Scientific master-pattern and crystal views remain native anyplotlib figures.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from uuid import uuid4
|
|
12
|
+
|
|
13
|
+
import anywidget
|
|
14
|
+
import numpy as np
|
|
15
|
+
import traitlets
|
|
16
|
+
|
|
17
|
+
from de_ebsd.sim.detector import EBSDDetector
|
|
18
|
+
from de_ebsd.sim.microscope import Microscope
|
|
19
|
+
|
|
20
|
+
__all__ = ["DepthWidget", "MicroscopeWidget"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _PortableWidget(anywidget.AnyWidget):
|
|
24
|
+
"""Export the actual renderer without a notebook manager or CDN dependency."""
|
|
25
|
+
|
|
26
|
+
def _repr_html_(self):
|
|
27
|
+
identity = f"de-ebsd-{uuid4().hex}"
|
|
28
|
+
state = {
|
|
29
|
+
name: getattr(self, name)
|
|
30
|
+
for name in self.traits(sync=True)
|
|
31
|
+
if not name.startswith("_") and name != "layout"
|
|
32
|
+
}
|
|
33
|
+
payload = json.dumps(state, allow_nan=False).replace("<", "\\u003c")
|
|
34
|
+
renderer = str(self._esm).replace("</script", "<\\/script")
|
|
35
|
+
return f'''<div id="{identity}"></div><script type="module">
|
|
36
|
+
{renderer}
|
|
37
|
+
const state = {payload};
|
|
38
|
+
const events = new Map();
|
|
39
|
+
const model = {{
|
|
40
|
+
get: key => state[key],
|
|
41
|
+
set(key, value) {{
|
|
42
|
+
state[key] = value;
|
|
43
|
+
for (const callback of events.get(`change:${{key}}`) || []) callback();
|
|
44
|
+
}},
|
|
45
|
+
on(key, callback) {{
|
|
46
|
+
if (!events.has(key)) events.set(key, new Set());
|
|
47
|
+
events.get(key).add(callback);
|
|
48
|
+
}},
|
|
49
|
+
off(key, callback) {{ events.get(key)?.delete(callback); }},
|
|
50
|
+
save_changes() {{}},
|
|
51
|
+
}};
|
|
52
|
+
render({{model, el: document.getElementById("{identity}")}});
|
|
53
|
+
</script>'''
|
|
54
|
+
|
|
55
|
+
def to_html(self):
|
|
56
|
+
"""Interactive standalone HTML; edits do not run Python simulations."""
|
|
57
|
+
return (
|
|
58
|
+
'<!doctype html><html><head><meta charset="utf-8">'
|
|
59
|
+
'<meta name="viewport" content="width=device-width,initial-scale=1">'
|
|
60
|
+
"<title>de-ebsd experiment inspector</title></head><body>"
|
|
61
|
+
+ self._repr_html_()
|
|
62
|
+
+ "</body></html>"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class MicroscopeWidget(_PortableWidget):
|
|
67
|
+
"""Editable geometry with laboratory side view and detector-face inset.
|
|
68
|
+
|
|
69
|
+
Edits never mutate inputs or recompute existing master patterns. Read an
|
|
70
|
+
edited setup explicitly with to_microscope()/to_detector().
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
_esm = Path(__file__).with_name("setup_widget.js").read_text(encoding="utf-8")
|
|
74
|
+
energy_kev = traitlets.Float(20.0, min=0.001).tag(sync=True)
|
|
75
|
+
sample_tilt = traitlets.Float(70.0, min=0.0, max=90.0).tag(sync=True)
|
|
76
|
+
detector_tilt = traitlets.Float(0.0).tag(sync=True)
|
|
77
|
+
azimuthal = traitlets.Float(0.0).tag(sync=True)
|
|
78
|
+
twist = traitlets.Float(0.0).tag(sync=True)
|
|
79
|
+
probe_diameter_nm = traitlets.Float(0.0, min=0.0).tag(sync=True)
|
|
80
|
+
pcx = traitlets.Float(0.5).tag(sync=True)
|
|
81
|
+
pcy = traitlets.Float(0.5).tag(sync=True)
|
|
82
|
+
pcz = traitlets.Float(0.5, min=0.000001).tag(sync=True)
|
|
83
|
+
detector_rows = traitlets.Int(480, min=1).tag(sync=True)
|
|
84
|
+
detector_cols = traitlets.Int(480, min=1).tag(sync=True)
|
|
85
|
+
px_size = traitlets.Float(1.0, min=0.000001).tag(sync=True)
|
|
86
|
+
crystal_label = traitlets.Unicode("").tag(sync=True)
|
|
87
|
+
has_detector = traitlets.Bool(False).tag(sync=True)
|
|
88
|
+
|
|
89
|
+
@traitlets.validate(
|
|
90
|
+
"energy_kev",
|
|
91
|
+
"sample_tilt",
|
|
92
|
+
"detector_tilt",
|
|
93
|
+
"azimuthal",
|
|
94
|
+
"twist",
|
|
95
|
+
"probe_diameter_nm",
|
|
96
|
+
"pcx",
|
|
97
|
+
"pcy",
|
|
98
|
+
"pcz",
|
|
99
|
+
"px_size",
|
|
100
|
+
)
|
|
101
|
+
def _finite(self, proposal):
|
|
102
|
+
if not np.isfinite(proposal["value"]):
|
|
103
|
+
raise traitlets.TraitError("geometry values must be finite")
|
|
104
|
+
return proposal["value"]
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def from_setup(cls, microscope=None, detector=None, crystal=None):
|
|
108
|
+
widget = cls()
|
|
109
|
+
if microscope is not None:
|
|
110
|
+
widget.energy_kev = microscope.energy_kev
|
|
111
|
+
widget.sample_tilt = microscope.sample_tilt
|
|
112
|
+
widget.azimuthal = microscope.azimuthal
|
|
113
|
+
widget.probe_diameter_nm = microscope.probe_diameter_nm or 0.0
|
|
114
|
+
if detector is not None:
|
|
115
|
+
widget.has_detector = True
|
|
116
|
+
widget.detector_rows, widget.detector_cols = detector.shape
|
|
117
|
+
widget.pcx, widget.pcy, widget.pcz = detector.pattern_center
|
|
118
|
+
widget.detector_tilt = detector.tilt
|
|
119
|
+
widget.twist = detector.twist
|
|
120
|
+
widget.px_size = detector.px_size
|
|
121
|
+
if microscope is not None and not np.allclose(
|
|
122
|
+
[microscope.sample_tilt, microscope.azimuthal],
|
|
123
|
+
[detector.sample_tilt, detector.azimuthal],
|
|
124
|
+
):
|
|
125
|
+
raise ValueError("microscope and detector sample_tilt/azimuthal must agree")
|
|
126
|
+
widget.sample_tilt = detector.sample_tilt
|
|
127
|
+
widget.azimuthal = detector.azimuthal
|
|
128
|
+
if crystal is not None:
|
|
129
|
+
widget.crystal_label = _phase_name(crystal)
|
|
130
|
+
return widget
|
|
131
|
+
|
|
132
|
+
def to_microscope(self):
|
|
133
|
+
return Microscope(
|
|
134
|
+
energy=self.energy_kev * 1e3,
|
|
135
|
+
sample_tilt=self.sample_tilt,
|
|
136
|
+
azimuthal=self.azimuthal,
|
|
137
|
+
probe_diameter_nm=self.probe_diameter_nm or None,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def to_detector(self):
|
|
141
|
+
return EBSDDetector(
|
|
142
|
+
shape=(self.detector_rows, self.detector_cols),
|
|
143
|
+
pattern_center=(self.pcx, self.pcy, self.pcz),
|
|
144
|
+
sample_tilt=self.sample_tilt,
|
|
145
|
+
tilt=self.detector_tilt,
|
|
146
|
+
azimuthal=self.azimuthal,
|
|
147
|
+
twist=self.twist,
|
|
148
|
+
px_size=self.px_size,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class DepthWidget(_PortableWidget):
|
|
153
|
+
"""Read-only depth model, with local energy and slice selection."""
|
|
154
|
+
|
|
155
|
+
_esm = Path(__file__).with_name("depth_widget.js").read_text(encoding="utf-8")
|
|
156
|
+
energies_kev = traitlets.List().tag(sync=True)
|
|
157
|
+
profiles = traitlets.List().tag(sync=True)
|
|
158
|
+
integration_bins = traitlets.List().tag(sync=True)
|
|
159
|
+
depth_step = traitlets.Float(1.0).tag(sync=True)
|
|
160
|
+
energy_index = traitlets.Int(0, min=0).tag(sync=True)
|
|
161
|
+
slice_index = traitlets.Int(0, min=0).tag(sync=True)
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def from_distribution(cls, depth, energy_kev=None):
|
|
165
|
+
counts = np.asarray(depth.accum_z, dtype=float)
|
|
166
|
+
energies = np.asarray(depth.energies_kev, dtype=float)
|
|
167
|
+
if (
|
|
168
|
+
counts.ndim != 4
|
|
169
|
+
or 0 in counts.shape
|
|
170
|
+
or len(energies) != counts.shape[0]
|
|
171
|
+
or not np.isfinite(counts).all()
|
|
172
|
+
or (counts < 0).any()
|
|
173
|
+
or not np.isfinite(energies).all()
|
|
174
|
+
or not np.isfinite(depth.depth_step)
|
|
175
|
+
or depth.depth_step <= 0
|
|
176
|
+
or not np.isfinite(depth.n_total)
|
|
177
|
+
or depth.n_total <= 0
|
|
178
|
+
):
|
|
179
|
+
raise ValueError("depth display requires finite nonnegative counts and positive scales")
|
|
180
|
+
index = depth.n_energies - 1 if energy_kev is None else depth.energy_index(energy_kev)
|
|
181
|
+
return cls(
|
|
182
|
+
energies_kev=energies.tolist(),
|
|
183
|
+
profiles=(counts.sum(axis=(2, 3)) / depth.n_total).tolist(),
|
|
184
|
+
integration_bins=depth.integration_depths().tolist(),
|
|
185
|
+
depth_step=depth.depth_step,
|
|
186
|
+
energy_index=index,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _phase_name(crystal):
|
|
191
|
+
return "+".join(dict.fromkeys(site.element for site in crystal.sites)) or "phase"
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: de-ebsd
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Differentiable, GPU-accelerated EBSD: dynamical master-pattern simulation, Monte Carlo transport, indexing, refinement and HR-EBSD, in PyTorch
|
|
5
|
+
Author-email: Carter Francis <cartsfrancis@gmail.com>
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/directelectron/de-ebsd
|
|
8
|
+
Project-URL: Source, https://github.com/directelectron/de-ebsd
|
|
9
|
+
Project-URL: Issues, https://github.com/directelectron/de-ebsd/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/directelectron/de-ebsd/blob/main/CHANGELOG.rst
|
|
11
|
+
Project-URL: Documentation, https://directelectron.github.io/de-ebsd/
|
|
12
|
+
Keywords: EBSD,dynamical-diffraction,Bloch-wave,master-pattern,pytorch,kikuchipy
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: NOTICE
|
|
25
|
+
Requires-Dist: numpy
|
|
26
|
+
Requires-Dist: torch>=2.4
|
|
27
|
+
Requires-Dist: orix
|
|
28
|
+
Requires-Dist: diffsims
|
|
29
|
+
Requires-Dist: h5py
|
|
30
|
+
Requires-Dist: anyplotlib
|
|
31
|
+
Requires-Dist: anywidget
|
|
32
|
+
Provides-Extra: validate
|
|
33
|
+
Requires-Dist: kikuchipy; extra == "validate"
|
|
34
|
+
Provides-Extra: live
|
|
35
|
+
Requires-Dist: cupy-cuda12x; extra == "live"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# de-ebsd
|
|
39
|
+
|
|
40
|
+
Differentiable, GPU-accelerated EBSD in PyTorch: dynamical master-pattern
|
|
41
|
+
simulation from a crystal structure, native Monte Carlo electron transport,
|
|
42
|
+
orientation indexing (dictionary, spherical-harmonic and live), gradient and
|
|
43
|
+
high-resolution refinement, pattern-center calibration and HR-EBSD strain. The
|
|
44
|
+
API is composable and object oriented, in the manner of
|
|
45
|
+
[abTEM](https://github.com/abTEM/abTEM), and every intermediate stage is
|
|
46
|
+
inspectable.
|
|
47
|
+
|
|
48
|
+
A master pattern is the backscattered-electron intensity as a function of
|
|
49
|
+
crystal direction, stored on the square-Lambert grid. de-ebsd builds it from
|
|
50
|
+
first principles -- crystal, structure factors with absorption, reflections,
|
|
51
|
+
Bloch-wave dynamical solve, depth integration over a Monte Carlo exit-depth
|
|
52
|
+
profile -- and then runs the inverse problem against measured patterns. The
|
|
53
|
+
physics is ported from [EMsoft](https://github.com/EMsoft-org/EMsoftOO)
|
|
54
|
+
(Callahan & De Graef 2013), which remains the validation oracle (de-ebsd does
|
|
55
|
+
not call EMsoft at runtime); see [NOTICE](NOTICE). Indexing follows EMSphInx
|
|
56
|
+
(Lenthe, Singh & De Graef 2019) and emits [orix](https://github.com/pyxem/orix)
|
|
57
|
+
objects, so [kikuchipy](https://github.com/pyxem/kikuchipy) and other tools can
|
|
58
|
+
use it as a backend.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Windows / Linux with uv (Python >= 3.11; torch comes from the CUDA 12.4
|
|
63
|
+
index on Windows and the CPU index on Linux, configured in `pyproject.toml`):
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
git clone https://github.com/directelectron/de-ebsd
|
|
67
|
+
cd de-ebsd
|
|
68
|
+
uv sync
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The distribution is named `de-ebsd`; the Python package is `de_ebsd`. The
|
|
72
|
+
fused CUDA kernels of live indexing need CuPy: `uv sync --extra live`.
|
|
73
|
+
|
|
74
|
+
## Quickstart: simulation
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import de_ebsd as de
|
|
78
|
+
|
|
79
|
+
crystal = de.Crystal.from_parameters(
|
|
80
|
+
a=0.5431, space_group=227, atoms=[("Si", (0.125, 0.125, 0.125))]
|
|
81
|
+
)
|
|
82
|
+
microscope = de.Microscope(energy=20e3, sample_tilt=70.0)
|
|
83
|
+
sim = de.MasterPatternSimulator(
|
|
84
|
+
crystal,
|
|
85
|
+
microscope,
|
|
86
|
+
npx=500,
|
|
87
|
+
dmin=0.05,
|
|
88
|
+
bethe=de.BetheParameters(),
|
|
89
|
+
# backend="bloch_prism" is the default: the batched dynamical solve.
|
|
90
|
+
# "bloch" is the one-direction-at-a-time float64 reference it reproduces.
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# every stage is inspectable (all figures render through anyplotlib):
|
|
94
|
+
sim.structure_factors().show() # |U_g| per family, absences, V_0
|
|
95
|
+
sim.reflections(k=(0, 0, 1)).show() # Bethe strong / weak split for one beam
|
|
96
|
+
sim.dynamical_matrix(k=(0, 0, 1)).show()
|
|
97
|
+
|
|
98
|
+
master = sim.compute(device="cuda") # -> MasterPattern
|
|
99
|
+
master.show(projection="lambert") # also "stereographic" and "sphere"
|
|
100
|
+
sim.crystal.show() # real 3-D expanded crystal structure
|
|
101
|
+
|
|
102
|
+
# refine and recompute (structure factors are reused when still valid):
|
|
103
|
+
better = sim.refine(npx=1000, dmin=0.04)
|
|
104
|
+
|
|
105
|
+
# project to a detector for a batch of orientations (orix Rotation):
|
|
106
|
+
detector = de.EBSDDetector(shape=(480, 480), pattern_center=(0.5, 0.5, 0.6))
|
|
107
|
+
patterns = master.project(detector, orientation=rotations)
|
|
108
|
+
|
|
109
|
+
# interactive geometry widget in Jupyter (anywidget):
|
|
110
|
+
sim.show_setup(detector=detector)
|
|
111
|
+
|
|
112
|
+
# phase composition for Jupyter or a host application; figures stay native:
|
|
113
|
+
phase = sim.crystal.overview(master_pattern=master)
|
|
114
|
+
sim.microscope.show(detector=detector, crystal=sim.crystal)
|
|
115
|
+
|
|
116
|
+
# STEM zone-axis exploration: geometric Kikuchi lines + kinematic spots,
|
|
117
|
+
# independently toggleable in one projection; no master pattern required:
|
|
118
|
+
explorer = sim.crystal.explore(energy_kev=200, dmin=0.1)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The exit-depth statistics the dynamical solve integrates over come from a native
|
|
122
|
+
Monte Carlo (`de_ebsd.sim.montecarlo`) unless you pass a `DepthDistribution`,
|
|
123
|
+
for example one read from an EMsoft Monte Carlo file.
|
|
124
|
+
|
|
125
|
+
## Quickstart: indexing
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from de_ebsd.index import (
|
|
129
|
+
DictionaryIndexer,
|
|
130
|
+
SphericalIndexer,
|
|
131
|
+
refine_orientation,
|
|
132
|
+
remove_background,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
patterns = remove_background(raw, static_bg=static_bg, operation="divide")
|
|
136
|
+
|
|
137
|
+
# Spherical indexing: one SO(3) cross-correlation per pattern, on the GPU.
|
|
138
|
+
indexer = SphericalIndexer(master, detector, bandwidth=68, device="cuda")
|
|
139
|
+
rotations, quality = indexer.index(patterns)
|
|
140
|
+
|
|
141
|
+
# Dictionary indexing over a fundamental-zone sample, as an orix CrystalMap:
|
|
142
|
+
xmap = DictionaryIndexer(master, detector, resolution=2.5).index_scan(scan, step=0.5)
|
|
143
|
+
|
|
144
|
+
# Sharpen a coarse index by gradient or Levenberg-Marquardt refinement:
|
|
145
|
+
refined, score = refine_orientation(patterns, master, detector, rotations, method="lm")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Also in `de_ebsd.index`: `refine_hr` (band-edge refinement of orientation and,
|
|
149
|
+
optionally, pattern center), `determine_pattern_center` (one center shared by
|
|
150
|
+
many patterns), `hrebsd` (lattice strain and rotation by cross-correlation
|
|
151
|
+
against a reference pattern) and `LiveIndexer`, which indexes, refines and
|
|
152
|
+
strain-fits a camera's frames where they already are on the GPU, at thousands of
|
|
153
|
+
patterns a second.
|
|
154
|
+
|
|
155
|
+
## Examples
|
|
156
|
+
|
|
157
|
+
The [examples folder](examples/) contains executable Sphinx-Gallery tutorials,
|
|
158
|
+
grouped by the layer they exercise.
|
|
159
|
+
|
|
160
|
+
**[Master-pattern simulation](examples/simulation/)** -- the forward chain:
|
|
161
|
+
|
|
162
|
+
- [CIF to detector](examples/simulation/cif_to_detector.py): silicon structure,
|
|
163
|
+
native Monte Carlo, diffraction intermediates, full 3D master pattern,
|
|
164
|
+
orix orientations, detector images, phase overview, and HDF5 round trip.
|
|
165
|
+
- [Energy-resolved simulation](examples/simulation/energy_resolved_simulation.py):
|
|
166
|
+
nickel transport statistics and dynamical patterns at multiple energies.
|
|
167
|
+
- [Resolution and backends](examples/simulation/resolution_and_backends.py):
|
|
168
|
+
grid refinement, detector-space differences, and PRISM/Bloch comparison,
|
|
169
|
+
plus the microscope, probe, detector and depth-slice inspectors.
|
|
170
|
+
- [Compare with EMsoft](examples/simulation/compare_emsoft.py): use the bundled
|
|
171
|
+
nickel reference's crystal, Bethe settings and Monte Carlo profile, then
|
|
172
|
+
compare both hemispheres, normalized residuals, and detector patterns.
|
|
173
|
+
- [STEM orientation explorer](examples/simulation/stem_orientation_explorer.py):
|
|
174
|
+
a band-line sphere, crystal structure, and a combined lines/spots view. It
|
|
175
|
+
provides geometric band centerlines and relative elastic kinematic spot
|
|
176
|
+
intensities; it does not simulate transmission Kikuchi contrast or
|
|
177
|
+
convergent-beam discs.
|
|
178
|
+
|
|
179
|
+
**[Orientation indexing](examples/indexing/)** -- the inverse problem, each on a
|
|
180
|
+
synthetic two-grain scan with known orientations:
|
|
181
|
+
|
|
182
|
+
- [Dictionary indexing](examples/indexing/dictionary_indexing.py): background
|
|
183
|
+
removal, a fundamental-zone template library, a `CrystalMap` with IPF and
|
|
184
|
+
quality maps, and Levenberg-Marquardt refinement to sub-degree accuracy.
|
|
185
|
+
- [Spherical indexing](examples/indexing/spherical_indexing.py): the SO(3)
|
|
186
|
+
cross-correlation surface, the bandwidth accuracy/cost trade-off and how it
|
|
187
|
+
fails when truncated too far, then refinement off the peak.
|
|
188
|
+
|
|
189
|
+
Run scripts with `uv run python examples/simulation/cif_to_detector.py`. They
|
|
190
|
+
use small CPU-friendly teaching settings; see
|
|
191
|
+
[examples/README.rst](examples/README.rst) for execution, display, and
|
|
192
|
+
convergence notes.
|
|
193
|
+
|
|
194
|
+
## Documentation
|
|
195
|
+
|
|
196
|
+
The full site -- user guide, design notes, the executable example gallery, and
|
|
197
|
+
an API reference generated from the docstrings -- is published at
|
|
198
|
+
<https://directelectron.github.io/de-ebsd/>. To build it locally:
|
|
199
|
+
|
|
200
|
+
```shell
|
|
201
|
+
uv sync --group docs
|
|
202
|
+
uv run python -m sphinx -b html -W --keep-going docs docs/_build/html
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Open `docs/_build/html/index.html`. The build executes every example, so a
|
|
206
|
+
broken example fails the build.
|
|
207
|
+
|
|
208
|
+
Start at [`docs/user/conventions.rst`](docs/user/conventions.rst) before
|
|
209
|
+
interpreting any number: units, the Cartesian crystal frame, square-Lambert
|
|
210
|
+
storage, the orientation convention and the space-group origin choice are all
|
|
211
|
+
load-bearing, and they are what make de-ebsd's output comparable to EMsoft's
|
|
212
|
+
and kikuchipy's. The design notes under [`docs/dev/`](docs/dev/) cover the
|
|
213
|
+
architecture, the dynamical algorithm, the Monte Carlo, the indexers and the
|
|
214
|
+
validation numbers.
|
|
215
|
+
|
|
216
|
+
## Validation
|
|
217
|
+
|
|
218
|
+
EMsoft is the oracle (validation only). The script compares a simulated master
|
|
219
|
+
pattern with EMsoft references by per-pixel Pearson correlation of the Lambert
|
|
220
|
+
maps -- scale invariant, so normalization differences do not matter:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
uv run python scripts/validate_master_pattern.py --material ni
|
|
224
|
+
uv run python scripts/validate_master_pattern.py --material si \
|
|
225
|
+
--mc /path/to/Si_MC.h5 --device cuda
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Ni uses kikuchipy's bundled master pattern and runs with no external files. Si
|
|
229
|
+
needs a local EMsoft `Si_MC.h5` reference run (not redistributed here) -- point
|
|
230
|
+
`--mc` or `DE_EBSD_SI_MC` at your copy.
|
|
231
|
+
|
|
232
|
+
**Si r = 1.0000** at native npx-500 against `Si_MC.h5`, and **Ni r = 1.00000**
|
|
233
|
+
against a matched-settings EMsoft master; cubic and tetragonal phases, single-
|
|
234
|
+
and multi-component, agree to that precision. The npx-500 Si master (about two
|
|
235
|
+
million directions) computes in about 10 s (fp32) on a Pascal TITAN X, roughly
|
|
236
|
+
10 times faster than EMsoft on a 24-thread CPU for a full energy-resolved
|
|
237
|
+
master. Monoclinic settings and one hexagonal intensity residual are the open
|
|
238
|
+
items; see the validation page of the design notes.
|
|
239
|
+
|
|
240
|
+
## Development
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
uv run pytest
|
|
244
|
+
uv run ruff check
|
|
245
|
+
uv run ruff format --check
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## License
|
|
249
|
+
|
|
250
|
+
GPL-3.0-or-later. See [LICENSE](LICENSE) and [NOTICE](NOTICE) for the work this
|
|
251
|
+
package is built on.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
de_ebsd/__init__.py,sha256=2R1Wzpzn46bZkEd0Citsyfs40HSvCyBozP0zF588Y5U,2113
|
|
2
|
+
de_ebsd/core/__init__.py,sha256=S50uL6VEj-vhj2EWnMbc9khHwCTGplXZb7BkbXgzpnQ,750
|
|
3
|
+
de_ebsd/core/constants.py,sha256=Myd3_n3r7pxZa9wOrUh8VSy4vrfHp1y_UOZP-ClIqQw,3202
|
|
4
|
+
de_ebsd/core/device.py,sha256=KhrkdALz7lZhoKx4ARU3_tazsUUusBFcijFK3coY7Pw,360
|
|
5
|
+
de_ebsd/core/geometry.py,sha256=UetwFkMSJ2GS1tOefIqRpqwJ8atw8IwQuJoGtg7Grlg,2617
|
|
6
|
+
de_ebsd/core/lambert.py,sha256=Snhu7CpUfIzoq7BrEBEEeOeqklV9Urn51q3qCn_8IYQ,5636
|
|
7
|
+
de_ebsd/core/rotation.py,sha256=FoQKm4eXi2zeqBviIHrjCpeBIcyx_IvHJ6AQq2hHTLc,5238
|
|
8
|
+
de_ebsd/crystal/__init__.py,sha256=r526mVbO-DXp43Q2RYs0KvL1NR_YS_L6M7sesvdprGc,669
|
|
9
|
+
de_ebsd/crystal/lattice.py,sha256=JNsRitSHxi_l3TxytWutV_MMTltZu5zYM6pTHiNlxyE,18538
|
|
10
|
+
de_ebsd/crystal/scattering.py,sha256=BiawEYuBtMhX4gsupVV2aAA4cqX3ZE0AuHZpEsZ8FJI,11194
|
|
11
|
+
de_ebsd/crystal/scattering_torch.py,sha256=GQU95u6Lk6rpRg0Y12ANKkzM7b5AFBXw8p-uR5BIY2k,8965
|
|
12
|
+
de_ebsd/crystal/structure_factors.py,sha256=wiYRgUbSStwlse9ZWl_LZapEQhpgdvX1k14c1ooriKU,11015
|
|
13
|
+
de_ebsd/crystal/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
de_ebsd/crystal/data/element_properties.py,sha256=wApsi2JKzs8T3ET6wOG84U3FbMN27xvBYieYKAcEJFk,1860
|
|
15
|
+
de_ebsd/crystal/data/scattering_tables.py,sha256=iX2wli6NgeRVDWn1z_u2AeRrnP-VUVylCyPqpn_G5-Q,16357
|
|
16
|
+
de_ebsd/diffraction/__init__.py,sha256=Gjid94oeawbvq2pWE71VKmjnIKZmhcjzwPSQeScLxRk,1177
|
|
17
|
+
de_ebsd/diffraction/backends.py,sha256=ze16Dcq4HwrBTxlptPWch9B468oYrVWxZPErVCi7nGU,12144
|
|
18
|
+
de_ebsd/diffraction/bethe.py,sha256=RdYUWS9i1UG--kcu8_Y_UfkLUzJNmRYUGjfzXAOb28g,839
|
|
19
|
+
de_ebsd/diffraction/kinematic.py,sha256=hXA2hp4pxc3kO8hIop7o7DS4AAd0xtR8zsng4WI1pmY,17298
|
|
20
|
+
de_ebsd/diffraction/kvectors.py,sha256=Ic1XJgQs03rjM5GOhSfJYiqPbBVQpcD4f1clfdVULew,4886
|
|
21
|
+
de_ebsd/diffraction/prism.py,sha256=7Src9NPts6LtvUJb61izM4GVWUdsR7hU8J4l_ISc0xI,9890
|
|
22
|
+
de_ebsd/diffraction/reflections.py,sha256=pJh9ktSUqSmX9Tpbe70L6V3Rlwd3sV09M-E567e6n8A,8130
|
|
23
|
+
de_ebsd/index/__init__.py,sha256=jDj4Q_IxWduESve0eW1kRdNJHGk8BE1I_dm-GX12h2c,2023
|
|
24
|
+
de_ebsd/index/_kernels.py,sha256=jrsk-7Ael9YHCP_wzRGLFh1Ads6nz8WtcHKqD5nrzGA,8233
|
|
25
|
+
de_ebsd/index/backproject.py,sha256=2LB-W3RLXAKzXHMt6gNJXq4Ih6pqbPsqXixNHkgK6x4,7341
|
|
26
|
+
de_ebsd/index/crosscorr.py,sha256=QQlk37BCHTwP6jenQuLgBlbCIP0g9UU1j2SSnaeYtrc,28059
|
|
27
|
+
de_ebsd/index/dictionary.py,sha256=raj8Q-MF8ptlBzICdJnkQSK727OP1infc1qA5f-uRLc,15251
|
|
28
|
+
de_ebsd/index/io.py,sha256=xEPzhfnkAhPWytQ38Hn16Y1vsE30Eb5JYUhlZ42TM24,12361
|
|
29
|
+
de_ebsd/index/preprocess.py,sha256=1E7aPbWgACjbFoZakZiyGZ2NcemRwSZSI596_E59SPU,6672
|
|
30
|
+
de_ebsd/index/live/__init__.py,sha256=NIN0GkG0-jglfOMNXqeCdaYwFVJjM3erw5RV2IQWcfE,126
|
|
31
|
+
de_ebsd/index/live/background.py,sha256=Igs0IyUhGnhIulwRqIcskYUbmWOuPWiUwHLpvyWIcjc,4697
|
|
32
|
+
de_ebsd/index/live/calibration.py,sha256=--AOwvfADAmqpIIx8NwS4Oo4_Qjp9CjviBHInej99wg,3130
|
|
33
|
+
de_ebsd/index/live/common.py,sha256=58lkc7z4EIeNDeS9SWHsEx_oFZNDFxM1yZxmuQgxvmo,2036
|
|
34
|
+
de_ebsd/index/live/deformation.py,sha256=lervj_iY9E4CZzwOqU2R1CHmh3Wyzva_NWOQ1j-V0dQ,14066
|
|
35
|
+
de_ebsd/index/live/indexer.py,sha256=Nne84trTGP6EO4lb970eNwpxEK84PMpUI0dxMlR5l-k,19076
|
|
36
|
+
de_ebsd/index/refine/__init__.py,sha256=V9UESmUAp1IJkAx-fPOsKHQuw3pLdw06dt-90n_yAfk,325
|
|
37
|
+
de_ebsd/index/refine/highres.py,sha256=oilFaN-ej7KWFOLogOTrFyNJlE-FL6AtetPnAHIjI14,20564
|
|
38
|
+
de_ebsd/index/refine/levenberg.py,sha256=sL3-sfkNirj0xd25XRnmk_wsJsVFdiMxuPKKlZ8HhuU,1044
|
|
39
|
+
de_ebsd/index/refine/orientation.py,sha256=hFwxrenVd90z0ShlF2c0jj9oz8sm67qs2L16H2ro-GQ,15363
|
|
40
|
+
de_ebsd/index/refine/pattern_center.py,sha256=jfBAIImjmHcepFbGBHoWcyKN7ymhcJyTovImJllWpU0,14845
|
|
41
|
+
de_ebsd/index/spherical/__init__.py,sha256=3-Abio7NeLOeQr8Xh3S7Z5P517muh4EoR42LgCIQFm0,958
|
|
42
|
+
de_ebsd/index/spherical/correlation.py,sha256=V0L5aDCQYs_XL4egOwiN_7zC4ODw76fLa42m8Yt4KcU,4821
|
|
43
|
+
de_ebsd/index/spherical/harmonics.py,sha256=9beJ7MBvxL9z5hsqWWn1RLKcM1-1_RzfYCo-ZPkczrA,13072
|
|
44
|
+
de_ebsd/index/spherical/indexer.py,sha256=QrjQsve7dFd-Xtc4nXK7H-tnJEO22BULeLUguFCZxaw,14787
|
|
45
|
+
de_ebsd/index/spherical/wigner.py,sha256=tl60rzeUQ4hD1sl51730ShbpdkNS4mSXuaJOC5GW5SQ,7115
|
|
46
|
+
de_ebsd/sim/__init__.py,sha256=NpQpmclRQHzyOX3VmClgIOPzbQpARd6LVCOw6a6m6ps,642
|
|
47
|
+
de_ebsd/sim/detector.py,sha256=lBp1H48gd-7hK-p-ME4EGWIW1Dx-L1RxhZjA-C4g3cw,5059
|
|
48
|
+
de_ebsd/sim/masterpattern.py,sha256=3b8PgONOeMIVUZNjfIdNWdkcVwaSnnX7mfY1mMONgdE,9285
|
|
49
|
+
de_ebsd/sim/microscope.py,sha256=XaxP87N4APKYreWIuDWdtA7r6ofI85QGypm5xRg0KpY,3149
|
|
50
|
+
de_ebsd/sim/simulator.py,sha256=A5sTfj8i5MS-7O2vq0yG7UysLJsVgZchoz4Ie3XvaKU,12025
|
|
51
|
+
de_ebsd/sim/montecarlo/__init__.py,sha256=1kNvxm5VOEvSAxq7UB9Vc6WDwIx7GhkXwMdQvSVaAUY,499
|
|
52
|
+
de_ebsd/sim/montecarlo/depth.py,sha256=YTVM3IT4a15E_zUJeH9ccr3vwOx8_SXzJPx8wUx_Rtk,6658
|
|
53
|
+
de_ebsd/sim/montecarlo/transport.py,sha256=1yniQ-JBfL7nZ3Gc2HxHEW0gPapX2chDGVm-xbwab4U,20694
|
|
54
|
+
de_ebsd/viz/__init__.py,sha256=_9r_z04l-0RVVDA2WjbWfpu2twArVqoXceyXTBv100c,1442
|
|
55
|
+
de_ebsd/viz/camera.py,sha256=AnLOjq46hcoERF7zifg5reYXkc2LQJZv3ssya9jY-vw,2186
|
|
56
|
+
de_ebsd/viz/depth_widget.js,sha256=FSFxwQtCgmJT8ebvy6hXwLnzwocUuaNKoah7gm5sE30,5925
|
|
57
|
+
de_ebsd/viz/explorer.py,sha256=KkSfnCddA6u2LwbcW4TygaqUvlTuVaBZRwnNtkMQ2p4,26115
|
|
58
|
+
de_ebsd/viz/figures.py,sha256=S9kT7gL7IpU4_WIEXrn2ZcSxRdn_14WPARf4AXacEFA,2388
|
|
59
|
+
de_ebsd/viz/maps.py,sha256=ARbngihHbDbhshI50krCw3fT3xtBL4mnVdbHfzUSLS0,10514
|
|
60
|
+
de_ebsd/viz/patterns.py,sha256=mRKKZ5eUrsCLwP7_Ar6NsPcIZJ5RaILF9NtDLI8U7sA,5788
|
|
61
|
+
de_ebsd/viz/setup_widget.js,sha256=mdaJplaYLfDLTfPyLcZi-biwfidp0Jb-iuVPLt3Wau4,12141
|
|
62
|
+
de_ebsd/viz/views.py,sha256=SdIDocKWOTqgb4CZkMogjQk9k9o7auKqBI2xKC-EMnU,4684
|
|
63
|
+
de_ebsd/viz/widgets.py,sha256=yWqAsHZOGXIS4HjfxR2oGqjwvuXiLltwL8pfzp8lfNg,7228
|
|
64
|
+
de_ebsd-0.2.0.dist-info/licenses/LICENSE,sha256=v1Fr86wVTKRvW6ogT1m8daMI2FbBTYfy8F1AeVOlk9o,35155
|
|
65
|
+
de_ebsd-0.2.0.dist-info/licenses/NOTICE,sha256=0cW-1S8ZVedeYdAa-iVV-WqKkza5F203vhFbesGUXkI,2338
|
|
66
|
+
de_ebsd-0.2.0.dist-info/METADATA,sha256=JtkRrzLtOP66d_0idje7Y8iZ-OsUFlpElYjR277s3Tc,10750
|
|
67
|
+
de_ebsd-0.2.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
68
|
+
de_ebsd-0.2.0.dist-info/top_level.txt,sha256=qsZnl1OBHXFetZDzxHVYURMzNGwfuEjo-KBRbmngz2I,8
|
|
69
|
+
de_ebsd-0.2.0.dist-info/RECORD,,
|