From fe00479236752a1aa0f729e77500ced55cff4074 Mon Sep 17 00:00:00 2001 From: spyke7 Date: Thu, 12 Mar 2026 01:44:56 +0530 Subject: [PATCH 1/2] written from_grid and native for dx and mrc --- gridData/OpenDX.py | 27 +++++++++++++++++++++++++++ gridData/mrc.py | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/gridData/OpenDX.py b/gridData/OpenDX.py index a081942..5a52260 100644 --- a/gridData/OpenDX.py +++ b/gridData/OpenDX.py @@ -523,6 +523,33 @@ def __init__(self,classid='0',components=None,comments=None): self.components = components self.comments= comments + @staticmethod + def from_grid(grid, type=None, typequote='"', **kwargs): + comments = [ + "OpenDX density file written by gridDataFormats.Grid.export()", + "File format: http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm#HDREDF", + "Data are embedded in the header and tied to the grid positions.", + "Data is written in C array order: In grid[x,y,z] the axis z is fastest", + "varying, then y, then finally x, i.e. z is the innermost loop.", + ] + if grid.metadata: + comments.append("Meta data stored with the python Grid object:") + for k in grid.metadata: + comments.append(" " + str(k) + " = " + str(grid.metadata[k])) + comments.append("(Note: the VMD dx-reader chokes on comments below this line)") + + components = dict( + positions=gridpositions(1, grid.grid.shape, grid.origin, grid.delta), + connections=gridconnections(2, grid.grid.shape), + data=array(3, grid.grid, type=type, typequote=typequote), + ) + dx_field = field('density', components=components, comments=comments) + return dx_field + + @property + def native(self): + return self + def _openfile_writing(self, filename): """Returns a regular or gz file stream for writing""" if filename.endswith('.gz'): diff --git a/gridData/mrc.py b/gridData/mrc.py index 676d993..61963cd 100644 --- a/gridData/mrc.py +++ b/gridData/mrc.py @@ -100,6 +100,25 @@ def __init__(self, filename=None, assume_volumetric=False): self.filename = filename if filename is not None: self.read(filename, assume_volumetric=assume_volumetric) + + @staticmethod + def from_grid(grid, **kwargs): + mrc_obj = MRC() + + mrc_obj.array = grid.grid + mrc_obj.delta = np.diag(grid.delta) + mrc_obj.origin = grid.origin + mrc_obj.rank = 3 + + if hasattr(grid, "_mrc_header"): + mrc_obj.header = grid._mrc_header + + return mrc_obj + + @property + def native(self): + """Native object is the MRC wrapper itself.""" + return self def read(self, filename, assume_volumetric=False): """Populate the instance from the MRC/CCP4 file *filename*.""" From 42436760e07292b56d3375206482ef5463578665 Mon Sep 17 00:00:00 2001 From: spyke7 Date: Mon, 16 Mar 2026 16:31:54 +0530 Subject: [PATCH 2/2] updated core.py, test_dx.py and test_mrc.py --- gridData/core.py | 68 ++++++++++++++++++++------------------ gridData/tests/test_dx.py | 23 +++++++++++++ gridData/tests/test_mrc.py | 21 ++++++++++++ 3 files changed, 79 insertions(+), 33 deletions(-) diff --git a/gridData/core.py b/gridData/core.py index 035d769..1282d99 100644 --- a/gridData/core.py +++ b/gridData/core.py @@ -212,6 +212,12 @@ class Grid(object): #: Default format for exporting with :meth:`export`. default_format = 'DX' + + converter = { + 'MRC': mrc.MRC.from_grid, + 'VDB': None, + 'DX': OpenDX.field.from_grid, + } def __init__(self, grid=None, edges=None, origin=None, delta=None, metadata=None, interpolation_spline_order=3, @@ -598,6 +604,32 @@ def _load_plt(self, filename, **kwargs): grid, edges = g.histogramdd() self._load(grid=grid, edges=edges, metadata=self.metadata) + def convert_to(self, format_specifier, tolerance=None, **kwargs): + """Generates an instance of the native object for a given format + + Implemented formats: + + DX + :mod:`OpenDX` + MRC + :mod:`mrc` MRC/CCP4 format + + Parameters + ---------- + format_specifier : str + + tolerance : float (default is None) + + Returns + ------- + native object + + """ + fmt_upper = format_specifier.upper() + + wrapper = self.converter[fmt_upper](self, **kwargs) + return wrapper.native + def export(self, filename, file_format=None, type=None, typequote='"'): """export density to file using the given format. @@ -673,29 +705,8 @@ def _export_dx(self, filename, type=None, typequote='"', **kwargs): """ root, ext = os.path.splitext(filename) filename = root + '.dx' - - comments = [ - 'OpenDX density file written by gridDataFormats.Grid.export()', - 'File format: http://opendx.sdsc.edu/docs/html/pages/usrgu068.htm#HDREDF', - 'Data are embedded in the header and tied to the grid positions.', - 'Data is written in C array order: In grid[x,y,z] the axis z is fastest', - 'varying, then y, then finally x, i.e. z is the innermost loop.'] - - # write metadata in comments section - if self.metadata: - comments.append('Meta data stored with the python Grid object:') - for k in self.metadata: - comments.append(' ' + str(k) + ' = ' + str(self.metadata[k])) - comments.append( - '(Note: the VMD dx-reader chokes on comments below this line)') - - components = dict( - positions=OpenDX.gridpositions(1, self.grid.shape, self.origin, - self.delta), - connections=OpenDX.gridconnections(2, self.grid.shape), - data=OpenDX.array(3, self.grid, type=type, typequote=typequote), - ) - dx = OpenDX.field('density', components=components, comments=comments) + dx = OpenDX.field.from_grid(self, type=type, typequote=typequote, **kwargs) + if ext == '.gz': filename = root + ext dx.write(filename) @@ -721,16 +732,7 @@ def _export_mrc(self, filename, **kwargs): .. versionadded:: 1.1.0 """ - # Create MRC object and populate with Grid data - mrc_file = mrc.MRC() - mrc_file.array = self.grid - mrc_file.delta = numpy.diag(self.delta) - mrc_file.origin = self.origin - mrc_file.rank = 3 - - # Transfer header if it exists (preserves axis ordering and other metadata) - if hasattr(self, '_mrc_header'): - mrc_file.header = self._mrc_header + mrc_file = mrc.MRC.from_grid(self, **kwargs) # Write to file mrc_file.write(filename) diff --git a/gridData/tests/test_dx.py b/gridData/tests/test_dx.py index ad3f12c..8dce09e 100644 --- a/gridData/tests/test_dx.py +++ b/gridData/tests/test_dx.py @@ -90,3 +90,26 @@ def test_delta_precision(tmpdir): g.delta, g2.delta, decimal=7, err_msg="deltas of written grid do not match original") + +def test_dx_from_grid(): + data = np.ones((5, 5, 5), dtype=np.float32) + g = Grid(data, origin=[1.0, 2.0, 3.0], delta=[0.5, 0.5, 0.5]) + g.metadata['name'] = 'test_density' + g.metadata['author'] = 'test_user' + + dx_field = gridData.OpenDX.field.from_grid(g) + + assert isinstance(dx_field, gridData.OpenDX.field) + + assert any('test_density' and 'test_user' in str(c) for c in dx_field.comments) + # assert any('test_user' in str(c) for c in dx_field.comments) + + assert_equal(dx_field.components['data'].array, data) + assert_equal(dx_field.components['positions'].origin, g.origin) + +def test_dx_native(): + data = np.ones((5, 5, 5)) + g = Grid(data, origin=[0, 0, 0], delta=[1, 1, 1]) + + dx_field = gridData.OpenDX.field.from_grid(g) + assert dx_field.native is dx_field \ No newline at end of file diff --git a/gridData/tests/test_mrc.py b/gridData/tests/test_mrc.py index 9b0723c..53ba9fc 100644 --- a/gridData/tests/test_mrc.py +++ b/gridData/tests/test_mrc.py @@ -142,6 +142,27 @@ def test_origin(self, grid, ccp4data): def test_data(self, grid, ccp4data): assert_allclose(grid.grid, ccp4data.array) + + def test_mrc_from_grid(self): + data = np.arange(27, dtype=np.float32).reshape((3, 3, 3)) + g = Grid(data, origin=[1.0, 2.0, 3.0], delta=[0.5, 0.5, 0.5]) + + mrc_obj = mrc.MRC.from_grid(g) + + assert isinstance(mrc_obj, mrc.MRC) + + assert_equal(mrc_obj.array, data) + assert_allclose(mrc_obj.delta, np.diag(g.delta)) + assert_allclose(mrc_obj.origin, g.origin) + assert mrc_obj.rank == 3 + + def test_mrc_native_property(self): + data = np.ones((3, 3, 3)) + g = Grid(data, origin=[0, 0, 0], delta=[1, 1, 1]) + + mrc_obj = mrc.MRC.from_grid(g) + + assert mrc_obj.native is mrc_obj class TestMRCWrite: """Tests for MRC write functionality"""