8000 add LAMMPS .grid(.gz) import by alphataubio · Pull Request #181 · RBVI/ChimeraX · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

add LAMMPS .grid(.gz) import #181

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

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions src/bundles/map_data/bundle_info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
suffixes=".hed,.img" />
<Provider name="Imaris map" nicknames="ims" category="Volume data" suffixes=".ims" />
<Provider name="IMOD map" nicknames="imodmap" category="Volume data" suffixes=".rec" />
<Provider name="LAMMPS grid3d" nicknames="grid3d" category="Volume data" suffixes=".grid3d" />
<Provider name="MacMolPlt grid" nicknames="macmolplt" category="Volume data" suffixes=".mmp" />
<Provider name="MRC density map" nicknames="mrc" category="Volume data" suffixes=".mrc" />
<Provider name="NetCDF map" nicknames="netcdfmap" category="Volume data"
Expand Down
2 changes: 1 addition & 1 deletion src/bundles/map_data/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ TOP = ../../../..
include $(TOP)/mk/config.make

SUBDIRS = amira apbs brix ccp4 cmap delphi deltavision dock dsn6 emanhdf gaussian \
gopenmol hdf imagestack imagic imod ims macmolplt mrc priism profec \
gopenmol hdf imagestack imagic imod ims lammps macmolplt mrc priism profec \
pif situs spider tom_em uhbd xplor

PKG_DIR = $(PYSITEDIR)/chimerax/map_data
Expand Down
17 changes: 15 additions & 2 deletions src/bundles/map_data/src/fileformats.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ def __init__(self, description, name, prefixes, suffixes, *,
self.allow_directory = allow_directory
self.check_path = check_path

print(f"*** name {name} suffixes {suffixes}")

@property
def open_func(self):
module_name = self.name
print(f"*** module_name {module_name}")
module = __import__(module_name, globals(), level = 1)
return module.open

Expand Down Expand Up @@ -90,7 +93,8 @@ def save_func(self):
MapFileFormat('SPIDER volume data', 'spider', ['spider'], ['spi','vol']),
MapFileFormat('TOM toolbox EM density map', 'tom_em', ['tom_em'], ['em']),
MapFileFormat('UHBD grid, binary', 'uhbd', ['uhbd'], ['grd']),
]
MapFileFormat('LAMMPS grid3d', 'lammps', ['lammps'], ['grid3d']),
]

# -----------------------------------------------------------------------------
# The electrostatics file types are opened using a surface colormapping tool
Expand Down Expand Up @@ -146,6 +150,8 @@ def suffix_warning(paths):
#
def open_file(path, file_type = None, **kw):

print("*** open_file()")

if file_type is None:
p = path if isinstance(path, str) else path[0]
file_type = file_type_from_suffix(p)
Expand Down Expand Up @@ -181,7 +187,9 @@ def open_file(path, file_type = None, **kw):
# -----------------------------------------------------------------------------
#
def file_type_from_suffix(path):


print("*** file_type_from_suffix()")

for ff in file_formats:
for suffix in ff.suffixes:
if has_suffix(path, suffix):
Expand All @@ -192,6 +200,8 @@ def file_type_from_suffix(path):
#
def file_type_from_colon_specifier(path):

print("*** file_type_from_colon_specifier()")

try:
colon_position = path.rindex(':')
except ValueError:
Expand All @@ -209,6 +219,9 @@ def file_type_from_colon_specifier(path):
# -----------------------------------------------------------------------------
#
def file_format_by_name(name):

print("*** file_format_by_name()")

for ff in file_formats:
if ff.name == name or name in ff.suffixes or name in ff.prefixes:
return ff
Expand Down
26 changes: 26 additions & 0 deletions src/bundles/map_data/src/lammps/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# === UCSF ChimeraX Copyright ===
# Copyright 2016 Regents of the University of California.
# All rights reserved. This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use. For details see:
# https://www.rbvi.ucsf.edu/chimerax/docs/licensing.html
# This notice must be embedded in or attached to all copies,
# including partial copies, of the software or any revisions
# or derivations thereof.
# === UCSF ChimeraX Copyright ===

TOP = ../../../../..
include $(TOP)/mk/config.make

PKG_DIR = $(PYSITEDIR)/chimerax/map_data/lammps

PYSRCS = __init__.py lammps_grid.py lammps_format.py

all: $(PYOBJS)

install: all
-mkdir -p $(PKG_DIR)
$(RSYNC) $(PYSRCS) $(PKG_DIR)

clean:
rm -rf __pycache__
24 changes: 24 additions & 0 deletions src/bundles/map_data/src/lammps/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# === UCSF ChimeraX Copyright ===
# Copyright 2016 Regents of the University of California.
# All rights reserved. This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use. For details see:
# https://www.rbvi.ucsf.edu/chimerax/docs/licensing.html
# This notice must be embedded in or attached to all copies,
# including partial copies, of the software or any revisions
# or derivations thereof.
# === UCSF ChimeraX Copyright ===

# -----------------------------------------------------------------------------
# LAMMPS grid3d dump file reader.
#

print("*** ok 1a")

def open(path):
from .lammps_grid import LammpsGrid
print("*** ok 1b")
return [LammpsGrid(path)]


# open /Users/mitch/Dropbox/github/hmx/spice/nitrite/nitrite.grid3d
207 changes: 207 additions & 0 deletions src/bundles/map_data/src/lammps/lammps_format.py
AE88
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# === UCSF ChimeraX Copyright ===
# Copyright 2016 Regents of the University of California.
# All rights reserved. This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use. For details see:
# https://www.rbvi.ucsf.edu/chimerax/docs/licensing.html
# This notice must be embedded in or attached to all copies,
# including partial copies, of the software or any revisions
# or derivations thereof.
# === UCSF ChimeraX Copyright ===

# -----------------------------------------------------------------------------
# Read LAMMPS grid3d format map data.
#
import os
import numpy

class Lammps_Grid_Data:
"""
Parses LAMMPS grid3d format files produced by the 'dump grid' command.
"""
def __init__(self, path):
self.path = path
self.name = os.path.basename(path)

# Parse file to get grid metadata
if path.endswith('.gz'):
import gzip
f = gzip.open(path, 'rt')
else:
f = open(path, 'r')

try:
self.parse_header(f)
finally:
f.close()

def parse_header(self, file):
"""Parse the LAMMPS grid3d file and extract metadata."""
# LAMMPS grid data variables
self.timesteps = []
self.matrix_size = None # (nx, ny, nz)
self.origin = None # (x0, y0, z0)
self.step = None # (dx, dy, dz)
self.columns = None # List of data column names
self.data_sections = [] # List of (timestep, start_pos, num_entries)

# Read through file to find all sections
lines = file.readlines()
line_index = 0

while line_index < len(lines):
line = lines[line_index].strip()

# Parse ITEM: TIMESTEP
if line.startswith("ITEM: TIMESTEP"):
line_index += 1
timestep = int(lines[line_index].strip())
self.timesteps.append(timestep)

# Parse ITEM: GRID SIZE
elif line.startswith("ITEM: GRID SIZE"):
line_index += 1
parts = lines[line_index].strip().split()
if len(parts) >= 3:
# LAMMPS grid dimensions are (nx, ny, nz)
self.matrix_size = (int(parts[0]), int(parts[1]), int(parts[2]))

# Parse ITEM: GRID ORIGIN
elif line.startswith("ITEM: GRID ORIGIN"):
line_index += 1
parts = lines[line_index].strip().split()
if len(parts) >= 3:
self.origin = (float(parts[0]), float(parts[1]), float(parts[2]))

# Parse ITEM: GRID SPACING
elif line.startswith("ITEM: GRID SPACING"):
line_index += 1
parts = lines[line_index].strip().split()
if len(parts) >= 3:
self.step = (float(parts[0]), float(parts[1]), float(parts[2]))

# Parse ITEM: GRID CELLS
elif line.startswith("ITEM: GRID CELLS"):
header = line.split()
# Skip "ITEM: GRID CELLS" and get column names
self.columns = header[3:]

if self.matrix_size is None:
raise ValueError("Grid size not defined before GRID CELLS section")

# Record the position in the file for later data reading
start_pos = line_index + 1

# Calculate expected number of data entries
nx, ny, nz = self.matrix_size
num_entries = nx * ny * nz

# Record data section info
current_timestep = self.timesteps[-1] if self.timesteps else 0
self.data_sections.append((current_timestep, start_pos, num_entries))

# Skip the data section - we'll read it on demand
line_index += num_entries
continue

line_index += 1

# Use first column for the initial grid
if len(self.columns) > 0:
self.current_column = self.columns[0]
else:
raise ValueError("No grid data columns found")

# Set element type
from numpy import float32
self.element_type = float32

# Validate that we have all required metadata
if self.matrix_size is None:
raise ValueError("Grid size not found in file")
if self.origin is None:
raise ValueError("Grid origin not found in file")
if self.step is None:
raise ValueError("Grid spacing not found in file")
if not self.data_sections:
raise ValueError("No grid data sections found in file")

def read_matrix(self, ijk_origin, ijk_size, ijk_step, progress):
"""
Read and return the specified submatrix from the file.
For LAMMPS grid3d format, we need to read and parse the entire grid.
"""
# Currently just read the first data section and first column
timestep, start_pos, num_entries = self.data_sections[0]
column_idx = self.columns.index(self.current_column)

# Read the whole file again
if self.path.endswith('.gz'):
import gzip
f = gzip.open(self.path, 'rt')
else:
f = open(self.path, 'r')

try:
lines = f.readlines()

# Create numpy array for the data
nx, ny, nz = self.matrix_size
data = numpy.zeros((nz, ny, nx), dtype=self.element_type)

# Read the data section
for i in range(num_entries):
if progress and i % 1000 == 0:
progress.percent = 100.0 * i / num_entries

line_idx = start_pos + i
if line_idx >= len(lines):
break

line = lines[line_idx].strip()
parts = line.split()

# LAMMPS format: ix iy iz value1 value2 ...
# We expect at least 3 + len(columns) values
if len(parts) < 3 + len(self.columns):
continue

ix = int(parts[0])
iy = int(parts[1])
iz = int(parts[2])

# Get the value for the current column
value = float(parts[3 + column_idx])

# Store in data array (in ZYX index order)
if 0 <= ix < nx and 0 <= iy < ny and 0 <= iz < nz:
data[iz, iy, ix] = value

# Extract the requested submatrix
submatrix = self._submatrix(data, ijk_origin, ijk_size, ijk_step)
return submatrix

finally:
f.close()

def _submatrix(self, data, ijk_origin, ijk_size, ijk_step):
"""Extract a submatrix from the data array."""
ox, oy, oz = ijk_origin
sx, sy, sz = ijk_size
stx, sty, stz = ijk_step

# Adjust for our ZYX index order
i0, i1, i2 = oz, oy, ox
s0, s1, s2 = sz, sy, sx
st0, st1, st2 = stz, sty, stx

# Extract the submatrix
if st0 == 1 and st1 == 1 and st2 == 1:
submatrix = data[i0:i0+s0, i1:i1+s1, i2:i2+s2].copy()
else:
submatrix = data[
i0:i0+s0*st0:st0,
i1:i1+s1*st1:st1,
i2:i2+s2*st2:st2].copy()

return submatrix
52 changes: 52 additions & 0 deletions src/bundles/map_data/src/lammps/lammps_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# === UCSF ChimeraX Copyright ===
# Copyright 2016 Regents of the University of California.
# All rights reserved. This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use. For details see:
# https://www.rbvi.ucsf.edu/chimerax/docs/licensing.html
# This notice must be embedded in or attached to all copies,
# including partial copies, of the software or any revisions
# or derivations thereof.
# === UCSF ChimeraX Copyright ===

# === UCSF ChimeraX Copyright ===
# Copyright 2016 Regents of the University of California.
# All rights reserved. This software provided pursuant to a
# license agreement containing restrictions on its disclosure,
# duplication and use. For details see:
# https://www.rbvi.ucsf.edu/chimerax/docs/licensing.html
# This notice must be embedded in or attached to all copies,
# including partial copies, of the software or any revisions
# or derivations thereof.
# === UCSF ChimeraX Copyright ===

# -----------------------------------------------------------------------------
# Wrap LAMMPS grid3d data as grid data for displaying as surfaces, meshes, and volumes.
#
from .. import GridData

# -----------------------------------------------------------------------------
#
class LammpsGrid(GridData):
"""
Reads LAMMPS grid3d format files produced by the 'dump grid' command in LAMMPS.
"""
def __init__(self, path):

print("*** ok 2")


from . import lammps_format
d = lammps_format.Lammps_Grid_Data(path)

self.lammps_data = d

GridData.__init__(self, d.matrix_size, d.element_type,
origin=d.origin, step=d.step,
path=path, file_type='grid3d',
name=d.name)

# ---------------------------------------------------------------------------
#
def read_matrix(self, ijk_origin, ijk_size, ijk_step, progress):
return self.lammps_data.read_matrix(ijk_origin, ijk_size, ijk_step, progress)
Loading
Loading
0