distinguish isclose/allclose and __eq__

This commit is contained in:
Martin Diehl 2021-04-05 18:24:03 +02:00
parent 0ef6e43e62
commit d5806075d4
5 changed files with 114 additions and 18 deletions

View File

@ -239,7 +239,9 @@ class Orientation(Rotation):
"""
matching_type = all([hasattr(other,attr) and getattr(self,attr) == getattr(other,attr)
for attr in ['family','lattice','parameters']])
return np.logical_and(super().__eq__(other),matching_type)
s = self if self.family is None else self.reduced
o = other if other.family is None else other.reduced
return np.logical_and(super(__class__,s).__eq__(o),matching_type)
def __ne__(self,other):
"""
@ -254,6 +256,59 @@ class Orientation(Rotation):
return np.logical_not(self==other)
def isclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
"""
Report where values are approximately equal to corresponding ones of other Orientation.
Parameters
----------
other : Orientation
Orientation to compare against.
rtol : float, optional
Relative tolerance of equality.
atol : float, optional
Absolute tolerance of equality.
equal_nan : bool, optional
Consider matching NaN values as equal. Defaults to True.
Returns
-------
mask : numpy.ndarray bool
Mask indicating where corresponding orientations are close.
"""
matching_type = all([hasattr(other,attr) and getattr(self,attr) == getattr(other,attr)
for attr in ['family','lattice','parameters']])
s = self if self.family is None else self.reduced
o = other if other.family is None else other.reduced
return np.logical_and(super(__class__,s).isclose(o),matching_type)
def allclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
"""
Test whether all values are approximately equal to corresponding ones of other Orientation.
Parameters
----------
other : Orientation
Orientation to compare against.
rtol : float, optional
Relative tolerance of equality.
atol : float, optional
Absolute tolerance of equality.
equal_nan : bool, optional
Consider matching NaN values as equal. Defaults to True.
Returns
-------
answer : bool
Whether all values are close between both orientations.
"""
return np.all(self.isclose(other,rtol,atol,equal_nan))
def __mul__(self,other):
"""
Compose this orientation with other.

View File

@ -103,29 +103,20 @@ class Rotation:
"""
Equal to other.
Equality is determined taking limited floating point precision into account.
See numpy.allclose for details.
Parameters
----------
other : Rotation
Rotation to check for equality.
"""
s = self.quaternion
o = other.quaternion
if self.shape == () == other.shape:
return np.allclose(s,o) or (np.isclose(s[0],0.0) and np.allclose(s,-1.0*o))
else:
return np.all(np.isclose(s,o),-1) + np.all(np.isclose(s,-1.0*o),-1) * np.isclose(s[...,0],0.0)
return np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1),
np.all(self.quaternion == -1.0*other.quaternion,axis=-1))
def __ne__(self,other):
"""
Not equal to other.
Equality is determined taking limited floating point precision into
account. See numpy.allclose for details.
Parameters
----------
other : Rotation
@ -135,6 +126,57 @@ class Rotation:
return np.logical_not(self==other)
def isclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
"""
Report where values are approximately equal to corresponding ones of other Rotation.
Parameters
----------
other : Rotation
Rotation to compare against.
rtol : float, optional
Relative tolerance of equality.
atol : float, optional
Absolute tolerance of equality.
equal_nan : bool, optional
Consider matching NaN values as equal. Defaults to True.
Returns
-------
mask : numpy.ndarray bool
Mask indicating where corresponding rotations are close.
"""
s = self.quaternion
o = other.quaternion
return np.logical_or(np.all(np.isclose(s, o,rtol,atol,equal_nan),axis=-1),
np.all(np.isclose(s,-1.0*o,rtol,atol,equal_nan),axis=-1))
def allclose(self,other,rtol=1e-5,atol=1e-8,equal_nan=True):
"""
Test whether all values are approximately equal to corresponding ones of other Rotation.
Parameters
----------
other : Rotation
Rotation to compare against.
rtol : float, optional
Relative tolerance of equality.
atol : float, optional
Absolute tolerance of equality.
equal_nan : bool, optional
Consider matching NaN values as equal. Defaults to True.
Returns
-------
answer : bool
Whether all values are close between both rotations.
"""
return np.all(self.isclose(other,rtol,atol,equal_nan))
def __array__(self):
"""Initializer for numpy."""
return self.quaternion

View File

@ -140,6 +140,5 @@ class TestConfigMaterial:
if update:
cur.save(ref_path/'measured.material_yaml')
for i,m in enumerate(ref['material']):
assert Rotation(m['constituents'][0]['O']) == \
Rotation(cur['material'][i]['constituents'][0]['O'])
assert Rotation(m['constituents'][0]['O']).isclose(Rotation(cur['material'][i]['constituents'][0]['O']))
assert cur.is_valid and cur['phase'] == ref['phase'] and cur['homogenization'] == ref['homogenization']

View File

@ -222,7 +222,7 @@ class TestOrientation:
blend = util.shapeblender(o.shape,p.shape)
for loc in np.random.randint(0,blend,(10,len(blend))):
assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \
== o.disorientation(p)[tuple(loc)]
.isclose(o.disorientation(p)[tuple(loc)])
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
def test_disorientation360(self,lattice):

View File

@ -960,7 +960,7 @@ class TestRotation:
if axis_angle[3] > np.pi:
axis_angle[3] -= 2.*np.pi
axis_angle *= -1
assert R**pwr == Rotation.from_axis_angle(axis_angle)
assert (R**pwr).isclose(Rotation.from_axis_angle(axis_angle))
def test_rotate_inverse(self):
R = Rotation.from_random()
@ -1027,7 +1027,7 @@ class TestRotation:
def test_invariant(self):
R = Rotation.from_random()
assert R/R == R*R**(-1) == Rotation()
assert (R/R).isclose(R*R**(-1)) and (R/R).isclose(Rotation())
@pytest.mark.parametrize('item',[np.ones(3),np.ones((3,3)), np.ones((3,3,3,3))])
def test_apply(self,item):