From 82dc224db220bcb9416429371c08f7da2e5b5b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 2 Apr 2024 19:31:53 +0200 Subject: [PATCH 01/19] Simplify test failing on macOS with Python 3.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- orix/tests/plot/test_stereographic_plot.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/orix/tests/plot/test_stereographic_plot.py b/orix/tests/plot/test_stereographic_plot.py index dd399b59..4be1cd9b 100644 --- a/orix/tests/plot/test_stereographic_plot.py +++ b/orix/tests/plot/test_stereographic_plot.py @@ -495,20 +495,20 @@ def test_pdf_args_raises(self): class TestRestrictToFundamentalSector: def test_restrict_to_fundamental_sector(self): - fig1, ax1 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) + _, ax1 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) vertices = ax1.patches[0].get_verts() - # C1's has no fundamental sector, so the circle marking the + # C1 has no fundamental sector, so the circle marking the # edge of the axis region should be unchanged - fig2, ax2 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) + _, ax2 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) ax2.restrict_to_sector(symmetry.C1.fundamental_sector) assert np.allclose(vertices, ax2.patches[0].get_verts()) - # C6's fundamental sector is 1 / 6 of the unit sphere, with + # C6 fundamental sector is 1 / 6 of the unit sphere, with # half of it in the upper hemisphere - fig3, ax3 = plt.subplots(ncols=2, subplot_kw=dict(projection=PROJ_NAME)) + _, ax3 = plt.subplots(ncols=2, subplot_kw=dict(projection=PROJ_NAME)) ax3[0].restrict_to_sector(symmetry.C6.fundamental_sector) - assert not np.allclose(vertices, ax3[0].patches[0].get_verts()) + assert not np.allclose(vertices[:10], ax3[0].patches[0].get_verts()[:10]) assert ax3[0].patches[1].get_label() == "sa_sector" # Ensure grid lines are clipped by sector @@ -518,13 +518,13 @@ def test_restrict_to_fundamental_sector(self): # Oh's fundamental sector is only in the upper hemisphere, # so the same as C1's sector applies for the lower hemisphere fs = symmetry.Oh.fundamental_sector - fig4, ax4 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) + _, ax4 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) ax4.restrict_to_sector(fs) upper_patches4 = ax4.patches assert len(upper_patches4) == 2 assert upper_patches4[1].get_label() == "sa_sector" - fig5, ax5 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) + _, ax5 = plt.subplots(subplot_kw=dict(projection=PROJ_NAME)) ax5.hemisphere = "lower" ax5.restrict_to_sector(fs) lower_patches4 = ax5.patches From 06847cecf8fc293a7aa1c895024ce384c315e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 2 Apr 2024 20:04:23 +0200 Subject: [PATCH 02/19] Add test dependency on pytest-rerunfailures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 1e127c58..f8935932 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ "numpydoc", "pytest >= 5.4", "pytest-cov >= 2.8.1", + "pytest-rerunfailures", "pytest-xdist", ], } From c0d4123e01b9cb79e069615b643e88d62d7c3c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 2 Apr 2024 20:04:45 +0200 Subject: [PATCH 03/19] Rerun flaky tests using pytest-rerunfailures on GitHub CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .github/workflows/build.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 034ef4ba..3df842a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,9 +10,6 @@ on: workflow_dispatch: workflow: '*' -env: - MPLBACKEND: agg - jobs: code: name: code style @@ -59,15 +56,16 @@ jobs: name: ${{ matrix.os }}-py${{ matrix.python-version }}${{ matrix.LABEL }} runs-on: ${{ matrix.os }} timeout-minutes: 15 + env: + MPLBACKEND: agg strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ["3.10", "3.11"] + python-version: ['3.10', '3.11'] include: - os: ubuntu-latest python-version: 3.7 - OLDEST_SUPPORTED_VERSION: true DEPENDENCIES: diffpy.structure==3 matplotlib==3.5 LABEL: -oldest steps: @@ -84,7 +82,7 @@ jobs: pip install -U -e .'[doc, tests]' - name: Install oldest supported version - if: ${{ matrix.OLDEST_SUPPORTED_VERSION }} + if: ${{ contains(matrix.LABEL, 'oldest') }} run: | pip install ${{ matrix.DEPENDENCIES }} @@ -102,7 +100,7 @@ jobs: - name: Run tests run: | - pytest -n 2 --cov=orix --pyargs orix + pytest --pyargs orix --reruns 2 -n 2 --cov=orix - name: Generate line coverage if: ${{ matrix.os == 'ubuntu-latest' }} From 2a5a177396700337928ff1f9da68dc3140c261da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 2 Apr 2024 20:05:15 +0200 Subject: [PATCH 04/19] Clarify change of atom positions in Phase when enforcing axes alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- CHANGELOG.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f84b0e01..abdec641 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,8 +31,9 @@ Added - The ``random()`` methods of ``Orientation`` and ``Misorientation`` now accept ``symmetry``. A ``random()`` method is also added to ``Vector3d`` and ``Miller``, the latter accepting a ``phase``. -- ``Added orix.sampling.get_sample_zone_axis`` for getting zone axes for some point group. -- ``Added orix.sampling.get_sample_reduced_fundamental`` for getting reduced +- Added ``orix.sampling.get_sample_zone_axis()`` for getting zone axes for some point + group. +- Added ``orix.sampling.get_sample_reduced_fundamental()`` for getting reduced fundamental zone for some point group. Changed @@ -50,14 +51,13 @@ Deprecated and will be removed in v0.13. Use the existing ``from_axes_angles()`` and the new ``from_rodrigues()`` and ``from_homochoric()`` instead. -Removed -------- - Fixed ----- - Transparency of polar stereographic grid lines can now be controlled by Matplotlib's ``grid.alpha``, just like the azimuth grid lines. -- Previously ``Phase`` was failing to adjust atom position to accomodate for the change of basis. This is now fixed. +- Previously, ``Phase`` did not adjust atom positions when forcing + ``Phase.structure.lattice.base`` to use the crystal axes alignment ``e1 || a``, + ``e3 || c*``. This is now fixed. 2023-03-14 - version 0.11.1 =========================== From fcb632a679183592a189c4bc6657c08a5565a4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 2 Apr 2024 20:06:11 +0200 Subject: [PATCH 05/19] Add Carter Francis to package credits (not just Zenodo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- orix/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/orix/__init__.py b/orix/__init__.py index fbf0637c..1c4340d4 100644 --- a/orix/__init__.py +++ b/orix/__init__.py @@ -13,6 +13,7 @@ "Niels Cautaerts", "Austin Gerlt", "Anders Christian Mathisen", + "Carter Francis", "Simon Høgås", "Alexander Clausen", "Viljar Johan Femoen", From 7ee93f1193c2a2ecaa6c0fee484e1104715759db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 08:58:12 +0200 Subject: [PATCH 06/19] Remove PDF build of docs for now so that "latest" build passes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- readthedocs.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/readthedocs.yaml b/readthedocs.yaml index d56c3312..d79c568b 100644 --- a/readthedocs.yaml +++ b/readthedocs.yaml @@ -17,9 +17,10 @@ build: apt_packages: - imagemagick -# Build doc in all formats (HTML, PDF and ePub) +# Doc formats formats: - - pdf + - htmlzip +# - pdf conda: environment: doc/environment.yml From 86d03d8e2e321146822163f45766e069ed0ee684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 08:58:53 +0200 Subject: [PATCH 07/19] Move example of creation of empty crystal map to examples gallery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- examples/crystal_maps/create_empty_map.py | 19 +++++++++++++++++++ orix/crystal_map/crystal_map.py | 11 ----------- 2 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 examples/crystal_maps/create_empty_map.py diff --git a/examples/crystal_maps/create_empty_map.py b/examples/crystal_maps/create_empty_map.py new file mode 100644 index 00000000..437de6f5 --- /dev/null +++ b/examples/crystal_maps/create_empty_map.py @@ -0,0 +1,19 @@ +""" +======================== +Create empty crystal map +======================== + +This example shows how to create an empty crystal map of a given shape. +By empty, we here mean that it is filled with identity rotations. + +This crystal map can be useful for testing. +""" + +from orix.crystal_map import CrystalMap + +xmap = CrystalMap.empty((5, 10)) + +print(xmap) +print(xmap.rotations) + +xmap.plot("x") diff --git a/orix/crystal_map/crystal_map.py b/orix/crystal_map/crystal_map.py index d0cfe2d1..aae07db9 100644 --- a/orix/crystal_map/crystal_map.py +++ b/orix/crystal_map/crystal_map.py @@ -775,17 +775,6 @@ def empty( ------- xmap Crystal map. - - Examples - -------- - >>> from orix.crystal_map import CrystalMap - >>> xmap = CrystalMap.empty((5, 10)) - >>> xmap - Phase Orientations Name Space group Point group Proper point group Color - 0 50 (100.0%) None None None None tab:blue - Properties: - Scan unit: px - >>> xmap.plot("x") # Increasing towards the right """ d, n = create_coordinate_arrays(shape, step_sizes) d["rotations"] = Rotation.identity((n,)) From 92a08bf2e41b93b122ddec2c0e8605b26601dc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 08:59:39 +0200 Subject: [PATCH 08/19] Pass "c" to Matplotlib for setting facecolor instead of "fc" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- doc/tutorials/crystal_reference_frame.ipynb | 6 +++--- doc/tutorials/point_groups.ipynb | 6 +++--- .../misorientation_from_aligning_directions.py | 2 +- .../orientations/orientation_from_aligning_directions.py | 3 ++- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/tutorials/crystal_reference_frame.ipynb b/doc/tutorials/crystal_reference_frame.ipynb index 254db03f..5c6d2f5e 100644 --- a/doc/tutorials/crystal_reference_frame.ipynb +++ b/doc/tutorials/crystal_reference_frame.ipynb @@ -220,7 +220,7 @@ "source": [ "## Alignment of symmetry operations\n", "\n", - "To see where the crystallographic axes about which the point group symmetry operations rotate, we can add symmetry operations to the figure, like is done in the [Visualizing point groups](point_groups.ipynb) tutorial for all point groups supported in orix" + "To see which crystallographic axes the point group symmetry operations rotate about, we can add symmetry operations to the figure, like is done in the [Visualizing point groups](point_groups.ipynb) tutorial for all point groups supported in orix" ] }, { @@ -238,7 +238,7 @@ "outputs": [], "source": [ "R = Rotation.from_axes_angles([0, 1, 0], -65, degrees=True)\n", - "phase.point_group.plot(figure=fig, orientation=R, fc=\"none\", ec=\"C0\", s=150)\n", + "phase.point_group.plot(figure=fig, orientation=R)\n", "fig" ] }, @@ -299,7 +299,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.8" } }, "nbformat": 4, diff --git a/doc/tutorials/point_groups.ipynb b/doc/tutorials/point_groups.ipynb index 13bba18c..800f9439 100644 --- a/doc/tutorials/point_groups.ipynb +++ b/doc/tutorials/point_groups.ipynb @@ -127,10 +127,10 @@ " # respectively, for Symmetry.plot()\n", "\n", " # vectors on the upper hemisphere are shown as open circles\n", - " ax[i].scatter(v, marker=\"o\", fc=\"None\", ec=\"k\", s=150)\n", + " ax[i].scatter(v, marker=\"o\", c=\"None\", ec=\"C0\", s=150)\n", " # vectors on the lower hemisphere are reprojected onto the upper\n", " # hemisphere and shown as crosses\n", - " ax[i].scatter(v_reproject, marker=\"+\", ec=\"C0\", s=150)\n", + " ax[i].scatter(v_reproject, marker=\"+\", c=\"C0\", s=150)\n", "\n", " ax[i].set_title(f\"${S}$ $({Si.name})$\")\n", " ax[i].set_labels(\"$e_1$\", \"$e_2$\", None)" @@ -156,7 +156,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.8" } }, "nbformat": 4, diff --git a/examples/misorientations/misorientation_from_aligning_directions.py b/examples/misorientations/misorientation_from_aligning_directions.py index 1fcf8bc0..80d5246c 100644 --- a/examples/misorientations/misorientation_from_aligning_directions.py +++ b/examples/misorientations/misorientation_from_aligning_directions.py @@ -64,8 +64,8 @@ # Plot the two directions in the (unrotated) first crystal's reference # frame as open circles fig = t_cubic.scatter( + c="none", ec=["r", "b"], - fc="none", grid=True, axes_labels=["e1", "e2"], return_figure=True, diff --git a/examples/orientations/orientation_from_aligning_directions.py b/examples/orientations/orientation_from_aligning_directions.py index cbfb6d24..472cd150 100644 --- a/examples/orientations/orientation_from_aligning_directions.py +++ b/examples/orientations/orientation_from_aligning_directions.py @@ -1,3 +1,4 @@ +# %% r""" ==================================== Orientation from aligning directions @@ -39,8 +40,8 @@ # Plot the reference orientation sample directions as empty circles fig = v.scatter( + c="none", ec=["r", "b"], - fc="none", grid=True, axes_labels=["X", "Y"], return_figure=True, From f3c4a22604b76da62e11e5e7591da1852212b04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 09:00:29 +0200 Subject: [PATCH 09/19] Encapsulate PyPI selectors in string, ".[dev]", so it works on Mac with zsh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- doc/dev/building_writing_documentation.rst | 5 +---- doc/dev/running_writing_tests.rst | 7 ++----- doc/dev/setting_up_development_installation.rst | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/doc/dev/building_writing_documentation.rst b/doc/dev/building_writing_documentation.rst index 657d69a5..5bd8d66d 100644 --- a/doc/dev/building_writing_documentation.rst +++ b/doc/dev/building_writing_documentation.rst @@ -10,7 +10,7 @@ New documents should fit into one of these categories. We use :doc:`Sphinx ` for documenting functionality. Install necessary dependencies to build the documentation:: - pip install --editable .[doc] + pip install --editable ".[doc]" .. note:: @@ -19,9 +19,6 @@ Install necessary dependencies to build the documentation:: See the section on the :ref:`data module ` for more details. -If you get an error message running the above in a ``zsh`` shell, try wrapping the last -part in a string, like ``'.[doc]'``. - Then, build the documentation from the ``doc`` directory:: cd doc diff --git a/doc/dev/running_writing_tests.rst b/doc/dev/running_writing_tests.rst index 53bbaa66..f1bffa23 100644 --- a/doc/dev/running_writing_tests.rst +++ b/doc/dev/running_writing_tests.rst @@ -6,10 +6,7 @@ The tests reside in a ``tests`` module. Tests are short methods that call functions in ``orix`` and compare resulting output values with known answers. Install necessary dependencies to run the tests:: - pip install --editable .[tests] - -If you get an error message running the above in a ``zsh`` shell, try wrapping the last -part in a string, like ``'.[tests]'``. + pip install --editable ".[tests]" Some useful :doc:`fixtures ` are available in the ``conftest.py`` file. @@ -39,7 +36,7 @@ Docstring examples are tested :doc:`with pytest ` as well already available in the namespace as ``np`` and ``plt``, respectively. The docstring tests can be run from the top directory:: - pytest --doctest-modules --ignore-glob=orix/tests orix/*.py + pytest orix --doctest-modules --ignore-glob=orix/tests Tips for writing tests of Numba decorated functions: diff --git a/doc/dev/setting_up_development_installation.rst b/doc/dev/setting_up_development_installation.rst index 37d6f0a7..dec8e07c 100644 --- a/doc/dev/setting_up_development_installation.rst +++ b/doc/dev/setting_up_development_installation.rst @@ -26,7 +26,7 @@ with the `Miniconda distribution Date: Thu, 4 Apr 2024 09:01:04 +0200 Subject: [PATCH 10/19] Update list of applications paper with the one from @maclariz on Ti MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- doc/user/applications.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/user/applications.rst b/doc/user/applications.rst index 2633f932..d55f8fa4 100644 --- a/doc/user/applications.rst +++ b/doc/user/applications.rst @@ -12,6 +12,14 @@ If you think your work should be listed here, please raise an issue `on GitHub `__ or `contact the developers `__. +2024 +==== +- I. MacLaren, E. Frutos-Myro, S. Zeltmann, C. Ophus, "A method for crystallographic + mapping of an alpha-beta titanium alloy with nanometre resolution using scanning + precession electron diffraction and open-source software libraries," *Journal of + Microscopy*, 1-9 (2024). + https://doi/10.1111/jmi.13275. + 2022 ==== From 2a33e3c0ae43c2e1da5cbf549428149d52898561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 09:01:29 +0200 Subject: [PATCH 11/19] Add links to DREAM.3D and pymicro docs to our related projects docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- doc/user/related_projects.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/user/related_projects.rst b/doc/user/related_projects.rst index f3f8db20..bb911a94 100644 --- a/doc/user/related_projects.rst +++ b/doc/user/related_projects.rst @@ -24,6 +24,8 @@ find useful: orix depends on numpy-quaternion for quaternion multiplication. - `texture `_: Python scripts for analysis of crystallographic texture. -- pymicro: Python package to work with material microstructures and 3D data sets. -- Dream3D: C++ library to reconstruct, instatiate, quantify, mesh, handle and visualize - multidimensional (3D), multimodal data (mainly EBSD orientation data). \ No newline at end of file +- `pymicro `_`: Python package to work with material + microstructures and 3D data sets. +- `DREAM.3D `_`: C++ library to reconstruct, instatiate, quantify, + mesh, handle and visualize multidimensional (3D), multimodal data (mainly EBSD + orientation data). \ No newline at end of file From 5ed1d151cf9904a562a94fae0c7ed12aa1aa9590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Thu, 4 Apr 2024 09:01:51 +0200 Subject: [PATCH 12/19] Replace deprecated use of inset axes in Matplotlib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .../zoom_inset_region.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/examples/stereographic_projection/zoom_inset_region.py b/examples/stereographic_projection/zoom_inset_region.py index ea35911b..47115cf9 100644 --- a/examples/stereographic_projection/zoom_inset_region.py +++ b/examples/stereographic_projection/zoom_inset_region.py @@ -10,7 +10,6 @@ """ import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1.inset_locator import InsetPosition from orix import plot, projections, sampling from orix.vector import Vector3d @@ -38,22 +37,19 @@ # The zoomed inset rectangle origin (x, y), width and height rect = [0.15, 0.2, 0.43, 0.43] -# Add a new stereographic projection axis with a grid resolution of 2 -# degrees to the figure and plot the vectors here as well -ax_inset = fig.add_axes(rect, projection="stereographic") -ax_inset.stereographic_grid(True, 2, 2) -ax_inset.scatter(v2) -ax_inset.scatter(v_ref, c="r") - -# Restrict the inset region to the extent vectors +# Add a new stereographic projection axis and zoom in +ax_inset = ax.inset_axes(rect, projection="stereographic") ax_inset.set( xlim=(x_inset.min(), x_inset.max()), ylim=(y_inset.min(), y_inset.max()), ) +# Add a grid of 2 degrees resolution and re-plot the vectors +ax_inset.stereographic_grid(True, 2, 2) +ax_inset.scatter(v2) +ax_inset.scatter(v_ref, c="r") + # Add lines indicating the inset zoom -ip = InsetPosition(ax, rect) -ax_inset.set_axes_locator(ip) ax.indicate_inset_zoom(ax_inset, edgecolor="k") # Add border to the inset region From b8c55ea22efbf90d073af18cedb2ae882e383d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Sun, 7 Apr 2024 15:27:36 +0200 Subject: [PATCH 13/19] Add new example showing the use of get_sample_reduced_fundamental() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .../rotations_mapping_fundamental_sector.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 examples/rotations/rotations_mapping_fundamental_sector.py diff --git a/examples/rotations/rotations_mapping_fundamental_sector.py b/examples/rotations/rotations_mapping_fundamental_sector.py new file mode 100644 index 00000000..66c9cf9f --- /dev/null +++ b/examples/rotations/rotations_mapping_fundamental_sector.py @@ -0,0 +1,57 @@ +""" +================================================ +Rotations mapping the fundamental sector on *S2* +================================================ + +This example shows how to sample rotations :math:`\mathbf{R}` that when +rotating the vector :math:`\mathbf{v_z} = (0, 0, 1)`, the resulting +vectors cover the fundamental sector of a given Laue class. + +We show this by comparing the vectors we get by: + +1. sampling rotations for *4/mmm* and then rotating :math:`\mathbf{v_z}` +2. sampling all of *S2* but only keeping those within the corresponding + fundamental sector. + +Apart from the first rotation, all rotations have a Euler angle +:math:`\phi = 0^{\circ}`. +These "reduced" rotations are useful in template matching of spot +patterns from the transmission electron microscope. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from orix import plot, sampling +from orix.quaternion import symmetry +from orix.vector import Vector3d + +# Sample rotations with an average misorientation +res = 2 +pg = symmetry.D4h # 4/mmm + +R = sampling.get_sample_reduced_fundamental(res, point_group=pg) +print(np.allclose(R.to_euler()[1:, 0], 0)) + +######################################################################## +# Get vectors within the fundamental sector following the two routes +v1 = R * Vector3d.zvector() + +v2 = sampling.sample_S2(res) +v2 = v2[v2 <= pg.fundamental_sector] + +# Only equivalent for the same S2 sampling method +print(np.allclose(v1.data, v2.data)) +print(v1) +print(v2) + +######################################################################## +# Plot the vectors in the fundamental sector of 4/mmm +fig, (ax0, ax1) = plt.subplots( + ncols=2, subplot_kw={"projection": "ipf", "symmetry": pg}, layout="tight" +) +ax0.scatter(v1, s=5) +ax1.scatter(v2, c="C1", s=5) +ax0.set_title("Rotated Z vectors", loc="left") +ax1.set_title("Directly sampled", loc="left") +_ = fig.suptitle("Vectors in the fundamental sector of 4/mmm", y=0.8) From 661a73ee589be602143dba4a9a2d27823688f84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Sun, 7 Apr 2024 15:28:31 +0200 Subject: [PATCH 14/19] Make git ignore doc file with Sphinx-Gallery execution times MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 215efae1..244b1526 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ doc/build/ doc/examples/ doc/reference/generated/ doc/source/_autosummary/ +doc/sg_execution_times.rst # PyBuilder target/ From 5d535fbaf20378aa31e72575a2d88ade772d054d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 9 Apr 2024 21:56:10 +0200 Subject: [PATCH 15/19] Remove get_sample_zone_axis() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- orix/sampling/__init__.py | 2 - orix/sampling/sample_generators.py | 71 ---------------------------- orix/tests/sampling/test_sampling.py | 33 +------------ 3 files changed, 1 insertion(+), 105 deletions(-) diff --git a/orix/sampling/__init__.py b/orix/sampling/__init__.py index 5a0c0d7e..0f051f15 100644 --- a/orix/sampling/__init__.py +++ b/orix/sampling/__init__.py @@ -33,14 +33,12 @@ get_sample_fundamental, get_sample_local, get_sample_reduced_fundamental, - get_sample_zone_axis, ) __all__ = [ "get_sample_fundamental", "get_sample_reduced_fundamental", "get_sample_local", - "get_sample_zone_axis", "sample_S2", "sample_S2_methods", "uniform_SO3_sample", diff --git a/orix/sampling/sample_generators.py b/orix/sampling/sample_generators.py index 921d7ea0..52bc8314 100644 --- a/orix/sampling/sample_generators.py +++ b/orix/sampling/sample_generators.py @@ -20,13 +20,11 @@ import numpy as np -from orix.crystal_map import Phase from orix.quaternion import OrientationRegion, Rotation, Symmetry, symmetry from orix.quaternion.symmetry import get_point_group from orix.sampling import sample_S2 from orix.sampling.SO3_sampling import _three_uniform_samples_method, uniform_SO3_sample from orix.sampling._cubochoric_sampling import cubochoric_sampling -from orix.vector import Vector3d def get_sample_fundamental( @@ -221,72 +219,3 @@ def get_sample_reduced_fundamental( euler_angles = np.vstack([phi1, phi, phi2]).T return Rotation.from_euler(euler_angles, degrees=False) - - -def _corners_to_centroid_and_edge_centers(corners): - """ - Produces the midpoints and center of a trio of corners - Parameters - ---------- - corners : list of lists - Three corners of a streographic triangle - Returns - ------- - list_of_corners : list - Length 7, elements ca, cb, cc, mean, cab, cbc, cac where naming is such that - ca is the first corner of the input, and cab is the midpoint between - corner a and corner b. - """ - ca, cb, cc = corners[0], corners[1], corners[2] - mean = tuple(np.add(np.add(ca, cb), cc)) - cab = tuple(np.add(ca, cb)) - cbc = tuple(np.add(cb, cc)) - cac = tuple(np.add(ca, cc)) - return [ca, cb, cc, mean, cab, cbc, cac] - - -def get_sample_zone_axis( - density: str = "3", - phase: Phase = None, - return_directions: bool = False, -) -> Rotation: - """Produces rotations to align various crystallographic directions with - the sample zone axes. - - Parameters - ---------- - density - Either '3' or '7' for the number of directions to return. - phase - The phase for which the zone axis rotations are required. - return_directions - If True, returns the directions as well as the rotations. - """ - system = phase.point_group.system - corners_dict = { - "cubic": [(0, 0, 1), (1, 0, 1), (1, 1, 1)], - "hexagonal": [(0, 0, 1), (2, 1, 0), (1, 1, 0)], - "orthorhombic": [(0, 0, 1), (1, 0, 0), (0, 1, 0)], - "tetragonal": [(0, 0, 1), (1, 0, 0), (1, 1, 0)], - "trigonal": [(0, 0, 1), (-1, -2, 0), (1, -1, 0)], - "monoclinic": [(0, 0, 1), (0, 1, 0), (0, -1, 0)], - } - if density == "3": - direction_list = corners_dict[system] - elif density == "7": - direction_list = _corners_to_centroid_and_edge_centers(corners_dict[system]) - else: - raise ValueError("Density must be either 3 or 7") - - # rotate the directions to the z axis - rots = np.stack( - [ - Rotation.from_align_vectors(v, Vector3d.zvector()).data - for v in direction_list - ] - ) - rotations = Rotation(rots) - if return_directions: - return rotations, direction_list - else: - return rotations diff --git a/orix/tests/sampling/test_sampling.py b/orix/tests/sampling/test_sampling.py index 4c9a546f..2952b05b 100644 --- a/orix/tests/sampling/test_sampling.py +++ b/orix/tests/sampling/test_sampling.py @@ -16,18 +16,15 @@ # You should have received a copy of the GNU General Public License # along with orix. If not, see . -from diffpy.structure import Atom, Lattice, Structure import numpy as np import pytest -from orix.crystal_map import Phase from orix.quaternion import Rotation -from orix.quaternion.symmetry import C1, C2, C4, C6, D6, get_point_group +from orix.quaternion.symmetry import C2, C4, C6, D6, get_point_group from orix.sampling import ( get_sample_fundamental, get_sample_local, get_sample_reduced_fundamental, - get_sample_zone_axis, uniform_SO3_sample, ) from orix.sampling.SO3_sampling import _resolution_to_num_steps @@ -199,31 +196,3 @@ def test_get_sample_reduced_fundamental(self): assert ( np.abs(rotations.size / rotations6.size) - 6 < 0.1 ) # about 6 times more rotations - - @pytest.mark.parametrize("density", ("3", "7", "5")) - @pytest.mark.parametrize("get_directions", (True, False)) - def test_get_zone_axis(self, density, get_directions): - a = 5.431 - latt = Lattice(a, a, a, 90, 90, 90) - atom_list = [] - for coords in [[0, 0, 0], [0.5, 0, 0.5], [0, 0.5, 0.5], [0.5, 0.5, 0]]: - x, y, z = coords[0], coords[1], coords[2] - atom_list.append( - Atom(atype="Si", xyz=[x, y, z], lattice=latt) - ) # Motif part A - atom_list.append( - Atom(atype="Si", xyz=[x + 0.25, y + 0.25, z + 0.25], lattice=latt) - ) # Motif part B - struct = Structure(atoms=atom_list, lattice=latt) - p = Phase(structure=struct, space_group=227) - if density == "5": - with pytest.raises(ValueError): - get_sample_zone_axis(phase=p, density=density) - else: - if get_directions: - rot, _ = get_sample_zone_axis( - phase=p, density=density, return_directions=True - ) - else: - rot = get_sample_zone_axis(phase=p, density=density) - assert isinstance(rot, Rotation) From 574b205e3cc6e7685311eecc214a965cb193230d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 9 Apr 2024 21:57:13 +0200 Subject: [PATCH 16/19] Add example showing how to get rotations mapping Z-vector to crystal directions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .../rotating_z_to_high_symmetry_directions.py | 59 +++++++++++++++++++ .../rotations_mapping_fundamental_sector.py | 18 +++--- examples/rotations/sampling_rotations.py | 47 --------------- 3 files changed, 68 insertions(+), 56 deletions(-) create mode 100644 examples/rotations/rotating_z_to_high_symmetry_directions.py delete mode 100644 examples/rotations/sampling_rotations.py diff --git a/examples/rotations/rotating_z_to_high_symmetry_directions.py b/examples/rotations/rotating_z_to_high_symmetry_directions.py new file mode 100644 index 00000000..20fe95ab --- /dev/null +++ b/examples/rotations/rotating_z_to_high_symmetry_directions.py @@ -0,0 +1,59 @@ +""" +===================================================== +Rotating z-vector to high-symmetry crystal directions +===================================================== + +This example shows how to sample high-symmetry crystal directions +:math:`\mathbf{t} = [u, v, w]` (or zone axes) using +:meth:`orix.vector.Miller.from_highest_indices`. +We will also get the rotations :math:`R` rotating :math:`\mathbf{v_z} = (0, 0, 1)` to +:math:`\mathbf{t}`. + +We do the following to obtain the high-symmetry crystal directions: + +1. Select a point group, here :math:`S = mmm`. +2. Sample all directions :math:`\mathbf{t_i}` with indices of -1, 0, and 1 +3. Project :math:`\mathbf{t_i}` to the fundamental sector of the Laue group of :math:`S` + (which in this case is itself) +4. Discard symmetrically equivalent and other duplicate crystal directions. + Vectors such as [001] and [002] are considered equal after we make them unit vectors. +5. Round the vector indices to the closest smallest integer (below a default of 20). + +The rotations :math:`R` can be useful e.g. when simulating diffraction patterns from +crystals with one of the high-symmetry zone axes :math:`\mathbf{t}` aligned along the +beam path. +""" + +from orix.crystal_map import Phase +from orix.quaternion import Rotation +from orix.vector import Miller, Vector3d + +phase = Phase(point_group="mmm") +t = Miller.from_highest_indices(phase, uvw=[1, 1, 1]) +t = t.in_fundamental_sector() +t = t.unit.unique(use_symmetry=True).round() +print(t) + +######################################################################## +# Get the rotations that rotate :math:`\mathbf{v_z}` to these crystal +# directions +vz = Miller(uvw=[0, 0, 1], phase=t.phase) +R = Rotation.identity(t.size) +for i, t_i in enumerate(t): + R[i] = Rotation.from_align_vectors(t_i, vz) +print(R) + +######################################################################## +# Plot the crystal directions within the fundamental sector of Laue +# group :math:`mmm` + +fig = t.scatter( + vector_labels=[str(vi).replace(".", "") for vi in t.coordinates], + text_kwargs={ + "size": 15, + "offset": (0, 0.03), + "bbox": {"fc": "w", "pad": 2, "alpha": 0.75}, + }, + return_figure=True, +) +fig.axes[0].restrict_to_sector(t.phase.point_group.fundamental_sector) diff --git a/examples/rotations/rotations_mapping_fundamental_sector.py b/examples/rotations/rotations_mapping_fundamental_sector.py index 66c9cf9f..8f195dad 100644 --- a/examples/rotations/rotations_mapping_fundamental_sector.py +++ b/examples/rotations/rotations_mapping_fundamental_sector.py @@ -3,20 +3,20 @@ Rotations mapping the fundamental sector on *S2* ================================================ -This example shows how to sample rotations :math:`\mathbf{R}` that when -rotating the vector :math:`\mathbf{v_z} = (0, 0, 1)`, the resulting -vectors cover the fundamental sector of a given Laue class. +This example shows how to sample rotations :math:`\mathbf{R}` that when rotating the +vector :math:`\mathbf{v_z} = (0, 0, 1)`, the resulting vectors cover the fundamental +sector of a given Laue class. We show this by comparing the vectors we get by: -1. sampling rotations for *4/mmm* and then rotating :math:`\mathbf{v_z}` -2. sampling all of *S2* but only keeping those within the corresponding - fundamental sector. +1. Sampling rotations for *4/mmm* and then rotating :math:`\mathbf{v_z}` +2. Sampling all of *S2* but only keeping those within the corresponding fundamental + sector. Apart from the first rotation, all rotations have a Euler angle :math:`\phi = 0^{\circ}`. -These "reduced" rotations are useful in template matching of spot -patterns from the transmission electron microscope. +These "reduced" rotations can be useful in template matching of spot patterns from the +transmission electron microscope. """ import matplotlib.pyplot as plt @@ -46,7 +46,7 @@ print(v2) ######################################################################## -# Plot the vectors in the fundamental sector of 4/mmm +# Plot the vectors in the fundamental sector of Laue group 4/mmm fig, (ax0, ax1) = plt.subplots( ncols=2, subplot_kw={"projection": "ipf", "symmetry": pg}, layout="tight" ) diff --git a/examples/rotations/sampling_rotations.py b/examples/rotations/sampling_rotations.py deleted file mode 100644 index cc3c32a6..00000000 --- a/examples/rotations/sampling_rotations.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -================== -Sampling rotations -================== - -This example shows how to sample some phase object in Orix. We will -get both the zone axis and the reduced fundamental zone rotations for -the phase of interest. -""" - -from diffpy.structure import Atom, Lattice, Structure - -from orix.crystal_map import Phase -from orix.sampling import get_sample_reduced_fundamental, get_sample_zone_axis -from orix.vector import Vector3d - -a = 5.431 -latt = Lattice(a, a, a, 90, 90, 90) -atom_list = [] -for coords in [[0, 0, 0], [0.5, 0, 0.5], [0, 0.5, 0.5], [0.5, 0.5, 0]]: - x, y, z = coords[0], coords[1], coords[2] - atom_list.append(Atom(atype="Si", xyz=[x, y, z], lattice=latt)) # Motif part A - atom_list.append( - Atom(atype="Si", xyz=[x + 0.25, y + 0.25, z + 0.25], lattice=latt) - ) # Motif part B -struct = Structure(atoms=atom_list, lattice=latt) -p = Phase(structure=struct, space_group=227) -reduced_fun = get_sample_reduced_fundamental(resolution=4, point_group=p.point_group) - -vect_rot = ( - reduced_fun * Vector3d.zvector() -) # get the vector representation of the rotations -vect_rot.scatter(grid=True) # plot the stereographic projection of the rotations - -# %% - -zone_axis_rot, directions = get_sample_zone_axis( - phase=p, density="7", return_directions=True -) # get the zone axis rotations -zone_vect_rot = ( - zone_axis_rot * Vector3d.zvector() -) # get the vector representation of the rotations -zone_vect_rot.scatter( - grid=True, vector_labels=directions, text_kwargs={"size": 8, "rotation": 0} -) # plot the stereographic projection of the rotations - -# %% From 4a978dfc3ee725a0d089565c369518f5054826fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 9 Apr 2024 23:33:25 +0200 Subject: [PATCH 17/19] Improve test of sampling rotations taking Z-vector to fundamental sector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- orix/tests/sampling/test_sampling.py | 48 +++++++++++++++++++--------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/orix/tests/sampling/test_sampling.py b/orix/tests/sampling/test_sampling.py index 2952b05b..770827a5 100644 --- a/orix/tests/sampling/test_sampling.py +++ b/orix/tests/sampling/test_sampling.py @@ -20,7 +20,7 @@ import pytest from orix.quaternion import Rotation -from orix.quaternion.symmetry import C2, C4, C6, D6, get_point_group +from orix.quaternion.symmetry import C2, C4, C6, D6, Oh, get_point_group from orix.sampling import ( get_sample_fundamental, get_sample_local, @@ -34,6 +34,7 @@ _get_max_grid_angle, _get_start_and_end_index, ) +from orix.vector import Vector3d @pytest.fixture(scope="session") @@ -182,17 +183,34 @@ def test_get_sample_fundamental_space_group(self, C6_sample): assert np.isclose(ratio, 3, atol=0.2) def test_get_sample_reduced_fundamental(self): - rotations = get_sample_reduced_fundamental(resolution=4) - rotations2 = get_sample_reduced_fundamental(resolution=4, point_group=C2) - rotations4 = get_sample_reduced_fundamental(resolution=4, point_group=C4) - rotations6 = get_sample_reduced_fundamental(resolution=4, point_group=C4) - - assert ( - np.abs(rotations.size / rotations2.size) - 2 < 0.1 - ) # about 2 times more rotations - assert ( - np.abs(rotations2.size / rotations4.size) - 2 < 0.1 - ) # about 2 times more rotations - assert ( - np.abs(rotations.size / rotations6.size) - 6 < 0.1 - ) # about 6 times more rotations + vz = Vector3d.zvector() + + R_C1 = get_sample_reduced_fundamental(resolution=4) + v_C1 = R_C1 * vz + assert np.allclose(v_C1.mean().data, [0, 0, 0]) + + R_C4 = get_sample_reduced_fundamental(resolution=4, point_group=C4) + v_C4 = R_C4 * vz + assert np.all(v_C4 <= C4.fundamental_sector) + + R_C6 = get_sample_reduced_fundamental(resolution=4, point_group=C6) + v_C6 = R_C6 * vz + assert np.all(v_C6 <= C6.fundamental_sector) + + R_Oh = get_sample_reduced_fundamental(point_group=Oh) + v_Oh = R_Oh * vz + assert np.all(v_Oh <= Oh.fundamental_sector) + + # Some rotations have a phi1 Euler angle of multiples of pi, + # presumably due to rounding errors + phi1_C1 = R_C1.to_euler()[:, 0].round(7) + assert np.allclose(np.unique(phi1_C1), [0, 2 * np.pi], atol=1e-7) + phi1_C4 = R_C4.to_euler()[:, 0].round(7) + assert np.allclose(np.unique(phi1_C4), [0, np.pi / 2], atol=1e-7) + phi1_C6 = R_C6.to_euler()[:, 0].round(7) + assert np.allclose(np.unique(phi1_C6), [0, np.pi / 2], atol=1e-7) + phi1_Oh = R_Oh.to_euler()[:, 0].round(7) + assert np.allclose(np.unique(phi1_Oh), [0, np.pi / 2], atol=1e-7) + + R_Oh2 = get_sample_reduced_fundamental(point_group=Oh, method="icosahedral") + assert R_Oh.size > R_Oh2.size From 5d00993835547adb7905e8dea7eea191ac169b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Tue, 9 Apr 2024 23:41:33 +0200 Subject: [PATCH 18/19] Rephrase addition of new sampling function in changelog, remove non-user facing change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- CHANGELOG.rst | 8 ++-- orix/sampling/sample_generators.py | 71 ++++++++++++++++-------------- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index abdec641..db407070 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,10 +31,9 @@ Added - The ``random()`` methods of ``Orientation`` and ``Misorientation`` now accept ``symmetry``. A ``random()`` method is also added to ``Vector3d`` and ``Miller``, the latter accepting a ``phase``. -- Added ``orix.sampling.get_sample_zone_axis()`` for getting zone axes for some point - group. -- Added ``orix.sampling.get_sample_reduced_fundamental()`` for getting reduced - fundamental zone for some point group. +- Function ``orix.sampling.get_sample_reduced_fundamental()`` for sampling rotations + that rotate the Z-vector (0, 0, 1) onto the fundamental sector of the Laue group of a + given ``Symmetry``. Changed ------- @@ -43,7 +42,6 @@ Changed - Allow passing a tuple of integers to ``reshape()`` methods of 3D objects. - ``random()`` methods no longer accept a list as a valid shape: pass a tuple instead. - Increase minimal version of Matplotlib to >= 3.5. -- Updated copyright year to 2024. Deprecated ---------- diff --git a/orix/sampling/sample_generators.py b/orix/sampling/sample_generators.py index 52bc8314..6bdffae9 100644 --- a/orix/sampling/sample_generators.py +++ b/orix/sampling/sample_generators.py @@ -20,8 +20,8 @@ import numpy as np -from orix.quaternion import OrientationRegion, Rotation, Symmetry, symmetry -from orix.quaternion.symmetry import get_point_group +from orix.quaternion import OrientationRegion, Rotation, Symmetry +from orix.quaternion.symmetry import C1, get_point_group from orix.sampling import sample_S2 from orix.sampling.SO3_sampling import _three_uniform_samples_method, uniform_SO3_sample from orix.sampling._cubochoric_sampling import cubochoric_sampling @@ -40,7 +40,7 @@ def get_sample_fundamental( ---------- resolution The characteristic distance between a rotation and its neighbour - in degrees. + in degrees. Default is 2 degrees. point_group One of the 11 proper point groups. If not given, ``space_group`` must be. @@ -104,13 +104,13 @@ def get_sample_local( ---------- resolution The characteristic distance between a rotation and its neighbour - in degrees. + in degrees. Default is 2 degrees. center The rotation at which the grid is centered. The identity is used if not given. grid_width The largest angle of rotation in degrees away from center that - is acceptable. + is acceptable. Default is 10 degrees. method ``"cubochoric"`` (default), ``"haar_euler"`` or ``"quaternion"``. See :func:`~orix.sampling.uniform_SO3_sample` @@ -169,37 +169,42 @@ def _remove_larger_than_angle(rot: Rotation, max_angle: Union[int, float]) -> Ro def get_sample_reduced_fundamental( - resolution: float, - mesh: str = None, - point_group: Symmetry = None, + resolution: float = 2, + method: Optional[str] = None, + point_group: Optional[Symmetry] = None, ) -> Rotation: - """Produces rotations to align various crystallographic directions with - the z-axis, with the constraint that the first Euler angle phi_1=0. - The crystallographic directions sample the fundamental zone, representing - the smallest region of symmetrically unique directions of the relevant - crystal system or point group. + r"""Return a grid of rotations that rotate the Z-vector (0, 0, 1) + into the fundamental sector of a point group's Laue group. + + The rotations are constrained in that the first Euler angle is + :math:`\phi_1 = 0^{\circ}`. + Parameters ---------- resolution - An angle in degrees representing the maximum angular distance to a - first nearest neighbor grid point. - mesh - Type of meshing of the sphere that defines how the grid is created. See - orix.sampling.sample_S2 for all the options. A suitable default is - chosen depending on the crystal system. + The characteristic distance between a rotation and its neighbour + in degrees. Default is 2 degrees. + method + Name of method to mesh the unit sphere. See + :func:`orix.sampling.sample_S2` for options. If not given, a + suitable default is chosen given by the crystal system of the + given point group. point_group - Symmetry operations that determines the unique directions. Defaults to - no symmetry, which means sampling all 3D unit vectors. + Point group with symmetry operations that define the + :attr:`~orix.quaternion.symmetry.Symmetry.fundamental_sector` + on the unit sphere. If not given, rotations that rotate the + Z-vector onto the whole sphere are returned. + Returns ------- - Rotation - (N, 3) array representing Euler angles for the different orientations + R + Rotations of shape ``(n, 3)``. """ if point_group is None: - point_group = symmetry.C1 + point_group = C1 - if mesh is None: - s2_auto_sampling_map = { + if method is None: + sampling_method = { "triclinic": "icosahedral", "monoclinic": "icosahedral", "orthorhombic": "spherified_cube_edge", @@ -208,14 +213,14 @@ def get_sample_reduced_fundamental( "trigonal": "hexagonal", "hexagonal": "hexagonal", } - mesh = s2_auto_sampling_map[point_group.system] + method = sampling_method[point_group.system] - s2_sample = sample_S2(resolution, method=mesh) - fundamental = s2_sample[s2_sample <= point_group.fundamental_sector] + v = sample_S2(resolution, method=method) + v_fs = v[v <= point_group.fundamental_sector] - phi = fundamental.polar - phi2 = (np.pi / 2 - fundamental.azimuth) % (2 * np.pi) + phi = v_fs.polar + phi2 = (np.pi / 2 - v_fs.azimuth) % (2 * np.pi) phi1 = np.zeros(phi2.shape[0]) - euler_angles = np.vstack([phi1, phi, phi2]).T + euler = np.vstack([phi1, phi, phi2]).T - return Rotation.from_euler(euler_angles, degrees=False) + return Rotation.from_euler(euler, degrees=False) From d6a5c1aa2008c9fdd1bfbc1d249ca9ba2ff02611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Wed, 10 Apr 2024 22:26:39 +0200 Subject: [PATCH 19/19] Improve wording based on review by @CSSFrancis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- examples/crystal_maps/create_empty_map.py | 2 +- examples/rotations/rotating_z_to_high_symmetry_directions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/crystal_maps/create_empty_map.py b/examples/crystal_maps/create_empty_map.py index 437de6f5..f524b04c 100644 --- a/examples/crystal_maps/create_empty_map.py +++ b/examples/crystal_maps/create_empty_map.py @@ -4,7 +4,7 @@ ======================== This example shows how to create an empty crystal map of a given shape. -By empty, we here mean that it is filled with identity rotations. +By empty, we mean that it is filled with identity rotations. This crystal map can be useful for testing. """ diff --git a/examples/rotations/rotating_z_to_high_symmetry_directions.py b/examples/rotations/rotating_z_to_high_symmetry_directions.py index 20fe95ab..70232090 100644 --- a/examples/rotations/rotating_z_to_high_symmetry_directions.py +++ b/examples/rotations/rotating_z_to_high_symmetry_directions.py @@ -6,8 +6,8 @@ This example shows how to sample high-symmetry crystal directions :math:`\mathbf{t} = [u, v, w]` (or zone axes) using :meth:`orix.vector.Miller.from_highest_indices`. -We will also get the rotations :math:`R` rotating :math:`\mathbf{v_z} = (0, 0, 1)` to -:math:`\mathbf{t}`. +We will also return the rotations :math:`R` which rotate +:math:`\mathbf{v_z} = (0, 0, 1)` to :math:`\mathbf{t}`. We do the following to obtain the high-symmetry crystal directions: