pyxem / orix

Analysing crystal orientations and symmetry in Python
https://orix.readthedocs.io
GNU General Public License v3.0
79 stars 45 forks source link

CrystalMap.deepcopy() can throw ValueError in CrystalMapProperties.__setitem__() #408

Closed hakonanes closed 1 year ago

hakonanes commented 1 year ago

For some reason, this works

>>> from orix import data
>>> xmap = data.sdss_austenite_ferrite()
>>> _ = xmap[:, 0]  # Any call to __getitem__() not returning the full map
>>> print(xmap)  # "Touch" the CrystalMap.is_in_data array
Phase   Orientations       Name  Space group  Point group  Proper point group       Color
    1   5657 (48.4%)  austenite         None          432                 432    tab:blue
    2   6043 (51.6%)    ferrite         None          432                 432  tab:orange
Properties: iq, dp
Scan unit: um
>>> xmap2 = xmap.deepcopy()

while this fails

>>> _ = xmap[:, 0]
>>> xmap2 = xmap.deepcopy()
Traceback (most recent call last):
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/site-packages/IPython/core/interactiveshell.py", line 3378, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-9-03a74ac080f4>", line 3, in <module>
    xmap2 = xmap.deepcopy()
  File "/home/hakon/kode/orix/orix/crystal_map/crystal_map.py", line 805, in deepcopy
    return copy.deepcopy(self)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 271, in _reconstruct
    state = deepcopy(state, memo)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/home/hakon/miniconda3/envs/orix-dev/lib/python3.10/copy.py", line 298, in _reconstruct
    y[key] = value
  File "/home/hakon/kode/orix/orix/crystal_map/crystal_map_properties.py", line 95, in __setitem__
    array[is_in_data, ...] = value
ValueError: shape mismatch: value array of shape (11700,) could not be broadcast to indexing result of shape (100,)

It seems like the slicing before deep copying sets CrystalMap.is_in_data, which lingers even though the sliced map is not used. "Touching" the map in any way, like printing the map in the first snippet, ensures CrystalMap.is_in_data is correct and deep copying works.

The error is thrown in CrystalMapProperties.__setitem__() (called via CrystalMap.deepcopy()) when the value array (any array in CrystalMap.prop) doesn't fit in the array sliced by the CrystalMapProperties.is_in_data.

I encountered this when ensuring that the kikuchipy.signals.EBSD.xmap attribute (a crystal map) is sliced appropriately upon calls to EBSD.inav (via hyperspy.signals.BaseSignal.inav). I'll make a fix to main once I've ensured that the fix works as intended.

hakonanes commented 1 year ago

I have not encountered this error again after reporting it here... Will therefore leave it for a later release, or close it if I don't encounter it again.