Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLO output writer not working for lazy signals #2774

Closed
din14970 opened this issue Jun 22, 2021 · 3 comments
Closed

BLO output writer not working for lazy signals #2774

din14970 opened this issue Jun 22, 2021 · 3 comments
Milestone

Comments

@din14970
Copy link
Contributor

It seems that the BLO writer does not work for lazy signals. The error seems to be in the line containing tofile. This is problematic for converting larger 4DSTEM/NBED datasets to BLO. I'll try to fix this.
In addition, the writer is very particular about units and does not seem to accept angstroms.

@hakonanes
Copy link
Contributor

FYI, the writer was written by Vidar, @vidartf.

Yeah, I guess you have to write each pattern to memory in the loop

for img in signal._iterate_signal():
dp_head.tofile(f)
img.astype(endianess + 'u1').tofile(f)
dp_head['ID'] += 1

@ericpre
Copy link
Member

ericpre commented Jun 26, 2021

Can you please provide the traceback, in #2777, I can't see what changes would fix saving lazy signal.

@din14970
Copy link
Contributor Author

The issue is that dask arrays don't have thtofile method that np has.

Full tracebacks for reference (on RELEASE_next_patch bd1c12b74):

When one does not run into unit conversion issues (e.g. set signal units to nm):

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-11-ebacc5399fa7> in <module>
----> 1 data_file.save("test.blo")

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/signal.py in save(self, filename, overwrite, extension, **kwds)
   2838         if extension is not None:
   2839             filename = filename.with_suffix(f".{extension}")
-> 2840         io.save(filename, self, overwrite=overwrite, **kwds)
   2841 
   2842     def _replot(self):

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/io.py in save(filename, signal, overwrite, **kwds)
    781         # Pass as a string for now, pathlib.Path not
    782         # properly supported in io_plugins
--> 783         writer.file_writer(str(filename), signal, **kwds)
    784 
    785         _logger.info(f'{filename} was created')

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/io_plugins/blockfile.py in file_writer(filename, signal, **kwds)
    274             endianess +
    275             'u1')
--> 276         vbf.tofile(f)
    277         # Zero pad until next data block
    278         if f.tell() > int(header['Data_offset_2']):

AttributeError: 'Array' object has no attribute 'tofile'

Dimension issue (signal unit is 1/nm):

---------------------------------------------------------------------------
DimensionalityError                       Traceback (most recent call last)
<ipython-input-9-ebacc5399fa7> in <module>
----> 1 data_file.save("test.blo")

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/signal.py in save(self, filename, overwrite, extension, **kwds)
   2838         if extension is not None:
   2839             filename = filename.with_suffix(f".{extension}")
-> 2840         io.save(filename, self, overwrite=overwrite, **kwds)
   2841 
   2842     def _replot(self):

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/io.py in save(filename, signal, overwrite, **kwds)
    781         # Pass as a string for now, pathlib.Path not
    782         # properly supported in io_plugins
--> 783         writer.file_writer(str(filename), signal, **kwds)
    784 
    785         _logger.info(f'{filename} was created')

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/io_plugins/blockfile.py in file_writer(filename, signal, **kwds)
    257 def file_writer(filename, signal, **kwds):
    258     endianess = kwds.pop('endianess', '<')
--> 259     header, note = get_header_from_signal(signal, endianess=endianess)
    260     with open(filename, 'wb') as f:
    261         # Write header

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/io_plugins/blockfile.py in get_header_from_signal(signal, endianess)
    111     axes_manager = signal.axes_manager.deepcopy()
    112     axes_manager.convert_units('navigation', 'nm')
--> 113     axes_manager.convert_units('signal', 'cm')
    114 
    115     if axes_manager.navigation_dimension == 2:

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/axes.py in convert_units(self, axes, units, same_units, factor)
   1131                 offset = self.navigation_dimension if convert_navigation else 0
   1132                 units_sig = units[offset:]
-> 1133                 self._convert_axes_to_same_units(self.signal_axes,
   1134                                                  units_sig, factor)
   1135         else:

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/axes.py in _convert_axes_to_same_units(self, axes, units, factor)
   1147         # Set the same units for all axes, use the unit of the first axis
   1148         # as reference
-> 1149         axes[0].convert_to_units(units[0], factor=factor)
   1150         unit = axes[0].units  # after conversion, in case units[0] was None.
   1151         for axis in axes[1:]:

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/axes.py in convert_to_units(self, units, inplace, factor)
    156             out = self._convert_compact_units(factor, inplace=inplace)
    157         else:
--> 158             out = self._convert_units(units, inplace=inplace)
    159         return out
    160 

~/Documents/PythonProjects/FORKS/hyperspy/hyperspy/axes.py in _convert_units(self, converted_units, inplace)
    125         scale_pint = self.scale * _ureg(self.units)
    126         offset_pint = self.offset * _ureg(self.units)
--> 127         scale = float(scale_pint.to(_ureg(converted_units)).magnitude)
    128         offset = float(offset_pint.to(_ureg(converted_units)).magnitude)
    129         units = '{:~}'.format(scale_pint.to(_ureg(converted_units)).units)

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/quantity.py in to(self, other, *contexts, **ctx_kwargs)
    659         other = to_units_container(other, self._REGISTRY)
    660 
--> 661         magnitude = self._convert_magnitude_not_inplace(other, *contexts, **ctx_kwargs)
    662 
    663         return self.__class__(magnitude, other)

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/quantity.py in _convert_magnitude_not_inplace(self, other, *contexts, **ctx_kwargs)
    608                 return self._REGISTRY.convert(self._magnitude, self._units, other)
    609 
--> 610         return self._REGISTRY.convert(self._magnitude, self._units, other)
    611 
    612     def _convert_magnitude(self, other, *contexts, **ctx_kwargs):

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/registry.py in convert(self, value, src, dst, inplace)
    952             return value
    953 
--> 954         return self._convert(value, src, dst, inplace)
    955 
    956     def _convert(self, value, src, dst, inplace=False, check_dimensionality=True):

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/registry.py in _convert(self, value, src, dst, inplace)
   1838                 value, src = src._magnitude, src._units
   1839 
-> 1840         return super()._convert(value, src, dst, inplace)
   1841 
   1842     def _get_compatible_units(self, input_units, group_or_system):

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/registry.py in _convert(self, value, src, dst, inplace)
   1440 
   1441         if not (src_offset_unit or dst_offset_unit):
-> 1442             return super()._convert(value, src, dst, inplace)
   1443 
   1444         src_dim = self._get_dimensionality(src)

~/opt/anaconda3/envs/hyperspy-dev/lib/python3.8/site-packages/pint/registry.py in _convert(self, value, src, dst, inplace, check_dimensionality)
    985             # then the conversion cannot be performed.
    986             if src_dim != dst_dim:
--> 987                 raise DimensionalityError(src, dst, src_dim, dst_dim)
    988 
    989         # Here src and dst have only multiplicative units left. Thus we can

DimensionalityError: Cannot convert from '1 / nanometer' (1 / [length]) to 'centimeter' ([length])

It would seem that most 4D STEM datasets will run into this Dimension issue since DP's should have 1/length units. I guess real information about the geometry of the projector system / camera would be required and translated to the ASTAR coordinate system for a proper calibration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants