-
Notifications
You must be signed in to change notification settings - Fork 22
use mrcfile library for MRC/CCP4 file parsing #100
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
Changes from all commits
e639500
c373d92
508ab8b
ddf6a93
fc6e112
3129570
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| .. automodule:: gridData.mrc | ||
| :members: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| # gridDataFormats --- python modules to read and write gridded data | ||
| # Copyright (c) 2009-2021 Oliver Beckstein <orbeckst@gmail.com> | ||
| # Released under the GNU Lesser General Public License, version 3 or later. | ||
| # | ||
|
|
||
| """:mod:`mrc` --- the mrc/CCP4 volumetric data format | ||
| =================================================== | ||
|
|
||
| .. versionadded:: 0.7.0 | ||
|
|
||
| Reading of MRC/CCP4 volumetric files (`MRC2014 file format`_) using | ||
| the mrcfile_ library [Burnley2017]_. | ||
|
|
||
| This implementation replaces the :mod:`CCP4` module. | ||
|
|
||
| .. _mrcfile: https://mrcfile.readthedocs.io/ | ||
| .. _`MRC2014 file format`: http://www.ccpem.ac.uk/mrc_format/mrc2014.php | ||
|
|
||
|
|
||
| References | ||
| ---------- | ||
|
|
||
| .. [Burnley2017] Burnley T, Palmer C and Winn M (2017) Recent | ||
| developments in the CCP-EM software suite. *Acta | ||
| Cryst.* D73:469-477. doi: `10.1107/S2059798317007859`_ | ||
|
|
||
|
|
||
| .. _`10.1107/S2059798317007859`: https://doi.org/10.1107/S2059798317007859 | ||
|
|
||
| Classes | ||
| ------- | ||
|
|
||
| """ | ||
| from __future__ import absolute_import | ||
| from six.moves import range | ||
|
|
||
| import numpy as np | ||
| import mrcfile | ||
|
|
||
|
|
||
| class MRC(object): | ||
| """Represent a MRC/CCP4 file. | ||
|
|
||
| Load `MRC/CCP4 2014 <MRC2014 file format>`_ 3D volumetric data with | ||
| the mrcfile_ library. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| filename : str (optional) | ||
| input file (or stream), can be compressed | ||
|
|
||
|
|
||
| Attributes | ||
| ---------- | ||
| header : numpy.recarray | ||
| Header data from the MRC file as a numpy record array. | ||
|
|
||
| array : numpy.ndarray | ||
| Data as a 3-dimensional array where axis 0 corresponds to X, | ||
| axis 1 to Y, and axis 2 to Z. This order is always enforced, | ||
| regardless of the order in the mrc file. | ||
|
|
||
| delta : numpy.ndarray | ||
| Diagonal matrix with the voxel size in X, Y, and Z direction | ||
| (taken from the :attr:`mrcfile.mrcfile.voxel_size` attribute) | ||
|
|
||
| origin : numpy.ndarray | ||
| numpy array with coordinates of the coordinate system origin | ||
| (taken from :attr:`header.origin`) | ||
|
|
||
| rank : int | ||
| The integer 3, denoting that only 3D maps are read. | ||
|
|
||
|
|
||
| Notes | ||
| ----- | ||
| * Only volumetric (3D) densities are read. | ||
| * Only orthorhombic unitcells supported (other raise :exc:`ValueError`) | ||
| * Only reading is currently supported. | ||
|
|
||
|
|
||
| .. versionadded:: 0.7.0 | ||
|
|
||
| """ | ||
|
|
||
| def __init__(self, filename=None): | ||
| self.filename = filename | ||
| if filename is not None: | ||
| self.read(filename) | ||
|
|
||
| def read(self, filename): | ||
| """Populate the instance from the MRC/CCP4 file *filename*.""" | ||
| if filename is not None: | ||
| self.filename = filename | ||
| with mrcfile.open(filename) as mrc: | ||
| if not mrc.is_volume(): #pragma: no cover | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is calling validate worth it too? (not sure how much of an issue a non-valid mrc file is)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to read a file with an iffy header and just get the data. Not sure, TBH.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No implementing for now because I don't understand the implication/standard use.
IAlibay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| raise ValueError( | ||
| "MRC file {} is not a volumetric density.".format(filename)) | ||
| self.header = h = mrc.header.copy() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any difference between header and extended_header here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't know — experts??
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From https://www.ccpem.ac.uk/mrc_format/mrc2014.php,
The
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to have access to
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a personal-use case in mind. But, if it isn't difficult, it could be beneficial in cases we haven't thought of yet. Not everything in the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am adding the header as undocumented |
||
| # check for being orthorhombic | ||
| if not np.allclose([h.cellb.alpha, h.cellb.beta, h.cellb.gamma], | ||
| [90, 90, 90]): | ||
| raise ValueError("Only orthorhombic unitcells are currently " | ||
| "supported, not " | ||
| "alpha={0}, beta={1}, gamma={2}".format( | ||
| h.cellb.alpha, h.cellb.beta, h.cellb.gamma)) | ||
| # mrc.data[z, y, x] indexed: convert to x,y,z as used in GridDataFormats | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to do further manipulations here?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. If the file has
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, this needs to be fixed then. Perhaps that fixes #76, too. Code welcome!!!
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ultimately, this and calculating the origin correctly did fix #76 |
||
| # together with the axes orientation information in mapc/mapr/maps. | ||
| # mapc, mapr, maps = 1, 2, 3 for Fortran-ordering and 3, 2, 1 for C-ordering. | ||
| # Other combinations are possible. We reorder the data for the general case | ||
| # by sorting mapc, mapr, maps in ascending order, i.e., to obtain x,y,z. | ||
| # mrcfile provides the data in zyx shape (without regard to map*) so we first | ||
| # transpose it to xyz and then reorient with axes_c_order. | ||
| # | ||
| # All other "xyz" quantitities are also reordered. | ||
| axes_order = np.hstack([h.mapc, h.mapr, h.maps]) | ||
| axes_c_order = np.argsort(axes_order) | ||
| transpose_order = np.argsort(axes_order[::-1]) | ||
| self.array = np.transpose(mrc.data, axes=transpose_order) | ||
| self.delta = np.diag(np.array([mrc.voxel_size.x, mrc.voxel_size.y, mrc.voxel_size.z])) | ||
| # the grid is shifted to the MRC origin by offset | ||
| # (assume orthorhombic) | ||
| offsets = np.hstack([h.nxstart, h.nystart, h.nzstart])[axes_c_order] * np.diag(self.delta) | ||
| # GridData origin is centre of cell at x=col=0, y=row=0 z=seg=0 | ||
| self.origin = np.hstack([h.origin.x, h.origin.y, h.origin.z]) + offsets | ||
| self.rank = 3 | ||
|
|
||
| @property | ||
| def shape(self): | ||
| """Shape of the :attr:`array`""" | ||
| return self.array.shape | ||
|
|
||
| @property | ||
| def edges(self): | ||
| """Edges of the grid cells, origin at centre of 0,0,0 grid cell. | ||
|
|
||
| Only works for regular, orthonormal grids. | ||
| """ | ||
| # TODO: Add triclinic cell support. | ||
| return [self.delta[d, d] * np.arange(self.shape[d] + 1) + | ||
| self.origin[d] - 0.5 * self.delta[d, d] | ||
| for d in range(self.rank)] | ||
|
|
||
| def histogramdd(self): | ||
| """Return array data as (edges,grid), i.e. a numpy nD histogram.""" | ||
| return (self.array, self.edges) | ||
|
|
||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.