Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ The rules for this file:
* accompany each entry with github issue/PR number (Issue #xyz)

-------------------------------------------------------------------------------
MM/DD/2026 orbeckst

* 1.3.0

Changes

* update init signature for OpenDX.DXClass to include name and components
as optional kwargs to streamline init in child classes (PR #179)


05/22/2026 orbeckst, spyke7

* 1.2.0
Expand Down
56 changes: 27 additions & 29 deletions gridData/OpenDX.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
:members:

"""

import numpy
import re
import gzip
Expand Down Expand Up @@ -229,12 +230,12 @@ def _gzip_open(filename, mode="rt"):
class DXclass(object):
"""'class' object as defined by OpenDX"""

def __init__(self, classid):
def __init__(self, classid, name=None, component=None):
"""id is the object number"""
self.id = classid # serial number of the object
self.name = None # name of the DXclass
self.component = None # component type
self.D = None # dimensions
self.name = name # name of the DXclass
self.component = component # component type
self.D = 3 # dimensions

def write(self, stream, optstring="", quote=False):
"""write the 'object' line; additional args are packed in string"""
Expand Down Expand Up @@ -279,12 +280,11 @@ class gridpositions(DXclass):
def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs):
if shape is None or origin is None or delta is None:
raise ValueError("all keyword arguments are required")
self.id = classid
self.name = "gridpositions"
self.component = "positions"
super().__init__(classid, name="gridpositions", component="positions")
self.shape = numpy.asarray(shape) # D dimensional shape
self.origin = numpy.asarray(origin) # D vector
self.rank = len(self.shape) # D === rank
assert self.rank == self.D, "DXClass is only used for 3D arrays"

self.delta = numpy.asarray(delta) # DxD array of grid spacings
# gridDataFormats actually provides a simple 1D array with the deltas because only
Expand All @@ -301,9 +301,7 @@ def __init__(self, classid, shape=None, origin=None, delta=None, **kwargs):
)

def write(self, stream):
super(gridpositions, self).write(
stream, ("counts " + self.ndformat(" %d")) % tuple(self.shape)
)
super().write(stream, ("counts " + self.ndformat(" %d")) % tuple(self.shape))
self._write_line(stream, "origin %f %f %f\n" % tuple(self.origin))
for delta in self.delta:
self._write_line(
Expand All @@ -329,9 +327,7 @@ class gridconnections(DXclass):
def __init__(self, classid, shape=None, **kwargs):
if shape is None:
raise ValueError("all keyword arguments are required")
self.id = classid
self.name = "gridconnections"
self.component = "connections"
super().__init__(classid, name="gridconnections", component="connections")
self.shape = numpy.asarray(shape) # D dimensional shape

def write(self, stream):
Expand Down Expand Up @@ -410,9 +406,7 @@ def __init__(self, classid, array=None, type=None, typequote='"', **kwargs):
"""
if array is None:
raise ValueError("array keyword argument is required")
self.id = classid
self.name = "array"
self.component = "data"
super().__init__(classid, name="array", component="data")
# detect type https://github.com/MDAnalysis/GridDataFormats/issues/35
if type is None:
self.array = numpy.asarray(array)
Expand Down Expand Up @@ -464,7 +458,7 @@ def write(self, stream):
).format(self.type, list(self.dx_types.keys()))
)
typelabel = self.typequote + self.type + self.typequote
super(array, self).write(
super().write(
stream,
"type {0} rank 0 items {1} data follows".format(typelabel, self.array.size),
)
Expand Down Expand Up @@ -544,6 +538,11 @@ def __init__(self, classid="0", components=None, comments=None):
dx = OpenDX.field('density',[gridpoints,gridconnections,array])

"""
super().__init__(
classid, # can be an arbitrary string
name="field",
component=None, # cannot be a component of a field
)
if components is None:
components = dict(positions=None, connections=None, data=None)
if comments is None:
Expand All @@ -553,9 +552,6 @@ def __init__(self, classid="0", components=None, comments=None):
]
elif type(comments) is not list:
comments = [str(comments)]
self.id = classid # can be an arbitrary string
self.name = "field"
self.component = None # cannot be a component of a field
self.components = components
self.comments = comments

Expand Down Expand Up @@ -584,8 +580,8 @@ def from_grid(cls, grid, type=None, typequote='"', **kwargs):
-------
field
OpenDX field wrapper


.. versionadded:: 1.2.0
"""
comments = [
Expand All @@ -612,10 +608,10 @@ def from_grid(cls, grid, type=None, typequote='"', **kwargs):
@property
def native(self):
"""Return native object

The "native" object is the :class:`gridData.OpenDX.field` itself.


.. versionadded:: 1.2.0
"""
return self
Expand Down Expand Up @@ -647,7 +643,7 @@ def write(self, filename):
for component, object in self.sorted_components():
object.write(outfile)
# the field object itself
super(field, self).write(outfile, quote=True)
super().write(outfile, quote=True)
for component, object in self.sorted_components():
self._write_line(
outfile, 'component "%s" value %s\n' % (component, str(object.id))
Expand Down Expand Up @@ -683,9 +679,11 @@ def read(self, stream):
except (UnicodeDecodeError, RecursionError) as err:
# parser got confused, likely not a valid file
# (RecursionError was only observed on Windows)
raise ValueError("DX file could not be read. "
"The original error was\n"
f" {err.__class__.__name__}: {err}")
raise ValueError(
"DX file could not be read. "
"The original error was\n"
f" {err.__class__.__name__}: {err}"
)

def add(self, component, DXobj):
"""add a component to the field"""
Expand Down
Loading