Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
"name": "Niels Cautaerts",
"orcid": "0000-0002-6402-9879"
},
{
"name": "Austin Gerlt",
"orcid": "0000-0002-2204-2055",
"affiliation": "The Ohio State University"
},
{
"name": "Viljar Johan Femoen",
"affiliation": "Norwegian University of Science and Technology"
Expand All @@ -43,11 +48,6 @@
"orcid": "0000-0003-2564-1851",
"affiliation": "University of Wisconsin Madison"
},
{
"name": "Austin Gerlt",
"orcid": "0000-0002-2204-2055",
"affiliation": "The Ohio State University"
},
{
"name": "Simon Høgås"
},
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ Removed

Deprecated
----------
- Method :meth:`~orix.quaternion.Misorientation.map_into_symmetry_reduced_zone` for
(mis)orientations have been deprecated in favor of
:meth:`~orix.quaternion.Misorientation.reduce` and will be removed in version 0.15.0.

Fixed
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"# Stack and map into the Oh fundamental zone\n",
"ori = Orientation.stack([cluster1, cluster2, cluster3]).flatten()\n",
"ori.symmetry = Oh\n",
"ori = ori.map_into_symmetry_reduced_zone()"
"ori = ori.reduce()"
]
},
{
Expand Down Expand Up @@ -158,7 +158,7 @@
"mori2 = (~ori).outer(ori)\n",
"\n",
"mori2.symmetry = Oh\n",
"mori2 = mori2.map_into_symmetry_reduced_zone()\n",
"mori2 = mori2.reduce()\n",
"\n",
"D2 = mori2.angle"
]
Expand Down
8 changes: 4 additions & 4 deletions doc/tutorials/clustering_misorientations.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@
"metadata": {},
"outputs": [],
"source": [
"ori = ori.map_into_symmetry_reduced_zone()"
"ori = ori.reduce()"
]
},
{
Expand Down Expand Up @@ -216,7 +216,7 @@
"outputs": [],
"source": [
"mori.symmetry = (D6, D6)\n",
"mori = mori.map_into_symmetry_reduced_zone()"
"mori = mori.reduce()"
]
},
{
Expand Down Expand Up @@ -308,7 +308,7 @@
"\n",
" # Map into the fundamental zone\n",
" mori_i.symmetry = (D6, D6)\n",
" mori_i = mori_i.map_into_symmetry_reduced_zone()\n",
" mori_i = mori_i.reduce()\n",
"\n",
" # Get the cluster mean\n",
" mori_i = mori_i.mean()\n",
Expand All @@ -321,7 +321,7 @@
"\n",
"# Map into the fundamental zone\n",
"cluster_means.symmetry = (D6, D6)\n",
"cluster_means = cluster_means.map_into_symmetry_reduced_zone()\n",
"cluster_means = cluster_means.reduce()\n",
"cluster_means"
]
},
Expand Down
6 changes: 3 additions & 3 deletions doc/tutorials/clustering_orientations.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
"metadata": {},
"outputs": [],
"source": [
"ori = ori.map_into_symmetry_reduced_zone()"
"ori = ori.reduce()"
]
},
{
Expand Down Expand Up @@ -320,7 +320,7 @@
"\n",
"# Map into the fundamental zone\n",
"cluster_means.symmetry = D6\n",
"cluster_means = cluster_means.map_into_symmetry_reduced_zone()\n",
"cluster_means = cluster_means.reduce()\n",
"cluster_means"
]
},
Expand Down Expand Up @@ -393,7 +393,7 @@
"\n",
"# Map into the fundamental zone\n",
"ori_recentered.symmetry = D6\n",
"ori_recentered = ori_recentered.map_into_symmetry_reduced_zone()\n",
"ori_recentered = ori_recentered.reduce()\n",
"\n",
"cluster_means_recentered = Orientation.stack(\n",
" [ori_recentered[all_labels == l].mean() for l in unique_cluster_labels]\n",
Expand Down
4 changes: 3 additions & 1 deletion doc/tutorials/crystal_map.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@
"outputs": [],
"source": [
"# Directly access *private* cache data path from module\n",
"_target = data._fetcher.path / \"sdss/sdss_ferrite_austenite.ang\"\n",
"from orix.data._data import _fetcher\n",
"\n",
"_target = _fetcher.path / \"sdss/sdss_ferrite_austenite.ang\"\n",
"\n",
"# Read each column from the file\n",
"eu1, eu2, eu3, x, y, iq, dp, phase_id = np.loadtxt(_target, unpack=True)\n",
Expand Down
2 changes: 1 addition & 1 deletion orix/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
"Phillip Crout",
"Duncan Johnstone",
"Niels Cautaerts",
"Austin Gerlt",
"Viljar Johan Femoen",
"Anders Christian Mathisen",
"Zhou Xu",
"Carter Francis",
"Austin Gerlt",
"Simon Høgås",
"Alessandra da Silva",
"Ondrej Lexa",
Expand Down
20 changes: 20 additions & 0 deletions orix/_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#
# Copyright 2018-2025 the orix developers
#
# This file is part of orix.
#
# orix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# orix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with orix. If not, see <http://www.gnu.org/licenses/>.
#

"""Private utilities used across modules."""
File renamed without changes.
40 changes: 23 additions & 17 deletions orix/_util.py → orix/_utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
# along with orix. If not, see <http://www.gnu.org/licenses/>.
#

"""Helper functions and classes for managing orix."""

"""Utilities for deprecating methods, functions, and properties."""

import functools
import inspect
from typing import Callable, Literal
import warnings

from orix.constants import VisibleDeprecationWarning
from orix._utils.constants import VisibleDeprecationWarning


class deprecated:
Expand All @@ -40,23 +40,23 @@ class deprecated:

def __init__(
self,
since,
removal=None,
object_type="function",
alternative=None,
):
since: str | int | float,
removal: str | int | float | None = None,
object_type: Literal["function", "property"] = "function",
alternative: str | None = None,
) -> None:
"""Visible deprecation warning.

Parameters
----------
since : str, int or float
since
The release at which this API became deprecated.
removal : str, int or float, optional
removal
The expected removal version.
object_type : str, optional
object_type
Type of the deprecated object, either "function" (default)
or "property".
alternative : str, optional
alternative
An alternative API that the user may use in place of the
deprecated API.
"""
Expand All @@ -65,7 +65,7 @@ def __init__(
self.removal = removal
self.object_type = object_type

def __call__(self, func):
def __call__(self, func: Callable) -> Callable:
# Wrap function or property to raise warning when called, and
# add warning to docstring if function or property is deprecated

Expand All @@ -88,7 +88,7 @@ def __call__(self, func):
)

@functools.wraps(func)
def wrapped(*args, **kwargs):
def wrapped(*args, **kwargs) -> Callable:
warnings.simplefilter(
action="always", category=VisibleDeprecationWarning, append=True
)
Expand Down Expand Up @@ -124,15 +124,21 @@ class deprecated_argument:
<https://github.com/scikit-image/scikit-image/blob/main/skimage/_shared/utils.py#L115>`_.
"""

def __init__(self, name, since, removal, alternative=None):
def __init__(
self,
name: str,
since: str | int | float,
removal: str | int | float,
alternative: str | None = None,
) -> None:
self.name = name
self.since = since
self.removal = removal
self.alternative = alternative

def __call__(self, func):
def __call__(self, func: Callable) -> Callable:
@functools.wraps(func)
def wrapped(*args, **kwargs):
def wrapped(*args, **kwargs) -> Callable:
if self.name in kwargs.keys():
msg = (
f"Argument `{self.name}` is deprecated and will be removed in "
Expand Down
2 changes: 1 addition & 1 deletion orix/io/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from h5py import File, is_hdf5
import numpy as np

from orix._util import deprecated
from orix._utils.deprecation import deprecated
from orix.crystal_map.crystal_map import CrystalMap
from orix.io.plugins import plugin_list
from orix.io.plugins._h5ebsd import hdf5group2dict
Expand Down
2 changes: 1 addition & 1 deletion orix/plot/crystal_map_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

from orix.constants import installed, verify_dependency_or_raise
from orix._utils.constants import installed, verify_dependency_or_raise

if TYPE_CHECKING: # pragma: no cover
if installed["matplotlib-scalebar"]:
Expand Down
2 changes: 1 addition & 1 deletion orix/plot/rotation_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def transform(
raise TypeError("fundamental_zone is not an OrientationRegion object.")
# if any in xs are out of fundamental_zone, calculate symmetry reduction
if not (xs < fundamental_zone).all():
xs = xs.map_into_symmetry_reduced_zone()
xs = xs.reduce()

if isinstance(xs, Rotation):
if isinstance(xs, OrientationRegion):
Expand Down
2 changes: 1 addition & 1 deletion orix/quaternion/_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import numba as nb
import numpy as np

from orix import constants
from orix._utils import constants


@nb.njit("int64(float64[:])", cache=True, fastmath=True, nogil=True)
Expand Down
44 changes: 38 additions & 6 deletions orix/quaternion/misorientation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from scipy.spatial.transform import Rotation as SciPyRotation
from tqdm import tqdm

from orix._utils.deprecation import deprecated
from orix.quaternion.orientation_region import OrientationRegion
from orix.quaternion.rotation import Rotation
from orix.quaternion.symmetry import C1, Symmetry, _get_unique_symmetry_elements
Expand Down Expand Up @@ -340,6 +341,7 @@ def equivalent(self, grain_exchange: bool = False) -> Misorientation:

return self.__class__(equivalent).flatten()

@deprecated(since="0.14", removal="0.15", alternative="reduce")
def map_into_symmetry_reduced_zone(self, verbose: bool = False) -> Misorientation:
"""Return equivalent transformations which have the smallest
angle of rotation as a new misorientation.
Expand All @@ -365,22 +367,52 @@ def map_into_symmetry_reduced_zone(self, verbose: bool = False) -> Misorientatio
[[-0.7071 0.7071 0. 0. ]
[ 0. 1. 0. 0. ]]
"""
return self.reduce(verbose)

def reduce(self, verbose: bool = False) -> Misorientation:
"""Return equivalent transformations which have the smallest
angle of rotation as a new misorientation.

Parameters
----------
verbose
Whether to print a progressbar. Default is ``False``.

Returns
-------
M
A new misorientation object with the assigned symmetry.

Examples
--------
>>> from orix.quaternion.symmetry import C4, C2
>>> data = np.array([[0.5, 0.5, 0.5, 0.5], [0, 1, 0, 0]])
>>> M = Misorientation(data)
>>> M.symmetry = (C4, C2)
>>> M.reduce()
Misorientation (2,) 4, 2
[[-0.7071 0.7071 0. 0. ]
[ 0. 1. 0. 0. ]]
"""
Gl, Gr = self._symmetry
fz = OrientationRegion.from_symmetry(Gl, Gr)
symmetry_pairs = iproduct(Gl, Gr)
if verbose:
symmetry_pairs = tqdm(symmetry_pairs, total=Gl.size * Gr.size)

orientation_region = OrientationRegion.from_symmetry(Gl, Gr)
o_inside = self.__class__.identity(self.shape)
# There is one and only one combination of `symmetry_pairs` that
# moves an arbitrary rotation into fz. Apply the combinations
# iteratively to the outside quaternions until all are inside.
reduced = self.__class__.identity(self.shape)
outside = np.ones(self.shape, dtype=bool)
for gl, gr in symmetry_pairs:
o_transformed = gl * self[outside] * gr
o_inside[outside] = o_transformed
outside = ~(o_inside < orientation_region)
reduced[outside] = o_transformed
outside = ~(reduced < fz)
if not np.any(outside):
break
o_inside._symmetry = (Gl, Gr)
return o_inside
reduced._symmetry = (Gl, Gr)
return reduced

def scatter(
self,
Expand Down
13 changes: 7 additions & 6 deletions orix/quaternion/orientation.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,13 @@ def __repr__(self) -> str:
return f"{self.__class__.__name__} {self.shape} {self.symmetry.name}\n{data}"

def __sub__(self, other: Orientation) -> Misorientation:
if isinstance(other, Orientation):
# Call to Object3d.squeeze() doesn't carry over symmetry
M = Misorientation(self * ~other).squeeze()
M.symmetry = (self.symmetry, other.symmetry)
return M.map_into_symmetry_reduced_zone()
return NotImplemented
if not isinstance(other, Orientation):
return NotImplemented
# Call to Object3d.squeeze() doesn't carry over symmetry
M = Misorientation(self * ~other).squeeze()
M.symmetry = (self.symmetry, other.symmetry)
M = M.reduce()
return M

# ------------------------ Class methods ------------------------- #

Expand Down
2 changes: 1 addition & 1 deletion orix/quaternion/orientation_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import numpy as np

from orix import constants
from orix._utils import constants
from orix.quaternion.quaternion import Quaternion
from orix.quaternion.rotation import Rotation
from orix.quaternion.symmetry import C1, Symmetry, get_distinguished_points
Expand Down
Loading
Loading