Skip to content

Commit

Permalink
handle new oxdna topology inclduing custom
Browse files Browse the repository at this point in the history
  • Loading branch information
BradyAJohnston committed Nov 28, 2024
1 parent e3a215c commit 6ff0847
Show file tree
Hide file tree
Showing 5 changed files with 5,525 additions and 30 deletions.
20 changes: 10 additions & 10 deletions molecularnodes/blender_manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ wheels = [
"./wheels/biotite-0.41.2-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/biotite-0.41.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/biotite-0.41.2-cp311-cp311-win_amd64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-win_amd64.whl",
"./wheels/contourpy-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/contourpy-1.3.1-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/contourpy-1.3.1-cp311-cp311-win_amd64.whl",
"./wheels/cycler-0.12.1-py3-none-any.whl",
"./wheels/fasteners-0.19-py3-none-any.whl",
"./wheels/fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl",
"./wheels/fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/fonttools-4.54.1-cp311-cp311-win_amd64.whl",
"./wheels/fonttools-4.55.0-cp311-cp311-macosx_10_9_universal2.whl",
"./wheels/fonttools-4.55.0-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/fonttools-4.55.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/fonttools-4.55.0-cp311-cp311-win_amd64.whl",
"./wheels/joblib-1.4.2-py3-none-any.whl",
"./wheels/kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl",
Expand All @@ -62,7 +62,7 @@ wheels = [
"./wheels/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/msgpack-1.1.0-cp311-cp311-win_amd64.whl",
"./wheels/networkx-3.4.2-py3-none-any.whl",
"./wheels/packaging-24.1-py3-none-any.whl",
"./wheels/packaging-24.2-py3-none-any.whl",
"./wheels/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
Expand All @@ -81,7 +81,7 @@ wheels = [
"./wheels/six-1.16.0-py2.py3-none-any.whl",
"./wheels/starfile-0.5.6-py3-none-any.whl",
"./wheels/threadpoolctl-3.5.0-py3-none-any.whl",
"./wheels/tqdm-4.66.6-py3-none-any.whl",
"./wheels/tqdm-4.67.0-py3-none-any.whl",
"./wheels/typing_extensions-4.12.2-py3-none-any.whl",
"./wheels/tzdata-2024.2-py2.py3-none-any.whl",
]
Expand Down
119 changes: 99 additions & 20 deletions molecularnodes/entities/trajectory/oxdna/OXDNAParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,103 @@ def parse(self, **kwargs):

return top

def _parseatoms(self):
with open(self.filename) as f:
first_line = f.readline()
@classmethod
def _is_new_topology(self, filename) -> bool:
with open(filename) as f:
return "5->3" in f.readline()

@classmethod
def _read_topo_new(cls, filename) -> Topology:
with open(filename) as f:
lines = f.readlines()
n_atoms, n_chains, direction = np.array(lines[0].split())
n_atoms = int(n_atoms)
atom_idx = np.arange(n_atoms)

res_name_list = []
chain_id_list = []
for i, line in enumerate(lines[1:]):
is_rna = "type=RNA" in line
is_dna = not is_rna
contains_custom_base = "(" in line and ")" in line

line_split = line.split()
bases = line_split[0]

chain_id_list.append(np.repeat(i, len(bases)))

base_list = []
start = 0
end = 0
in_custom_base = False
for i, letter in enumerate(bases):
if letter == "(":
start = i + 1
in_custom_base = True
continue
if letter == ")":
end = i
base_list.append(line[start:end])
in_custom_base = False
continue

is_new_topology = "5->3" in first_line
if in_custom_base:
continue

if not is_new_topology:
dimensions = np.array(first_line.split(), dtype=int)
n_atoms = dimensions[0]
array = np.loadtxt(self.filename, skiprows=1, max_rows=n_atoms, dtype=str)
base_list.append(letter)

# each topology item has two bond columns, which say what the base is bonded
# from and what it is bonded to. -1 means it is not bonded
# we need to turn that into an array of bond pairs
bond_idx = np.zeros((n_atoms * 2, 2), int)
row_numbers = np.arange(n_atoms, dtype=int)
for i in range(2):
rows = row_numbers + (i * n_atoms)
bond_idx[rows, 0] = array[:, (i + 2)]
bond_idx[rows, 1] = row_numbers
res_name_list.append(np.array(base_list))

# drop any that have -1 as they aren't bonded to anything
mask = np.logical_and(bond_idx[:, 0] != -1, bond_idx[:, 1] != -1)
bond_idx = bond_idx[mask, :]
res_names = np.hstack(res_name_list)
chain_ids = np.hstack(chain_id_list)

bond_idx = np.zeros((n_atoms, 2), dtype=int)
bond_idx[:, :] = -1

for i in atom_idx:
if i == 1:
continue
if chain_ids[i] == chain_ids[-1]:
bond_idx[i, :] = np.array((i, i - 1), dtype=int)

mask = np.logical_and(bond_idx[:, 0] != -1, bond_idx[:, 1] != -1)
bond_idx = bond_idx[mask, :]

attrs = []
for Attr in (Atomids, Resnums, Resids):
attrs.append(Attr(atom_idx))

attrs.append(ChainIDs(chain_ids))
attrs.append(Resnames(res_names))

topo = Topology(n_atoms, n_atoms, 1, attrs=attrs)
bonds = Bonds(bond_idx)
topo.add_TopologyAttr(bonds)

return topo

@classmethod
def _read_topo_old(cls, filename) -> Topology:
with open(filename) as f:
first_line = f.readline()

dimensions = np.array(first_line.split())
n_atoms = int(dimensions[0])
array = np.loadtxt(filename, skiprows=1, max_rows=n_atoms, dtype=str)

# each topology item has two bond columns, which say what the base is bonded
# from and what it is bonded to. -1 means it is not bonded
# we need to turn that into an array of bond pairs
bond_idx = np.zeros((n_atoms * 2, 2), int)
row_numbers = np.arange(n_atoms, dtype=int)
for i in range(2):
rows = row_numbers + (i * n_atoms)
bond_idx[rows, 0] = array[:, (i + 2)]
bond_idx[rows, 1] = row_numbers

# drop any that have -1 as they aren't bonded to anything
mask = np.logical_and(bond_idx[:, 0] != -1, bond_idx[:, 1] != -1)
bond_idx = bond_idx[mask, :]

attrs = []
idx = np.arange(1, n_atoms + 1, dtype=int)
Expand All @@ -55,3 +128,9 @@ def _parseatoms(self):
topo.add_TopologyAttr(bonds)

return topo

def _parseatoms(self):
if self._is_new_topology(self.filename):
return self._read_topo_new(self.filename)
else:
return self._read_topo_old(self.filename)
Loading

0 comments on commit 6ff0847

Please sign in to comment.