{ "cells": [ { "cell_type": "markdown", "id": "8b9b51ab-7a89-437f-80b6-080030a6233b", "metadata": { "nbsphinx": "hidden" }, "source": [ "This notebook is part of the `kikuchipy` documentation https://kikuchipy.org.\n", "Links to the documentation won't work from the notebook." ] }, { "cell_type": "markdown", "id": "48f0168b-a986-4467-a59d-6e0af1301df9", "metadata": {}, "source": [ "# Hough indexing\n", "\n", "In this tutorial, we will perform Hough/Radon indexing (HI) with [PyEBSDIndex](https://pyebsdindex.readthedocs.io).\n", "We'll use a tiny dataset of recrystallized, polycrystalline nickel available with kikuchipy.\n", "\n", "
\n", "\n", "Note\n", "\n", "PyEBSDIndex is an optional dependency of kikuchipy.\n", "It can be installed with both `pip` and `conda` (from `conda-forge`).\n", "See their [installation instructions](https://pyebsdindex.readthedocs.io/en/latest/user/installation.html) for how to install PyEBSDIndex.\n", "\n", "
\n", "\n", "Let's import necessary libraries" ] }, { "cell_type": "code", "execution_count": null, "id": "386299e8-8698-4efa-a913-440baf6d389e", "metadata": {}, "outputs": [], "source": [ "# Exchange inline for notebook or qt5 (from pyqt) for interactive plotting\n", "%matplotlib inline\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from diffpy.structure import Atom, Lattice, Structure\n", "from diffsims.crystallography import ReciprocalLatticeVector\n", "import kikuchipy as kp\n", "from orix import io, plot\n", "from orix.crystal_map import Phase, PhaseList\n", "from orix.vector import Vector3d\n", "\n", "\n", "plt.rcParams.update({\"font.size\": 15, \"lines.markersize\": 15})" ] }, { "cell_type": "markdown", "id": "3167fc89-7080-4ed7-a146-3b098875e08e", "metadata": {}, "source": [ "Load the dataset of (75, 55) nickel EBSD patterns of (60, 60) pixels with a step size of 1.5 μm" ] }, { "cell_type": "code", "execution_count": null, "id": "f91c0b61-37ce-4666-aeb1-e665ca3a0e8b", "metadata": {}, "outputs": [], "source": [ "s = kp.data.nickel_ebsd_large(allow_download=True)\n", "s" ] }, { "cell_type": "markdown", "id": "086b69bb-712d-414b-81b0-5e955c4bcaf6", "metadata": {}, "source": [ "## Pre-indexing maps\n", "\n", "We start by inspecting two indexing-independent maps showing microstructural features: a [virtual backscatter electron (VBSE) image](virtual_backscatter_electron_imaging.ipynb) and an [image quality (IQ) map](feature_maps.ipynb#Image-quality).\n", "The VBSE image gives a qualitative orientation contrast and is created using the BSE yield on the detector.\n", "We should use the BSE yield of the raw unprocessed patterns.\n", "The IQ map correlates a higher image quality with sharpness of Kikuchi bands.\n", "We should thus use processed patterns here." ] }, { "cell_type": "code", "execution_count": null, "id": "cd9f52d8-1e0b-43d2-bd32-085cea15b19c", "metadata": {}, "outputs": [], "source": [ "vbse_imager = kp.imaging.VirtualBSEImager(s)\n", "print(vbse_imager.grid_shape)" ] }, { "cell_type": "markdown", "id": "9d67599a-f11e-4d48-87bd-3959ebe9a420", "metadata": {}, "source": [ "Get the VBSE image by coloring the three grid tiles in the center of the detector red, green, and blue" ] }, { "cell_type": "code", "execution_count": null, "id": "5ff2bde2-acc2-4b1c-88a5-df96119cb090", "metadata": {}, "outputs": [], "source": [ "maps_vbse_rgb = vbse_imager.get_rgb_image(r=(2, 1), g=(2, 2), b=(2, 3))\n", "maps_vbse_rgb" ] }, { "cell_type": "markdown", "id": "1b85b14b-b91b-45ad-a39b-bb5c9d782e56", "metadata": {}, "source": [ "Plot the VBSE image" ] }, { "cell_type": "code", "execution_count": null, "id": "aa72ad12-fdd3-4d1b-a80a-3f7eb883061b", "metadata": {}, "outputs": [], "source": [ "maps_vbse_rgb.plot()" ] }, { "cell_type": "markdown", "id": "bad0046f-ab46-4478-8703-2dc09f3990f5", "metadata": {}, "source": [ "The orientation contrast shows that the region of interest covers 20-30 grains.\n", "Several of the grains seem to contain annealing twins.\n", "\n", "Enhance the Kikuchi bands by removing the static and dynamic background (see the [pattern processing tutorial](pattern_processing.ipynb) for details)" ] }, { "cell_type": "code", "execution_count": null, "id": "748b330c-0681-43ac-925b-951ebcd402ae", "metadata": {}, "outputs": [], "source": [ "s.remove_static_background()\n", "s.remove_dynamic_background()" ] }, { "cell_type": "markdown", "id": "2d4459e4-6923-47bc-8a00-7c31a6b685cd", "metadata": {}, "source": [ "Get the IQ map" ] }, { "cell_type": "code", "execution_count": null, "id": "dec9bad2-c017-45c9-ab91-32db09c3a0b8", "metadata": {}, "outputs": [], "source": [ "maps_iq = s.get_image_quality()" ] }, { "cell_type": "markdown", "id": "ba216058-097a-44e7-85d1-20e30464c679", "metadata": {}, "source": [ "Plot the IQ map (using the [CrystalMap.plot()](https://orix.readthedocs.io/en/stable/reference/generated/orix.crystal_map.CrystalMap.plot.html) method of the [EBSD.xmap](../reference/generated/kikuchipy.signals.EBSD.xmap.rst) attribute)" ] }, { "cell_type": "code", "execution_count": null, "id": "480d83ad-361a-40f9-97a2-1437b5d76dd2", "metadata": {}, "outputs": [], "source": [ "s.xmap.plot(\n", " maps_iq.ravel(), # Array must be 1D\n", " cmap=\"gray\",\n", " colorbar=True,\n", " colorbar_label=\"Image quality, $Q$\",\n", " remove_padding=True,\n", ")" ] }, { "cell_type": "markdown", "id": "81023608-d459-490c-805c-a93b59594bf3", "metadata": {}, "source": [ "We recognize the boundaries of grains and (presumably) the annealing twins seen in the VBSE image.\n", "There are some dark lines, e.g. to the lower and upper left, which look like scratches on the sample surface." ] }, { "cell_type": "markdown", "id": "784d523f-238b-4065-abea-314159a50de9", "metadata": {}, "source": [ "## Calibrate detector-sample geometry\n", "\n", "Indexing requires knowledge of the position of the sample with respect to the detector.\n", "The detector-sample geometry is described by the projection or pattern center (PC) and the tilts of the detector and the sample (see the [reference frames tutorial](reference_frames.ipynb) for all conventions).\n", "We assume the tilts are known and are thus required input.\n", "We will estimate the PC.\n", "We do so by optimizing an initial guess of the PC (obtained from similar experiments on the same microscope) using a few selected patterns.\n", "\n", "All detector-sample geometry parameters are conveniently stored in an [EBSDDetector](../reference/generated/kikuchipy.detectors.EBSDDetector.rst)" ] }, { "cell_type": "code", "execution_count": null, "id": "3085ad18-b7bd-4fce-95fa-e3a9a8c3ea9a", "metadata": {}, "outputs": [], "source": [ "sig_shape = s.axes_manager.signal_shape[::-1] # Make (rows, columns)\n", "det = kp.detectors.EBSDDetector(sig_shape, sample_tilt=70)\n", "det" ] }, { "cell_type": "markdown", "id": "602ee407-2f25-4021-9f18-f299f587cfd2", "metadata": {}, "source": [ "Extract selected patterns from the full dataset.\n", "The patterns should be spread out evenly in a map grid to prevent the estimation being biased by diffraction from particular grains or areas of the sample" ] }, { "cell_type": "code", "execution_count": null, "id": "e007ff94-019d-498a-a6b7-4820bf60147d", "metadata": {}, "outputs": [], "source": [ "grid_shape = (5, 4)\n", "s_grid, idx = s.extract_grid(grid_shape, return_indices=True)\n", "s_grid" ] }, { "cell_type": "markdown", "id": "10c679b7-0b31-4afe-9152-40a2cd2f85d3", "metadata": {}, "source": [ "Plot the grid from where the patterns are extracted on the IQ map" ] }, { "cell_type": "code", "execution_count": null, "id": "bf54b0aa-bd42-4200-bc8d-a36558757d07", "metadata": {}, "outputs": [], "source": [ "nav_shape = s.axes_manager.navigation_shape[::-1]\n", "\n", "kp.draw.plot_pattern_positions_in_map(\n", " rc=idx.reshape(2, -1).T, # Shape (n patterns, 2)\n", " roi_shape=nav_shape, # Or maps_iq.shape\n", " roi_image=maps_iq,\n", ")" ] }, { "cell_type": "markdown", "id": "b9b740e5-c178-4236-8bcc-415e85bd9948", "metadata": {}, "source": [ "We optimize one PC per pattern in this grid using [EBSD.hough_indexing_optimize_pc()](../reference/generated/kikuchipy.signals.EBSD.hough_indexing_optimize_pc.rst).\n", "The method calls the `PyEBSDIndex` function\n", "[pcopt.optimize()](https://pyebsdindex.readthedocs.io/en/stable/reference/generated/pyebsdindex.pcopt.optimize.html) internally.\n", "Hough indexing with `PyEBSDIndex` requires the use of an [EBSDIndexer](https://pyebsdindex.readthedocs.io/en/stable/reference/generated/pyebsdindex.ebsd_index.EBSDIndexer.html).\n", "The indexer stores the list of candidate phases, detector information, and indexing parameters such as the resolution of the Hough transform and the number of bands to use for orientation estimation.\n", "We could create this indexer from scratch.\n", "Another approach is to get it from an `EBSDDetector` via [EBSDDetector.get_indexer()](../reference/generated/kikuchipy.detectors.EBSDDetector.get_indexer.rst).\n", "This method requires a [PhaseList](https://orix.readthedocs.io/en/stable/reference/generated/orix.crystal_map.PhaseList.html).\n", "\n", "We can optionally pass in a list of reflectors per phase (either directly the \\{hkl\\} or [ReciprocalLatticeVector](https://diffsims.readthedocs.io/en/stable/reference.html#diffsims.crystallography.ReciprocalLatticeVector)).\n", "The strongest reflectors (bands) for a phase are most likely to be detected in the Radon transform for indexing.\n", "Our reflector list should ideally contain these bands.\n", "We also need to make sure that our reflector list has enough bands for consistent indexing.\n", "This is especially important for multi-phase indexing.\n", "We can build up a suitable reflector list with `ReciprocalLatticeVector`; see e.g. the tutorial on [kinematical simulations](kinematical_ebsd_simulations.ipynb) for how to do this for nickel (point group m-3m), the tetragonal sigma phase in steels (4/mmm), and an hexagonal silicon carbide phase (6mm)." ] }, { "cell_type": "code", "execution_count": null, "id": "ab80ae0d-01df-48df-a8d6-acbe89f31aa2", "metadata": {}, "outputs": [], "source": [ "phase_list = PhaseList(\n", " Phase(\n", " name=\"ni\",\n", " space_group=225,\n", " structure=Structure(\n", " lattice=Lattice(3.5236, 3.5236, 3.5236, 90, 90, 90),\n", " atoms=[Atom(\"Ni\", [0, 0, 0])],\n", " ),\n", " ),\n", ")\n", "phase_list" ] }, { "cell_type": "code", "execution_count": null, "id": "071b1dfb-1a23-4f11-9a16-d3f5df3a5418", "metadata": {}, "outputs": [], "source": [ "indexer = det.get_indexer(\n", " phase_list,\n", " [[1, 1, 1], [2, 0, 0], [2, 2, 0], [3, 1, 1]],\n", " nBands=10,\n", " tSigma=2,\n", " rSigma=2\n", ")\n", "\n", "print(indexer.vendor)\n", "print(indexer.sampleTilt)\n", "print(indexer.camElev)\n", "print(indexer.PC)\n", "\n", "print(indexer.phaselist[0].latticeparameter)\n", "print(indexer.phaselist[0].polefamilies)" ] }, { "cell_type": "markdown", "id": "7de31498-4c49-4b17-b9f1-c7f570047989", "metadata": {}, "source": [ "We overwrote the defaults of some of the Hough indexing parameters to use values suggested in PyEBSDIndex' [Radon indexing tutorial](https://pyebsdindex.readthedocs.io/en/stable/tutorials/ebsd_index_demo.html):\n", "\n", "* tSigma: size of the Gaussian kernel in the $\\theta$ direction in the Radon transform $(\\rho, \\theta)$\n", "* rSigma: size of the Gaussian kernel in the $\\rho$ direction\n", "\n", "We also set the number of bands to search for in the Radon transform to 10.\n", "This is because testing has shown that the default number of 9 can be too few bands for some of the patterns in this dataset." ] }, { "cell_type": "markdown", "id": "50b66e56-df61-4252-bc07-2bf8c37405a3", "metadata": {}, "source": [ "Now, we can optimize the PCs for each pattern in the extracted grid.\n", "(We will \"overwrite\" the existing detector variable.)\n", "We use the particle swarm optimization (PSO) algorithm implemented in `PyEBSDIndex`\n", "The search limit range is set to +/- 0.05 (default is 0.2) since we are sufficiently confident that all PCs are within this range; if we were not, we should increase the search limit." ] }, { "cell_type": "code", "execution_count": null, "id": "7e737efa-229d-462a-aef5-851032b29b54", "metadata": {}, "outputs": [], "source": [ "det = s_grid.hough_indexing_optimize_pc(\n", " pc0=[0.42, 0.22, 0.50], # Initial guess based on previous experiments\n", " indexer=indexer,\n", " batch=True,\n", " method=\"PSO\",\n", " search_limit=0.05,\n", ")\n", "\n", "# Print mean and standard deviation\n", "print(det.pc_flattened.mean(axis=0))\n", "print(det.pc_flattened.std(0))" ] }, { "cell_type": "markdown", "id": "ef2b49ce-3194-413c-b564-f223f0cccd13", "metadata": {}, "source": [ "Plot the PCs" ] }, { "cell_type": "code", "execution_count": null, "id": "edb85679-0358-4300-ac23-a738e52732ab", "metadata": {}, "outputs": [], "source": [ "det.plot_pc(\"scatter\", s=50, annotate=True)" ] }, { "cell_type": "markdown", "id": "7928b35d-a315-4d75-8322-a98fe847bc45", "metadata": {}, "source": [ "The values do not order nicely in the grid they were extracted from...\n", "This is not surprising since they are only (60, 60) pixels wide!\n", "Fortunately, the spread is small, and, since the region of interest covers such as small area, we can use the mean PC for indexing." ] }, { "cell_type": "code", "execution_count": null, "id": "96991049-7742-4851-817c-6e7c308b50cc", "metadata": {}, "outputs": [], "source": [ "det.pc = det.pc_average" ] }, { "cell_type": "markdown", "id": "8c6cc769-8ee2-499e-a9be-46f4c8d15dc6", "metadata": {}, "source": [ "We can check the position of the mean PC on the detector before using it" ] }, { "cell_type": "code", "execution_count": null, "id": "7eb88c8b-0018-4ae6-a3d9-fd7014b9765d", "metadata": {}, "outputs": [], "source": [ "det.plot(pattern=s_grid.inav[0, 0].data)" ] }, { "cell_type": "markdown", "id": "a0692f45-3059-46d0-a5c8-df2b0fadbd2e", "metadata": {}, "source": [ "## Perform indexing\n", "\n", "We will index all patterns with this PC calibration.\n", "We get a new indexer from the detector with the average PC as determined from the optimization above" ] }, { "cell_type": "code", "execution_count": null, "id": "54710226-9623-4261-9100-e27239be3978", "metadata": {}, "outputs": [], "source": [ "indexer = det.get_indexer(\n", " phase_list,\n", " [[1, 1, 1], [2, 0, 0], [2, 2, 0], [3, 1, 1]],\n", " nBands=10,\n", " tSigma=2,\n", " rSigma=2\n", ")\n", "indexer.PC" ] }, { "cell_type": "markdown", "id": "59ac5e5b-5e59-4c5b-9b0b-b3cd035e92e6", "metadata": {}, "source": [ "Hough indexing is done with [EBSD.hough_indexing()](../reference/generated/kikuchipy.signals.EBSD.hough_indexing.rst).\n", "Since we ask `PyEBSDIndex` to be \"verbose\" when reporting on the indexing progress, a figure with the last pattern and its Radon transform is shown.\n", "We need to pass the phase list again to `EBSD.hough_indexing()` (the indexer does not keep all phase information stored in the list [atoms are lost]) for the phases to be described correctly in the returned [CrystalMap](https://orix.readthedocs.io/en/stable/reference/generated/orix.crystal_map.CrystalMap.html)." ] }, { "cell_type": "code", "execution_count": null, "id": "1830c550-c4e7-4a62-9fc3-8c9772726497", "metadata": {}, "outputs": [], "source": [ "xmap = s.hough_indexing(phase_list=phase_list, indexer=indexer, verbose=2)" ] }, { "cell_type": "code", "execution_count": null, "id": "bc302021-c9ee-470d-ad48-90ddf1207643", "metadata": {}, "outputs": [], "source": [ "xmap" ] }, { "cell_type": "markdown", "id": "b52c3b99-3f6b-4025-8ad0-83d7dd7f66a3", "metadata": {}, "source": [ "We see that all points were indexed as nickel.\n", "\n", "Using [orix](https://orix.readthedocs.io/en/stable/reference/generated/orix.io.save.html#orix.io.save), the indexing results can be exported to an HDF5 file or a text file (.ang) importable by software such as `MTEX` or other commercial software" ] }, { "cell_type": "code", "execution_count": null, "id": "5491ebb1-78f4-4239-96e2-50887e91eb87", "metadata": {}, "outputs": [], "source": [ "#io.save(\"xmap_ni.h5\", xmap)\n", "#io.save(\n", "# \"xmap_ni.ang\",\n", "# xmap,\n", "# image_quality_prop=\"pq\",\n", "# confidence_index_prop=\"cm\",\n", "# extra_prop=\"nmatch\",\n", "#)" ] }, { "cell_type": "markdown", "id": "4b95f09e-f834-4cd2-a6b6-188d586a4829", "metadata": {}, "source": [ "Before analyzing the returned orientations, however, we should validate our results." ] }, { "attachments": {}, "cell_type": "markdown", "id": "26510f7d-5fb6-4b02-8fa2-1745334798ec", "metadata": {}, "source": [ "## Validate indexing results\n", "\n", "We validate our results by inspecting indexing quality metrics, inverse pole figure (IPF) maps, and comparing geometrical simulations to the experimental patterns.\n", "\n", "Plot quality metrics" ] }, { "cell_type": "code", "execution_count": null, "id": "42eb10aa-f94a-4f73-8b27-ece7a9366b6f", "metadata": {}, "outputs": [], "source": [ "aspect_ratio = xmap.shape[1] / xmap.shape[0]\n", "figsize = (8 * aspect_ratio, 4.5 * aspect_ratio)\n", "\n", "fig, axes = plt.subplots(nrows=2, ncols=2, figsize=figsize, layout=\"tight\")\n", "for ax, to_plot in zip(axes.ravel(), [\"pq\", \"cm\", \"fit\", \"nmatch\"]):\n", " im = ax.imshow(xmap.get_map_data(to_plot))\n", " fig.colorbar(im, ax=ax, label=to_plot)\n", " ax.axis(\"off\")" ] }, { "cell_type": "code", "execution_count": null, "id": "cea4d93e-3fb5-4d77-b8c3-f8ef7baddb3e", "metadata": {}, "outputs": [], "source": [ "fig, axes = plt.subplots(ncols=2, nrows=2, figsize=(10, 5), layout=\"tight\")\n", "for ax, to_plot in zip(axes.ravel(), [\"pq\", \"cm\", \"fit\", \"nmatch\"]):\n", " ax.hist(xmap.prop[to_plot], bins=100)\n", " ax.set(xlabel=to_plot, ylabel=\"Frequency\");" ] }, { "cell_type": "markdown", "id": "d31d51e9-db59-4643-90f1-33db6da7ac72", "metadata": {}, "source": [ "The pattern quality (PQ) and confidence metric (CM) maps show little variation across the sample.\n", "The most important map here is that of the pattern fit, also known as the mean angular error/deviation (MAE/MAD): it shows the average angular deviation between the positions of each detected band to the closest \"theoretical\" band in the indexed solution.\n", "The pattern fit is below an OK fit of 1.4$^{\\circ}$ for all patterns.\n", "We see that the highest (worst) fit is found in the upper left corner where we recognized some scratches in our IQ map.\n", "The final map (*nmatch*) shows that most detected bands were matched inside most of the grains, with as few as four on some grain boundaries and triple junctions.\n", "See `PyEBSDIndex`' [Radon indexing tutorial](https://pyebsdindex.readthedocs.io/en/latest/tutorials/ebsd_index_demo.html) for a complete explanation of all the indexing quality metrics." ] }, { "cell_type": "markdown", "id": "6b5721ae-85bf-4604-89c2-80967f6b81a7", "metadata": {}, "source": [ "Create a color key to get IPF colors with" ] }, { "cell_type": "code", "execution_count": null, "id": "18eb8100-cc02-455d-9bd3-6e864589dfb1", "metadata": {}, "outputs": [], "source": [ "v_ipf = Vector3d.xvector()\n", "sym = xmap.phases[0].point_group\n", "\n", "ckey = plot.IPFColorKeyTSL(sym, v_ipf)\n", "ckey" ] }, { "cell_type": "markdown", "id": "77451774-c1fc-40e6-a94c-fcd626a20695", "metadata": {}, "source": [ "Each point is assigned a color based on which crystal direction $\\left$ points in a certain sample direction.\n", "Let's plot the IPF-X map with the confidence metric map overlayed" ] }, { "cell_type": "code", "execution_count": null, "id": "dac157a4-3b96-49f8-a5eb-f3987c9af076", "metadata": { "nbsphinx-thumbnail": { "tooltip": "Hough indexing using PyEBSDIndex" }, "tags": [ "nbsphinx-thumbnail" ] }, "outputs": [], "source": [ "rgb_x = ckey.orientation2color(xmap.rotations)\n", "fig = xmap.plot(rgb_x, overlay=\"cm\", remove_padding=True, return_figure=True)\n", "\n", "# Place color key in bottom right corner, coordinates are [left, bottom, width, height]\n", "ax_ckey = fig.add_axes(\n", " [0.76, 0.08, 0.2, 0.2], projection=\"ipf\", symmetry=sym\n", ")\n", "ax_ckey.plot_ipf_color_key(show_title=False)\n", "ax_ckey.patch.set_facecolor(\"None\")" ] }, { "cell_type": "markdown", "id": "f252e330-0405-4b06-a422-e50291d6509f", "metadata": {}, "source": [ "Let's also plot the three IPF maps for sample **X**, **Y**, and **Z** side by side" ] }, { "cell_type": "code", "execution_count": null, "id": "99d5f1ff-4919-40b8-aea2-d2e7b8a72d8b", "metadata": { "tags": [] }, "outputs": [], "source": [ "directions = Vector3d(((1, 0, 0), (0, 1, 0), (0, 0, 1)))\n", "n = directions.size\n", "\n", "figsize = (4 * n * aspect_ratio, n * aspect_ratio)\n", "fig, ax = plt.subplots(ncols=n, figsize=figsize)\n", "for i, title in zip(range(n), [\"X\", \"Y\", \"Z\"]):\n", " ckey.direction = directions[i]\n", " rgb = ckey.orientation2color(xmap.rotations)\n", " ax[i].imshow(rgb.reshape(xmap.shape + (3,)))\n", " ax[i].set_title(f\"IPF-{title}\")\n", " ax[i].axis(\"off\")\n", "fig.subplots_adjust(wspace=0.02)" ] }, { "cell_type": "markdown", "id": "4a700d96-3b7c-4a8f-a170-118664de8fb7", "metadata": {}, "source": [ "The IPF maps show grains and twins as we expected from the VBSE image and IQ map obtained before indexing.\n", "\n", "Plot geometrical simulations on top of the experimental patterns (see the [geometrical simulations tutorial](geometrical_ebsd_simulations.ipynb) for details)" ] }, { "cell_type": "code", "execution_count": null, "id": "3abfc6c2-761d-4fac-856a-a76973f287b2", "metadata": {}, "outputs": [], "source": [ "ref = ReciprocalLatticeVector(\n", " phase=xmap.phases[0], hkl=[[1, 1, 1], [2, 0, 0], [2, 2, 0], [3, 1, 1]]\n", ")\n", "ref = ref.symmetrise()\n", "simulator = kp.simulations.KikuchiPatternSimulator(ref)\n", "sim = simulator.on_detector(det, xmap.rotations.reshape(*xmap.shape))" ] }, { "cell_type": "markdown", "id": "b166a003-07b0-4567-a82a-374f178e44b1", "metadata": {}, "source": [ "Add markers to EBSD signal" ] }, { "cell_type": "code", "execution_count": null, "id": "2d692d56-8e94-4b8c-bfe0-e2faba5431ce", "metadata": {}, "outputs": [], "source": [ "# To remove existing markers\n", "# del s.metadata.Markers\n", "\n", "markers = sim.as_markers()\n", "s.add_marker(markers, plot_marker=False, permanent=True)" ] }, { "cell_type": "markdown", "id": "e81634c2-eaa7-4c75-967a-bd6a02ed1fcc", "metadata": {}, "source": [ "Navigate patterns with simulations in the IPF-X map (see the [visualization tutorial](visualizing_patterns.ipynb) for details)" ] }, { "cell_type": "code", "execution_count": null, "id": "bc8f8eb5-9309-4f3d-aeb0-1b4acbf83cdd", "metadata": {}, "outputs": [], "source": [ "maps_nav_rgb = kp.draw.get_rgb_navigator(rgb_x.reshape(xmap.shape + (3,)))" ] }, { "cell_type": "code", "execution_count": null, "id": "a93e4267-ec14-40d3-b7f3-492c90d1743a", "metadata": {}, "outputs": [], "source": [ "s.plot(maps_nav_rgb)" ] }, { "cell_type": "markdown", "id": "850eade8-aa9c-4f0c-9610-5d919310cab8", "metadata": {}, "source": [ "## What's next?" ] }, { "cell_type": "markdown", "id": "a338d588-f626-4b44-95c6-df44ab4f5d1e", "metadata": {}, "source": [ "If we require a high angular resolution, we might achieve this via refining returned orientations using dynamical simulations.\n", "See the [refinement section](pattern_matching.ipynb#Refinement) of the pattern matching tutorial for how to do this.\n", "\n", "If our validation shows unexpectedly bad results, there are a few key parameters we should look into:\n", "\n", "* Phase information: lattice parameters or space group symmetry might be incorrect.\n", "* Detector-sample geometry: sample and detector tilts, but most importantly, the projection center!\n", "* Hough indexing parameters:\n", " * Reflector list: perhaps the default list or the list passed in by us contain too few reflectors, or they are not the brightest bands for a particular phase?\n", " * The Gaussian kernel widths for parameters $(\\rho, \\theta)$ in the Radon transform can affect which bands are detected (wider or narrower). A parameter search might be benefitial.\n", " \n", "If we want to speed up Hough indexing, we could try to use `PyEBSDIndex`' multi-threading functionality ([see the [Radon indexing demo](https://pyebsdindex.readthedocs.io/en/stable/tutorials/ebsd_index_demo.html) for details)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 }