Skip to content

Commit

Permalink
reorder MRC data according to mapc,mapr,maps
Browse files Browse the repository at this point in the history
- mrcfile stores data in z,y,x format: we use the information
  of the axis orientation in mapc, mapr. maps to orient the
  data in the GridDataFormats x,y,z coordinate system
- correctly reorient and center coordinates from MRC
  - fix #76
  - add tests
- mrcfile only reshapes the data to nz,ny,nx but does not take
  the mapc, mapr, maps into account. For gridData we need to
  do the coordinate system reorientation after transposing the
  mrcfile.data to nx, ny, nz.
- add test (using CCP4_1JZV from the test data which contains
  mapc, mapr, maps = 2, 1, 3
- manually checked 1cbs.ccp4 from issue #76 (also a 2, 1, 3)
  and orientation is now correct but there is still an offset error
  that needs to be fixed
- update CHANGELOG (and add @tluchko)

Co-authored-by: tluchko <31545346+tluchko@users.noreply.github.com>
  • Loading branch information
orbeckst and tluchko committed Feb 20, 2022
1 parent c373d92 commit 508ab8b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ The rules for this file:
* accompany each entry with github issue/PR number (Issue #xyz)

------------------------------------------------------------------------------
??/??/2022 orbeckst
??/??/2022 orbeckst, tluchko

* 0.7.0
* 0.7.0

Enhancements

* use mrcfile library to parse MRC files (including CCP4) using the
new mrc.MRC class (issue #83)

Fixes

* The new mrc module correctly reorients the coordinate system based
on mapc, mapr, maps and correctly calculates the origin (issue #76)

Deprecations

* The CCP4 module (replaced by mrc) will be removed in 0.8.0.
Expand Down
23 changes: 19 additions & 4 deletions gridData/mrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,24 @@ def read(self, filename):
"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
self.array = np.transpose(mrc.data)
self.delta = np.diag([mrc.voxel_size.x, mrc.voxel_size.y, mrc.voxel_size.z])
self.origin = np.array([h.origin.x, h.origin.y, h.origin.z])
# 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
Expand All @@ -119,7 +134,7 @@ def shape(self):

@property
def edges(self):
"""Edges of the grid cells, origin at centre of 0,0,..,0 grid cell.
"""Edges of the grid cells, origin at centre of 0,0,0 grid cell.
Only works for regular, orthonormal grids.
"""
Expand Down
20 changes: 20 additions & 0 deletions gridData/tests/test_mrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,28 @@ def test_ccp4_read_header(ccp4data, name, value):
else:
assert_equal(ccp4data.header[name], value)

def test_axes_orientation(ccp4data):
# correctly interpret mapc, mapr, maps = 2, 1, 3
# for nx, ny, nz = 96, 76, 70.
# see also #76
assert_equal(ccp4data.shape, (76, 96, 70))

def test_delta(ccp4data):
assert_almost_equal(ccp4data.delta, np.array(
[[0.5452381, 0. , 0. ],
[0. , 0.5452381, 0. ],
[0. , 0. , 0.5603125]], dtype=np.float32))

def test_origin(ccp4data):
# shift with nxstart, nystart, nzstart and delta
#
# (visual comparison of CCP4 and DX file in ChimeraX at same
# level shows full agreement)
assert_almost_equal(ccp4data.origin, [-12.5404758, -2.1809523, 57.151876 ])

def test_triclinic_ValueError():
with pytest.raises(ValueError,
match="Only orthorhombic unitcells are currently "
"supported, not"):
Grid(datafiles.MRC_EMD3001, file_format="MRC")

0 comments on commit 508ab8b

Please sign in to comment.