diff --git a/MDANSE/Extensions/.gitignore b/MDANSE/Extensions/.gitignore
deleted file mode 100644
index d5419cf253..0000000000
--- a/MDANSE/Extensions/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/*.c
-/*.cpp
-/*.html
-/xtc/xtc.c
-/xtc/trr.c
-/xtc/*.html
\ No newline at end of file
diff --git a/MDANSE/Extensions/atoms_in_shell.pyx b/MDANSE/Extensions/atoms_in_shell.pyx
deleted file mode 100644
index 126987314d..0000000000
--- a/MDANSE/Extensions/atoms_in_shell.pyx
+++ /dev/null
@@ -1,162 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import cython
-import numpy as np
-cimport numpy as np
-from numpy cimport ndarray
-
-cdef extern from "math.h":
-
- double floor(double x)
- double ceil(double x)
- double sqrt(double x)
-
-cdef inline double round(double r):
- return floor(r + 0.5) if (r > 0.0) else ceil(r - 0.5)
-
-def atoms_in_shell_real(ndarray[np.float64_t, ndim=2] config not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- ndarray[np.float64_t, ndim=2] rcell not None,
- int refIndex,
- float mini,
- float maxi):
-
- cdef double x, y, z, refx, refy, refz, refsx, refsy, refsz, sdx, sdy, sdz, rx, ry, rz, r2
-
- cdef int i
-
- cdef ndarray[np.float64_t, ndim=2] scaleconfig = np.empty((config.shape[0], 3), dtype=np.float64)
-
- cdef double mini2 = mini**2
- cdef double maxi2 = maxi**2
-
- refx = config[refIndex, 0]
- refy = config[refIndex, 1]
- refz = config[refIndex, 2]
-
- for 0 <= i < config.shape[0]:
-
- x = config[i, 0]
- y = config[i, 1]
- z = config[i, 2]
-
- scaleconfig[i, 0] = x*rcell[0, 0] + y*rcell[0, 1] + z*rcell[0, 2]
- scaleconfig[i, 1] = x*rcell[1, 0] + y*rcell[1, 1] + z*rcell[1, 2]
- scaleconfig[i, 2] = x*rcell[2, 0] + y*rcell[2, 1] + z*rcell[2, 2]
-
- refsx = scaleconfig[refIndex, 0]
- refsy = scaleconfig[refIndex, 1]
- refsz = scaleconfig[refIndex, 2]
-
- indexes = []
-
- for 0 <= i < config.shape[0]:
-
- if i == refIndex:
- continue
-
- sdx = scaleconfig[i, 0] - refsx
- sdy = scaleconfig[i, 1] - refsy
- sdz = scaleconfig[i, 2] - refsz
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- rx = sdx*cell[0, 0] + sdy*cell[0, 1] + sdz*cell[0, 2]
- ry = sdx*cell[1, 0] + sdy*cell[1, 1] + sdz*cell[1, 2]
- rz = sdx*cell[2, 0] + sdy*cell[2, 1] + sdz*cell[2, 2]
-
- r2 = rx*rx + ry*ry + rz*rz
-
- if r2 >= mini2 and r2 <= maxi2:
- indexes.append(i)
-
- return indexes
-
-def atoms_in_shell_nopbc(ndarray[np.float64_t, ndim=2] config not None,
- int refIndex,
- float mini,
- float maxi):
-
- cdef double x, y, z, refx, refy, refz, sdx, sdy, sdz, rx, ry, rz, r2
-
- cdef int i
-
- refx = config[refIndex,0]
- refy = config[refIndex,1]
- refz = config[refIndex,2]
-
- cdef double mini2 = mini**2
- cdef double maxi2 = maxi**2
-
- indexes = []
-
- for 0 <= i < config.shape[0]:
-
- if i == refIndex:
- continue
-
- rx = config[i,0] - refx
- ry = config[i,1] - refy
- rz = config[i,2] - refz
-
- r2 = rx*rx + ry*ry + rz*rz
-
- if r2 >= mini2 and r2 <= maxi2:
- indexes.append(i)
-
- return indexes
-
-def atoms_in_shell_box(ndarray[np.float64_t, ndim=2] config not None,
- int refIndex,
- float mini,
- float maxi):
-
- cdef double x, y, z, refx, refy, refz, sdx, sdy, sdz, r2
-
- cdef int i
-
- cdef double mini2 = mini**2
- cdef double maxi2 = maxi**2
-
- refx = config[refIndex,0]
- refy = config[refIndex,1]
- refz = config[refIndex,2]
-
- indexes = []
-
- for 0 <= i < config.shape[0]:
-
- if i == refIndex:
- continue
-
- sdx = config[i,0] - refx
- sdy = config[i,1] - refy
- sdz = config[i,2] - refz
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- r2 = sdx*sdx + sdy*sdy + sdz*sdz
-
- if r2 >= mini2 and r2 <= maxi2:
- indexes.append(i)
-
- return indexes
diff --git a/MDANSE/Extensions/com_trajectory.pyx b/MDANSE/Extensions/com_trajectory.pyx
deleted file mode 100644
index 54a8182d4a..0000000000
--- a/MDANSE/Extensions/com_trajectory.pyx
+++ /dev/null
@@ -1,206 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import sys
-
-import cython
-import numpy as np
-cimport numpy as np
-
-cdef extern from "math.h":
-
- double floor(double x)
- double ceil(double x)
- double sqrt(double x)
-
-cdef inline double round(double r):
- return floor(r + 0.5) if (r > 0.0) else ceil(r - 0.5)
-
-def _recursive_contiguity(
- np.ndarray[np.float64_t, ndim=2] box_coords,
- np.ndarray[np.int8_t, ndim=1] processed not None,
- bonds,
- ref):
-
- cdef int bat
-
- cdef double brefx, brefy, brefz, bx, by, bz, bdx, bdy, bdz
-
- brefx = box_coords[ref,0]
- brefy = box_coords[ref,1]
- brefz = box_coords[ref,2]
-
- bonded_atoms = bonds[ref]
-
- processed[ref] = 1
-
- for bat in bonded_atoms:
-
- if processed[bat] == 1:
- continue
-
- bx = box_coords[bat,0]
- by = box_coords[bat,1]
- bz = box_coords[bat,2]
-
- bdx = bx - brefx
- bdy = by - brefy
- bdz = bz - brefz
-
- bdx -= round(bdx)
- bdy -= round(bdy)
- bdz -= round(bdz)
-
- bx = brefx + bdx
- by = brefy + bdy
- bz = brefz + bdz
-
- box_coords[bat,0] = bx
- box_coords[bat,1] = by
- box_coords[bat,2] = bz
-
- _recursive_contiguity(box_coords,processed, bonds, bat)
-
-@cython.boundscheck(False)
-@cython.wraparound(False)
-@cython.cdivision(True)
-def com_trajectory(
- np.ndarray[np.float64_t, ndim=3] coords not None,
- np.ndarray[np.float64_t, ndim=3] cell not None,
- np.ndarray[np.float64_t, ndim=3] rcell not None,
- np.ndarray[np.float64_t, ndim=1] masses not None,
- chemical_entity_indexes,
- selected_indexes,
- bonds,
- box_coordinates = False):
-
- cdef double x, y, z, refx, refy, refz, \
- srefx, srefy, srefz, sx, sy, sz, sdx, sdy, sdz, \
- sumMasses, comx, comy, comz
-
- cdef int i, j, idx, idx0
-
- cdef np.ndarray[np.float64_t, ndim=2] trajectory = np.empty((coords.shape[0],3),dtype=np.float64)
-
- cdef np.ndarray[np.float64_t, ndim=2] com_coords
-
- cdef np.ndarray[np.int8_t] processed
-
- cdef np.ndarray[np.float64_t, ndim=3] box_coords = np.empty((coords.shape[0],coords.shape[1],3),dtype=np.float64)
-
-
- old_recursionlimit = sys.getrecursionlimit()
- sys.setrecursionlimit(100000)
-
- # Loop over the time
- for 0 <= i < coords.shape[0]:
-
- # Loop over the atoms
- for 0 <= j < coords.shape[1]:
-
- x = coords[i,j,0]
- y = coords[i,j,1]
- z = coords[i,j,2]
-
- # Convert the real coordinates to box coordinates
- box_coords[i,j,0] = x*rcell[i,0,0] + y*rcell[i,0,1] + z*rcell[i,0,2]
- box_coords[i,j,1] = x*rcell[i,1,0] + y*rcell[i,1,1] + z*rcell[i,1,2]
- box_coords[i,j,2] = x*rcell[i,2,0] + y*rcell[i,2,1] + z*rcell[i,2,2]
-
- # Loop over the time
- for 0 <= i < coords.shape[0]:
-
- com_coords = box_coords[i,:,:]
-
- processed = np.zeros((com_coords.shape[0],), dtype=np.int8)
-
- for idxs in chemical_entity_indexes:
-
- if len(idxs) > 1:
- ref_idx = idxs.pop(0)
- _recursive_contiguity(com_coords, processed, bonds, ref_idx)
-
- idx0 = selected_indexes[0]
-
- # The first atom is taken as reference
- srefx = com_coords[idx0,0]
- srefy = com_coords[idx0,1]
- srefz = com_coords[idx0,2]
-
- comx = masses[0]*srefx
- comy = masses[0]*srefy
- comz = masses[0]*srefz
-
- sumMasses = masses[0]
-
- # Loop over the other atoms (if any)
- for j in range(1,len(selected_indexes)):
-
- idx = selected_indexes[j]
-
- sx = com_coords[idx,0]
- sy = com_coords[idx,1]
- sz = com_coords[idx,2]
-
- # Update the center of mass
- comx += masses[j]*sx
- comy += masses[j]*sy
- comz += masses[j]*sz
-
- sumMasses += masses[j]
-
- if i == 0:
-
- trajectory[i,0] = comx/sumMasses
- trajectory[i,1] = comy/sumMasses
- trajectory[i,2] = comz/sumMasses
-
- # The step i-1 is taken as the reference
- else:
-
- comx /= sumMasses
- comy /= sumMasses
- comz /= sumMasses
-
- sdx = comx - trajectory[i-1,0]
- sdy = comy - trajectory[i-1,1]
- sdz = comz - trajectory[i-1,2]
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- trajectory[i,0] = trajectory[i-1,0] + sdx
- trajectory[i,1] = trajectory[i-1,1] + sdy
- trajectory[i,2] = trajectory[i-1,2] + sdz
-
- if not box_coordinates:
-
- for 0 <= i < trajectory.shape[0]:
-
- x = trajectory[i,0]
- y = trajectory[i,1]
- z = trajectory[i,2]
-
- trajectory[i,0] = x*cell[i,0,0] + y*cell[i,0,1] + z*cell[i,0,2]
- trajectory[i,1] = x*cell[i,1,0] + y*cell[i,1,1] + z*cell[i,1,2]
- trajectory[i,2] = x*cell[i,2,0] + y*cell[i,2,1] + z*cell[i,2,2]
-
- sys.setrecursionlimit(old_recursionlimit)
-
- return trajectory
-
diff --git a/MDANSE/Extensions/contiguous_coordinates.pyx b/MDANSE/Extensions/contiguous_coordinates.pyx
deleted file mode 100644
index 92bb9aa539..0000000000
--- a/MDANSE/Extensions/contiguous_coordinates.pyx
+++ /dev/null
@@ -1,298 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import sys
-
-import cython
-import numpy as np
-cimport numpy as np
-from numpy cimport ndarray
-
-
-cdef extern from "math.h":
-
- double floor(double x)
- double ceil(double x)
- double sqrt(double x)
-
-cdef inline double round(double r):
- return floor(r + 0.5) if (r > 0.0) else ceil(r - 0.5)
-
-def contiguous_coordinates_real(ndarray[np.float64_t, ndim=2] coords not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- ndarray[np.float64_t, ndim=2] rcell not None,
- indexes):
-
- cdef double x, y, z, sdx, sdy, sdz, newx, newy, newz
-
- cdef int i
-
-
- cdef ndarray[np.float64_t, ndim=2] contiguous_coords = np.empty((coords.shape[0],3),dtype=np.float64)
-
- cdef ndarray[np.float64_t, ndim=2] scaleconfig = np.empty((coords.shape[0],3),dtype=np.float64)
-
- for 0 <= i < coords.shape[0]:
-
- x = coords[i,0]
- y = coords[i,1]
- z = coords[i,2]
-
- scaleconfig[i,0] = x*rcell[0,0] + y*rcell[0,1] + z*rcell[0,2]
- scaleconfig[i,1] = x*rcell[1,0] + y*rcell[1,1] + z*rcell[1,2]
- scaleconfig[i,2] = x*rcell[2,0] + y*rcell[2,1] + z*rcell[2,2]
-
- for idxs in indexes:
-
- if not idxs:
- continue
-
- contiguous_coords[idxs[0],0] = coords[idxs[0],0]
- contiguous_coords[idxs[0],1] = coords[idxs[0],1]
- contiguous_coords[idxs[0],2] = coords[idxs[0],2]
-
- if len(idxs) == 1:
- continue
-
- for idx in idxs[1:]:
-
- sdx = scaleconfig[idx,0] - scaleconfig[idxs[0],0]
- sdy = scaleconfig[idx,1] - scaleconfig[idxs[0],1]
- sdz = scaleconfig[idx,2] - scaleconfig[idxs[0],2]
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- newx = scaleconfig[idxs[0],0] + sdx
- newy = scaleconfig[idxs[0],1] + sdy
- newz = scaleconfig[idxs[0],2] + sdz
-
- contiguous_coords[idx,0] = newx*cell[0,0] + newy*cell[0,1] + newz*cell[0,2]
- contiguous_coords[idx,1] = newx*cell[1,0] + newy*cell[1,1] + newz*cell[1,2]
- contiguous_coords[idx,2] = newx*cell[2,0] + newy*cell[2,1] + newz*cell[2,2]
-
- return contiguous_coords
-
-def contiguous_coordinates_box(ndarray[np.float64_t, ndim=2] coords not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- indexes):
-
- cdef double sdx, sdy, sdz, newx, newy, newz
-
- cdef ndarray[np.float64_t, ndim=2] contiguous_coords = np.empty((coords.shape[0], 3), dtype=np.float64)
-
- for idxs in indexes:
- contiguous_coords[idxs[0], 0] = coords[idxs[0], 0]
- contiguous_coords[idxs[0], 1] = coords[idxs[0], 1]
- contiguous_coords[idxs[0], 2] = coords[idxs[0], 2]
-
- if len(idxs) == 1:
- continue
-
- for idx in idxs[1:]:
-
- sdx = coords[idx, 0] - coords[idxs[0], 0]
- sdy = coords[idx, 1] - coords[idxs[0], 1]
- sdz = coords[idx, 2] - coords[idxs[0], 2]
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- newx = coords[idxs[0], 0] + sdx
- newy = coords[idxs[0], 1] + sdy
- newz = coords[idxs[0], 2] + sdz
-
- contiguous_coords[idx, 0] = newx*cell[0, 0] + newy*cell[0, 1] + newz*cell[0, 2]
- contiguous_coords[idx, 1] = newx*cell[1, 0] + newy*cell[1, 1] + newz*cell[1, 2]
- contiguous_coords[idx, 2] = newx*cell[2, 0] + newy*cell[2, 1] + newz*cell[2, 2]
-
- return contiguous_coords
-
-def contiguous_offsets_real(ndarray[np.float64_t, ndim=2] coords not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- ndarray[np.float64_t, ndim=2] rcell not None,
- indexes):
-
- cdef double x, y, z, sdx, sdy, sdz
-
- cdef int i
-
- cdef ndarray[np.float64_t, ndim=2] scaleconfig = np.empty((coords.shape[0],3),dtype=np.float64)
-
- cdef ndarray[np.float64_t, ndim=2] offsets = np.zeros((coords.shape[0],3),dtype=np.float64)
-
- for 0 <= i < coords.shape[0]:
-
- x = coords[i,0]
- y = coords[i,1]
- z = coords[i,2]
-
- scaleconfig[i,0] = x*rcell[0,0] + y*rcell[0,1] + z*rcell[0,2]
- scaleconfig[i,1] = x*rcell[1,0] + y*rcell[1,1] + z*rcell[1,2]
- scaleconfig[i,2] = x*rcell[2,0] + y*rcell[2,1] + z*rcell[2,2]
-
- for idxs in indexes:
- if len(idxs) == 1:
- continue
-
- for idx in idxs[1:]:
-
- sdx = scaleconfig[idx,0] - scaleconfig[idxs[0],0]
- sdy = scaleconfig[idx,1] - scaleconfig[idxs[0],1]
- sdz = scaleconfig[idx,2] - scaleconfig[idxs[0],2]
-
- offsets[idx,0] = -round(sdx)
- offsets[idx,1] = -round(sdy)
- offsets[idx,2] = -round(sdz)
-
- return offsets
-
-def contiguous_offsets_box(ndarray[np.float64_t, ndim=2] coords not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- indexes):
-
- cdef double sdx, sdy, sdz
-
- cdef ndarray[np.float64_t, ndim=2] offsets = np.zeros((coords.shape[0], 3), dtype=np.float64)
-
- for idxs in indexes:
- if len(idxs) == 1:
- continue
-
- for idx in idxs[1:]:
-
- sdx = coords[idx, 0] - coords[idxs[0], 0]
- sdy = coords[idx, 1] - coords[idxs[0], 1]
- sdz = coords[idx, 2] - coords[idxs[0], 2]
-
- offsets[idx, 0] = -round(sdx)
- offsets[idx, 1] = -round(sdy)
- offsets[idx, 2] = -round(sdz)
-
- return offsets
-
-def _recursive_contiguity(
- ndarray[np.float64_t, ndim=2] contiguous_coords,
- ndarray[np.float64_t, ndim=2] cell not None,
- ndarray[np.float64_t, ndim=2] rcell not None,
- ndarray[np.int8_t, ndim=1] processed not None,
- bonds,
- seed):
-
- cdef double refx, refy, refz, brefx, brefy, brefz,x, y, z, bx, by, bz, bdx, bdy, bdz
-
- # The seed atom is marked as processed
- processed[seed] = 1
-
- # Convert from real to box coordinates for the seed atom
- refx = contiguous_coords[seed,0]
- refy = contiguous_coords[seed,1]
- refz = contiguous_coords[seed,2]
-
- brefx = refx*rcell[0,0] + refy*rcell[0,1] + refz*rcell[0,2]
- brefy = refx*rcell[1,0] + refy*rcell[1,1] + refz*rcell[1,2]
- brefz = refx*rcell[2,0] + refy*rcell[2,1] + refz*rcell[2,2]
-
- bonded_atoms = bonds[seed]
-
- # Loop over the atoms bonded to the seed
- for bat in bonded_atoms:
-
- # If the bonded atom is marked as processed skip it
- if processed[bat] == 1:
- continue
-
- # Convert from real to box coordinates for the bonded atom
- x = contiguous_coords[bat,0]
- y = contiguous_coords[bat,1]
- z = contiguous_coords[bat,2]
-
- bx = x*rcell[0,0] + y*rcell[0,1] + z*rcell[0,2]
- by = x*rcell[1,0] + y*rcell[1,1] + z*rcell[1,2]
- bz = x*rcell[2,0] + y*rcell[2,1] + z*rcell[2,2]
-
- # Apply the PBC
- bdx = bx - brefx
- bdy = by - brefy
- bdz = bz - brefz
-
- bdx -= round(bdx)
- bdy -= round(bdy)
- bdz -= round(bdz)
-
- bx = brefx + bdx
- by = brefy + bdy
- bz = brefz + bdz
-
- # Convert back from box to real coordinates
- contiguous_coords[bat,0] = bx*cell[0,0] + by*cell[0,1] + bz*cell[0,2]
- contiguous_coords[bat,1] = bx*cell[1,0] + by*cell[1,1] + bz*cell[1,2]
- contiguous_coords[bat,2] = bx*cell[2,0] + by*cell[2,1] + bz*cell[2,2]
-
- _recursive_contiguity(contiguous_coords,cell,rcell,processed,bonds,bat)
-
-def continuous_coordinates(
- ndarray[np.float64_t, ndim=2] coords not None,
- ndarray[np.float64_t, ndim=2] cell not None,
- ndarray[np.float64_t, ndim=2] rcell not None,
- chemical_system,
- selected_indexes=None):
-
- cdef int ref_idx
-
- cdef ndarray[np.float64_t, ndim=2] continuous_coords = coords
-
- cdef np.ndarray[np.int8_t] processed = np.zeros((coords.shape[0],), dtype=np.int8)
-
- old_recursionlimit = sys.getrecursionlimit()
- sys.setrecursionlimit(100000)
-
- # Retrieve the top level chemical entities to which belong each of the selected atom
- atoms = chemical_system.atom_list
- if selected_indexes is None:
- selected_indexes = [at.index for at in atoms]
-
- chemical_entities = set([atoms[idx].top_level_chemical_entity for idx in selected_indexes])
-
- # Set the bond network for these chemical entities
- bonds = {}
- chemical_entities_indexes = []
- for ce in chemical_entities:
- for at in ce.atom_list:
- bonds[at.index] = [bat.index for bat in at.bonds]
- chemical_entities_indexes.append(at.index)
-
- chemical_entities_indexes.sort()
-
- for idx in chemical_entities_indexes:
-
- _recursive_contiguity(continuous_coords, cell, rcell, processed, bonds, idx)
-
- sys.setrecursionlimit(old_recursionlimit)
-
- return continuous_coords[selected_indexes,:]
-
-
-
-
-
-
-
-
-
diff --git a/MDANSE/Extensions/fast_calculation.pyx b/MDANSE/Extensions/fast_calculation.pyx
deleted file mode 100644
index 4933c57643..0000000000
--- a/MDANSE/Extensions/fast_calculation.pyx
+++ /dev/null
@@ -1,121 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import cython
-import numpy as np
-cimport numpy as np
-
-
-cdef extern from "math.h":
-
- double floor(double x)
- double ceil(double x)
- double sqrt(double x)
-
-
-cdef inline double round(double r):
- return floor(r + 0.5) if (r > 0.0) else ceil(r - 0.5)
-
-
-@cython.cdivision(True)
-@cython.boundscheck(False)
-@cython.wraparound(False)
-def cpt_cluster_connectivity_nopbc(
- np.ndarray[np.float64_t, ndim=2] coords,
- np.ndarray[np.float64_t, ndim=1] covRadii,
- np.float32_t tolerance):
-
- '''
- Compute the connectivity of an atom cluster.
- '''
- bonds = []
- cdef int i, j, nbat
- cdef float radius, distance
-
- nbat = len(covRadii)
-
- for i in range(nbat-1):
- radiusi = covRadii[i] + tolerance
- for j in range(i+1,nbat):
- radius = radiusi + covRadii[j]
- distance = (coords[i,0] - coords[j,0])**2 + (coords[i,1] - coords[j,1])**2 + (coords[i,2] - coords[j,2])**2
- if distance <= (radius*radius):
- bonds.append([i,j])
- return bonds
-
-
-@cython.cdivision(True)
-@cython.boundscheck(False)
-@cython.wraparound(False)
-def cpt_cluster_connectivity_pbc(
- np.ndarray[np.float64_t, ndim=2] coords,
- np.ndarray[np.float64_t, ndim=2] cell not None,
- np.ndarray[np.float64_t, ndim=2] rcell not None,
- np.ndarray[np.float64_t, ndim=1] covRadii,
- np.float32_t tolerance,
- bonds):
-
- '''
- Compute the connectivity of an atom cluster.
- '''
-
- cdef int i, j, nbat
-
- cdef float radius, distance, sdx, sdy, sdz, rx, ry, rz, r
-
- nbat = len(covRadii)
-
- cdef np.ndarray[np.float64_t, ndim=2] scaleconfig = np.empty((coords.shape[0],3),dtype=np.float64)
-
- for 0 <= i < coords.shape[0]:
-
- x = coords[i,0]
- y = coords[i,1]
- z = coords[i,2]
-
- scaleconfig[i,0] = x*rcell[0,0] + y*rcell[0,1] + z*rcell[0,2]
- scaleconfig[i,1] = x*rcell[1,0] + y*rcell[1,1] + z*rcell[1,2]
- scaleconfig[i,2] = x*rcell[2,0] + y*rcell[2,1] + z*rcell[2,2]
-
- for i in range(nbat-1):
-
- radiusi = covRadii[i] + tolerance
-
- for j in range(i+1,nbat):
- radius = radiusi + covRadii[j]
-
- sdx = scaleconfig[j,0] - scaleconfig[i,0]
- sdy = scaleconfig[j,1] - scaleconfig[i,1]
- sdz = scaleconfig[j,2] - scaleconfig[i,2]
-
- sdx -= round(sdx)
- sdy -= round(sdy)
- sdz -= round(sdz)
-
- rx = sdx*cell[0,0] + sdy*cell[0,1] + sdz*cell[0,2]
- ry = sdx*cell[1,0] + sdy*cell[1,1] + sdz*cell[1,2]
- rz = sdx*cell[2,0] + sdy*cell[2,1] + sdz*cell[2,2]
-
- r = rx*rx + ry*ry + rz*rz
-
- if r <= (radius*radius):
- bonds.append([i,j])
-
- return bonds
-
-
-
diff --git a/MDANSE/Extensions/mic_fast_calc.pyx b/MDANSE/Extensions/mic_fast_calc.pyx
deleted file mode 100644
index 3a1555074e..0000000000
--- a/MDANSE/Extensions/mic_fast_calc.pyx
+++ /dev/null
@@ -1,193 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-cimport numpy as np
-import numpy as np
-from numpy cimport ndarray
-
-from libcpp.vector cimport vector
-from libcpp.pair cimport pair
-from libcpp cimport bool
-
-ctypedef pair[ int, vector[int] ] equiv_t
-ctypedef vector[double] point
-
-cdef inline bool exclude_from_bounded_3Dbox(double x,
- double y,
- double z,
- double Xmin,
- double Xmax,
- double Ymin,
- double Ymax,
- double Zmin,
- double Zmax,
- double border):
- return not ((Xmin-border <=x) and (x <= Xmax+border) and (Ymin-border <= y) and (y <= Ymax+border) and (Zmin-border <= z) and (z <= Zmax+border))
-
-cdef inline bool exclude_from_bounded_2Dbox(double x,
- double y,
- double Xmin,
- double Xmax,
- double Ymin,
- double Ymax,
- double border):
- return not ((Xmin-border <=x) and (x <= Xmax+border) and (Ymin-border <= y) and (y <= Ymax+border))
-
-
-
-def mic_generator_2D(double[:,:] pts not None, double border, double[:] box_param):
-
- cdef int i, m, new_id, nb_init_points, nb_final_points
- cdef double x, y, Xmin, Xmax, Ymin, Ymax, j, k, n0, n1
- cdef vector[equiv_t] equivalence
- cdef vector[point] new_points
- cdef equiv_t e
- cdef point n
- cdef double lol[3]
- cdef ndarray[np.float64_t, ndim = 2] res
-
- nb_init_points = pts.shape[0]
-
- Xmax = box_param[0]
- Ymax = box_param[1]
- Xmin = 0
- Ymin = 0
-
- lol[0] = -1
- lol[1] = 0
- lol[2] = 1
-
- for i in range(nb_init_points):
- x = pts[i,0]
- y = pts[i,1]
- for j in lol[0:3]:
- for k in lol[0:3]:
- if j == 0 and k == 0:
- continue
- n0 = x+j*(Xmax-Xmin)
- n1 = y+k*(Ymax-Ymin)
-
- if exclude_from_bounded_2Dbox(n0, n1, Xmin, Xmax, Ymin, Ymax, border):
- continue
- n = point()
- n.push_back(n0)
- n.push_back(n1)
- new_points.push_back(n)
- new_id = new_points.size() + nb_init_points
- for m in range(equivalence.size()):
- if equivalence[m].first == i:
- equivalence[m].second.push_back(new_id)
- continue
- e = equiv_t()
- e.first=i
- e.second.push_back(new_id)
- equivalence.push_back(e)
- d = {}
- for i in range(equivalence.size()):
- d[equivalence[i].first] = equivalence[i].second
-
- nb_final_points = pts.shape[0] + new_points.size()
-
- res = np.zeros((nb_init_points + new_points.size() ,2), dtype = np.float64)
-
- for i in range(nb_init_points):
- res[i,0] = pts[i,0]
- res[i,1] = pts[i,1]
-
- for i in range(new_points.size()):
- j = i + nb_init_points
- res[j,0] = new_points[i][0]
- res[j,1] = new_points[i][1]
-
-
- return res, d
-
-
-
-def mic_generator_3D(double[:,:] pts not None, double border, double[:] box_param):
-
- cdef int i, j_int, m, new_id, nb_init_points
- cdef double x, y, z, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, j, k, l, n0, n1, n2
- cdef vector[equiv_t] equivalence
- cdef vector[point] new_points
- cdef equiv_t e
- cdef point n
- cdef double lol[3]
- cdef ndarray[np.float64_t, ndim = 2] res
-
- nb_init_points = pts.shape[0]
-
- Xmax = box_param[0]
- Ymax = box_param[1]
- Zmax = box_param[2]
- Xmin = 0
- Ymin = 0
- Zmin = 0
-
- lol[0] = -1
- lol[1] = 0
- lol[2] = 1
-
- for i in range(nb_init_points):
- x = pts[i,0]
- y = pts[i,1]
- z = pts[i,2]
- for j in lol[0:3]:
- for k in lol[0:3]:
- for l in lol[0:3]:
- if j == 0 and k == 0 and l == 0:
- continue
- n0 = x+j*(Xmax-Xmin)
- n1 = y+k*(Ymax-Ymin)
- n2 = z+l*(Zmax-Zmin)
-
- if exclude_from_bounded_3Dbox(n0, n1, n2, Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, border):
- continue
- n = point()
- n.push_back(n0)
- n.push_back(n1)
- n.push_back(n2)
- new_points.push_back(n)
- new_id = new_points.size() + nb_init_points
- for m in range(equivalence.size()):
- if equivalence[m].first == i:
- equivalence[m].second.push_back(new_id)
- continue
- e = equiv_t()
- e.first=i
- e.second.push_back(new_id)
- equivalence.push_back(e)
-
- d = {}
- for i in range(equivalence.size()):
- d[equivalence[i].first] = equivalence[i].second
-
- res = np.zeros((nb_init_points + new_points.size() ,3), dtype = np.float64)
-
- for i in range(nb_init_points):
- res[i,0] = pts[i,0]
- res[i,1] = pts[i,1]
- res[i,2] = pts[i,2]
-
- for i in range(new_points.size()):
- j = i + nb_init_points
- j_int = int(j)
- res[j_int,0] = new_points[i][0]
- res[j_int,1] = new_points[i][1]
- res[j_int,2] = new_points[i][2]
-
- return res, d
diff --git a/MDANSE/Extensions/sas_fast_calc.pyx b/MDANSE/Extensions/sas_fast_calc.pyx
deleted file mode 100644
index 88cfdebfc5..0000000000
--- a/MDANSE/Extensions/sas_fast_calc.pyx
+++ /dev/null
@@ -1,157 +0,0 @@
-
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import cython
-import numpy as np
-cimport numpy as np
-from numpy cimport ndarray
-from libc.string cimport memset
-
-cdef extern from "math.h":
- double floor(double x)
- double ceil(double x)
- double sqrt(double x)
-
-cdef packed struct neighbour_t:
- np.int32_t index
- np.float64_t dist
-
-@cython.boundscheck(False)
-@cython.wraparound(False)
-def sas(ndarray[np.float64_t, ndim = 2] config not None,
- indexes not None,
- ndarray[np.float64_t, ndim = 2] vdwRadii_list not None,
- ndarray[np.float64_t, ndim = 2] sphere_points not None,
- double probe_radius_value):
-
- # Computes the Solvent Accessible Surface Based on the algorithm published by Shrake, A., and J. A. Rupley. JMB (1973) 79:351-371.
-
- cdef int total, i, j, k, n, isAccessible, nAccessiblePoints
- cdef double sas, dist, v, radi, r, radius, two_times_prob_radius
- cdef double Xposi, Yposi, Zposi, Xposj, Yposj, Zposj, Xposk, Yposk, Zposk, Xs, Ys, Zs, Xguess, Yguess, Zguess, dx, dy, dz
-
- # The solvent accessible surface for the running frame (given by index var).
- total = (
- THIS IS USABLE, BUT STILL AT AN EARLY STAGE AND NOT OPTIMISED
-
- Finds potential molecules in the trajectory, based on
- interatomic distances.
-
- The tolerance is a fraction of expected bond length calculated from covalent radii.
- This means that a pair of C and H atoms will be considered as connected by a bond
- if they are at a distance smaller than (r_C + r_H) * (1 + tolerance).
- """
-
- label = "Molecule Finder"
-
- category = (
- "Analysis",
- "Trajectory",
- )
-
- ancestor = ["hdf_trajectory", "molecular_viewer"]
-
- settings = collections.OrderedDict()
- settings["trajectory"] = ("HDFTrajectoryConfigurator", {})
- settings["tolerance"] = (
- "FloatConfigurator",
- {"default": 0.25},
- )
- settings["frames"] = (
- "FramesConfigurator",
- {"dependencies": {"trajectory": "trajectory"}, "default": (0, -1, 1)},
- )
- settings["output_files"] = (
- "OutputTrajectoryConfigurator",
- {"format": "MDTFormat"},
- )
-
- def initialize(self):
- """
- Initialize the input parameters and analysis self variables
- """
- super().initialize()
-
- self.numberOfSteps = self.configuration["frames"]["number"]
- self._input_trajectory = self.configuration["trajectory"]["instance"]
- self._tolerance = self.configuration["tolerance"]["value"]
- chemical_system = self._input_trajectory.chemical_system
-
- conn = Connectivity(trajectory=self._input_trajectory)
- conn.find_molecules(tolerance=self._tolerance)
- conn.add_bond_information()
- chemical_system.rebuild(conn._molecules)
- configuration = chemical_system.configuration
- coords = configuration.contiguous_configuration().coordinates
- for entity in chemical_system.chemical_entities:
- if entity.number_of_atoms > 1:
- moltester = MoleculeTester(entity, coords)
- try:
- inchistring = moltester.identify_molecule()
- except:
- inchistring = ""
- if len(inchistring) > 0:
- entity.name = inchistring
- else:
- entity.name = brute_formula(entity)
-
- # The output trajectory is opened for writing.
- self._output_trajectory = TrajectoryWriter(
- self.configuration["output_files"]["file"],
- chemical_system,
- self.numberOfSteps,
- positions_dtype=self.configuration["output_files"]["dtype"],
- chunking_limit=self.configuration["output_files"]["chunk_size"],
- compression=self.configuration["output_files"]["compression"],
- initial_charges=self.configuration["trajectory"]["instance"].charges(0),
- )
-
- def run_step(self, index):
- """
- Runs a single step of the job.\n
-
- :Parameters:
- #. index (int): The index of the step.
- :Returns:
- #. index (int): The index of the step.
- #. None
- """
-
- # get the Frame index
- frameIndex = self.configuration["frames"]["value"][index]
-
- n_coms = self._output_trajectory.chemical_system.number_of_atoms
-
- conf = self.configuration["trajectory"]["instance"].configuration(frameIndex)
- conf = conf.contiguous_configuration()
-
- coords = conf.coordinates
-
- variables = {}
- if self.configuration["trajectory"]["instance"].has_variable("velocities"):
- variables = {
- "velocities": self.configuration["trajectory"]["instance"]
- .variable("velocities")[frameIndex, :, :]
- .astype(np.float64)
- }
-
- if conf.is_periodic:
- com_conf = PeriodicRealConfiguration(
- self._output_trajectory.chemical_system,
- coords,
- conf.unit_cell,
- **variables,
- )
- else:
- com_conf = RealConfiguration(
- self._output_trajectory.chemical_system, coords, **variables
- )
-
- self._output_trajectory.chemical_system.configuration = com_conf
-
- # The times corresponding to the running index.
- time = self.configuration["frames"]["time"][index]
-
- charge = self.configuration["trajectory"]["instance"].charges(index)
-
- self._output_trajectory.dump_configuration(time)
-
- self._output_trajectory.write_charges(charge, index)
-
- return index, None
-
- def combine(self, index, x):
- """
- Combines returned results of run_step.\n
- :Parameters:
- #. index (int): The index of the step.\n
- #. x (any): The returned result(s) of run_step
- """
- pass
-
- def finalize(self):
- """
- Finalizes the calculations (e.g. averaging the total term, output files creations ...).
- """
-
- # The input trajectory is closed.
- self.configuration["trajectory"]["instance"].close()
-
- # The output trajectory is closed.
- self._output_trajectory.close()
- super().finalize()
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py
index 6b65f337c5..cb827cde9e 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/NeutronDynamicTotalStructureFactor.py
@@ -18,7 +18,6 @@
import numpy as np
-from MDANSE.Chemistry import ATOMS_DATABASE
from MDANSE.Core.Error import Error
from MDANSE.Framework.Jobs.IJob import IJob
@@ -390,8 +389,12 @@ def finalize(self):
# Compute coherent functions and structure factor
for pair in self._elementsPairs:
- bi = ATOMS_DATABASE.get_atom_property(pair[0], "b_coherent")
- bj = ATOMS_DATABASE.get_atom_property(pair[1], "b_coherent")
+ bi = self.configuration["trajectory"]["instance"].get_atom_property(
+ pair[0], "b_coherent"
+ )
+ bj = self.configuration["trajectory"]["instance"].get_atom_property(
+ pair[1], "b_coherent"
+ )
ni = nAtomsPerElement[pair[0]]
nj = nAtomsPerElement[pair[1]]
ci = ni / nTotalAtoms
@@ -426,7 +429,9 @@ def finalize(self):
# Compute incoherent functions and structure factor
for element, ni in nAtomsPerElement.items():
- bi = ATOMS_DATABASE.get_atom_property(element, "b_incoherent2")
+ bi = self.configuration["trajectory"]["instance"].get_atom_property(
+ element, "b_incoherent2"
+ )
ni = nAtomsPerElement[element]
ci = ni / nTotalAtoms
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py
index cb9669905f..5a78dfeba7 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/PairDistributionFunction.py
@@ -129,7 +129,7 @@ def finalize(self):
self.hIntra[idi, idj] += self.hIntra[idj, idi]
self.hInter[idi, idj] += self.hInter[idj, idi]
- fact = nij * nFrames * shellVolumes
+ fact = 2 * nij * nFrames * shellVolumes
pdf_intra = self.hIntra[idi, idj, :] / fact
pdf_inter = self.hInter[idi, idj, :] / fact
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py
index 5b40c2addb..1143f0f3ff 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionAutoCorrelationFunction.py
@@ -21,7 +21,6 @@
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.Mathematics.Arithmetic import weight
from MDANSE.Mathematics.Signal import normalize
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
class PositionAutoCorrelationFunction(IJob):
@@ -74,7 +73,12 @@ class PositionAutoCorrelationFunction(IJob):
)
settings["weights"] = (
"WeightsConfigurator",
- {"dependencies": {"atom_selection": "atom_selection"}},
+ {
+ "dependencies": {
+ "trajectory": "trajectory",
+ "atom_selection": "atom_selection",
+ }
+ },
)
settings["output_files"] = (
"OutputFilesConfigurator",
@@ -110,9 +114,9 @@ def initialize(self):
partial_result=True,
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -126,11 +130,10 @@ def run_step(self, index):
"""
# get atom index
- indexes = self.configuration["atom_selection"]["indexes"][index]
- atoms = [self._atoms[idx] for idx in indexes]
+ indices = self.configuration["atom_selection"]["indices"][index]
series = self.configuration["trajectory"]["instance"].read_com_trajectory(
- atoms,
+ indices,
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py
index 9ebc6d34cd..28989ade79 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/PositionPowerSpectrum.py
@@ -20,8 +20,7 @@
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.Mathematics.Arithmetic import weight
-from MDANSE.Mathematics.Signal import differentiate, get_spectrum
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
+from MDANSE.Mathematics.Signal import get_spectrum
from MDANSE.MLogging import LOG
@@ -71,7 +70,10 @@ class PositionPowerSpectrum(IJob):
"WeightsConfigurator",
{
"default": "atomic_weight",
- "dependencies": {"atom_selection": "atom_selection"},
+ "dependencies": {
+ "trajectory": "trajectory",
+ "atom_selection": "atom_selection",
+ },
},
)
settings["output_files"] = (
@@ -151,9 +153,9 @@ def initialize(self):
main_result=True,
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -170,11 +172,10 @@ def run_step(self, index):
trajectory = self.configuration["trajectory"]["instance"]
# get atom index
- indexes = self.configuration["atom_selection"]["indexes"][index]
- atoms = [self._atoms[idx] for idx in indexes]
+ indices = self.configuration["atom_selection"]["indices"][index]
series = trajectory.read_com_trajectory(
- atoms,
+ indices,
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/RadiusOfGyration.py b/MDANSE/Src/MDANSE/Framework/Jobs/RadiusOfGyration.py
index 00931c72f5..82a0333bab 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/RadiusOfGyration.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/RadiusOfGyration.py
@@ -81,9 +81,9 @@ def initialize(self):
main_result=True,
)
- self._indexes = [
+ self._indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
@@ -113,7 +113,7 @@ def run_step(self, index):
conf = self.configuration["trajectory"]["instance"].configuration(frameIndex)
rog = radius_of_gyration(
- conf["coordinates"][self._indexes, :], masses=self._masses, root=True
+ conf["coordinates"][self._indices, :], masses=self._masses, root=True
)
return index, rog
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/RigidBodyTrajectory.py b/MDANSE/Src/MDANSE/Framework/Jobs/RigidBodyTrajectory.py
index 015c87a916..1aa6682aed 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/RigidBodyTrajectory.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/RigidBodyTrajectory.py
@@ -20,16 +20,14 @@
import h5py
-from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import AtomCluster
+from MDANSE.Mathematics.Geometry import center_of_mass
from MDANSE.Framework.Jobs.IJob import IJob, JobError
from MDANSE.Mathematics.LinearAlgebra import Quaternion, Vector
from MDANSE.Mathematics.Transformation import Translation
-from MDANSE.MolecularDynamics.Configuration import _Configuration, RealConfiguration
+from MDANSE.MolecularDynamics.Configuration import RealConfiguration
from MDANSE.MolecularDynamics.Trajectory import (
RigidBodyTrajectoryGenerator,
TrajectoryWriter,
- sorted_atoms,
)
@@ -120,16 +118,14 @@ def initialize(self):
dtype=np.float64,
)
- atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ atoms = self.configuration["trajectory"]["instance"].chemical_system.atom_list
self._groups = []
for i in range(self.configuration["atom_selection"]["selection_length"]):
- indexes = self.configuration["atom_selection"]["indexes"][i]
+ indices = self.configuration["atom_selection"]["indices"][i]
self._groups.append(
- AtomCluster("", [atoms[idx] for idx in indexes], parentless=True)
+ AtomCluster("", [atoms[idx] for idx in indices], parentless=True)
)
self.numberOfSteps = len(self._groups)
@@ -142,8 +138,8 @@ def initialize(self):
unitCell = trajectory.unit_cell(self.referenceFrame)
selectedAtoms = []
- for indexes in self.configuration["atom_selection"]["indexes"]:
- for idx in indexes:
+ for indices in self.configuration["atom_selection"]["indices"]:
+ for idx in indices:
selectedAtoms.append(atoms[idx])
# Create trajectory
@@ -194,7 +190,7 @@ def finalize(self):
""" """
group_coms = [
- group.center_of_mass(self._reference_configuration)
+ center_of_mass(self._reference_configuration[group])
for group in self._groups
]
@@ -235,9 +231,10 @@ def finalize(self):
Vector(*xyz)
)
- self._output_trajectory._chemical_system.configuration = real_configuration
self._output_trajectory.dump_configuration(
- time, units={"time": "ps", "unit_cell": "nm", "coordinates": "nm"}
+ real_configuration,
+ time,
+ units={"time": "ps", "unit_cell": "nm", "coordinates": "nm"},
)
outputFile = h5py.File(self.configuration["output_files"]["file"], "r+")
@@ -261,7 +258,7 @@ def finalize(self):
# Loop over the groups.
for comp in range(self.configuration["atom_selection"]["selection_length"]):
- aIndexes = self.configuration["atom_selection"]["indexes"][comp]
+ aIndexes = self.configuration["atom_selection"]["indices"][comp]
outputFile.attrs["info"] += "Group %s: %s\n" % (
comp,
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareDeviation.py b/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareDeviation.py
index 3c59460640..1ceeb2001f 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareDeviation.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareDeviation.py
@@ -19,7 +19,6 @@
import numpy as np
from MDANSE.Framework.Jobs.IJob import IJob
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
class RootMeanSquareDeviation(IJob):
@@ -111,9 +110,9 @@ def initialize(self):
main_result=True,
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -123,11 +122,10 @@ def run_step(self, index):
@type index: int.
"""
- indexes = self.configuration["atom_selection"]["indexes"][index]
- atoms = [self._atoms[idx] for idx in indexes]
+ indices = self.configuration["atom_selection"]["indices"][index]
series = self.configuration["trajectory"]["instance"].read_com_trajectory(
- atoms,
+ indices,
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareFluctuation.py b/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareFluctuation.py
index f161da2b67..5b8f3f190f 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareFluctuation.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/RootMeanSquareFluctuation.py
@@ -18,7 +18,6 @@
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.MolecularDynamics.Analysis import mean_square_fluctuation
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
class RootMeanSquareFluctuation(IJob):
@@ -71,17 +70,17 @@ def initialize(self):
self.numberOfSteps = self.configuration["atom_selection"]["selection_length"]
- # Will store the indexes.
- indexes = [
+ # Will store the indices.
+ indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
if self.configuration["grouping_level"]["value"] == "atom":
- self._outputData.add("indexes", "LineOutputVariable", indexes)
+ self._outputData.add("indices", "LineOutputVariable", indices)
else:
self._outputData.add(
- "indexes",
+ "indices",
"LineOutputVariable",
self.configuration["grouping_level"]["group_indices"],
)
@@ -91,14 +90,14 @@ def initialize(self):
"rmsf",
"LineOutputVariable",
(self.configuration["atom_selection"]["selection_length"],),
- axis="indexes",
+ axis="indices",
units="nm",
main_result=True,
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -111,11 +110,10 @@ def run_step(self, index):
#. rmsf (np.array): the calculated root mean square fluctuation for atom index
"""
# read the particle trajectory
- indexes = self.configuration["atom_selection"]["indexes"][index]
- atoms = [self._atoms[idx] for idx in indexes]
+ indices = self.configuration["atom_selection"]["indices"][index]
series = self.configuration["trajectory"]["instance"].read_com_trajectory(
- atoms,
+ indices,
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/SolventAccessibleSurface.py b/MDANSE/Src/MDANSE/Framework/Jobs/SolventAccessibleSurface.py
index 5ed7947b91..79e1b22859 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/SolventAccessibleSurface.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/SolventAccessibleSurface.py
@@ -15,13 +15,70 @@
#
import collections
+from typing import List
import numpy as np
+from scipy.spatial import KDTree
-from MDANSE.Chemistry import ATOMS_DATABASE
from MDANSE.Framework.Jobs.IJob import IJob
+from MDANSE.MolecularDynamics.Configuration import padded_coordinates
from MDANSE.Mathematics.Geometry import generate_sphere_points
-from MDANSE.Extensions import sas_fast_calc
+
+
+def solvent_accessible_surface(
+ coords: np.ndarray,
+ indexes: List[int],
+ vdwRadii: np.ndarray,
+ sphere_points: np.ndarray,
+ probe_radius_value: float,
+):
+
+ # Computes the Solvent Accessible Surface Based on the algorithm published by Shrake, A., and J. A. Rupley. JMB (1973) 79:351-371.
+
+ sas = 0.0
+ tree = KDTree(coords)
+ max_dist = np.max(vdwRadii) + probe_radius_value
+ min_dist = np.min(vdwRadii) + probe_radius_value
+ sphere_indices = set(range(len(sphere_points)))
+ for idx in indexes:
+ sphere_tree = KDTree(
+ coords[idx] + sphere_points * (vdwRadii[idx] + probe_radius_value)
+ )
+ distance_dict = sphere_tree.sparse_distance_matrix(tree, max_distance=max_dist)
+ pair_array = np.array([pair for pair in distance_dict.keys()])
+ value_array = np.array([value for value in distance_dict.values()])
+ combined_array = np.hstack(
+ [pair_array, value_array.reshape((len(value_array), 1))]
+ )[np.where(pair_array[:, 1] != idx)]
+ blocked_for_sure = set(
+ combined_array[:, 0][np.where(combined_array[:, 2] <= min_dist)]
+ )
+ free_for_sure = sphere_indices - set(combined_array[:, 0])
+ uncertain = sphere_indices - free_for_sure - blocked_for_sure
+ confirmed = set()
+ if len(uncertain) > 0:
+ uncertain_lines = np.array(
+ [line for line in combined_array if line[0] in uncertain]
+ )
+ neighbour_radii = np.array(
+ [vdwRadii[int(line[1])] for line in uncertain_lines]
+ )
+ confirmed = set(
+ uncertain_lines[:, 0][
+ np.where(
+ uncertain_lines[:, 2] < neighbour_radii + probe_radius_value
+ )
+ ]
+ )
+ free_for_sure.update(uncertain - confirmed)
+ sas += (
+ len(free_for_sure)
+ / len(sphere_points)
+ * 4
+ * np.pi
+ * (vdwRadii[idx] + probe_radius_value) ** 2
+ )
+ return sas
class SolventAccessibleSurface(IJob):
@@ -100,30 +157,17 @@ def initialize(self):
generate_sphere_points(self.configuration["n_sphere_points"]["value"]),
dtype=np.float64,
)
- # The solid angle increment used to convert the sas from a number of accessible point to a surface.
- self.solidAngleIncr = 4.0 * np.pi / len(self.spherePoints)
-
- # A mapping between the atom indexes and covalent_radius radius for the whole universe.
- self.vdwRadii = dict(
- [
- (
- at.index,
- ATOMS_DATABASE.get_atom_property(at.symbol, "covalent_radius"),
- )
- for at in self.configuration["trajectory"][
- "instance"
- ].chemical_system.atom_list
- ]
- )
- self.vdwRadii_list = np.zeros(
- (max(self.vdwRadii.keys()) + 1, 2), dtype=np.float64
- )
- for k, v in self.vdwRadii.items():
- self.vdwRadii_list[k] = np.array([k, v])[:]
- self._indexes = [
+ # A mapping between the atom indices and covalent_radius radius for the whole universe.
+ self.vdwRadii = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_property(
+ "vdw_radius"
+ ) # should it be covalent?
+
+ self._indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
@@ -143,12 +187,27 @@ def run_step(self, index):
# The configuration is made continuous.
conf = conf.continuous_configuration()
-
- # Loop over the indexes of the selected atoms for the sas calculation.
- sas = sas_fast_calc.sas(
- conf["coordinates"],
- self._indexes,
- self.vdwRadii_list,
+ unit_cell = conf._unit_cell
+
+ if conf.is_periodic:
+ padding_thickness = 1.05 * max(
+ self.configuration["probe_radius"]["value"], np.max(self.vdwRadii)
+ )
+ coords, atom_indices = padded_coordinates(
+ conf["coordinates"],
+ unit_cell,
+ padding_thickness,
+ )
+ temp_vdw_radii = [self.vdwRadii[atom_index] for atom_index in atom_indices]
+ else:
+ coords = conf["coordinates"]
+ temp_vdw_radii = self.vdwRadii
+
+ # Loop over the indices of the selected atoms for the sas calculation.
+ sas = solvent_accessible_surface(
+ coords,
+ self._indices,
+ temp_vdw_radii,
self.spherePoints,
self.configuration["probe_radius"]["value"],
)
@@ -172,9 +231,6 @@ def finalize(self):
Finalize the job.
"""
- # The SAS is converted from a number of accessible points to a surface.
- self._outputData["sas"] *= self.solidAngleIncr
-
# Write the output variables.
self._outputData.write(
self.configuration["output_files"]["root"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py
index 5e20929d7a..2c9445f0a1 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/StaticStructureFactor.py
@@ -77,6 +77,7 @@ class StaticStructureFactor(DistanceHistogram):
{
"default": "b_coherent",
"dependencies": {
+ "trajectory": "trajectory",
"atom_selection": "atom_selection",
"atom_transmutation": "atom_transmutation",
},
@@ -176,7 +177,7 @@ def finalize(self):
self.hIntra[idi, idj] += self.hIntra[idj, idi]
self.hInter[idi, idj] += self.hInter[idj, idi]
- fact = nij * nFrames * shellVolumes
+ fact = 2 * nij * nFrames * shellVolumes
pdfIntra = self.hIntra[idi, idj, :] / fact
pdfInter = self.hInter[idi, idj, :] / fact
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/Temperature.py b/MDANSE/Src/MDANSE/Framework/Jobs/Temperature.py
index 740c0a5581..31f5e3822e 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/Temperature.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/Temperature.py
@@ -18,11 +18,9 @@
import numpy as np
-from MDANSE.Chemistry import ATOMS_DATABASE
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.Framework.Units import measure
from MDANSE.Mathematics.Signal import differentiate
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
KB = measure(1.380649e-23, "kg m2/s2 K").toval("uma nm2/ps2 K")
@@ -114,9 +112,9 @@ def initialize(self):
units="K",
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -129,11 +127,11 @@ def run_step(self, index):
#. kineticEnergy (np.array): The calculated kinetic energy
"""
- atom = self._atoms[index]
+ symbol = self._atoms[index]
- symbol = atom.symbol
-
- mass = ATOMS_DATABASE.get_atom_property(symbol, "atomic_weight")
+ mass = self.configuration["trajectory"]["instance"].get_atom_property(
+ symbol, "atomic_weight"
+ )
trajectory = self.configuration["trajectory"]["instance"]
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/TrajectoryEditor.py b/MDANSE/Src/MDANSE/Framework/Jobs/TrajectoryEditor.py
index 7173202a66..407af90dbf 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/TrajectoryEditor.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/TrajectoryEditor.py
@@ -19,17 +19,14 @@
import numpy as np
from MDANSE.Framework.Jobs.IJob import IJob
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.UnitCell import UnitCell
from MDANSE.MolecularDynamics.Trajectory import TrajectoryWriter
-from MDANSE.MolecularDynamics.Trajectory import sorted_atoms
from MDANSE.MolecularDynamics.Configuration import (
PeriodicRealConfiguration,
RealConfiguration,
)
-from MDANSE.MolecularDynamics.TrajectoryUtils import brute_formula
from MDANSE.MolecularDynamics.Connectivity import Connectivity
-from MDANSE.Chemistry.Structrures import MoleculeTester
class TrajectoryEditor(IJob):
@@ -98,6 +95,9 @@ def initialize(self):
self.numberOfSteps = self.configuration["frames"]["number"]
self._input_trajectory = self.configuration["trajectory"]["instance"]
+ self._input_chemical_system = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system
if self.configuration["unit_cell"]["apply"]:
self._new_unit_cell = UnitCell(self.configuration["unit_cell"]["value"])
@@ -105,37 +105,36 @@ def initialize(self):
self._new_unit_cell for _ in range(len(self._input_trajectory))
]
- atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
-
# The collection of atoms corresponding to the atoms selected for output.
- indexes = [
+ indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
- self._indices = indexes
- self._selectedAtoms = [atoms[ind] for ind in indexes]
- elements = self.configuration["atom_selection"]["elements"]
+ self._indices = indices
+ temp_copy = list(self._input_chemical_system.atom_list)
+ indices_per_element = self.configuration["atom_selection"].get_indices()
+ for element, numbers in indices_per_element.items():
+ for num in numbers:
+ temp_copy[num] = element
+ self._selectedAtoms = [temp_copy[ind] for ind in indices]
+ name_list = [self._input_chemical_system.name_list[ind] for ind in indices]
new_chemical_system = ChemicalSystem("Edited system")
- new_chemical_system.from_element_list([entry[0] for entry in elements])
+ new_chemical_system.initialise_atoms(self._selectedAtoms, name_list)
if self.configuration["molecule_tolerance"]["use_it"]:
tolerance = self.configuration["molecule_tolerance"]["value"]
- conn = Connectivity(trajectory=self._input_trajectory, selection=indexes)
- conn.find_molecules(tolerance=tolerance)
- conn.add_bond_information()
- new_chemical_system.rebuild(conn._molecules)
+ conn = Connectivity(trajectory=self._input_trajectory, selection=indices)
+ conn.find_bonds(tolerance=tolerance)
+ conn.add_bond_information(new_chemical_system)
conf = self.configuration["trajectory"]["instance"].configuration(
self.configuration["frames"]["value"][0]
)
- conf = conf.contiguous_configuration()
- coords = conf.coordinates[indexes]
+ coords = conf.coordinates[indices]
if conf.is_periodic:
com_conf = PeriodicRealConfiguration(
new_chemical_system,
- coords[self._indices],
+ coords,
conf.unit_cell,
)
else:
@@ -143,19 +142,13 @@ def initialize(self):
new_chemical_system,
coords,
)
- new_chemical_system.configuration = com_conf
coords = com_conf.contiguous_configuration().coordinates
- for entity in new_chemical_system.chemical_entities:
- if entity.number_of_atoms > 1:
- moltester = MoleculeTester(entity, coords)
- try:
- inchistring = moltester.identify_molecule()
- except:
- inchistring = ""
- if len(inchistring) > 0:
- entity.name = inchistring
- else:
- entity.name = brute_formula(entity)
+ else:
+ new_chemical_system.add_bonds(self._input_chemical_system._bonds)
+ for key in self._input_chemical_system._clusters.keys():
+ new_chemical_system.add_clusters(
+ self._input_chemical_system._clusters[key]
+ )
# The output trajectory is opened for writing.
self._output_trajectory = TrajectoryWriter(
@@ -182,7 +175,7 @@ def run_step(self, index):
frameIndex = self.configuration["frames"]["value"][index]
conf = self.configuration["trajectory"]["instance"].configuration(frameIndex)
- conf = conf.contiguous_configuration()
+ conf = conf.contiguous_configuration(bring_to_centre=True)
charges = self.configuration["trajectory"]["instance"].charges(frameIndex)
coords = conf.coordinates
@@ -214,8 +207,6 @@ def run_step(self, index):
**variables,
)
- self._output_trajectory.chemical_system.configuration = com_conf
-
new_charges = np.zeros(len(self._indices))
for number, at_index in enumerate(self._indices):
try:
@@ -227,7 +218,7 @@ def run_step(self, index):
# The times corresponding to the running index.
time = self.configuration["frames"]["time"][index]
- self._output_trajectory.dump_configuration(time)
+ self._output_trajectory.dump_configuration(com_conf, time)
self._output_trajectory.write_charges(new_charges, index)
return index, None
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/UnfoldedTrajectory.py b/MDANSE/Src/MDANSE/Framework/Jobs/UnfoldedTrajectory.py
index 673783b6f5..845188cd9e 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/UnfoldedTrajectory.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/UnfoldedTrajectory.py
@@ -18,7 +18,6 @@
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.MolecularDynamics.Trajectory import TrajectoryWriter
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
class UnfoldedTrajectory(IJob):
@@ -62,31 +61,29 @@ def initialize(self):
self.numberOfSteps = self.configuration["frames"]["number"]
- atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ atoms = self.configuration["trajectory"]["instance"].chemical_system.atom_list
# The collection of atoms corresponding to the atoms selected for output.
- indexes = [
+ indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
- self._selectedAtoms = [atoms[ind] for ind in indexes]
- self._selection_indices = indexes
+ self._selectedAtoms = [atoms[ind] for ind in indices]
+ self._selection_indices = indices
# The output trajectory is opened for writing.
self._outputTraj = TrajectoryWriter(
self.configuration["output_files"]["file"],
self.configuration["trajectory"]["instance"].chemical_system,
self.numberOfSteps,
- self._selectedAtoms,
+ self._selection_indices,
positions_dtype=self.configuration["output_files"]["dtype"],
chunking_limit=self.configuration["output_files"]["chunk_size"],
compression=self.configuration["output_files"]["compression"],
initial_charges=[
self.configuration["trajectory"]["instance"].charges(0)[ind]
- for ind in indexes
+ for ind in indices
],
)
@@ -110,8 +107,6 @@ def run_step(self, index):
cloned_conf = conf.clone(self._outputTraj.chemical_system)
- self._outputTraj.chemical_system.configuration = cloned_conf
-
# The time corresponding to the running index.
time = self.configuration["frames"]["time"][index]
@@ -119,7 +114,7 @@ def run_step(self, index):
self._selection_indices
]
# Write the step.
- self._outputTraj.dump_configuration(time)
+ self._outputTraj.dump_configuration(cloned_conf, time)
self._outputTraj.write_charges(charge, index)
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py
index 4cdad36be0..7dfd561780 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionDistinct.py
@@ -15,15 +15,179 @@
#
import collections
import itertools as it
+from typing import List, Dict, Tuple
import numpy as np
-from MDANSE.Extensions import van_hove
+from MDANSE.MLogging import LOG
from MDANSE.Framework.Jobs.IJob import IJob, JobError
from MDANSE.MolecularDynamics.TrajectoryUtils import atom_index_to_molecule_index
from MDANSE.Mathematics.Arithmetic import weight
+def distance_array_2D(
+ ref_atoms: np.ndarray, other_atoms: np.ndarray, cell_array: np.ndarray
+):
+ """Given two input arrays of atomic positions sized
+ (N,3) and (M,3), returns an (M, N) array of distances
+ between the atoms.
+
+ Parameters
+ ----------
+ ref_atoms : np.ndarray
+ (N, 3)-shaped array of atom positions
+ other_atoms : np.ndarray
+ (M, 3)-shaped array of atom positions
+ cell_array : np.ndarray
+ direct matrix of the unit cell of the system
+
+ Returns
+ -------
+ np.ndarray
+ (N, M)-shaped array of distances between atoms from the two arrays
+ """
+ diff_frac = other_atoms.reshape((len(other_atoms), 1, 3)) - ref_atoms.reshape(
+ (1, len(ref_atoms), 3)
+ )
+ temp = diff_frac
+ temp -= np.round(temp)
+ diff_real = np.matmul(temp, cell_array)
+ r = np.sqrt((diff_real**2).sum(axis=2))
+ return r
+
+
+def van_hove_distinct(
+ cell: np.ndarray,
+ indices_intra: Dict[int, Tuple[List[int]]],
+ symbolindex: List[int],
+ intra: np.ndarray,
+ total: np.ndarray,
+ scaleconfig_t0: np.ndarray,
+ scaleconfig_t1: np.ndarray,
+ rmin: float,
+ dr: float,
+):
+ """Calculates the distance histogram between the configurations at
+ times t0 and t1. Distances are calculated using the minimum image
+ convention which are all worked out using the fractional coordinates
+ with the unit cell of the configuration at time t1. The function can
+ be used to calculate the distinct part of the van Hove function.
+
+ The original implementation by Miguel Angel Gonzalez (Institut Laue
+ Langevin) has now been replaced by numpy functions.
+
+ Parameters
+ ----------
+ cell : np.ndarray
+ direct matrix of the unit cell of the system
+ indices_intra : Dict[int, Tuple[List[int]]]
+ array indices of the distance matrix elements for each molecule in the system
+ symbolindex : List[int]
+ list of int values of atom types in the system
+ intra : np.ndarray
+ the array accumulating the intramolecular distance counts for different atom type pairs
+ total : np.ndarray
+ the array accumulating all the distance counts for different atom type pairs
+ scaleconfig_t0 : np.ndarray
+ array of atom positions at time t0
+ scaleconfig_t1 : np.ndarray
+ array of atom positions at time t1
+ rmin : float
+ lowest distance allowed in the binning of the results
+ dr : float
+ size of the binning step
+
+ Returns
+ -------
+ Tuple[np.ndarray]
+ intra and total input arrays modified by adding new counts
+ """
+
+ nbins = intra.shape[2]
+ unique_types = np.unique(symbolindex)
+ type_indices = {}
+ for type1 in unique_types:
+ type_indices[type1] = np.where(symbolindex == type1)
+
+ all_distances = distance_array_2D(scaleconfig_t0, scaleconfig_t1, cell.T)
+
+ bins = ((all_distances - rmin) / dr).astype(int)
+
+ bins[range(len(symbolindex)), range(len(symbolindex))] = -1
+
+ for dkey, indices in indices_intra.items():
+ type1, type2 = dkey
+ sub_bins = bins[indices]
+ bin_numbers, bin_counts = np.unique(
+ sub_bins,
+ return_counts=True,
+ )
+ for bin, counts in zip(bin_numbers, bin_counts):
+ if bin < 0:
+ continue
+ if bin >= nbins:
+ continue
+ intra[type1, type2, bin] += counts
+
+ for type1 in unique_types:
+ for type2 in unique_types:
+ sub_bins = bins[np.ix_(type_indices[type1][0], type_indices[type2][0])]
+ bin_numbers, bin_counts = np.unique(
+ sub_bins,
+ return_counts=True,
+ )
+ for bin, counts in zip(bin_numbers, bin_counts):
+ if bin < 0:
+ continue
+ if bin >= nbins:
+ continue
+ total[type1, type2, bin] += counts
+
+ return intra, total
+
+
+def find_index_groups(
+ molindex: List[int],
+ symbolindex: List[int],
+):
+ """Finds and returns the indices of the distance array which
+ will be used for calculating the intramolecular distances.
+ These indices are expected to remain fixed within a run and
+ are only calculated once.
+
+ Parameters
+ ----------
+ molindex : List[int]
+ list containing, for each atom, the number of its corresponding molecule
+ symbolindex : List[int]
+ atom type given as an int number for each atom in the simulation
+
+ Returns
+ -------
+ Dict[Tuple[int], Tuple[List[int]]]
+ A dictionary of (atom_type1, atom_type2) : row_index_list, column_index_list values
+ """
+ unique_types = np.unique(symbolindex)
+ intra = {}
+ for s1 in unique_types:
+ for s2 in unique_types:
+ intra[(s1, s2)] = [], []
+ valid_indices = [x for x in range(len(molindex)) if molindex[x] >= 0]
+ for i in valid_indices:
+ for j in valid_indices:
+ if i == j:
+ continue
+ mol1 = molindex[i]
+ mol2 = molindex[j]
+ type1 = symbolindex[i]
+ type2 = symbolindex[j]
+ dkey = (type1, type2)
+ if mol1 == mol2:
+ intra[dkey][0].append(i)
+ intra[dkey][1].append(j)
+ return intra
+
+
class VanHoveFunctionDistinct(IJob):
"""The van Hove function is related to the intermediate scattering
function via a Fourier transform and the dynamic structure factor
@@ -69,7 +233,12 @@ class VanHoveFunctionDistinct(IJob):
)
settings["weights"] = (
"WeightsConfigurator",
- {"dependencies": {"atom_selection": "atom_selection"}},
+ {
+ "dependencies": {
+ "trajectory": "trajectory",
+ "atom_selection": "atom_selection",
+ }
+ },
)
settings["output_files"] = (
"OutputFilesConfigurator",
@@ -170,13 +339,12 @@ def initialize(self):
lut = atom_index_to_molecule_index(
self.configuration["trajectory"]["instance"].chemical_system
)
- self._indexes = [
+ self._indices = [
idx
- for idxs in self.configuration["atom_selection"]["indexes"]
+ for idxs in self.configuration["atom_selection"]["indices"]
for idx in idxs
]
- self._indexes = np.array(self._indexes, dtype=np.int32)
- self.indexToMolecule = np.array([lut[i] for i in self._indexes], dtype=np.int32)
+ self.indexToMolecule = np.array([lut[i] for i in self._indices], dtype=np.int32)
self.indexToSymbol = np.array(
[
self.selectedElements.index(name)
@@ -208,6 +376,8 @@ def initialize(self):
(self.nElements, self.nElements, self.n_mid_points, self.numberOfSteps)
)
+ self.indices_intra = find_index_groups(self.indexToMolecule, self.indexToSymbol)
+
def run_step(self, time: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
"""Calculates the distance histogram between the configurations
at the inputted time difference. The distance histograms are
@@ -225,7 +395,7 @@ def run_step(self, time: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
inter and intramolecular distance histograms.
"""
bins_intra = np.zeros((self.nElements, self.nElements, self.n_mid_points))
- bins_inter = np.zeros((self.nElements, self.nElements, self.n_mid_points))
+ bins_total = np.zeros((self.nElements, self.nElements, self.n_mid_points))
# average the distance histograms at the inputted time
# difference over a number of configuration
@@ -234,28 +404,28 @@ def run_step(self, time: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
conf_t0 = self.configuration["trajectory"]["instance"].configuration(
frame_index_t0
)
- coords_t0 = conf_t0["coordinates"]
+ coords_t0 = conf_t0["coordinates"][self._indices]
frame_index_t1 = self.configuration["frames"]["value"][i + time]
conf_t1 = self.configuration["trajectory"]["instance"].configuration(
frame_index_t1
)
- coords_t1 = conf_t1["coordinates"]
+ coords_t1 = conf_t1["coordinates"][self._indices]
direct_cell = conf_t1.unit_cell.transposed_direct
inverse_cell = conf_t1.unit_cell.transposed_inverse
scaleconfig_t0 = coords_t0 @ inverse_cell
scaleconfig_t1 = coords_t1 @ inverse_cell
- inter = np.zeros_like(bins_inter)
- intra = np.zeros_like(bins_inter)
+ intra = np.zeros_like(bins_intra)
+ total = np.zeros_like(bins_total)
- van_hove.van_hove_distinct(
+ intra, total = van_hove_distinct(
direct_cell,
- self.indexToMolecule,
+ self.indices_intra,
self.indexToSymbol,
intra,
- inter,
+ total,
scaleconfig_t0,
scaleconfig_t1,
self.configuration["r_values"]["first"],
@@ -266,9 +436,9 @@ def run_step(self, time: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
# we multiply my the volume here and divide by the number
# of atoms in finalize.
bins_intra += conf_t1.unit_cell.volume * intra
- bins_inter += conf_t1.unit_cell.volume * inter
+ bins_total += conf_t1.unit_cell.volume * total
- return time, (bins_intra, bins_inter)
+ return time, (bins_intra, bins_total)
def combine(self, time: int, x: tuple[np.ndarray, np.ndarray]):
"""Add the results into the histograms for the inputted time
@@ -283,7 +453,7 @@ def combine(self, time: int, x: tuple[np.ndarray, np.ndarray]):
configurations at the inputted time difference.
"""
self.h_intra[..., time] += x[0]
- self.h_inter[..., time] += x[1]
+ self.h_inter[..., time] += x[1] - x[0]
def finalize(self):
"""Using the distance histograms calculate, normalize and save the
@@ -305,7 +475,7 @@ def finalize(self):
self.h_intra[idi, idj] += self.h_intra[idj, idi]
self.h_inter[idi, idj] += self.h_inter[idj, idi]
- fact = nij * self.n_configs * self.shell_volumes
+ fact = 2 * nij * self.n_configs * self.shell_volumes
van_hove_intra = self.h_intra[idi, idj, ...] / fact[:, np.newaxis]
van_hove_inter = self.h_inter[idi, idj, ...] / fact[:, np.newaxis]
van_hove_total = van_hove_intra + van_hove_inter
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py
index 056c78b9c1..16bceccbf1 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/VanHoveFunctionSelf.py
@@ -17,11 +17,55 @@
import numpy as np
-from MDANSE.Extensions import van_hove
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.Mathematics.Arithmetic import weight
+def van_hove_self(
+ xyz: np.ndarray,
+ histograms: np.ndarray,
+ cell_vols: np.ndarray,
+ rmin: float,
+ dr: float,
+ n_configs: int,
+ n_frames: int,
+):
+ """Calculates the distance histogram between an atom at time t0
+ and the same atom at a time t0 + t. The results from this function
+ can be used to calculate the self part of the van Hove function.
+
+ Parameters
+ ----------
+ xyz : np.ndarray
+ The trajectory of an atom.
+ histograms : np.ndarray
+ The histograms to be updated.
+ cell_vols : np.ndarray
+ The cell volumes.
+ rmin : float
+ The minimum distance of the histogram.
+ dr : float
+ The distances between histogram bins.
+ n_configs : int
+ Number of configs to be averaged over.
+ n_frames : int
+ Number of correlation frames.
+ """
+
+ nbins = histograms.shape[0]
+
+ for i in range(n_configs):
+ x0 = xyz[i]
+ r_array = xyz[i : i + n_frames] - x0.reshape((1, 3))
+ distance_array = np.sqrt((r_array**2).sum(axis=1))
+ bins = ((distance_array - rmin) / dr).astype(int)
+ valid_bins = np.logical_and(bins >= 0, bins < nbins)
+ for j in range(n_frames):
+ if valid_bins[j]:
+ histograms[bins[j], j] += cell_vols[i + j]
+ return histograms
+
+
class VanHoveFunctionSelf(IJob):
"""The van Hove function is related to the intermediate scattering
function via a Fourier transform and the dynamic structure factor
@@ -66,7 +110,12 @@ class VanHoveFunctionSelf(IJob):
)
settings["weights"] = (
"WeightsConfigurator",
- {"dependencies": {"atom_selection": "atom_selection"}},
+ {
+ "dependencies": {
+ "trajectory": "trajectory",
+ "atom_selection": "atom_selection",
+ }
+ },
)
settings["output_files"] = (
"OutputFilesConfigurator",
@@ -184,7 +233,7 @@ def run_step(self, atm_index: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
last = self.configuration["frames"]["last"] + 1
step = self.configuration["frames"]["step"]
- idx = self.configuration["atom_selection"]["indexes"][atm_index][0]
+ idx = self.configuration["atom_selection"]["indices"][atm_index][0]
series = self.configuration["trajectory"]["instance"].read_atomic_trajectory(
idx,
first=first,
@@ -200,7 +249,7 @@ def run_step(self, atm_index: int) -> tuple[int, tuple[np.ndarray, np.ndarray]]:
]
)
- van_hove.van_hove_self(
+ histograms = van_hove_self(
series,
histograms,
cell_vols,
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py
index 55c96ed2f5..5a9edcf3b5 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/VelocityAutoCorrelationFunction.py
@@ -20,7 +20,6 @@
from MDANSE.Framework.Jobs.IJob import IJob
from MDANSE.Mathematics.Arithmetic import weight
from MDANSE.Mathematics.Signal import differentiate, normalize
-from MDANSE.MolecularDynamics.TrajectoryUtils import sorted_atoms
class VelocityAutoCorrelationFunction(IJob):
@@ -90,7 +89,12 @@ class VelocityAutoCorrelationFunction(IJob):
)
settings["weights"] = (
"WeightsConfigurator",
- {"dependencies": {"atom_selection": "atom_selection"}},
+ {
+ "dependencies": {
+ "trajectory": "trajectory",
+ "atom_selection": "atom_selection",
+ }
+ },
)
settings["output_files"] = (
"OutputFilesConfigurator",
@@ -134,9 +138,9 @@ def initialize(self):
main_result=True,
)
- self._atoms = sorted_atoms(
- self.configuration["trajectory"]["instance"].chemical_system.atom_list
- )
+ self._atoms = self.configuration["trajectory"][
+ "instance"
+ ].chemical_system.atom_list
def run_step(self, index):
"""
@@ -153,11 +157,11 @@ def run_step(self, index):
trajectory = self.configuration["trajectory"]["instance"]
# get atom index
- indexes = self.configuration["atom_selection"]["indexes"][index]
+ indices = self.configuration["atom_selection"]["indices"][index]
if self.configuration["interpolation_order"]["value"] == 0:
series = trajectory.read_configuration_trajectory(
- indexes[0],
+ indices[0],
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
@@ -165,7 +169,7 @@ def run_step(self, index):
)
else:
series = trajectory.read_atomic_trajectory(
- indexes[0],
+ indices[0],
first=self.configuration["frames"]["first"],
last=self.configuration["frames"]["last"] + 1,
step=self.configuration["frames"]["step"],
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/Voronoi.py b/MDANSE/Src/MDANSE/Framework/Jobs/Voronoi.py
index 5840fb49ad..19dde6be18 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/Voronoi.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/Voronoi.py
@@ -16,20 +16,23 @@
import collections
import math
+from typing import List
import numpy as np
from scipy.spatial import Voronoi as scipyVoronoi
from scipy.spatial import Delaunay as scipyDelaunay
-from MDANSE.Extensions import mic_fast_calc
+from MDANSE.MolecularDynamics.Configuration import padded_coordinates
from MDANSE.Framework.Jobs.IJob import IJob
-def no_exc_min(l):
+def no_exc_min(numbers: List[float]):
try:
- return min(l)
- except:
- return -np.pi
+ return min(numbers)
+ except ValueError:
+ return -1
+ except TypeError:
+ return -2
class VoronoiError(Exception):
@@ -38,11 +41,14 @@ class VoronoiError(Exception):
class Voronoi(IJob):
"""
- Computes the volume of each Voronoi cell and corresponding 'neighbourhood' statistics for 3d systems.
- Delaunay triangulation is used for the decomposition of polytops into simplexes,
- Voronoi and Delaunay tessellation are calculated using a cython wrapping of the Qhull library (scipy wrapping used as Externals)
+ Computes the volume of each Voronoi cell and corresponding 'neighbourhood'
+ statistics for 3d systems. Vornoi diagram and Delaunay tesselation are
+ used as implemented in scipy.spatial module. Replicas of atoms from
+ the simulation box will be included in the calculation within
+ a finite distance from the box wall (given in nm).
- Voronoi analysis is another commonly-used, complementary method for characterising the local structure of a system.
+ Voronoi analysis is another commonly-used, complementary method for
+ characterising the local structure of a system.
**Acknowledgement:**\n
Gael Goret, PELLEGRINI Eric
@@ -68,7 +74,7 @@ class Voronoi(IJob):
"BooleanConfigurator",
{"label": "apply periodic_boundary_condition", "default": True},
)
- settings["pbc_border_size"] = ("FloatConfigurator", {"mini": 0.0, "default": 0.0})
+ settings["pbc_border_size"] = ("FloatConfigurator", {"mini": 0.0, "default": 0.2})
settings["output_files"] = (
"OutputFilesConfigurator",
{"formats": ["MDAFormat", "TextFormat"]},
@@ -97,9 +103,7 @@ def initialize(self):
# Will store neighbourhood histogram for voronoi regions.
self.neighbourhood_hist = {}
- first_conf = self.configuration["trajectory"][
- "instance"
- ].chemical_system.configuration
+ first_conf = self.configuration["trajectory"]["instance"].configuration()
try:
cell = first_conf.unit_cell.direct
@@ -126,28 +130,31 @@ def run_step(self, index):
frameIndex = self.configuration["frames"]["value"][index]
conf = self.configuration["trajectory"]["instance"].configuration(frameIndex)
+ unit_cell = conf._unit_cell
if self.configuration["pbc"]["value"]:
- conf, _ = mic_fast_calc.mic_generator_3D(
+ coords, _ = padded_coordinates(
conf["coordinates"],
+ unit_cell,
self.configuration["pbc_border_size"]["value"],
- self.cell_param,
)
+ else:
+ coords = conf["coordinates"]
- # Computing Voronoi Diagram ...
- Voronoi = scipyVoronoi(conf)
+ # Computing Voronoi Diagram
+ Voronoi = scipyVoronoi(coords)
vertices_coords = Voronoi.vertices # Option qhull v p
- # Extracting valid Voronoi regions ...
+ # Extracting valid Voronoi regions
points_ids = Voronoi.regions # Option qhull v FN
valid_regions_points_ids = []
valid_region_id = []
region_id = -1
for p in Voronoi.point_region:
region_id += 1
- l = points_ids[p]
- if no_exc_min(l) >= 0:
- valid_regions_points_ids.append(l)
+ id_list = points_ids[p]
+ if no_exc_min(id_list) >= 0:
+ valid_regions_points_ids.append(id_list)
valid_region_id.append(region_id)
valid_regions = {}
@@ -155,11 +162,11 @@ def run_step(self, index):
vrid = valid_region_id[i]
valid_regions[vrid] = valid_regions_points_ids[i]
- # Extracting ridges of the valid Voronoi regions ...
+ # Extracting ridges of the valid Voronoi regions
input_sites = Voronoi.ridge_points # Option qhull v Fv (part of)
self.max_region_id = input_sites.max()
- # Calculating neighbourhood ...
+ # Calculating neighbourhood
neighbourhood = np.zeros((self.max_region_id + 1), dtype=np.int32)
for s in input_sites.ravel():
neighbourhood[s] += 1
@@ -168,12 +175,12 @@ def run_step(self, index):
for i in range(len(neighbourhood)):
v = neighbourhood[i]
if i in valid_region_id:
- if v not in self.neighbourhood_hist:
+ if v not in self.neighbourhood_hist.keys():
self.neighbourhood_hist[v] = 1
else:
self.neighbourhood_hist[v] += 1
- # Delaunay Tesselation of each valid voronoi region ...
+ # Delaunay Tesselation of each valid voronoi region
delaunay_regions_for_each_valid_voronoi_region = {}
for vrid, ids in list(valid_regions.items()):
if vrid >= self.nb_init_pts:
@@ -187,7 +194,7 @@ def run_step(self, index):
lut[dv] for dv in Delaunay.simplices
]
- # Volume Computation ... "
+ # Volume Computation
global_volumes = {}
for vrid, regions in list(
delaunay_regions_for_each_valid_voronoi_region.items()
diff --git a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py
index 254f492f13..5da649cec0 100644
--- a/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py
+++ b/MDANSE/Src/MDANSE/Framework/Jobs/XRayStaticStructureFactor.py
@@ -18,25 +18,24 @@
import numpy as np
-from MDANSE.Chemistry import ATOMS_DATABASE
from MDANSE.Framework.Jobs.DistanceHistogram import DistanceHistogram
from MDANSE.Mathematics.Arithmetic import weight
-def atomic_scattering_factor(element, qvalues):
+def atomic_scattering_factor(element, qvalues, trajectory):
a = np.empty((4,), dtype=np.float64)
- a[0] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_a1")
- a[1] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_a2")
- a[2] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_a3")
- a[3] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_a4")
+ a[0] = trajectory.get_atom_property(element, "xray_asf_a1")
+ a[1] = trajectory.get_atom_property(element, "xray_asf_a2")
+ a[2] = trajectory.get_atom_property(element, "xray_asf_a3")
+ a[3] = trajectory.get_atom_property(element, "xray_asf_a4")
b = np.empty((4,), dtype=np.float64)
- b[0] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_b1")
- b[1] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_b2")
- b[2] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_b3")
- b[3] = ATOMS_DATABASE.get_atom_property(element, "xray_asf_b4")
+ b[0] = trajectory.get_atom_property(element, "xray_asf_b1")
+ b[1] = trajectory.get_atom_property(element, "xray_asf_b2")
+ b[2] = trajectory.get_atom_property(element, "xray_asf_b3")
+ b[3] = trajectory.get_atom_property(element, "xray_asf_b4")
- c = ATOMS_DATABASE.get_atom_property(element, "xray_asf_c")
+ c = trajectory.get_atom_property(element, "xray_asf_c")
return c + np.sum(
a[:, np.newaxis]
@@ -69,12 +68,18 @@ class XRayStaticStructureFactor(DistanceHistogram):
{"dependencies": {"trajectory": "trajectory"}},
)
settings["r_values"] = (
- "RangeConfigurator",
- {"valueType": float, "includeLast": True, "mini": 0.0},
+ "DistHistCutoffConfigurator",
+ {
+ "label": "r values (nm)",
+ "valueType": float,
+ "includeLast": True,
+ "mini": 0.0,
+ "dependencies": {"trajectory": "trajectory"},
+ },
)
settings["q_values"] = (
"RangeConfigurator",
- {"valueType": float, "includeLast": True, "mini": 0.0},
+ {"valueType": float, "includeLast": True, "mini": 0.0, "default": (0, 500, 1)},
)
settings["atom_selection"] = (
"AtomSelectionConfigurator",
@@ -165,7 +170,7 @@ def finalize(self):
self.hIntra[idi, idj] += self.hIntra[idj, idi]
self.hInter[idi, idj] += self.hInter[idj, idi]
- fact = nij * nFrames * shellVolumes
+ fact = 2 * nij * nFrames * shellVolumes
pdfIntra = self.hIntra[idi, idj, :] / fact
pdfInter = self.hInter[idi, idj, :] / fact
@@ -192,7 +197,14 @@ def finalize(self):
)
asf = dict(
- (k, atomic_scattering_factor(k, self._outputData["q"]))
+ (
+ k,
+ atomic_scattering_factor(
+ k,
+ self._outputData["q"],
+ self.configuration["trajectory"]["instance"],
+ ),
+ )
for k in list(nAtomsPerElement.keys())
)
diff --git a/MDANSE/Src/MDANSE/Framework/QVectors/IQVectors.py b/MDANSE/Src/MDANSE/Framework/QVectors/IQVectors.py
index 47588cabd3..573c1be92e 100644
--- a/MDANSE/Src/MDANSE/Framework/QVectors/IQVectors.py
+++ b/MDANSE/Src/MDANSE/Framework/QVectors/IQVectors.py
@@ -28,10 +28,10 @@ class QVectorsError(Error):
class IQVectors(Configurable, metaclass=SubclassFactory):
is_lattice = False
- def __init__(self, chemical_system, status=None):
+ def __init__(self, atom_configuration, status=None):
Configurable.__init__(self)
- self._chemical_system = chemical_system
+ self._atom_configuration = atom_configuration
self._status = status
diff --git a/MDANSE/Src/MDANSE/Framework/QVectors/LatticeQVectors.py b/MDANSE/Src/MDANSE/Framework/QVectors/LatticeQVectors.py
index 2a4da68fe1..537f545156 100644
--- a/MDANSE/Src/MDANSE/Framework/QVectors/LatticeQVectors.py
+++ b/MDANSE/Src/MDANSE/Framework/QVectors/LatticeQVectors.py
@@ -22,21 +22,17 @@
class LatticeQVectors(IQVectors):
is_lattice = True
- def __init__(self, chemical_system, status=None):
- super(LatticeQVectors, self).__init__(chemical_system, status)
+ def __init__(self, atom_configuration, status=None):
+ super(LatticeQVectors, self).__init__(atom_configuration, status)
- if self._chemical_system.configuration is None:
+ if atom_configuration is None:
raise QVectorsError("No configuration set for the chemical system")
- if not self._chemical_system.configuration.is_periodic:
+ if not atom_configuration.is_periodic:
raise QVectorsError(
"The universe must be periodic for building lattice-based Q vectors"
)
- self._inverseUnitCell = (
- 2.0 * np.pi * self._chemical_system.configuration.unit_cell.inverse
- )
+ self._inverseUnitCell = 2.0 * np.pi * atom_configuration.unit_cell.inverse
- self._directUnitCell = (
- 2.0 * np.pi * self._chemical_system.configuration.unit_cell.direct
- )
+ self._directUnitCell = 2.0 * np.pi * atom_configuration.unit_cell.direct
diff --git a/MDANSE/Src/MDANSE/IO/MinimalPDBReader.py b/MDANSE/Src/MDANSE/IO/MinimalPDBReader.py
index 9391573a1e..afb0b28d17 100644
--- a/MDANSE/Src/MDANSE/IO/MinimalPDBReader.py
+++ b/MDANSE/Src/MDANSE/IO/MinimalPDBReader.py
@@ -22,7 +22,7 @@
from MDANSE.MLogging import LOG
from MDANSE.Framework.Units import measure
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem, Atom
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import (
RealConfiguration,
PeriodicRealConfiguration,
@@ -109,7 +109,7 @@ def find_atoms(self, filename: str, frame_number: int = 0):
result.append(line)
elif "HETATM" in line[0:6]:
result.append(line)
- if "ENDMDL" in line[0:6]:
+ if "END" in line[0:3]:
fail_count += 1
if fail_count > 0:
break
@@ -119,7 +119,7 @@ def build_chemical_system(self, atom_lines: List[str]):
"""Build the chemical system.
Returns:
- MDANSE.Chemistry.ChemicalEntity.ChemicalSystem: the chemical system
+ MDANSE.Chemistry.ChemicalSystem.ChemicalSystem: the chemical system
"""
coordinates = []
@@ -128,16 +128,25 @@ def build_chemical_system(self, atom_lines: List[str]):
posx_slice = atom_line_slice("pos_x")
posy_slice = atom_line_slice("pos_y")
posz_slice = atom_line_slice("pos_z")
- pos_scaling = measure(1.0, "ang").toval("nm")
+ residue_slice = atom_line_slice("residue_name")
+ residue_number_slice = atom_line_slice("residue_number")
+
+ element_list = []
+ name_list = []
+ label_dict = {}
+ clusters = {}
- for atom_line in atom_lines:
+ for atom_number, atom_line in enumerate(atom_lines):
chemical_element = atom_line[element_slice].strip()
atom_name = atom_line[name_slice]
processed_atom_name = atom_name[:2].strip()
if len(processed_atom_name) == 2:
- processed_atom_name = (
- processed_atom_name[0].upper() + processed_atom_name[1].lower()
- )
+ if processed_atom_name[0].isnumeric():
+ processed_atom_name = processed_atom_name[1].upper()
+ else:
+ processed_atom_name = (
+ processed_atom_name[0].upper() + processed_atom_name[1].lower()
+ )
if len(chemical_element) == 2:
chemical_element = (
chemical_element[0].upper() + chemical_element[1].lower()
@@ -149,34 +158,41 @@ def build_chemical_system(self, atom_lines: List[str]):
else:
backup_element3 = "fail"
if backup_element in ATOMS_DATABASE.atoms:
- atom = Atom(symbol=backup_element, name=atom_name)
+ element_list.append(backup_element)
elif backup_element2 in ATOMS_DATABASE.atoms:
- atom = Atom(symbol=backup_element2, name=atom_name)
+ element_list.append(backup_element2)
elif backup_element3 in ATOMS_DATABASE.atoms:
- atom = Atom(symbol=backup_element3, name=atom_name)
+ element_list.append(backup_element3)
elif chemical_element in ATOMS_DATABASE.atoms:
- atom = Atom(symbol=chemical_element, name=atom_name)
+ element_list.append(chemical_element)
elif processed_atom_name in ATOMS_DATABASE.atoms:
- atom = Atom(symbol=processed_atom_name, name=atom_name)
+ element_list.append(processed_atom_name)
else:
- LOG.warning(f"Dummy atom introduce from line {atom_line}")
- atom = Atom(symbol="Du", name=atom_name)
- self._chemical_system.add_chemical_entity(atom)
+ LOG.warning(f"Dummy atom introduced from line {atom_line}")
+ element_list.append("Du")
x, y, z = (
atom_line[posx_slice],
atom_line[posy_slice],
atom_line[posz_slice],
)
coordinates.append([float(aaa) for aaa in [x, y, z]])
-
- coordinates = np.array(coordinates)
- coordinates *= pos_scaling
-
- if self._unit_cell is None:
- self._chemical_system.configuration = RealConfiguration(
- self._chemical_system, coordinates
- )
- else:
- self._chemical_system.configuration = PeriodicRealConfiguration(
- self._chemical_system, coordinates, UnitCell(self._unit_cell)
- )
+ residue_name = atom_line[residue_slice]
+ if residue_name not in label_dict.keys():
+ label_dict[residue_name] = []
+ label_dict[residue_name].append(atom_number)
+ name_list.append(atom_name.strip())
+ residue_number_string = atom_line[residue_number_slice]
+ try:
+ residue_number = int(residue_number_string)
+ except ValueError:
+ try:
+ residue_number = int(residue_number_string, base=16)
+ except ValueError:
+ continue
+ if (residue_name, residue_number) in clusters.keys():
+ clusters[(residue_name, residue_number)].append(atom_number)
+ else:
+ clusters[(residue_name, residue_number)] = [atom_number]
+ self._chemical_system.initialise_atoms(element_list, name_list)
+ self._chemical_system.add_labels(label_dict)
+ self._chemical_system.add_clusters(clusters.values())
diff --git a/MDANSE/Src/MDANSE/IO/PDB.py b/MDANSE/Src/MDANSE/IO/PDB.py
deleted file mode 100644
index 5d1280c489..0000000000
--- a/MDANSE/Src/MDANSE/IO/PDB.py
+++ /dev/null
@@ -1,1480 +0,0 @@
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-"""
-Parsing and writing of Protein Data Bank (PDB) files
-
-This module provides classes that represent PDB (Protein Data Bank)
-files and configurations contained in PDB files. It provides access to
-PDB files on two levels: low-level (line by line) and high-level
-(chains, residues, and atoms).
-
-Caution: The PDB file format has been heavily abused, and it is
-probably impossible to write code that can deal with all variants
-correctly. This modules tries to read the widest possible range of PDB
-files, but gives priority to a correct interpretation of the PDB
-format as defined by the Brookhaven National Laboratory.
-
-A special problem are atom names. The PDB file format specifies that
-the first two letters contain the right-justified chemical element
-name. A later modification allowed the initial space in hydrogen names
-to be replaced by a digit. Many programs ignore all this and treat the
-name as an arbitrary left-justified four-character name. This makes it
-difficult to extract the chemical element accurately; most programs
-write the '"CA"' for C_alpha in such a way that it actually stands for
-a calcium atom. For this reason a special element field has been added
-later, but only few files use it. In the absence of an element field,
-the code in this module attempts to guess the element using all information
-available.
-
-The low-level routines in this module do not try to deal with the atom
-name problem; they return and expect four-character atom names
-including spaces in the correct positions. The high-level routines use
-atom names without leading or trailing spaces, but provide and use the
-element field whenever possible. For output, they use the element
-field to place the atom name correctly, and for input, they construct
-the element field content from the atom name if no explicit element
-field is found in the file.
-
-Except where indicated, numerical values use the same units and
-conventions as specified in the PDB format description.
-
-Example::
-
- >>>conf = Structure('example.pdb')
- >>>print conf
- >>>for residue in conf.residues:
- >>> for atom in residue:
- >>> print atom
-
-@undocumented: atom_format
-@undocumented: anisou_format
-@undocumented: conect_format
-@undocumented: ter_format
-@undocumented: model_format
-@undocumented: header_format
-@undocumented: cryst1_format
-@undocumented: scalen_format
-@undocumented: mtrixn_format
-@undocumented: generic_format
-@undocumented: export_filters
-@undocumented: DummyChain
-"""
-import string
-
-import numpy as np
-
-from MDANSE.Chemistry import NUCLEOTIDES_DATABASE, RESIDUES_DATABASE, RESIDUE_ALT_NAMES
-from MDANSE.IO.FortranFormat import FortranFormat, FortranLine
-from MDANSE.IO.PDBExportFilters import export_filters
-from MDANSE.IO.TextFile import TextFile
-from MDANSE.Mathematics.LinearAlgebra import Vector, Tensor
-
-
-def cmp(a, b):
- return (a > b) - (a < b)
-
-
-#
-# Fortran formats for PDB entries
-#
-atom_format = FortranFormat("A6,I5,1X,A4,A1,A4,A1,I4,A1,3X,3F8.3,2F6.2,6X,A4,2A2")
-anisou_format = FortranFormat("A6,I5,1X,A4,A1,A4,A1,I4,A1,1X,6I7,2X,A4,2A2")
-conect_format = FortranFormat("A6,11I5")
-ter_format = FortranFormat("A6,I5,6X,A4,A1,I4,A1")
-model_format = FortranFormat("A6,4X,I4")
-header_format = FortranFormat("A6,4X,A40,A9,3X,A4")
-cryst1_format = FortranFormat("A6,3F9.3,3F7.2,1X,A11,I4")
-scalen_format = FortranFormat("A6,4X,3F10.6,5X,F10.5")
-mtrixn_format = FortranFormat("A6,1X,I3,3F10.6,5X,F10.5,4X,I1")
-generic_format = FortranFormat("A6,A74")
-
-
-#
-# Low-level file object. It represents line contents as Python dictionaries.
-# For output, there are additional methods that generate sequence numbers
-# for everything.
-#
-class PDBFile:
- """
- X{PDB} file with access at the record level
-
- The low-level file access is handled by the module
- L{Scientific.IO.TextFile}, therefore compressed files and URLs
- (for reading) can be used as well.
- """
-
- def __init__(self, file_or_filename, mode="r", subformat=None):
- """
- @param file_or_filename: the name of the PDB file, or a file object
- @type file_or_filename: C{str} or C{file}
- @param mode: the file access mode, 'r' (read) or 'w' (write)
- @type mode: C{str}
- @param subformat: indicates a specific dialect of the PDB format.
- Subformats are defined in
- L{Scientific.IO.PDBExportFilters}; they are used
- only when writing.
- @type subformat: C{str} or C{NoneType}
- """
-
- if isinstance(file_or_filename, str):
- self.file = TextFile(file_or_filename, mode)
- else:
- self.file = file_or_filename
- self.output = mode[0].lower() == "w"
- self.export_filter = None
- if subformat is not None:
- export = export_filters.get(subformat, None)
- if export is not None:
- self.export_filter = export()
- self.open = 1
- if self.output:
- self.data = {
- "serial_number": 0,
- "residue_number": 0,
- "chain_id": "",
- "segment_id": "",
- }
- self.het_flag = 0
- self.chain_number = -1
-
- def readLine(self):
- """
- Return the contents of the next non-blank line (= record) The
- return value is a tuple whose first element (a string)
- contains the record type. For supported record types (HEADER,
- CRYST1, SCALEn, MTRIXn, ATOM, HETATM, ANISOU, TERM, MODEL,
- CONECT), the items from the remaining fields are put into a
- dictionary which is returned as the second tuple element. Most
- dictionary elements are strings or numbers; atom positions are
- returned as a vector, and anisotropic temperature factors are
- returned as a rank-2 tensor, already multiplied by 1.e-4.
- White space is stripped from all strings except for atom
- names, whose correct interpretation can depend on an initial
- space. For unsupported record types, the second tuple element
- is a string containing the remaining part of the record.
-
- @returns: the contents of one PDB record
- @rtype: C{tuple}
- """
- while 1:
- line = self.file.readline()
- if not line:
- return ("END", "")
- if line[-1] == "\n":
- line = line[:-1]
- line = line.strip()
- if line:
- break
- line = line.ljust(80)
- type = line[:6].strip()
- if type == "ATOM" or type == "HETATM":
- line = FortranLine(line, atom_format)
- data = {
- "serial_number": line[1],
- "name": line[2],
- "alternate": line[3].strip(),
- "residue_name": line[4].strip(),
- "chain_id": line[5].strip(),
- "residue_number": line[6],
- "insertion_code": line[7].strip(),
- "position": Vector(line[8:11]),
- "occupancy": line[11],
- "temperature_factor": line[12],
- "segment_id": line[13].strip(),
- "element": line[14].strip(),
- "charge": line[15].strip(),
- }
- return type, data
- elif type == "ANISOU":
- line = FortranLine(line, anisou_format)
- data = {
- "serial_number": line[1],
- "name": line[2],
- "alternate": line[3].strip(),
- "residue_name": line[4].strip(),
- "chain_id": line[5].strip(),
- "residue_number": line[6],
- "insertion_code": line[7].strip(),
- "u": 1.0e-4
- * Tensor(
- [
- [line[8], line[11], line[12]],
- [line[11], line[9], line[13]],
- [line[12], line[13], line[10]],
- ]
- ),
- "segment_id": line[14].strip(),
- "element": line[15].strip(),
- "charge": line[16].strip(),
- }
- return type, data
- elif type == "TER":
- line = FortranLine(line, ter_format)
- data = {
- "serial_number": line[1],
- "residue_name": line[2].strip(),
- "chain_id": line[3].strip(),
- "residue_number": line[4],
- "insertion_code": line[5].strip(),
- }
- return type, data
- elif type == "CONECT":
- line = FortranLine(line, conect_format)
- data = {
- "serial_number": line[1],
- "bonded": [i for i in line[2:6] if i > 0],
- "hydrogen_bonded": [i for i in line[6:10] if i > 0],
- "salt_bridged": [i for i in line[10:12] if i > 0],
- }
- return type, data
- elif type == "MODEL":
- line = FortranLine(line, model_format)
- data = {"serial_number": line[1]}
- return type, data
- elif type == "HEADER":
- line = FortranLine(line, header_format)
- data = {"compound": line[1], "date": line[2], "pdb_code": line[3]}
- return type, data
- elif type == "CRYST1":
- line = FortranLine(line, cryst1_format)
- data = {
- "a": line[1],
- "b": line[2],
- "c": line[3],
- "alpha": line[4],
- "beta": line[5],
- "gamma": line[6],
- "space_group": line[7],
- "z": line[8],
- }
- return type, data
- elif type[:-1] == "SCALE":
- line = FortranLine(line, scalen_format)
- data = {"s1": line[1], "s2": line[2], "s3": line[3], "u": line[4]}
- return type, data
- elif type[:-1] == "MTRIX":
- line = FortranLine(line, mtrixn_format)
- data = {
- "serial": line[1],
- "m1": line[2],
- "m2": line[3],
- "m3": line[4],
- "v": line[5],
- "given": line[6] == 1,
- }
- return type, data
- else:
- return type, line[6:]
-
- def writeLine(self, type, data):
- """
- Write a line using record type and data dictionary in the
- same format as returned by readLine(). Default values are
- provided for non-essential information, so the data dictionary
- need not contain all entries.
-
- @param type: PDB record type
- @type type: C{str}
- @param data: PDB record data
- @type data: C{tuple}
- """
- if self.export_filter is not None:
- type, data = self.export_filter.processLine(type, data)
- if type is None:
- return
- line = [type]
- if type == "ATOM" or type == "HETATM":
- format = atom_format
- position = data["position"]
- line = line + [
- data.get("serial_number", 1),
- data.get("name"),
- data.get("alternate", ""),
- data.get("residue_name", "").rjust(3),
- data.get("chain_id", ""),
- data.get("residue_number", 1),
- data.get("insertion_code", ""),
- position[0],
- position[1],
- position[2],
- data.get("occupancy", 0.0),
- data.get("temperature_factor", 0.0),
- data.get("segment_id", ""),
- data.get("element", "").rjust(2),
- data.get("charge", ""),
- ]
- elif type == "ANISOU":
- format = anisou_format
- u = 1.0e4 * data["u"]
- u = [
- int(u[0, 0]),
- int(u[1, 1]),
- int(u[2, 2]),
- int(u[0, 1]),
- int(u[0, 2]),
- int(u[1, 2]),
- ]
- line = (
- line
- + [
- data.get("serial_number", 1),
- data.get("name"),
- data.get("alternate", ""),
- data.get("residue_name").rjust(3),
- data.get("chain_id", ""),
- data.get("residue_number", 1),
- data.get("insertion_code", ""),
- ]
- + u
- + [
- data.get("segment_id", ""),
- data.get("element", "").rjust(2),
- data.get("charge", ""),
- ]
- )
- elif type == "TER":
- format = ter_format
- line = line + [
- data.get("serial_number", 1),
- data.get("residue_name").rjust(3),
- data.get("chain_id", ""),
- data.get("residue_number", 1),
- data.get("insertion_code", ""),
- ]
- elif type == "CONECT":
- format = conect_format
- line = line + [data.get("serial_number")]
- line = line + (data.get("bonded", []) + 4 * [None])[:4]
- line = line + (data.get("hydrogen_bonded", []) + 4 * [None])[:4]
- line = line + (data.get("salt_bridged", []) + 2 * [None])[:2]
- elif type == "MODEL":
- format = model_format
- line = line + [data.get("serial_number")]
- elif type == "CRYST1":
- format = cryst1_format
- line = line + [
- data.get("a"),
- data.get("b"),
- data.get("c"),
- data.get("alpha"),
- data.get("beta"),
- data.get("gamma"),
- data.get("space_group"),
- data.get("z"),
- ]
- elif type[:-1] == "SCALE":
- format = scalen_format
- line = line + [
- data.get("s1"),
- data.get("s2"),
- data.get("s3"),
- data.get("u"),
- ]
- elif type[:-1] == "MTRIX":
- format = scalen_format
- line = line + [
- data.get("serial"),
- data.get("m1"),
- data.get("m2"),
- data.get("m3"),
- data.get("v"),
- int(data.get("given")),
- ]
- elif type == "HEADER":
- format = header_format
- line = line + [
- data.get("compound", ""),
- data.get("date", ""),
- data.get("pdb_code"),
- ]
- else:
- format = generic_format
- line = line + [data]
- self.file.write(str(FortranLine(line, format)) + "\n")
-
- def writeComment(self, text):
- """
- Write text into one or several comment lines.
- Each line of the text is prefixed with 'REMARK' and written
- to the file.
-
- @param text: the comment contents
- @type text: C{str}
- """
- while text:
- eol = text.find("\n")
- if eol == -1:
- eol = len(text)
- self.file.write("REMARK %s \n" % text[:eol])
- text = text[eol + 1 :]
-
- def writeAtom(
- self,
- name,
- position,
- occupancy=0.0,
- temperature_factor=0.0,
- element="",
- alternate="",
- ):
- """
- Write an ATOM or HETATM record using the information supplied.
- The residue and chain information is taken from the last calls to
- the methods L{nextResidue} and L{nextChain}.
-
- @param name: the atom name
- @type name: C{str}
- @param position: the atom position
- @type position: L{Scientific.Geometry.Vector}
- @param occupancy: the occupancy
- @type occupancy: C{float}
- @param temperature_factor: the temperature factor (B-factor)
- @type temperature_factor: C{float}
- @param element: the chemical element
- @type element: C{str}
- @param alternate: the alternate location character
- @type element: C{str}
- """
- if self.het_flag:
- type = "HETATM"
- else:
- type = "ATOM"
- name = name.upper()
- if (
- element != ""
- and len(element) == 1
- and name
- and name[0] == element
- and len(name) < 4
- ):
- name = " " + name
- self.data["name"] = name
- self.data["position"] = position
- self.data["serial_number"] = (self.data["serial_number"] + 1) % 100000
- self.data["alternate"] = alternate
- self.data["occupancy"] = occupancy
- self.data["temperature_factor"] = temperature_factor
- self.data["element"] = element
- self.writeLine(type, self.data)
-
- def nextResidue(self, name, number=None, terminus=None):
- """
- Signal the beginning of a new residue, starting with the
- next call to L{writeAtom}.
-
- @param name: the residue name
- @type name: C{str}
- @param number: the residue number. If C{None}, the residues
- will be numbered sequentially, starting from 1.
- @type number: C{int} or C{NoneType}
- @param terminus: C{None}, "C", or "N". This information
- is passed to export filters that can use this
- information in order to use different atom or
- residue names in terminal residues.
- """
- name = name.upper()
- if self.export_filter is not None:
- name, number = self.export_filter.processResidue(name, number, terminus)
- self.het_flag = not (
- name in RESIDUES_DATABASE
- or name in RESIDUE_ALT_NAMES
- or name in NUCLEOTIDES_DATABASE
- )
- self.data["residue_name"] = name
- self.data["residue_number"] = (self.data["residue_number"] + 1) % 10000
- self.data["insertion_code"] = ""
- if number is not None:
- if isinstance(number, int):
- if number >= 0:
- self.data["residue_number"] = number % 10000
- else:
- self.data["residue_number"] = -((-number) % 1000)
- else:
- self.data["residue_number"] = number.number % 10000
- self.data["insertion_code"] = number.insertion_code
-
- def nextChain(self, chain_id=None, segment_id=""):
- """
- Signal the beginning of a new chain.
-
- @param chain_id: a chain identifier. If C{None}, consecutive letters
- from the alphabet are used.
- @type chain_id: C{str} or C{NoneType}
- @param segment_id: a chain identifier
- @type segment_id: C{str}
- """
- if chain_id is None:
- self.chain_number = (self.chain_number + 1) % len(self._chain_ids)
- chain_id = self._chain_ids[self.chain_number]
- if self.export_filter is not None:
- chain_id, segment_id = self.export_filter.processChain(chain_id, segment_id)
- self.data["chain_id"] = (chain_id + " ")[:1]
- self.data["segment_id"] = (segment_id + " ")[:4]
- self.data["residue_number"] = 0
-
- _chain_ids = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-
- def terminateChain(self):
- """
- Signal the end of a chain.
- """
- if self.export_filter is not None:
- self.export_filter.terminateChain()
- self.data["serial_number"] = (self.data["serial_number"] + 1) % 100000
- self.writeLine("TER", self.data)
- self.data["chain_id"] = ""
- self.data["segment_id"] = ""
-
- def close(self):
- """
- Close the file. This method B{must} be called for write mode
- because otherwise the file will be incomplete.
- """
- if getattr(self, "open", False):
- if self.output:
- self.file.write("END\n")
- self.file.close()
- self.open = 0
-
- def __del__(self):
- self.close()
-
-
-#
-# High-level object representation of PDB file contents.
-#
-
-
-#
-# Representation of objects.
-#
-class PDBAtom:
- """
- Atom in a PDB structure
- """
-
- def __init__(self, name, position, **properties):
- """
- @param name: the atom name
- @type name: C{str}
- @param position: the atom position
- @type position: L{Scientific.Geometry.Vector}
- @param properties: any other atom properties as keyword parameters.
- These properties are stored in the atom object
- and can be accessed by indexing, as for
- dictionaries.
- """
- self.position = position
- self.properties = properties
- if self.properties.get("element", "") == "":
- if name[0] == " " or name[0] in string.digits:
- self.properties["element"] = name[1]
- elif name[1] in string.digits:
- self.properties["element"] = name[0]
- else:
- self.properties["element"] = name[0:2]
- self.name = name.strip()
- self.parent = None
-
- def __getitem__(self, item):
- """
- @param item: the name of a property, including "name" or "position"
- @type item: C{str}
- @returns: the property value
- """
- try:
- return self.properties[item]
- except KeyError:
- if item == "name":
- return self.name
- elif item == "position":
- return self.position
- else:
- raise KeyError("Undefined atom property: " + repr(item))
-
- def __setitem__(self, item, value):
- """
- @param item: the name of an existing or to be defined property
- @type item: C{str}
- @param value: the new value for the property
- """
- self.properties[item] = value
-
- def __str__(self):
- return self.__class__.__name__ + " " + self.name + " at " + str(self.position)
-
- __repr__ = __str__
-
- def type(self):
- """
- @returns: the six-letter record type, ATOM or HETATM
- @rtype: C{str}
- """
- return "ATOM "
-
- def writeToFile(self, file):
- """
- Write an atom record to a file
-
- @param file: a PDB file object or a filename
- @type file: L{PDBFile} or C{str}
- """
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- file.writeAtom(
- self.name,
- self.position,
- self.properties.get("occupancy", 0.0),
- self.properties.get("temperature_factor", 0.0),
- self.properties.get("element", ""),
- )
- if close:
- file.close()
-
-
-class PDBHetAtom(PDBAtom):
- """
- HetAtom in a PDB structure
-
- A subclass of Atom, which differs only in the return value
- of the method type().
- """
-
- def type(self):
- return "HETATM"
-
-
-class PDBGroup:
- """
- Atom group (residue or molecule) in a PDB file
-
- This is an abstract base class. Instances can be created using
- one of the subclasses (L{Molecule}, L{AminoAcidResidue},
- L{NucleotideResidue}).
-
- Group objects permit iteration over atoms with for-loops,
- as well as extraction of atoms by indexing with the
- atom name.
- """
-
- def __init__(self, name, atoms=None, number=None):
- """
- @param name: the name of the group
- @type name: C{str}
- @param atoms: a list of atoms (or C{None} for no atoms)
- @type atoms: C{list} or C{NoneType}
- @param number: the PDB residue number (or C{None})
- @type number: C{int} or C{NoneType}
- """
- self.name = name
- self.number = number
- self.atom_list = []
- self.atoms = {}
- if atoms:
- self.atom_list = atoms
- for a in atoms:
- self.atoms[a.name] = a
-
- def __len__(self):
- return len(self.atom_list)
-
- def __getitem__(self, item):
- """
- @param item: an integer index or an atom name
- @type item: C{int} or C{str}
- """
- if isinstance(item, int):
- return self.atom_list[item]
- else:
- return self.atoms[item]
-
- def __str__(self):
- s = self.__class__.__name__ + " " + self.name + ":\n"
- for atom in self.atom_list:
- s = s + " " + repr(atom) + "\n"
- return s
-
- __repr__ = __str__
-
- def isCompatible(self, residue_data):
- return (
- residue_data["residue_name"] == self.name
- and residue_data["residue_number"] == self.number
- )
-
- def addAtom(self, atom):
- """
- Add an atom to the group
-
- @param atom: the atom
- @type atom: L{Atom}
- """
- self.atom_list.append(atom)
- self.atoms[atom.name] = atom
- atom.parent = self
-
- def deleteAtom(self, atom):
- """
- Remove an atom from the group
-
- @param atom: the atom to be removed
- @type atom: L{Atom}
- @raises KeyError: if the atom is not part of the group
- """
- self.atom_list.remove(atom)
- del self.atoms[atom.name]
- atom.parent = None
-
- def deleteHydrogens(self):
- """
- Remove all hydrogen atoms of the group
- """
- delete = []
- for a in self.atom_list:
- if a.name[0] == "H" or (a.name[0] in string.digits and a.name[1] == "H"):
- delete.append(a)
- for a in delete:
- self.deleteAtom(a)
-
- def changeName(self, name):
- """
- Set the PDB residue name
-
- @param name: the new name
- @type name: C{str}
- """
- self.name = name
-
- def writeToFile(self, file):
- """
- Write the group to a file
-
- @param file: a PDBFile object or a file name
- @type file: L{PDBFile} or C{str}
- """
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- file.nextResidue(self.name, self.number, None)
- for a in self.atom_list:
- a.writeToFile(file)
- if close:
- file.close()
-
-
-class PDBMolecule(PDBGroup):
- """
- Molecule in a PDB file
-
- B{Note:} In PDB files, non-chain molecules are treated as residues,
- there is no separate molecule definition. This module defines
- every residue as a molecule that is not an amino acid residue or a
- nucleotide residue.
- """
-
- pass
-
-
-class PDBResidue(PDBGroup):
- pass
-
-
-class PDBAminoAcidResidue(PDBResidue):
- """
- Amino acid residue in a PDB file
- """
-
- is_amino_acid = 1
-
- def isCTerminus(self):
- """
- @returns: C{True} if the residue is in C-terminal configuration,
- i.e. if it has a second oxygen bound to the carbon atom of
- the peptide group. C{False} otherwise.
- @rtype: C{bool}
- """
- return self.name == "NME" or "OXT" in self.atoms or "OT2" in self.atoms
-
- def isNTerminus(self):
- """
- @returns: C{True} if the residue is in N-terminal configuration,
- i.e. if it contains more than one hydrogen bound to be
- nitrogen atom of the peptide group. C{False} otherwise.
- @rtype: C{bool}
- """
- return (
- "1HT" in self.atoms
- or "2HT" in self.atoms
- or "3HT" in self.atoms
- or "HT1" in self.atoms
- or "HT2" in self.atoms
- or "HT3" in self.atoms
- or "1H" in self.atoms
- or "2H" in self.atoms
- or "3H" in self.atoms
- or "H1" in self.atoms
- or "H2" in self.atoms
- or "H3" in self.atoms
- )
-
- def addAtom(self, atom):
- PDBResidue.addAtom(self, atom)
- if atom.name == "CA": # Make sure it's not a calcium
- atom.properties["element"] = "C"
-
- def writeToFile(self, file):
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- terminus = None
- if self.isCTerminus():
- terminus = "C"
- if self.isNTerminus():
- terminus = "N"
- file.nextResidue(self.name, self.number, terminus)
- for a in self.atom_list:
- a.writeToFile(file)
- if close:
- file.close()
-
-
-class PDBNucleotideResidue(PDBResidue):
- """
- Nucleotide residue in a PDB file
- """
-
- is_nucleotide = 1
-
- def __init__(self, name, atoms=None, number=None):
- self.pdbname = name
- name = name.strip()
- if name[0] != "D" and name[0] != "R":
- name = "D" + name
- PDBResidue.__init__(self, name, atoms, number)
- for a in atoms:
- if a.name == "O2*" or a.name == "O2'": # Ribose
- self.name = "R" + self.name[1:]
-
- def isCompatible(self, residue_data):
- return (
- residue_data["residue_name"] == self.name
- or residue_data["residue_name"] == self.pdbname
- ) and residue_data["residue_number"] == self.number
-
- def addAtom(self, atom):
- PDBResidue.addAtom(self, atom)
- if atom.name == "O2*" or atom.name == "O2'": # Ribose
- self.name = "R" + self.name[1:]
-
- def hasRibose(self):
- """
- @returns: C{True} if the residue has an atom named O2*
- @rtype: C{bool}
- """
- return "O2*" in self.atoms or "O2'" in self.atoms
-
- def hasDesoxyribose(self):
- """
- @returns: C{True} if the residue has no atom named O2*
- @rtype: C{bool}
- """
- return not self.hasRibose()
-
- def hasPhosphate(self):
- """
- @returns: C{True} if the residue has a phosphate group
- @rtype: C{bool}
- """
- return "P" in self.atoms
-
- def hasTerminalH(self):
- """
- @returns: C{True} if the residue has a 3-terminal H atom
- @rtype: C{bool}
- """
- return "H3T" in self.atoms
-
- def writeToFile(self, file):
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- terminus = None
- if not self.hasPhosphate():
- terminus = "5"
- file.nextResidue(self.name[1:], self.number, terminus)
- for a in self.atom_list:
- a.writeToFile(file)
- if close:
- file.close()
-
-
-class PDBChain:
- """Chain of PDB residues
-
- This is an abstract base class. Instances can be created using
- one of the subclasses (L{PeptideChain}, L{NucleotideChain}).
-
- Chain objects respond to len() and return their residues
- by indexing with integers.
- """
-
- def __init__(self, residues=None, chain_id=None, segment_id=None):
- """
- @param residues: a list of residue objects, or C{None} meaning
- that the chain is initially empty
- @type residues: C{list} or C{NoneType}
- @param chain_id: a one-letter chain identifier or C{None}
- @type chain_id: C{str} or C{NoneType}
- @param segment_id: a multi-character segment identifier or C{None}
- @type segment_id: C{str} or C{NoneType}
- """
- if residues is None:
- self.residues = []
- else:
- self.residues = residues
- self.chain_id = chain_id
- self.segment_id = segment_id
-
- def __len__(self):
- """
- @returns: the number of residues in the chain
- @rtype: C{int}
- """
- return len(self.residues)
-
- def sequence(self):
- """
- @returns: the list of residue names
- @rtype: C{list} of C{str}
- """
- return [r.name for r in self.residues]
-
- def __getitem__(self, index):
- """
- @param index: an index into the chain
- @type index: C{int}
- @returns: the residue corresponding to the index
- @rtype: L{AminoAcidResidue} or L{NucleotideResidue}
- @raises IndexError: if index exceeds the chain length
- """
- return self.residues[index]
-
- def __getslice__(self, i1, i2):
- """
- @param i1: in index into the chain
- @type i1: C{int}
- @param i2: in index into the chain
- @type i12 C{int}
- @returns: the subchain from i1 to i2
- @rtype: L{PeptideChain} or L{NucleotideChain}
- """
- return self.__class__(self.residues[i1:i2])
-
- def addResidue(self, residue):
- """
- Add a residue at the end of the chain
-
- @param residue: the residue to be added
- @type residue: L{AminoAcidResidue} or L{NucleotideResidue}
- """
- self.residues.append(residue)
-
- def removeResidues(self, first, last):
- """
- Remove residues in a given index range.
-
- @param first: the index of the first residue to be removed
- @type first: C{int}
- @param last: the index of the first residue to be kept, or C{None}
- meaning remove everything to the end of the chain.
- @type last: C{int} or C{NoneType}
- """
- if last is None:
- del self.residues[first:]
- else:
- del self.residues[first:last]
-
- def deleteHydrogens(self):
- """
- Remove all hydrogen atoms in the chain
- """
- for r in self.residues:
- r.deleteHydrogens()
-
- def writeToFile(self, file):
- """
- Write the chain to a file
-
- @param file: a PDBFile object or a file name
- @type file: L{PDBFile} or C{str}
- """
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- file.nextChain(self.chain_id, self.segment_id)
- for r in self.residues:
- r.writeToFile(file)
- file.terminateChain()
- if close:
- file.close()
-
-
-class PDBPeptideChain(PDBChain):
- """
- Peptide chain in a PDB file
- """
-
- def isTerminated(self):
- """
- @returns: C{True} if the last residue is in C-terminal configuration
- @rtype: C{bool}
- """
- return self.residues and self.residues[-1].isCTerminus()
-
- def isCompatible(self, chain_data, residue_data):
- return (
- chain_data["chain_id"] == self.chain_id
- and chain_data["segment_id"] == self.segment_id
- and (
- residue_data["residue_name"] in RESIDUES_DATABASE
- or residue_data["residue_name"] in RESIDUE_ALT_NAMES
- )
- )
-
-
-class PDBNucleotideChain(PDBChain):
- """
- Nucleotide chain in a PDB file
- """
-
- def isTerminated(self):
- """
- @returns: C{True} if the last residue is in 3-terminal configuration
- @rtype: C{bool}
- @note: There is no way to perform this test with standard PDB files.
- The algorithm used works for certain non-standard files only.
- """
- return self.residues and (
- self.residues[-1].name[-1] == "3" or self.residues[-1].hasTerminalH()
- )
-
- def isCompatible(self, chain_data, residue_data):
- return (
- chain_data["chain_id"] == self.chain_id
- and chain_data["segment_id"] == self.segment_id
- and residue_data["residue_name"] in NUCLEOTIDES_DATABASE
- )
-
-
-class PDBDummyChain(PDBChain):
- def __init__(self, structure, chain_id, segment_id):
- self.structure = structure
- self.chain_id = chain_id
- self.segment_id = segment_id
-
- def isTerminated(self):
- return 0
-
- def addResidue(self, residue):
- self.structure.addMolecule(residue)
-
- def isCompatible(self, chain_data, residue_data):
- return (
- chain_data["chain_id"] == self.chain_id
- and chain_data["segment_id"] == self.segment_id
- and residue_data["residue_name"] not in RESIDUES_DATABASE
- and residue_data["residue_name"] not in RESIDUE_ALT_NAMES
- and residue_data["residue_name"] not in NUCLEOTIDES_DATABASE
- )
-
-
-#
-# Residue number class for dealing with insertion codes
-#
-class ResidueNumber:
- """
- PDB residue number
-
- Most PDB residue numbers are simple integers, but when insertion
- codes are used a number can consist of an integer plus a letter.
- Such compound residue numbers are represented by this class.
- """
-
- def __init__(self, number, insertion_code):
- """
- @param number: the numeric part of the residue number
- @type number: C{int}
- @param insertion_code: the letter part of the residue number
- @type insertion_code: C{str}
- """
- self.number = number
- self.insertion_code = insertion_code
-
- def __cmp__(self, other):
- if isinstance(other, int):
- if self.number == other:
- return 1
- else:
- return cmp(self.number, other)
- if self.number == other.number:
- return cmp(self.insertion_code, other.insertion_code)
- else:
- return cmp(self.number, other.number)
-
- def __str__(self):
- return str(self.number) + self.insertion_code
-
- __repr__ = __str__
-
-
-#
-# The configuration class.
-#
-class Structure:
- """
- A high-level representation of the contents of a PDB file
-
- The components of a structure can be accessed in several ways
- ('s' is an instance of this class):
-
- - 's.residues' is a list of all PDB residues, in the order in
- which they occurred in the file.
-
- - 's.peptide_chains' is a list of PeptideChain objects, containing
- all peptide chains in the file in their original order.
-
- - 's.nucleotide_chains' is a list of NucleotideChain objects, containing
- all nucleotide chains in the file in their original order.
-
- - 's.molecules' is a list of all PDB residues that are neither
- amino acid residues nor nucleotide residues, in their original
- order.
-
- - 's.objects' is a list of all high-level objects (peptide chains,
- nucleotide chains, and molecules) in their original order.
-
- - 's.to_fractional' is the transformation from real-space coordinates
- to fractional coordinates, as read from the SCALEn records.
-
- - 's.from_fractional' is the transformation from fractional coordinates
- to real-space coordinates, the inverse of s.to_fractional.
-
- - 's.ncs_transformations' is a list of transformations that
- describe non-crystallographic symmetries, as read from the
- MTRIXn records.
-
- - if a CRYST1 record exists, 's.a', 's.b', 's.c', 's.alpha',
- 's.beta', 's.gamma' are the parameters of the unit cell and
- 's.space_group' is a string indicating the space group.
- If no CRYST1 record exists, all those values are None.
- Furthermore, 's.cs_transformations' is a list of transformations
- that describe crystallographic symmetries. If no CRYST1 record
- exists, the list is empty.
-
- An iteration over a Structure instance by a for-loop is equivalent
- to an iteration over the residue list.
- """
-
- def __init__(self, file_or_filename, model=0, alternate_code="A"):
- """
- @param file_or_filename: the name of the PDB file, or a file object.
- Compressed files and URLs are accepted,
- as for class L{PDBFile}.
- @type file_or_filename: C{str} or C{file}
- @param model: the number of the model to read from a multiple-model
- file. Only one model can be treated at a time.
- @type model: C{int}
- @param alternate_code: the version of the positions to be read
- from a file with alternate positions.
- @type alternate_code: single-letter C{str}
- """
-
- if isinstance(file_or_filename, str):
- self.filename = file_or_filename
- else:
- self.filename = ""
- self.model = model
- self.alternate = alternate_code
- self.pdb_code = ""
- self.residues = []
- self.objects = []
- self.peptide_chains = []
- self.nucleotide_chains = []
- self.molecules = {}
- self.to_fractional = self.from_fractional = None
- self.ncs_transformations = []
- self.cs_transformations = []
- self.a = self.b = self.c = None
- self.alpha = self.beta = self.gamma = None
- self.space_group = None
- self.parseFile(PDBFile(file_or_filename, "rt"))
- self.findSpaceGroupTransformations()
-
- peptide_chain_constructor = PDBPeptideChain
- nucleotide_chain_constructor = PDBNucleotideChain
- molecule_constructor = PDBMolecule
-
- def __len__(self):
- return len(self.residues)
-
- def __getitem__(self, item):
- return self.residues[item]
-
- def addMolecule(self, molecule):
- try:
- molecule_list = self.molecules[molecule.name]
- except KeyError:
- molecule_list = []
- self.molecules[molecule.name] = molecule_list
- molecule_list.append(molecule)
- self.objects.append(molecule)
-
- def extractData(self, data):
- atom_data = {}
- for name in [
- "serial_number",
- "name",
- "position",
- "occupancy",
- "temperature_factor",
- ]:
- atom_data[name] = data[name]
- for name in ["alternate", "charge"]:
- value = data[name]
- if value:
- atom_data[name] = value
- element = data["element"]
- if element != "":
- try:
- int(element)
- except ValueError:
- atom_data["element"] = element
- residue_data = {"residue_name": data["residue_name"]}
- number = data["residue_number"]
- insertion = data["insertion_code"]
- if insertion == "":
- residue_data["residue_number"] = number
- else:
- residue_data["residue_number"] = ResidueNumber(number, insertion)
- chain_data = {}
- for name in ["chain_id", "segment_id"]:
- chain_data[name] = data[name]
- if chain_data["segment_id"] == self.pdb_code:
- chain_data["segment_id"] = ""
- return atom_data, residue_data, chain_data
-
- def newResidue(self, residue_data):
- name = residue_data["residue_name"]
- residue_number = residue_data["residue_number"]
- if name in RESIDUES_DATABASE or name in RESIDUE_ALT_NAMES:
- residue = PDBAminoAcidResidue(name, [], residue_number)
- elif name in NUCLEOTIDES_DATABASE:
- residue = PDBNucleotideResidue(name, [], residue_number)
- else:
- residue = self.molecule_constructor(name, [], residue_number)
- self.residues.append(residue)
- return residue
-
- def newChain(self, residue, chain_data):
- if hasattr(residue, "is_amino_acid"):
- chain = self.peptide_chain_constructor(
- [], chain_data["chain_id"], chain_data["segment_id"]
- )
- self.peptide_chains.append(chain)
- self.objects.append(chain)
- elif hasattr(residue, "is_nucleotide"):
- chain = self.nucleotide_chain_constructor(
- [], chain_data["chain_id"], chain_data["segment_id"]
- )
- self.nucleotide_chains.append(chain)
- self.objects.append(chain)
- else:
- chain = PDBDummyChain(
- self, chain_data["chain_id"], chain_data["segment_id"]
- )
- return chain
-
- def parseFile(self, file):
- atom = None
- residue = None
- chain = None
- read = self.model == 0
- while 1:
- type, data = file.readLine()
- if type == "END":
- break
- elif type == "HEADER":
- self.pdb_code = data["pdb_code"]
- elif type == "CRYST1":
- for name, value in list(data.items()):
- setattr(self, name, value)
- self.space_group = self.space_group.strip()
- elif type[:-1] == "SCALE":
- if not hasattr(self, "_scale_matrix"):
- self._scale_matrix = {}
- self._scale_matrix[type[-1]] = data
- if type[-1] == "3": # last line read
- from MDANSE.Mathematics.Transformation import Shear, Translation
-
- l1 = self._scale_matrix["1"]
- l2 = self._scale_matrix["2"]
- l3 = self._scale_matrix["3"]
- s = np.array(
- [
- [l1["s1"], l1["s2"], l1["s3"]],
- [l2["s1"], l2["s2"], l2["s3"]],
- [l3["s1"], l3["s2"], l3["s3"]],
- ]
- )
- u = Vector(l1["u"], l2["u"], l3["u"])
- self.to_fractional = Translation(u) * Shear(s)
- self.from_fractional = self.to_fractional.inverse()
- del self._scale_matrix
- elif type[:-1] == "MTRIX":
- if not hasattr(self, "_ncs_matrix"):
- self._ncs_matrix = {}
- self._ncs_matrix[type[-1]] = data
- if type[-1] == "3": # last line read
- from MDANSE.Mathematics.Transformation import Rotation, Translation
-
- l1 = self._ncs_matrix["1"]
- l2 = self._ncs_matrix["2"]
- l3 = self._ncs_matrix["3"]
- m = np.array(
- [
- [l1["m1"], l1["m2"], l1["m3"]],
- [l2["m1"], l2["m2"], l2["m3"]],
- [l3["m1"], l3["m2"], l3["m3"]],
- ]
- )
- v = Vector(l1["v"], l2["v"], l3["v"])
- tr = Translation(v) * Rotation(Tensor(m))
- tr.given = data["given"]
- tr.serial = data["serial"]
- self.ncs_transformations.append(tr)
- del self._ncs_matrix
- elif type == "MODEL":
- read = data["serial_number"] == self.model
- if self.model == 0 and len(self.residues) == 0:
- read = 1
- elif type == "ENDMDL":
- read = 0
- elif read:
- if type == "ATOM" or type == "HETATM":
- alt = data["alternate"]
- if alt == "" or alt == self.alternate:
- atom_data, residue_data, chain_data = self.extractData(data)
- if type == "ATOM":
- atom = PDBAtom(*(), **atom_data)
- else:
- atom = PDBHetAtom(*(), **atom_data)
- new_chain = chain is None or not chain.isCompatible(
- chain_data, residue_data
- )
- new_residue = (
- new_chain
- or residue is None
- or not residue.isCompatible(residue_data)
- )
- if new_residue and chain is not None and chain.isTerminated():
- new_chain = 1
- if new_residue:
- residue = self.newResidue(residue_data)
- if new_chain:
- chain = self.newChain(residue, chain_data)
- chain.addResidue(residue)
- residue.addAtom(atom)
- elif type == "ANISOU":
- alt = data["alternate"]
- if alt == "" or alt == self.alternate:
- if atom is None:
- raise ValueError("ANISOU record before " + "ATOM record")
- atom["u"] = data["u"]
- elif type == "TERM":
- if chain is None:
- raise ValueError("TERM record before chain")
- chain = None
-
- def findSpaceGroupTransformations(self):
- if self.space_group is not None and self.to_fractional is not None:
- from MDANSE.IO.PDBSpaceGroups import getSpaceGroupTransformations
-
- try:
- trs = getSpaceGroupTransformations(self.space_group)
- except KeyError:
- return
- for tr in trs:
- tr = self.from_fractional * tr * self.to_fractional
- self.cs_transformations.append(tr)
-
- def renumberAtoms(self):
- """
- Renumber all atoms sequentially starting with 1
- """
- n = 0
- for residue in self.residues:
- for atom in residue:
- atom["serial_number"] = n
- n = n + 1
-
- def __repr__(self):
- s = self.__class__.__name__ + "(" + repr(self.filename)
- if self.model != 0:
- s = s + ", model=" + repr(self.model)
- if self.alternate != "A":
- s = s + ", alternate_code = " + repr(self.alternate)
- s = s + "):\n"
- for name, list in [
- ("Peptide", self.peptide_chains),
- ("Nucleotide", self.nucleotide_chains),
- ]:
- for c in list:
- s = s + " " + name + " chain "
- if c.segment_id:
- s = s + c.segment_id + " "
- elif c.chain_id:
- s = s + c.chain_id + " "
- s = s + "of length " + repr(len(c)) + "\n"
- for name, list in self.molecules.items():
- s = s + " " + repr(len(list)) + " " + name + " molecule"
- if len(list) == 1:
- s = s + "\n"
- else:
- s = s + "s\n"
- return s
-
- def writeToFile(self, file):
- """
- Write everything to a file
-
- @param file: a PDB file object or a filename
- @type file: L{PDBFile} or C{str}
- """
- close = 0
- if type(file) == type(""):
- file = PDBFile(file, "w")
- close = 1
- for o in self.objects:
- o.writeToFile(file)
- if close:
- file.close()
diff --git a/MDANSE/Src/MDANSE/IO/PDBExportFilters.py b/MDANSE/Src/MDANSE/IO/PDBExportFilters.py
deleted file mode 100644
index f014ac45f5..0000000000
--- a/MDANSE/Src/MDANSE/IO/PDBExportFilters.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-
-class PDBExportFilter:
- def processLine(self, type, data):
- return type, data
-
- def processResidue(self, name, number, terminus):
- return name, number
-
- def processChain(self, chain_id, segment_id):
- return chain_id, segment_id
-
- def terminateChain(self):
- pass
-
-
-#
-# XPlor export filter
-
-import string
-
-
-class XPlorExportFilter(PDBExportFilter):
- xplor_atom_names = {" OXT": "OT2"}
-
- def processLine(self, type, data):
- if type == "TER":
- return None, data
- if type == "ATOM" or type == "HETATM" or type == "ANISOU":
- name = self.xplor_atom_names.get(data["name"], data["name"])
- data["name"] = name
- return type, data
-
-
-export_filters = {"xplor": XPlorExportFilter}
diff --git a/MDANSE/Src/MDANSE/IO/PDBReader.py b/MDANSE/Src/MDANSE/IO/PDBReader.py
deleted file mode 100644
index 52c0b66242..0000000000
--- a/MDANSE/Src/MDANSE/IO/PDBReader.py
+++ /dev/null
@@ -1,664 +0,0 @@
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-import copy
-import string
-
-import numpy as np
-
-from MDANSE.Chemistry.ChemicalEntity import (
- is_molecule,
- Atom,
- AtomCluster,
- ChemicalSystem,
- Molecule,
- Nucleotide,
- NucleotideChain,
- Residue,
- PeptideChain,
- Protein,
-)
-from MDANSE.Chemistry import (
- ATOMS_DATABASE,
- MOLECULES_DATABASE,
- NUCLEOTIDES_DATABASE,
- RESIDUES_DATABASE,
- RESIDUE_ALT_NAMES,
-)
-from MDANSE.IO.PDB import PDBMolecule, PDBNucleotideChain, PDBPeptideChain, Structure
-from MDANSE.MolecularDynamics.Configuration import RealConfiguration
-
-
-class PDBReaderError(Exception):
- pass
-
-
-class PDBReader:
- def __init__(self, filename):
- """Constructor.
-
- Args:
- filename (str): the input PDB file
- """
-
- self._chemicalEntities = []
-
- self._struct = Structure(filename)
-
- self._build_chemical_entities()
-
- def _build_chemical_entities(self):
- """Build the chemical entities stored in the PDB file."""
-
- peptide_chains = []
- for pdb_element in self._struct.objects:
- if isinstance(pdb_element, PDBPeptideChain):
- peptide_chains.append(self._process_peptide_chain(pdb_element))
- else:
- if peptide_chains:
- p = Protein()
- p.set_peptide_chains(peptide_chains)
- self._chemicalEntities.append(p)
- peptide_chains = []
-
- if isinstance(pdb_element, PDBNucleotideChain):
- self._chemicalEntities.append(
- self._process_nucleotide_chain(pdb_element)
- )
-
- elif isinstance(pdb_element, PDBMolecule):
- if len(pdb_element) == 1:
- self._chemicalEntities.append(
- self._process_atom(pdb_element[0])
- )
- else:
- if is_molecule(pdb_element.name):
- self._chemicalEntities.append(
- self._process_molecule(pdb_element)
- )
- else:
- self._chemicalEntities.append(
- self._process_atom_cluster(pdb_element)
- )
-
- if peptide_chains:
- p = Protein()
- p.set_peptide_chains(peptide_chains)
- self._chemicalEntities.append(p)
- peptide_chains = []
-
- def _guess_atom_symbol(self, atom):
- """Guess the atom symbol from an atom name.
-
- Args:
- atom (str): thhe atom name
-
- Returns:
- str: the atom symbol
- """
-
- atom_without_digits = "".join([at for at in atom if at not in string.digits])
-
- comp = 1
- while True:
- if atom_without_digits[:comp] in ATOMS_DATABASE:
- return atom_without_digits[:comp]
- comp += 1
- if comp > len(atom_without_digits):
- raise PDBReaderError(atom)
-
- def _process_atom(self, atom):
- """Process a PDB atom.
-
- Args:
- atom (MDANSE.IO.PDB.PDBAtom): the PDB entry corresponding to the atom
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Atom: the processed atom
- """
-
- atname = atom.name.capitalize()
-
- atom_found = None
- for at, info in ATOMS_DATABASE.items():
- if at == atname:
- atom_found = Atom(name=at, **info)
- else:
- for alt in info.get("alternatives", []):
- if alt == atname:
- copy_info = copy.deepcopy(info)
- atom_found = Atom(name=at, **copy_info)
- atom_found.position = atom.position
- break
- else:
- continue
-
- if atom_found is None:
- raise PDBReaderError("The atom {} is unknown".format(atname))
-
- return atom_found
-
- def _process_atom_cluster(self, atom_cluster):
- """Process a PDB atom cluster.
-
- Args:
- atom (MDANSE.IO.PDB.PDBAtomCluster): the PDB entry corresponding to the atom cluster
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.AtomCluster: the processed atom cluster
- """
-
- ac_name = atom_cluster.name
-
- pdb_atoms = [at.name for at in atom_cluster]
-
- atoms = []
- for at in pdb_atoms:
- symbol = self._guess_atom_symbol(at)
- atoms.append(Atom(name=at, symbol=symbol))
-
- new_atom_cluster = AtomCluster(ac_name, atoms)
-
- return new_atom_cluster
-
- def _process_molecule(self, molecule):
- """Process a PDB molecule.
-
- Args:
- atom (MDANSE.IO.PDB.PDBMolecule): the PDB entry corresponding to the molecule
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Molecule: the processed molecule
- """
-
- code = molecule.name
-
- pdb_atoms = [at.name for at in molecule]
-
- atoms_found = [None] * len(pdb_atoms)
- for at, info in MOLECULES_DATABASE[code]["atoms"].items():
- try:
- idx = pdb_atoms.index(at)
- atoms_found[idx] = at
- except ValueError:
- for alt in info["alternatives"]:
- try:
- idx = pdb_atoms.index(alt)
- atoms_found[idx] = at
- except ValueError:
- continue
- else:
- break
- else:
- raise PDBReaderError("Unknown atom")
-
- molname = "{}_{}".format(code, molecule.number)
- new_molecule = Molecule(code, molname)
- new_molecule.reorder_atoms(atoms_found)
-
- return new_molecule
-
- def _process_nter_residue(self, residue):
- """Process a N terminus residue.
-
- Args:
- residue (MDANSE.IO.PDB.PDBResidue): the residue
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Residue: the processed residue
- """
-
- code = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- atoms_found = [None] * len(pdb_atoms)
-
- atoms_not_found = []
-
- for comp, pdb_atom in enumerate(pdb_atoms):
- # Loop over the atoms of this residue stored in the corresponding residue database entry
- for at, info in RESIDUES_DATABASE[code]["atoms"].items():
- # A match was found, pass to the next PDB atom
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- # No match was found, the PDB atom is marked as not found
- else:
- atoms_not_found.append(pdb_atom)
-
- # Fetch all the N ter variants from the residues database
- nter_variants = [
- (name, res)
- for name, res in RESIDUES_DATABASE.items()
- if res["is_n_terminus"]
- ]
-
- # The atoms that has not been found so far will be searched now in the N ter variants entries of the database
- if atoms_not_found:
- # Loop over the N ter variants of the residues database
- for name, res in nter_variants:
- # Loop over the atom of the current variant
- for at, info in res["atoms"].items():
- # These are all the names the atoms can take (actual DB name + alternatives)
- allNames = [at] + info["alternatives"]
- for aa in allNames:
- # The variant atom match one of the not found atoms, mark it as known and pass to the next variant atom
- if aa in atoms_not_found:
- idx = pdb_atoms.index(aa)
- atoms_found[idx] = at
- break
- # The variant atom was not found in the not found atoms, this variant can not be the right one. Skip it.
- else:
- break
- # All the variant atoms has been found in the not found atoms, this variant is the right one
- else:
- nter = name
- break
- else:
- raise PDBReaderError("The atom {} is unknown".format(at))
-
- resname = "{}{}".format(code, residue.number)
- new_residue = Residue(code, resname, variant=nter)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_5ter_residue(self, residue):
- """Process a 5 ter terminus nucleotide.
-
- Args:
- residue (MDANSE.IO.PDB.PDBNucleotide): the nucleotide
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Nucleotide: the processed nucleotide
- """
-
- resname = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- atoms_found = [None] * len(pdb_atoms)
-
- atoms_not_found = []
-
- for comp, pdb_atom in enumerate(pdb_atoms):
- for at, info in NUCLEOTIDES_DATABASE[resname]["atoms"].items():
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- else:
- atoms_not_found.append(pdb_atom)
-
- ter5_variants = [
- (name, res)
- for name, res in NUCLEOTIDES_DATABASE.items()
- if res["is_5ter_terminus"]
- ]
-
- if atoms_not_found:
- for name, res in ter5_variants:
- for at, info in res["atoms"].items():
- allNames = [at] + info["alternatives"]
- for aa in allNames:
- if aa in atoms_not_found:
- idx = pdb_atoms.index(aa)
- atoms_found[idx] = at
- break
- else:
- break
- else:
- nter = name
- break
- else:
- raise PDBReaderError("The atom {} is unknown".format(at))
-
- new_residue = Nucleotide(resname, residue.number, variant=nter)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_cter_residue(self, residue):
- """Process the C terminal residue.
-
- Args:
- residue: MDANSE.IO.PDB.PDBResidue
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Residue: the C ter residue
- """
-
- code = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- atoms_found = [None] * len(pdb_atoms)
-
- # Loop over the PDB atoms of this residue
- atoms_not_found = []
- for comp, pdb_atom in enumerate(pdb_atoms):
- # Loop over the atoms of this residue stored in the corresponding residue database entry
- for at, info in RESIDUES_DATABASE[code]["atoms"].items():
- # A match was found, pass to the next PDB atom
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- # No match was found, the PDB atom is marked as not found
- else:
- atoms_not_found.append(pdb_atom)
-
- # Fetch all the C ter variants from the residues database
- cter_variants = [
- (name, res)
- for name, res in RESIDUES_DATABASE.items()
- if res["is_c_terminus"]
- ]
-
- # The atoms that has not been found so far will be searched now in the C ter variants entries of the database
- cter = None
- if atoms_not_found:
- # Loop over the C ter variants of the residues database
- for name, res in cter_variants:
- # Loop over the atom of the current variant
- for at, info in res["atoms"].items():
- # These are all the names the atoms can take (actual DB name + alternatives)
- allNames = [at] + info["alternatives"]
- for aa in allNames:
- # The variant atom match one of the not found atoms, mark it as known and pass to the next variant atom
- if aa in atoms_not_found:
- idx = pdb_atoms.index(aa)
- atoms_found[idx] = at
- break
- # The variant atom was not found in the not found atoms, this variant can not be the right one. Skip it.
- else:
- break
- # All the variant atoms has been found in the not found atoms, this variant is the right one
- else:
- cter = name
- break
- else:
- raise PDBReaderError("The atoms {} are unknown".format(atoms_not_found))
-
- if cter is None:
- raise PDBReaderError(
- "Could not find a suitable CTER variant for residue {}{}".format(
- residue.name, residue.number
- )
- )
-
- resname = "{}{}".format(code, residue.number)
- new_residue = Residue(code, resname, variant=cter)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_3ter_residue(self, residue):
- """Process the 3 ter terminal nucleotide.
-
- Args:
- residue: MDANSE.IO.PDB.PDBNucleotide
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Nucleotide: the 3 ter nucleotide
- """
-
- resname = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- atoms_found = [None] * len(pdb_atoms)
-
- atoms_not_found = []
-
- for comp, pdb_atom in enumerate(pdb_atoms):
- for at, info in NUCLEOTIDES_DATABASE[resname]["atoms"].items():
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- else:
- atoms_not_found.append(pdb_atom)
-
- ter3_variants = [
- (name, res)
- for name, res in NUCLEOTIDES_DATABASE.items()
- if res["is_3ter_terminus"]
- ]
-
- if atoms_not_found:
- for name, res in ter3_variants:
- for at, info in res["atoms"].items():
- allNames = [at] + info["alternatives"]
- for aa in allNames:
- if aa in atoms_not_found:
- idx = pdb_atoms.index(aa)
- atoms_found[idx] = at
- break
- else:
- break
- else:
- cter = name
- break
- else:
- raise PDBReaderError("The atom {} is unknown".format(at))
-
- new_residue = Nucleotide(resname, residue.number, variant=cter)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_residue(self, residue):
- """Process a residue.
-
- Args:
- residue (MDANSE.IO.PDB.PDBResidue): the PDB residue
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Residue: the processed residue
- """
-
- code = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- if code in RESIDUE_ALT_NAMES:
- # RESIDUES_DATABASE is a many-to-one map multiple codes
- # can map to one residue in MDANSE.
- # If the code is in RESIDUE_ALT_NAMES then it is a
- # many-to-many map. In this case the code can map to many
- # different residues.
- for new_code in RESIDUE_ALT_NAMES[code]:
- # go through each name that code could be
- atoms_found = [None] * len(pdb_atoms)
- for comp, pdb_atom in enumerate(pdb_atoms):
- if len(atoms_found) != len(
- RESIDUES_DATABASE[new_code]["atoms"].items()
- ):
- # different number of atoms break and try the next name
- break
- for at, info in RESIDUES_DATABASE[new_code]["atoms"].items():
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- else:
- # unable to match the atom in the RESIDUES_DATABASE
- # try the next residue name
- break
- if None not in atoms_found:
- # matched all atoms found the residue so break
- break
- else:
- # went through all alternative names looks like we were
- # unable to match the code to the MDANSE residues
- raise PDBReaderError(
- "Unable to find residue for {}{}".format(code, residue.number)
- )
- # found the match from the alternate name to the name in
- # mdanse lets rename the code
- code = new_code
- residue.name = code
-
- else:
- atoms_found = [None] * len(pdb_atoms)
- for comp, pdb_atom in enumerate(pdb_atoms):
- for at, info in RESIDUES_DATABASE[code]["atoms"].items():
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- else:
- raise PDBReaderError(
- "The atom {}{}:{} is unknown".format(
- code, residue.number, pdb_atom
- )
- )
-
- resname = "{}{}".format(code, residue.number)
- new_residue = Residue(code, resname, variant=None)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_nucleotide(self, residue):
- """Process a nucleotide.
-
- Args:
- residue (MDANSE.IO.PDB.PDBNucleotide): the PDB nucleotide
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.Nucleotide: the processed nucleotide
- """
-
- resname = residue.name
-
- pdb_atoms = [at.name for at in residue]
-
- atoms_found = [None] * len(pdb_atoms)
-
- atoms_not_found = []
-
- for comp, pdb_atom in enumerate(pdb_atoms):
- for at, info in NUCLEOTIDES_DATABASE[resname]["atoms"].items():
- if pdb_atom == at or pdb_atom in info["alternatives"]:
- atoms_found[comp] = at
- break
- else:
- atoms_not_found.append(pdb_atom)
-
- if atoms_not_found:
- raise PDBReaderError("The atoms {} are unknown".format(atoms_not_found))
-
- new_residue = Nucleotide(resname, residue.number, variant=None)
- new_residue.set_atoms(atoms_found)
-
- return new_residue
-
- def _process_nucleotide_chain(self, pdb_element):
- """Process a PDB nucleotide chain.
-
- Args:
- pdb_element (MDANSE.IO.PDB.PDBNucleotideChain): the PDB nucleotide chain to process
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.NucleotideChain: the process nucleotide chain
- """
-
- nucleotide_chain = NucleotideChain(pdb_element.chain_id)
- residues = []
- # Loop over the residues of the nucleotide chain
- for comp, residue in enumerate(pdb_element.residues):
- # Case the 5 ter residue
- if comp == 0:
- res = self._process_5ter_residue(residue)
- # Case the 3 ter residue
- elif comp == len(pdb_element.residues) - 1:
- res = self._process_3ter_residue(residue)
- # Normal residue
- else:
- res = self._process_nucleotide(residue)
- residues.append(res)
- nucleotide_chain.set_nucleotides(residues)
-
- return nucleotide_chain
-
- def _process_peptide_chain(self, pdb_element):
- """Process a PDB peptide chain.
-
- Args:
- pdb_element (MDANSE.IO.PDB.PeptideChain): the PDB peptide chain to process
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.PeptideChain: the process peptide chain
- """
-
- peptide_chain = PeptideChain(pdb_element.chain_id)
- residues = []
- for comp, residue in enumerate(pdb_element.residues):
- if comp == 0:
- res = self._process_nter_residue(residue)
- elif comp == len(pdb_element.residues) - 1:
- res = self._process_cter_residue(residue)
- else:
- res = self._process_residue(residue)
- residues.append(res)
- peptide_chain.set_residues(residues)
-
- return peptide_chain
-
- def build_chemical_system(self):
- """Build the chemical system.
-
- Returns:
- MDANSE.Chemistry.ChemicalEntity.ChemicalSystem: the chemical system
- """
-
- chemical_system = ChemicalSystem()
-
- for ce in self._chemicalEntities:
- chemical_system.add_chemical_entity(ce)
-
- coordinates = []
- for obj in self._struct:
- for atom in obj.atom_list:
- coordinates.append(atom.position)
- coordinates = np.array(coordinates)
- coordinates *= 0.1
-
- chemical_system.configuration = RealConfiguration(chemical_system, coordinates)
-
- return chemical_system
-
-
-if __name__ == "__main__":
- print("Reading")
- pdb_reader = PDBReader("/home/pellegrini/apoferritin.pdb")
- print("Building chemical system")
- cs = pdb_reader.build_chemical_system()
-
- conf = RealConfiguration(
- cs,
- np.empty((cs.number_of_atoms(), 3), dtype=np.float64),
- np.empty((3, 3), dtype=np.float64),
- **{"velocities": np.empty((cs.number_of_atoms(), 3), dtype=np.float64)},
- )
- cs.configuration = conf
-
- cs1 = cs.copy()
-
- print(cs1.configuration["velocities"])
-
- # print('Serializing')
- # cs.serialize('test.h5')
- # print('Loading')
- # cs.load('test.h5')
- # print(cs.chemical_entities)
diff --git a/MDANSE/Src/MDANSE/IO/PDBSpaceGroups.py b/MDANSE/Src/MDANSE/IO/PDBSpaceGroups.py
deleted file mode 100644
index cb88673056..0000000000
--- a/MDANSE/Src/MDANSE/IO/PDBSpaceGroups.py
+++ /dev/null
@@ -1,4380 +0,0 @@
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import numpy as np
-
-from MDANSE.Mathematics.LinearAlgebra import Vector, Tensor
-from MDANSE.Mathematics.Transformation import Rotation, Translation
-
-
-class SpaceGroup(object):
- def __init__(self, number, labels, transformations):
- self.number = number
- self.labels = labels
- self.transformations = []
- for rot, trans in transformations:
- self.transformations.append(Translation(trans) * Rotation(Tensor(rot)))
-
-
-_space_group_table = {}
-
-
-def getSpaceGroupTransformations(space_group_label_or_number):
- try:
- return _space_group_table[space_group_label_or_number].transformations
- except KeyError:
- pass
- space_group_label = "".join(space_group_label_or_number.split())
- return _space_group_table[space_group_label].transformations
-
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(1, ["C1^1", "1", "P 1", "P1"], transformations)
-_space_group_table[1] = sg
-_space_group_table["C1^1"] = sg
-_space_group_table["1"] = sg
-_space_group_table["P 1"] = sg
-_space_group_table["P1"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 3,
- [
- "C2^1",
- "P 2y",
- "P121",
- "P2:b",
- "3:b",
- "C2^1",
- "P 2",
- "P112",
- "P2:c",
- "3:c",
- "C2^1",
- "P 2x",
- "P211",
- "P2:a",
- "3:a",
- ],
- transformations,
-)
-_space_group_table[3] = sg
-_space_group_table["C2^1"] = sg
-_space_group_table["P 2y"] = sg
-_space_group_table["P121"] = sg
-_space_group_table["P2:b"] = sg
-_space_group_table["3:b"] = sg
-_space_group_table["C2^1"] = sg
-_space_group_table["P 2"] = sg
-_space_group_table["P112"] = sg
-_space_group_table["P2:c"] = sg
-_space_group_table["3:c"] = sg
-_space_group_table["C2^1"] = sg
-_space_group_table["P 2x"] = sg
-_space_group_table["P211"] = sg
-_space_group_table["P2:a"] = sg
-_space_group_table["3:a"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 4,
- [
- "C2^2",
- "P 2yb",
- "P1211",
- "P21:b",
- "4:b",
- "C2^2",
- "P 2c",
- "P1121",
- "P21:c",
- "4:c",
- "C2^2",
- "P 2xa",
- "P2111",
- "P21:a",
- "4:a",
- ],
- transformations,
-)
-_space_group_table[4] = sg
-_space_group_table["C2^2"] = sg
-_space_group_table["P 2yb"] = sg
-_space_group_table["P1211"] = sg
-_space_group_table["P21:b"] = sg
-_space_group_table["4:b"] = sg
-_space_group_table["C2^2"] = sg
-_space_group_table["P 2c"] = sg
-_space_group_table["P1121"] = sg
-_space_group_table["P21:c"] = sg
-_space_group_table["4:c"] = sg
-_space_group_table["C2^2"] = sg
-_space_group_table["P 2xa"] = sg
-_space_group_table["P2111"] = sg
-_space_group_table["P21:a"] = sg
-_space_group_table["4:a"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 5,
- [
- "C2^3",
- "C 2y",
- "C121",
- "C2:b1",
- "5:b1",
- "C2^3",
- "A 2y",
- "A121",
- "C2:b2",
- "5:b2",
- "C2^3",
- "I 2y",
- "I121",
- "C2:b3",
- "5:b3",
- "C2^3",
- "A 2",
- "A112",
- "C2:c1",
- "5:c1",
- "C2^3",
- "B 2",
- "B2",
- "B112",
- "C2:c2",
- "5:c2",
- "C2^3",
- "I 2",
- "I112",
- "C2:c3",
- "5:c3",
- "C2^3",
- "B 2x",
- "B211",
- "C2:a1",
- "5:a1",
- "C2^3",
- "C 2x",
- "C211",
- "C2:a2",
- "5:a2",
- "C2^3",
- "I 2x",
- "I211",
- "C2:a3",
- "5:a3",
- ],
- transformations,
-)
-_space_group_table[5] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["C 2y"] = sg
-_space_group_table["C121"] = sg
-_space_group_table["C2:b1"] = sg
-_space_group_table["5:b1"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["A 2y"] = sg
-_space_group_table["A121"] = sg
-_space_group_table["C2:b2"] = sg
-_space_group_table["5:b2"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["I 2y"] = sg
-_space_group_table["I121"] = sg
-_space_group_table["C2:b3"] = sg
-_space_group_table["5:b3"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["A 2"] = sg
-_space_group_table["A112"] = sg
-_space_group_table["C2:c1"] = sg
-_space_group_table["5:c1"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["B 2"] = sg
-_space_group_table["B2"] = sg
-_space_group_table["B112"] = sg
-_space_group_table["C2:c2"] = sg
-_space_group_table["5:c2"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["I 2"] = sg
-_space_group_table["I112"] = sg
-_space_group_table["C2:c3"] = sg
-_space_group_table["5:c3"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["B 2x"] = sg
-_space_group_table["B211"] = sg
-_space_group_table["C2:a1"] = sg
-_space_group_table["5:a1"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["C 2x"] = sg
-_space_group_table["C211"] = sg
-_space_group_table["C2:a2"] = sg
-_space_group_table["5:a2"] = sg
-_space_group_table["C2^3"] = sg
-_space_group_table["I 2x"] = sg
-_space_group_table["I211"] = sg
-_space_group_table["C2:a3"] = sg
-_space_group_table["5:a3"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(16, ["D2^1", "16", "P 2 2", "P222"], transformations)
-_space_group_table[16] = sg
-_space_group_table["D2^1"] = sg
-_space_group_table["16"] = sg
-_space_group_table["P 2 2"] = sg
-_space_group_table["P222"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 17,
- [
- "D2^2",
- "17",
- "P 2c 2",
- "P2221",
- "D2^2",
- "P 2a 2a",
- "P2122",
- "17:cab",
- "D2^2",
- "P 2 2b",
- "P2212",
- "17:bca",
- ],
- transformations,
-)
-_space_group_table[17] = sg
-_space_group_table["D2^2"] = sg
-_space_group_table["17"] = sg
-_space_group_table["P 2c 2"] = sg
-_space_group_table["P2221"] = sg
-_space_group_table["D2^2"] = sg
-_space_group_table["P 2a 2a"] = sg
-_space_group_table["P2122"] = sg
-_space_group_table["17:cab"] = sg
-_space_group_table["D2^2"] = sg
-_space_group_table["P 2 2b"] = sg
-_space_group_table["P2212"] = sg
-_space_group_table["17:bca"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 18,
- [
- "D2^3",
- "18",
- "P 2 2ab",
- "P21212",
- "D2^3",
- "P 2bc 2",
- "P22121",
- "18:cab",
- "D2^3",
- "P 2ac 2ac",
- "P21221",
- "18:bca",
- ],
- transformations,
-)
-_space_group_table[18] = sg
-_space_group_table["D2^3"] = sg
-_space_group_table["18"] = sg
-_space_group_table["P 2 2ab"] = sg
-_space_group_table["P21212"] = sg
-_space_group_table["D2^3"] = sg
-_space_group_table["P 2bc 2"] = sg
-_space_group_table["P22121"] = sg
-_space_group_table["18:cab"] = sg
-_space_group_table["D2^3"] = sg
-_space_group_table["P 2ac 2ac"] = sg
-_space_group_table["P21221"] = sg
-_space_group_table["18:bca"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(19, ["D2^4", "19", "P 2ac 2ab", "P212121"], transformations)
-_space_group_table[19] = sg
-_space_group_table["D2^4"] = sg
-_space_group_table["19"] = sg
-_space_group_table["P 2ac 2ab"] = sg
-_space_group_table["P212121"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 20,
- [
- "D2^5",
- "20",
- "C 2c 2",
- "C2221",
- "D2^5",
- "A 2a 2a",
- "A2122",
- "20:cab",
- "D2^5",
- "B 2 2b",
- "B2212",
- "20:bca",
- ],
- transformations,
-)
-_space_group_table[20] = sg
-_space_group_table["D2^5"] = sg
-_space_group_table["20"] = sg
-_space_group_table["C 2c 2"] = sg
-_space_group_table["C2221"] = sg
-_space_group_table["D2^5"] = sg
-_space_group_table["A 2a 2a"] = sg
-_space_group_table["A2122"] = sg
-_space_group_table["20:cab"] = sg
-_space_group_table["D2^5"] = sg
-_space_group_table["B 2 2b"] = sg
-_space_group_table["B2212"] = sg
-_space_group_table["20:bca"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 21,
- [
- "D2^6",
- "21",
- "C 2 2",
- "C222",
- "D2^6",
- "A 2 2",
- "A222",
- "21:cab",
- "D2^6",
- "B 2 2",
- "B222",
- "21:bca",
- ],
- transformations,
-)
-_space_group_table[21] = sg
-_space_group_table["D2^6"] = sg
-_space_group_table["21"] = sg
-_space_group_table["C 2 2"] = sg
-_space_group_table["C222"] = sg
-_space_group_table["D2^6"] = sg
-_space_group_table["A 2 2"] = sg
-_space_group_table["A222"] = sg
-_space_group_table["21:cab"] = sg
-_space_group_table["D2^6"] = sg
-_space_group_table["B 2 2"] = sg
-_space_group_table["B222"] = sg
-_space_group_table["21:bca"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(22, ["D2^7", "22", "F 2 2", "F222"], transformations)
-_space_group_table[22] = sg
-_space_group_table["D2^7"] = sg
-_space_group_table["22"] = sg
-_space_group_table["F 2 2"] = sg
-_space_group_table["F222"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(23, ["D2^8", "23", "I 2 2", "I222"], transformations)
-_space_group_table[23] = sg
-_space_group_table["D2^8"] = sg
-_space_group_table["23"] = sg
-_space_group_table["I 2 2"] = sg
-_space_group_table["I222"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(24, ["D2^9", "24", "I 2b 2c", "I212121"], transformations)
-_space_group_table[24] = sg
-_space_group_table["D2^9"] = sg
-_space_group_table["24"] = sg
-_space_group_table["I 2b 2c"] = sg
-_space_group_table["I212121"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(75, ["C4^1", "75", "P 4", "P4"], transformations)
-_space_group_table[75] = sg
-_space_group_table["C4^1"] = sg
-_space_group_table["75"] = sg
-_space_group_table["P 4"] = sg
-_space_group_table["P4"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(76, ["C4^2", "76", "P 4w", "P41"], transformations)
-_space_group_table[76] = sg
-_space_group_table["C4^2"] = sg
-_space_group_table["76"] = sg
-_space_group_table["P 4w"] = sg
-_space_group_table["P41"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(77, ["C4^3", "77", "P 4c", "P42"], transformations)
-_space_group_table[77] = sg
-_space_group_table["C4^3"] = sg
-_space_group_table["77"] = sg
-_space_group_table["P 4c"] = sg
-_space_group_table["P42"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(78, ["C4^4", "78", "P 4cw", "P43"], transformations)
-_space_group_table[78] = sg
-_space_group_table["C4^4"] = sg
-_space_group_table["78"] = sg
-_space_group_table["P 4cw"] = sg
-_space_group_table["P43"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(79, ["C4^5", "79", "I 4", "I4"], transformations)
-_space_group_table[79] = sg
-_space_group_table["C4^5"] = sg
-_space_group_table["79"] = sg
-_space_group_table["I 4"] = sg
-_space_group_table["I4"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(80, ["C4^6", "80", "I 4bw", "I41"], transformations)
-_space_group_table[80] = sg
-_space_group_table["C4^6"] = sg
-_space_group_table["80"] = sg
-_space_group_table["I 4bw"] = sg
-_space_group_table["I41"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(89, ["D4^1", "89", "P 4 2", "P422"], transformations)
-_space_group_table[89] = sg
-_space_group_table["D4^1"] = sg
-_space_group_table["89"] = sg
-_space_group_table["P 4 2"] = sg
-_space_group_table["P422"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(90, ["D4^2", "90", "P 4ab 2ab", "P4212"], transformations)
-_space_group_table[90] = sg
-_space_group_table["D4^2"] = sg
-_space_group_table["90"] = sg
-_space_group_table["P 4ab 2ab"] = sg
-_space_group_table["P4212"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(91, ["D4^3", "91", "P 4w 2c", "P4122"], transformations)
-_space_group_table[91] = sg
-_space_group_table["D4^3"] = sg
-_space_group_table["91"] = sg
-_space_group_table["P 4w 2c"] = sg
-_space_group_table["P4122"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(92, ["D4^4", "92", "P 4abw 2nw", "P41212"], transformations)
-_space_group_table[92] = sg
-_space_group_table["D4^4"] = sg
-_space_group_table["92"] = sg
-_space_group_table["P 4abw 2nw"] = sg
-_space_group_table["P41212"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(93, ["D4^5", "93", "P 4c 2", "P4222"], transformations)
-_space_group_table[93] = sg
-_space_group_table["D4^5"] = sg
-_space_group_table["93"] = sg
-_space_group_table["P 4c 2"] = sg
-_space_group_table["P4222"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(94, ["D4^6", "94", "P 4n 2n", "P42212"], transformations)
-_space_group_table[94] = sg
-_space_group_table["D4^6"] = sg
-_space_group_table["94"] = sg
-_space_group_table["P 4n 2n"] = sg
-_space_group_table["P42212"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(95, ["D4^7", "95", "P 4cw 2c", "P4322"], transformations)
-_space_group_table[95] = sg
-_space_group_table["D4^7"] = sg
-_space_group_table["95"] = sg
-_space_group_table["P 4cw 2c"] = sg
-_space_group_table["P4322"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(96, ["D4^8", "96", "P 4nw 2abw", "P43212"], transformations)
-_space_group_table[96] = sg
-_space_group_table["D4^8"] = sg
-_space_group_table["96"] = sg
-_space_group_table["P 4nw 2abw"] = sg
-_space_group_table["P43212"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(97, ["D4^9", "97", "I 4 2", "I422"], transformations)
-_space_group_table[97] = sg
-_space_group_table["D4^9"] = sg
-_space_group_table["97"] = sg
-_space_group_table["I 4 2"] = sg
-_space_group_table["I422"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(98, ["D4^10", "98", "I 4bw 2bw", "I4122"], transformations)
-_space_group_table[98] = sg
-_space_group_table["D4^10"] = sg
-_space_group_table["98"] = sg
-_space_group_table["I 4bw 2bw"] = sg
-_space_group_table["I4122"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(143, ["C3^1", "143", "P 3", "P3"], transformations)
-_space_group_table[143] = sg
-_space_group_table["C3^1"] = sg
-_space_group_table["143"] = sg
-_space_group_table["P 3"] = sg
-_space_group_table["P3"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(144, ["C3^2", "144", "P 31", "P31"], transformations)
-_space_group_table[144] = sg
-_space_group_table["C3^2"] = sg
-_space_group_table["144"] = sg
-_space_group_table["P 31"] = sg
-_space_group_table["P31"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(145, ["C3^3", "145", "P 32", "P32"], transformations)
-_space_group_table[145] = sg
-_space_group_table["C3^3"] = sg
-_space_group_table["145"] = sg
-_space_group_table["P 32"] = sg
-_space_group_table["P32"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 146,
- ["C3^4", "R 3", "H 3", "R3:H", "146:H", "C3^4", "P 3*", "R3:R", "146:R"],
- transformations,
-)
-_space_group_table[146] = sg
-_space_group_table["C3^4"] = sg
-_space_group_table["R 3"] = sg
-_space_group_table["H 3"] = sg
-_space_group_table["R3:H"] = sg
-_space_group_table["146:H"] = sg
-_space_group_table["C3^4"] = sg
-_space_group_table["P 3*"] = sg
-_space_group_table["R3:R"] = sg
-_space_group_table["146:R"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(149, ["D3^1", "149", "P 3 2", "P312"], transformations)
-_space_group_table[149] = sg
-_space_group_table["D3^1"] = sg
-_space_group_table["149"] = sg
-_space_group_table["P 3 2"] = sg
-_space_group_table["P312"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(150, ["D3^2", "150", 'P 3 2"', "P321"], transformations)
-_space_group_table[150] = sg
-_space_group_table["D3^2"] = sg
-_space_group_table["150"] = sg
-_space_group_table['P 3 2"'] = sg
-_space_group_table["P321"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(151, ["D3^3", "151", "P 31 2c (0 0 1)", "P3112"], transformations)
-_space_group_table[151] = sg
-_space_group_table["D3^3"] = sg
-_space_group_table["151"] = sg
-_space_group_table["P 31 2c (0 0 1)"] = sg
-_space_group_table["P3112"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(152, ["D3^4", "152", 'P 31 2"', "P3121"], transformations)
-_space_group_table[152] = sg
-_space_group_table["D3^4"] = sg
-_space_group_table["152"] = sg
-_space_group_table['P 31 2"'] = sg
-_space_group_table["P3121"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(153, ["D3^5", "153", "P 32 2c (0 0 -1)", "P3212"], transformations)
-_space_group_table[153] = sg
-_space_group_table["D3^5"] = sg
-_space_group_table["153"] = sg
-_space_group_table["P 32 2c (0 0 -1)"] = sg
-_space_group_table["P3212"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(154, ["D3^6", "154", 'P 32 2"', "P3221"], transformations)
-_space_group_table[154] = sg
-_space_group_table["D3^6"] = sg
-_space_group_table["154"] = sg
-_space_group_table['P 32 2"'] = sg
-_space_group_table["P3221"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 3.0, 2.0 / 3.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(2.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(
- 155,
- ["D3^7", "R 3 2", "H 3 2", "R32:H", "155:H", "D3^7", "P 3* 2", "R32:R", "155:R"],
- transformations,
-)
-_space_group_table[155] = sg
-_space_group_table["D3^7"] = sg
-_space_group_table["R 3 2"] = sg
-_space_group_table["H 3 2"] = sg
-_space_group_table["R32:H"] = sg
-_space_group_table["155:H"] = sg
-_space_group_table["D3^7"] = sg
-_space_group_table["P 3* 2"] = sg
-_space_group_table["R32:R"] = sg
-_space_group_table["155:R"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(168, ["C6^1", "168", "P 6", "P6"], transformations)
-_space_group_table[168] = sg
-_space_group_table["C6^1"] = sg
-_space_group_table["168"] = sg
-_space_group_table["P 6"] = sg
-_space_group_table["P6"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(169, ["C6^2", "169", "P 61", "P61"], transformations)
-_space_group_table[169] = sg
-_space_group_table["C6^2"] = sg
-_space_group_table["169"] = sg
-_space_group_table["P 61"] = sg
-_space_group_table["P61"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(170, ["C6^3", "170", "P 65", "P65"], transformations)
-_space_group_table[170] = sg
-_space_group_table["C6^3"] = sg
-_space_group_table["170"] = sg
-_space_group_table["P 65"] = sg
-_space_group_table["P65"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(171, ["C6^4", "171", "P 62", "P62"], transformations)
-_space_group_table[171] = sg
-_space_group_table["C6^4"] = sg
-_space_group_table["171"] = sg
-_space_group_table["P 62"] = sg
-_space_group_table["P62"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(172, ["C6^5", "172", "P 64", "P64"], transformations)
-_space_group_table[172] = sg
-_space_group_table["C6^5"] = sg
-_space_group_table["172"] = sg
-_space_group_table["P 64"] = sg
-_space_group_table["P64"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(173, ["C6^6", "173", "P 6c", "P63"], transformations)
-_space_group_table[173] = sg
-_space_group_table["C6^6"] = sg
-_space_group_table["173"] = sg
-_space_group_table["P 6c"] = sg
-_space_group_table["P63"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(177, ["D6^1", "177", "P 6 2", "P622"], transformations)
-_space_group_table[177] = sg
-_space_group_table["D6^1"] = sg
-_space_group_table["177"] = sg
-_space_group_table["P 6 2"] = sg
-_space_group_table["P622"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(178, ["D6^2", "178", "P 61 2 (0 0 -1)", "P6122"], transformations)
-_space_group_table[178] = sg
-_space_group_table["D6^2"] = sg
-_space_group_table["178"] = sg
-_space_group_table["P 61 2 (0 0 -1)"] = sg
-_space_group_table["P6122"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 6.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 5.0 / 6.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(179, ["D6^3", "179", "P 65 2 (0 0 1)", "P6522"], transformations)
-_space_group_table[179] = sg
-_space_group_table["D6^3"] = sg
-_space_group_table["179"] = sg
-_space_group_table["P 65 2 (0 0 1)"] = sg
-_space_group_table["P6522"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(180, ["D6^4", "180", "P 62 2c (0 0 1)", "P6222"], transformations)
-_space_group_table[180] = sg
-_space_group_table["D6^4"] = sg
-_space_group_table["180"] = sg
-_space_group_table["P 62 2c (0 0 1)"] = sg
-_space_group_table["P6222"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 3.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 2.0 / 3.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(181, ["D6^5", "181", "P 64 2c (0 0 01)", "P6422"], transformations)
-_space_group_table[181] = sg
-_space_group_table["D6^5"] = sg
-_space_group_table["181"] = sg
-_space_group_table["P 64 2c (0 0 01)"] = sg
-_space_group_table["P6422"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, -1, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, -1, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 1, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 1, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(182, ["D6^6", "182", "P 6c 2c", "P6322"], transformations)
-_space_group_table[182] = sg
-_space_group_table["D6^6"] = sg
-_space_group_table["182"] = sg
-_space_group_table["P 6c 2c"] = sg
-_space_group_table["P6322"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(195, ["T^1", "195", "P 2 2 3", "P23"], transformations)
-_space_group_table[195] = sg
-_space_group_table["T^1"] = sg
-_space_group_table["195"] = sg
-_space_group_table["P 2 2 3"] = sg
-_space_group_table["P23"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(196, ["T^2", "196", "F 2 2 3", "F23"], transformations)
-_space_group_table[196] = sg
-_space_group_table["T^2"] = sg
-_space_group_table["196"] = sg
-_space_group_table["F 2 2 3"] = sg
-_space_group_table["F23"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(197, ["T^3", "197", "I 2 2 3", "I23"], transformations)
-_space_group_table[197] = sg
-_space_group_table["T^3"] = sg
-_space_group_table["197"] = sg
-_space_group_table["I 2 2 3"] = sg
-_space_group_table["I23"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(198, ["T^4", "198", "P 2ac 2ab 3", "P213"], transformations)
-_space_group_table[198] = sg
-_space_group_table["T^4"] = sg
-_space_group_table["198"] = sg
-_space_group_table["P 2ac 2ab 3"] = sg
-_space_group_table["P213"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(199, ["T^5", "199", "I 2b 2c 3", "I213"], transformations)
-_space_group_table[199] = sg
-_space_group_table["T^5"] = sg
-_space_group_table["199"] = sg
-_space_group_table["I 2b 2c 3"] = sg
-_space_group_table["I213"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(207, ["O^1", "207", "P 4 2 3", "P432"], transformations)
-_space_group_table[207] = sg
-_space_group_table["O^1"] = sg
-_space_group_table["207"] = sg
-_space_group_table["P 4 2 3"] = sg
-_space_group_table["P432"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(208, ["O^2", "208", "P 4n 2 3", "P4232"], transformations)
-_space_group_table[208] = sg
-_space_group_table["O^2"] = sg
-_space_group_table["208"] = sg
-_space_group_table["P 4n 2 3"] = sg
-_space_group_table["P4232"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(209, ["O^3", "209", "F 4 2 3", "F432"], transformations)
-_space_group_table[209] = sg
-_space_group_table["O^3"] = sg
-_space_group_table["209"] = sg
-_space_group_table["F 4 2 3"] = sg
-_space_group_table["F432"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(210, ["O^4", "210", "F 4d 2 3", "F4132"], transformations)
-_space_group_table[210] = sg
-_space_group_table["O^4"] = sg
-_space_group_table["210"] = sg
-_space_group_table["F 4d 2 3"] = sg
-_space_group_table["F4132"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(211, ["O^5", "211", "I 4 2 3", "I432"], transformations)
-_space_group_table[211] = sg
-_space_group_table["O^5"] = sg
-_space_group_table["211"] = sg
-_space_group_table["I 4 2 3"] = sg
-_space_group_table["I432"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(212, ["O^6", "212", "P 4acd 2ab 3", "P4332"], transformations)
-_space_group_table[212] = sg
-_space_group_table["O^6"] = sg
-_space_group_table["212"] = sg
-_space_group_table["P 4acd 2ab 3"] = sg
-_space_group_table["P4332"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(213, ["O^7", "213", "P 4bd 2ab 3", "P4132"], transformations)
-_space_group_table[213] = sg
-_space_group_table["O^7"] = sg
-_space_group_table["213"] = sg
-_space_group_table["P 4bd 2ab 3"] = sg
-_space_group_table["P4132"] = sg
-
-transformations = []
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 0.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 0.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(0.0, 1.0 / 2.0, 0.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 3.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, -1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, 0, 1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, 1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, 1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, -1, 0, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, 1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, -1, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, -1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, 0, 0, 1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, -1, 0, 0, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 1, 0, 0, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 0, 0, -1, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([1, 0, 0, 0, -1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0 / 2.0, 1.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 1, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(1.0, 1.0 / 2.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, -1, 0, 0, 0, 1])
-rot.shape = (3, 3)
-trans = Vector(1.0 / 2.0, 1.0, 1.0 / 2.0)
-transformations.append((rot, trans))
-rot = np.array([0, 1, 0, 1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, -1, 0, -1, 0, 0, 0, 0, -1])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, 1, 0, -1, 0, 1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 5.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([0, 0, -1, 0, -1, 0, -1, 0, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, 1, 0, 1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 5.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-rot = np.array([-1, 0, 0, 0, 0, -1, 0, -1, 0])
-rot.shape = (3, 3)
-trans = Vector(3.0 / 4.0, 3.0 / 4.0, 3.0 / 4.0)
-transformations.append((rot, trans))
-sg = SpaceGroup(214, ["O^8", "214", "I 4bd 2c 3", "I4132"], transformations)
-_space_group_table[214] = sg
-_space_group_table["O^8"] = sg
-_space_group_table["214"] = sg
-_space_group_table["I 4bd 2c 3"] = sg
-_space_group_table["I4132"] = sg
-
-
-del transformations
-del rot
-del trans
diff --git a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py
index fa08a203e6..a43bdd511b 100644
--- a/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py
+++ b/MDANSE/Src/MDANSE/Mathematics/Arithmetic.py
@@ -37,7 +37,12 @@ def get_weights(props, contents, dim):
else:
normFactor += fact
- if abs(normFactor) > 0.0: # if normFactor is 0, all weights are 0 too.
+ normalise = True
+ try:
+ len(normFactor)
+ except TypeError:
+ normalise = abs(normFactor) > 0.0 # if normFactor is 0, all weights are 0 too.
+ if normalise:
for k in list(weights.keys()):
weights[k] /= np.float64(normFactor)
diff --git a/MDANSE/Src/MDANSE/Mathematics/Geometry.py b/MDANSE/Src/MDANSE/Mathematics/Geometry.py
index 60639fc9b4..f21051b783 100644
--- a/MDANSE/Src/MDANSE/Mathematics/Geometry.py
+++ b/MDANSE/Src/MDANSE/Mathematics/Geometry.py
@@ -88,22 +88,24 @@ def build_cartesian_axes(origin, p1, p2, dtype=np.float64):
return n1, n2, n3
-def generate_sphere_points(n):
+def generate_sphere_points(n: int) -> np.ndarray:
"""Returns list of 3d coordinates of points on a sphere using the
Golden Section Spiral algorithm.
"""
- points = []
+ inputs = np.arange(int(n))
+ points = np.empty([len(inputs), 3])
inc = np.pi * (3 - np.sqrt(5))
offset = 2 / float(n)
- for k in range(int(n)):
- y = k * offset - 1 + (offset / 2)
- r = np.sqrt(1 - y * y)
- phi = k * inc
- points.append([np.cos(phi) * r, y, np.sin(phi) * r])
+ y = inputs * offset - 1 + (offset / 2)
+ r = np.sqrt(1 - y * y)
+ phi = inputs * inc
+ points[:, 0] = np.cos(phi) * r
+ points[:, 1] = y
+ points[:, 2] = np.sin(phi) * r
return points
diff --git a/MDANSE/Src/MDANSE/Mathematics/Graph.py b/MDANSE/Src/MDANSE/Mathematics/Graph.py
deleted file mode 100644
index 3f69613584..0000000000
--- a/MDANSE/Src/MDANSE/Mathematics/Graph.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# This file is part of MDANSE.
-#
-# MDANSE is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import collections
-
-
-class Node(object):
- def __init__(self, name, **kwargs):
- self._name = name
- self._links = set()
- for k, v in list(kwargs.items()):
- setattr(self, k, v)
-
- @property
- def name(self):
- return self._name
-
- @property
- def links(self):
- return self._links
-
- def add_link(self, other):
- self._links.add(other)
- other._links.add(self)
-
-
-class Graph(object):
- def __init__(self):
- self._nodes = collections.OrderedDict()
-
- @property
- def nodes(self):
- return self._nodes
-
- def add_node(self, name, **kwargs):
- self._nodes[name] = Node(name, **kwargs)
-
- def add_link(self, source, target):
- self._nodes[source].add_link(self._nodes[target])
-
- def build_connected_components(self):
- # List of connected components found. The order is random.
- result = []
-
- # Make a copy of the set, so we can modify it.
- nodes = [self._nodes[k] for k in sorted(self._nodes.keys())]
- nodes.reverse()
-
- # Iterate while we still have nodes to process.
- while nodes:
- # Get a random node and remove it from the global set.
- n = nodes.pop()
-
- # This set will contain the next group of nodes connected to each other.
- group = set([n])
-
- # Build a queue with this node in it.
- queue = [n]
-
- # Iterate the queue.
- # When it's empty, we finished visiting a group of connected nodes.
- while queue:
- # Consume the next item from the queue.
- n = queue.pop(0)
-
- # Fetch the neighbors.
- neighbors = n.links
-
- # Remove the neighbors we already visited.
- neighbors.difference_update(group)
-
- # Remove the remaining nodes from the global set.
- for neigh in neighbors:
- if neigh in nodes:
- nodes.remove(neigh)
-
- # Add them to the group of connected nodes.
- group.update(neighbors)
-
- # Add them to the queue, so we visit them in the next iterations.
- queue.extend(neighbors)
-
- # Sort the group
- group = list(group)
- group.sort(key=lambda n: n.name)
-
- # Add the group to the list of groups.
- result.append(group)
-
- # Return the list of groups.
- return result
diff --git a/MDANSE/Src/MDANSE/MolecularDynamics/Configuration.py b/MDANSE/Src/MDANSE/MolecularDynamics/Configuration.py
index 99aea88a39..f34c2f21f0 100644
--- a/MDANSE/Src/MDANSE/MolecularDynamics/Configuration.py
+++ b/MDANSE/Src/MDANSE/MolecularDynamics/Configuration.py
@@ -16,16 +16,264 @@
from __future__ import annotations
import abc
import copy
-from typing import Union, TYPE_CHECKING
+from typing import Union, TYPE_CHECKING, List, Tuple
+from functools import reduce
import numpy as np
+import networkx as nx
from numpy.typing import ArrayLike
if TYPE_CHECKING:
- from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem, Atom, _ChemicalEntity
+ from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.Mathematics.Transformation import RigidBodyTransformation
from MDANSE.MolecularDynamics.UnitCell import UnitCell
-from MDANSE.Extensions import atoms_in_shell, contiguous_coordinates
+
+
+def remove_jumps(input_coords: np.ndarray) -> np.ndarray:
+ """Takes a series of particle positions in time
+ and makes the motion continuous by removing any jumps across
+ the simulation box boundary.
+
+ Parameters
+ ----------
+ input_coords : np.ndarray
+ An (n_time_steps, 3) array of FRACTIONAL atom coordinates
+
+ Returns
+ -------
+ np.ndarray
+ The same array of atom positions, corrected for jumps by 1
+ full box length
+ """
+ steps = np.round(input_coords[1:] - input_coords[:-1]).astype(int)
+ offsets = np.zeros_like(input_coords)
+ for axis_index in range(3):
+ changes = np.argwhere(steps[:, axis_index])
+ for time_step_with_jump in changes:
+ try:
+ time_index = time_step_with_jump[0]
+ except IndexError:
+ continue
+ offsets[time_index + 1 :, axis_index] -= steps[time_index, axis_index]
+ return input_coords + offsets
+
+
+def contiguous_coordinates_real(
+ coords: np.ndarray,
+ cell: np.ndarray,
+ rcell: np.ndarray,
+ indices: List[Tuple[int]],
+ bring_to_centre: bool = False,
+):
+ """Translates atoms by a lattice vector. Returns a coordinate array
+ in which atoms in each segment are separated from the first atom
+ by less than half the simulation box length.
+
+ Parameters
+ ----------
+ coords : np.ndarray
+ Array of atom coordinates
+ cell : np.ndarray
+ 3x3 unit cell array
+ rcell : np.ndarray
+ 3x3 reciprocal cell array
+ indices : List[Tuple[int]]
+ a list of index group, as in [[1,2,3], [7,8]]
+ (this would ensure 2 and 3 are close to 1, and 8 is close to 7)
+ bring_to_centre: bool
+ if true, atoms are shifted to minimise the distance from the average
+ position and not from the first atom
+
+ Returns
+ -------
+ np.ndarray
+ new coordinate array with the translations applied
+ """
+
+ contiguous_coords = coords.copy()
+
+ scaleconfig = np.matmul(coords, rcell)
+
+ for idxs in indices:
+
+ if len(idxs) < 2:
+ continue
+ if bring_to_centre:
+ centre = np.mean(scaleconfig[idxs], axis=0)
+ minimum_offsets = scaleconfig[idxs] - centre
+ minimum_offsets -= np.round(minimum_offsets)
+ newconfig = centre + minimum_offsets
+ newconfig = np.matmul(newconfig, cell)
+ contiguous_coords[idxs] = newconfig
+ else:
+ minimum_offsets = scaleconfig[idxs[1:]] - scaleconfig[idxs[0]]
+ minimum_offsets -= np.round(minimum_offsets)
+ newconfig = scaleconfig[idxs[0]] + minimum_offsets
+ newconfig = np.matmul(newconfig, cell)
+ contiguous_coords[idxs[1:]] = newconfig
+
+ return contiguous_coords
+
+
+def contiguous_coordinates_box(
+ frac_coords: np.ndarray,
+ indices: List[Tuple[int]],
+ bring_to_centre: bool = False,
+):
+ """Translates atoms by a lattice vector. Returns a FRACTIONAL coordinate array
+ in which atoms in each segment are separated from the first atom
+ by less than half the simulation box length.
+
+ Parameters
+ ----------
+ coords : np.ndarray
+ Array of fractional coordinates
+ cell : np.ndarray
+ 3x3 unit cell array
+ indices : List[Tuple[int]]
+ a list of index group, as in [[1,2,3], [7,8]]
+ (this would ensure 2 and 3 are close to 1, and 8 is close to 7)
+ bring_to_centre: bool
+ if true, atoms are shifted to minimise the distance from the average
+ position and not from the first atom
+
+ Returns
+ -------
+ np.ndarray
+ array of atom coordinates with the translations applied
+ """
+
+ contiguous_coords = frac_coords.copy()
+
+ for tupleidxs in indices:
+
+ if len(tupleidxs) < 2:
+ continue
+
+ idxs = list(tupleidxs)
+ if bring_to_centre:
+ centre = np.mean(frac_coords[idxs], axis=0)
+ sdx = frac_coords[idxs] - centre
+ sdx -= np.round(sdx)
+ contiguous_coords[idxs] = frac_coords[idxs] + sdx
+ else:
+ sdx = frac_coords[idxs[1:]] - frac_coords[idxs[0]]
+ sdx -= np.round(sdx)
+ contiguous_coords[idxs[1:]] = frac_coords[idxs[0]] + sdx
+
+ return contiguous_coords
+
+
+def continuous_coordinates(
+ coords: np.ndarray,
+ cell: np.ndarray,
+ rcell: np.ndarray,
+ bond_list: List[Tuple[int]],
+):
+ """Translates atoms by lattice vectors to ensure that
+ no bonds are broken. Does nothing if no bonds are defined
+ in the system.
+
+ Parameters
+ ----------
+ coords : np.ndarray
+ Array of atom coordinates
+ cell : np.ndarray
+ 3x3 unit cell array
+ rcell : np.ndarray
+ 3x3 reciprocal cell array
+ bond_list : List[Tuple[int]]
+ List of bonds in the system
+
+ Returns
+ -------
+ np.ndarray
+ new array of atom coordinates with translations applied
+ """
+ atom_pool = list(range(len(coords)))
+ total_graph = nx.Graph()
+ total_graph.add_nodes_from(atom_pool)
+ total_graph.add_edges_from(bond_list)
+ segments = []
+ while len(atom_pool) > 0:
+ last_atom = atom_pool.pop()
+ temp_dict = nx.dfs_successors(total_graph, last_atom)
+ others = reduce(list.__add__, temp_dict.values(), [])
+ for atom in others:
+ atom_pool.pop(atom_pool.index(atom))
+ segment = [last_atom] + others
+ segments.append(sorted(segment))
+ return contiguous_coordinates_real(coords, cell, rcell, segments)
+
+
+def padded_coordinates(
+ coords: np.ndarray,
+ unit_cell: "UnitCell",
+ thickness: float,
+ fold_into_box: bool = True,
+) -> np.ndarray:
+ """Repeats coordinates in copies of the unit cell, and removes
+ the atoms that are now within the specified distance from the cell wall.
+ The returned coordinate array contains all the original atoms,
+ and additionally the atoms from the copies within the thickness
+ from the original cell walls.
+
+ Parameters
+ ----------
+ coords : np.ndarray
+ Array of all the atoms in the unit cell
+ unit_cell : UnitCell
+ an instance of the UnitCell class, defining the simulation box
+ thickness : float
+ thickness of the outer layer to be included
+ fold_into_box : bool
+ if True, translates all the atoms so their fractional coordinates are in [0.0, 1.0)
+
+ Returns
+ -------
+ np.ndarray
+ Array of atom coordinates, together with their copies
+
+ Raises
+ ------
+ VoronoiError
+ Any error that may indicate that a Voronoi job failed
+ """
+ if abs(thickness) < 1e-6:
+ return coords, np.arange(len(coords), dtype=int)
+ vectors = (
+ unit_cell.a_vector,
+ unit_cell.b_vector,
+ unit_cell.c_vector,
+ )
+ fractional_lengths = [thickness / np.linalg.norm(vector) for vector in vectors]
+ all_indices = np.arange(len(coords), dtype=int)
+ for axis in range(3):
+ extra_arrays = []
+ extra_indices = []
+ cutoff_max = 1 + fractional_lengths[axis]
+ cutoff_min = -fractional_lengths[axis]
+ for shift in [-1, 1]:
+ offset = vectors[axis] * shift
+ new_points = coords + offset.reshape((1, 3))
+ frac_points = np.matmul(new_points, unit_cell.inverse)
+ if fold_into_box:
+ frac_points -= np.floor(frac_points)
+ if shift > 0:
+ criterion = np.where(frac_points[:, axis] < cutoff_max)
+ new_points = new_points[criterion]
+ new_indices = all_indices[criterion]
+ else:
+ criterion = np.where(frac_points[:, axis] > cutoff_min)
+ new_points = new_points[criterion]
+ new_indices = all_indices[criterion]
+ if len(new_points) > 0:
+ extra_arrays.append(new_points)
+ extra_indices.append(new_indices)
+ if len(extra_arrays) > 0:
+ coords = np.vstack([coords] + extra_arrays)
+ all_indices = np.concatenate([all_indices] + extra_indices)
+ return coords, all_indices
class ConfigurationError(Exception):
@@ -40,7 +288,7 @@ def __init__(self, chemical_system: ChemicalSystem, coords: ArrayLike, **variabl
Constructor.
:param chemical_system: The chemical system described by this configuration.
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+ :type chemical_system: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem`
:param coords: the coordinates of all the particles in the chemical system
:type coords: numpy.ndarray
@@ -144,7 +392,7 @@ def chemical_system(self) -> ChemicalSystem:
Returns the chemical system stored in this configuration.
:return: the chemical system that this configuration describes
- :rtype: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+ :rtype: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem`
"""
return self._chemical_system
@@ -154,7 +402,7 @@ def clone(self, chemical_system: ChemicalSystem):
Clones this configuration.
:param chemical_system: the chemical system that this configuration describes
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+ :type chemical_system: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem`
"""
pass
@@ -201,7 +449,7 @@ def __init__(
Constructor.
:param chemical_system: The chemical system described by this configuration.
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+ :type chemical_system: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem`
:param coords: the coordinates of all the particles in the chemical system
:type coords: numpy.ndarray
@@ -226,7 +474,7 @@ def clone(self, chemical_system: Union[ChemicalSystem, None] = None):
:param chemical_system: the chemical system that is to be used for copying. It must have the same number of
atoms as the chemical system that this configuration describes
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem):
+ :type chemical_system: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem):
"""
if chemical_system is None:
chemical_system = self._chemical_system
@@ -332,40 +580,9 @@ def to_real_configuration(self) -> PeriodicRealConfiguration:
return real_conf
- def atoms_in_shell(
- self, ref: int, mini: float = 0.0, maxi: float = 10.0
- ) -> list[Atom]:
- """
- Returns all atoms found in a shell around a reference atom. The shell is a (hollow) sphere around the reference
- atom defined by parameters mini and maxi. All atoms within the sphere with radius maxi but not within that of
- radius mini are returned. Atoms that are exactly mini or maxi distance away from the reference atom ARE counted
- For more details, see :func: `MDANSE.Extensions.atoms_in_shell.atoms_in_shell_box`, which is called under the
- hood.
-
- :param ref: the index of the reference atom
- :type ref: int
-
- :param mini: the inner radius of the shell
- :type mini: float
-
- :param maxi: the outer radius of the shell
- :type maxi: float
-
- :return: list of atoms within the defined shell
- :rtype: list
- """
-
- indexes = atoms_in_shell.atoms_in_shell_box(
- self._variables["coordinates"].astype(np.float64), ref, mini, maxi
- )
-
- atom_list = self._chemical_system.atom_list
-
- selected_atoms = [atom_list[idx] for idx in indexes]
-
- return selected_atoms
-
- def contiguous_configuration(self) -> PeriodicBoxConfiguration:
+ def contiguous_configuration(
+ self, bring_to_centre: bool = False
+ ) -> PeriodicBoxConfiguration:
"""
Return a configuration with chemical entities made contiguous.
@@ -373,62 +590,20 @@ def contiguous_configuration(self) -> PeriodicBoxConfiguration:
:rtype: :class: `MDANSE.MolecularDynamics.Configuration.PeriodicBoxConfiguration`
"""
- indexes = []
- for ce in self._chemical_system.chemical_entities:
- indexes.append([at.index for at in ce.atom_list])
+ indices_grouped = reduce(
+ list.__add__, self._chemical_system._clusters.values(), []
+ )
- contiguous_coords = contiguous_coordinates.contiguous_coordinates_box(
- self._variables["coordinates"], self._unit_cell.transposed_direct, indexes
+ contiguous_coords = contiguous_coordinates_box(
+ self._variables["coordinates"],
+ indices_grouped,
+ bring_to_centre,
)
conf = self.clone()
conf._variables["coordinates"] = contiguous_coords
return conf
- def contiguous_offsets(
- self, chemical_entities: list[_ChemicalEntity] = None
- ) -> np.ndarray:
- """
- Returns the contiguity offsets for a list of chemical entities.
-
- :param chemical_entities: the list of chemical entities whose offsets are to be calculated or None for all
- entities in the chemical system
- :type chemical_entities: list
-
- :return: the offsets
- :rtype: numpy.ndarray
- """
-
- if chemical_entities is None:
- chemical_entities = self._chemical_system.chemical_entities
- else:
- for i, ce in enumerate(chemical_entities):
- root = ce.root_chemical_system
- if root is not self._chemical_system:
- raise ConfigurationError(
- "All the entities provided in the chemical_entities parameter must belong "
- "to the chemical system registered with this configuration, which is "
- f"{self._chemical_system.name}. However, the entity at index {i}, "
- f"{str(ce)}, is in chemical system "
- f"{root.name if root is not None else None}.\nExpected chemical system: "
- f"{repr(self._chemical_system)}\nActual chemical system: {repr(root)}\n"
- f"Faulty chemical entity: {repr(ce)}"
- )
-
- indexes = []
- for ce in chemical_entities:
- indexes.append([at.index for at in ce.atom_list])
-
- offsets = contiguous_coordinates.contiguous_offsets_box(
- self._variables["coordinates"][
- [item for sublist in indexes for item in sublist]
- ],
- self._unit_cell.transposed_direct,
- indexes,
- )
-
- return offsets
-
class PeriodicRealConfiguration(_PeriodicConfiguration):
is_periodic = True
@@ -472,45 +647,9 @@ def to_real_coordinates(self) -> np.ndarray:
"""
return self._variables["coordinates"]
- def atoms_in_shell(
- self, ref: int, mini: float = 0.0, maxi: float = 10.0
- ) -> list[Atom]:
- """
- Returns all atoms found in a shell around a reference atom. The shell is a (hollow) sphere around the reference
- atom defined by parameters mini and maxi. All atoms within the sphere with radius maxi but not within that of
- radius mini are returned. Atoms that are exactly mini or maxi distance away from the reference atom ARE counted
- For more details, see :func: `MDANSE.Extensions.atoms_in_shell.atoms_in_shell_real`, which is called under the
- hood.
-
- :param ref: the index of the reference atom
- :type ref: int
-
- :param mini: the inner radius of the shell
- :type mini: float
-
- :param maxi: the outer radius of the shell
- :type maxi: float
-
- :return: list of atoms within the defined shell
- :rtype: list
- """
-
- indexes = atoms_in_shell.atoms_in_shell_real(
- self._variables["coordinates"].astype(np.float64),
- self._unit_cell.transposed_direct,
- self._unit_cell.transposed_inverse,
- ref,
- mini,
- maxi,
- )
-
- atom_list = self._chemical_system.atom_list
-
- selected_atoms = [atom_list[idx] for idx in indexes]
-
- return selected_atoms
-
- def contiguous_configuration(self) -> PeriodicRealConfiguration:
+ def contiguous_configuration(
+ self, bring_to_centre: bool = False
+ ) -> PeriodicRealConfiguration:
"""
Return a configuration with chemical entities made contiguous.
@@ -518,15 +657,16 @@ def contiguous_configuration(self) -> PeriodicRealConfiguration:
:rtype: :class: `MDANSE.MolecularDynamics.Configuration.PeriodicBoxConfiguration`
"""
- indexes = []
- for ce in self._chemical_system.chemical_entities:
- indexes.append([at.index for at in ce.atom_list])
+ indices_grouped = reduce(
+ list.__add__, self._chemical_system._clusters.values(), []
+ )
- contiguous_coords = contiguous_coordinates.contiguous_coordinates_real(
+ contiguous_coords = contiguous_coordinates_real(
self._variables["coordinates"],
- self._unit_cell.transposed_direct,
- self._unit_cell.transposed_inverse,
- indexes,
+ self._unit_cell.direct,
+ self._unit_cell.inverse,
+ indices_grouped,
+ bring_to_centre,
)
conf = self.clone()
@@ -541,61 +681,17 @@ def continuous_configuration(self) -> PeriodicRealConfiguration:
:rtype: :class: `MDANSE.MolecularDynamics.Configuration.PeriodicBoxConfiguration`
"""
- contiguous_coords = contiguous_coordinates.continuous_coordinates(
+ continuous_coords = continuous_coordinates(
self._variables["coordinates"],
- self._unit_cell.transposed_direct,
- self._unit_cell.transposed_inverse,
- self._chemical_system,
+ self._unit_cell.direct,
+ self._unit_cell.inverse,
+ self.chemical_system._bonds,
)
conf = self.clone()
- conf._variables["coordinates"] = contiguous_coords
+ conf._variables["coordinates"] = continuous_coords
return conf
- def contiguous_offsets(
- self, chemical_entities: Union[None, list[_ChemicalEntity]] = None
- ) -> np.ndarray:
- """
- Returns the contiguity offsets for a list of chemical entities.
-
- :param chemical_entities: the list of chemical entities whose offsets are to be calculated or None for all
- entities in the chemical system
- :type chemical_entities: list
-
- :return: the offsets
- :rtype: numpy.ndarray
- """
-
- if chemical_entities is None:
- chemical_entities = self._chemical_system.chemical_entities
- else:
- for i, ce in enumerate(chemical_entities):
- root = ce.root_chemical_system
- if root is not self._chemical_system:
- raise ConfigurationError(
- "All the entities provided in the chemical_entities parameter must belong "
- "to the chemical system registered with this configuration, which is "
- f"{self._chemical_system.name}. However, the entity at index {i}, "
- f"{str(ce)}, is in chemical system "
- f"{root.name if root is not None else None}.\nExpected chemical system: "
- f"{repr(self._chemical_system)}\nActual chemical system: {repr(root)}\n"
- f"Faulty chemical entity: {repr(ce)}"
- )
- indexes = []
- for ce in chemical_entities:
- indexes.append([at.index for at in ce.atom_list])
-
- offsets = contiguous_coordinates.contiguous_offsets_real(
- self._variables["coordinates"][
- [item for sublist in indexes for item in sublist]
- ],
- self._unit_cell.transposed_direct,
- self._unit_cell.transposed_inverse,
- indexes,
- )
-
- return offsets
-
class RealConfiguration(_Configuration):
is_periodic = False
@@ -608,7 +704,7 @@ def clone(
:param chemical_system: the chemical system that is to be used for copying. It must have the same number of
atoms as the chemical system that this configuration describes
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+ :type chemical_system: :class: `MDANSE.Chemistry.ChemicalSystem.ChemicalSystem`
:return: the cloned configuration
:rtype: :class: `MDANSE.MolecularDynamics.Configuration.RealConfiguration`
@@ -641,40 +737,9 @@ def to_real_coordinates(self) -> np.ndarray:
"""
return self._variables["coordinates"]
- def atoms_in_shell(
- self, ref: int, mini: float = 0.0, maxi: float = 10.0
- ) -> list[Atom]:
- """
- Returns all atoms found in a shell around a reference atom. The shell is a (hollow) sphere around the reference
- atom defined by parameters mini and maxi. All atoms within the sphere with radius maxi but not within that of
- radius mini are returned. Atoms that are exactly mini or maxi distance away from the reference atom ARE counted
- For more details, see :func: `MDANSE.Extensions.atoms_in_shell.atoms_in_shell_nopbc`, which is called under the
- hood.
-
- :param ref: the index of the reference atom
- :type ref: int
-
- :param mini: the inner radius of the shell
- :type mini: float
-
- :param maxi: the outer radius of the shell
- :type maxi: float
-
- :return: list of atoms within the defined shell
- :rtype: list
- """
-
- indexes = atoms_in_shell.atoms_in_shell_nopbc(
- self._variables["coordinates"].astype(np.float64), ref, mini, maxi
- )
-
- atom_list = self._chemical_system.atom_list
-
- selected_atoms = [atom_list[idx] for idx in indexes]
-
- return selected_atoms
-
- def contiguous_configuration(self) -> RealConfiguration:
+ def contiguous_configuration(
+ self, bring_to_centre: bool = False
+ ) -> RealConfiguration:
"""
Return a configuration with chemical entities made contiguous, which is always itself.
@@ -692,54 +757,13 @@ def continuous_configuration(self) -> RealConfiguration:
"""
return self
- def contiguous_offsets(
- self, chemical_entities: Union[None, list[_ChemicalEntity]] = None
- ) -> np.ndarray:
- """
- Returns the contiguity offsets for a list of chemical entities, which are always zero for every atom.
-
- :param chemical_entities: the list of chemical entities whose offsets are to be calculated or None for all
- entities in the chemical system
- :type chemical_entities: list
-
- :return: the offsets
- :rtype: numpy.ndarray
- """
-
- if chemical_entities is None:
- chemical_entities = self._chemical_system.chemical_entities
- else:
- for j, ce in enumerate(chemical_entities):
- root = ce.root_chemical_system
- if root is not self._chemical_system:
- raise ConfigurationError(
- "All the entities provided in the chemical_entities parameter must belong "
- "to the chemical system registered with this configuration, which is "
- f"{self._chemical_system.name}. However, the entity at index {j}, "
- f"{str(ce)}, is in chemical system "
- f"{root.name if root is not None else None}.\nExpected chemical system: "
- f"{repr(self._chemical_system)}\nActual chemical system: {repr(root)}\n"
- f"Faulty chemical entity: {repr(ce)}"
- )
-
- number_of_particles = sum(
- [ce.total_number_of_atoms for ce in chemical_entities]
- )
-
- offsets = np.zeros((number_of_particles, 3))
-
- return offsets
-
if __name__ == "__main__":
np.random.seed(1)
- from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem
-
n_atoms = 2
cs = ChemicalSystem()
- for i in range(n_atoms):
- cs.add_chemical_entity(Atom(symbol="H"))
+ cs.initialise_atoms(["H", "H"])
coordinates = np.empty((n_atoms, 3), dtype=float)
coordinates[0, :] = [1, 1, 1]
@@ -748,5 +772,3 @@ def contiguous_offsets(
uc = np.array([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]])
conf = RealConfiguration(cs, coordinates)
-
- print(conf.atoms_in_shell(0, 0, 5))
diff --git a/MDANSE/Src/MDANSE/MolecularDynamics/Connectivity.py b/MDANSE/Src/MDANSE/MolecularDynamics/Connectivity.py
index 000484c7ea..a4f2b0841b 100644
--- a/MDANSE/Src/MDANSE/MolecularDynamics/Connectivity.py
+++ b/MDANSE/Src/MDANSE/MolecularDynamics/Connectivity.py
@@ -15,14 +15,14 @@
#
from itertools import product
-from typing import List, Dict
+from typing import List
import numpy as np
from numpy.typing import NDArray
from scipy.spatial import KDTree
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Trajectory import Trajectory
@@ -39,10 +39,11 @@ def __init__(
**kwargs,
):
self._chemical_system = trajectory.chemical_system
+ self._input_trajectory = trajectory
self._selection = selection
self._frames = trajectory
- self._unit_cell = self._chemical_system.configuration
- self._periodic = self._chemical_system.configuration.is_periodic
+ self._unit_cell = self._input_trajectory.configuration(0)
+ self._periodic = self._input_trajectory.configuration(0).is_periodic
self.check_composition(self._chemical_system)
self._bonds = None
self._bond_mapping = None
@@ -58,10 +59,10 @@ def check_composition(self, chemical: ChemicalSystem):
"""
if self._selection is not None:
atom_elements = [
- atom.symbol for atom in chemical.atoms if atom.index in self._selection
+ self._chemical_system.atom_list[index] for index in self._selection
]
else:
- atom_elements = [atom.symbol for atom in chemical.atoms]
+ atom_elements = self._chemical_system.atom_list
unique_elements = np.unique(atom_elements)
radii = {
element: ATOMS_DATABASE.get_atom_property(element, "covalent_radius")
@@ -126,7 +127,7 @@ def periodic_distances(
NDArray -- an (N,N) array of squared distances between all the atom pairs,
one for each combination of the unit cell vectors.
"""
- unit_cell = self._chemical_system.configuration.unit_cell
+ unit_cell = self._input_trajectory.configuration(frame_number).unit_cell
vector_a, vector_b, vector_c = (
unit_cell.a_vector,
unit_cell.b_vector,
@@ -168,7 +169,7 @@ def find_bonds(self, frames: List[int] = None, tolerance: float = 0.2):
for pair in pairs
}
total_max_length = np.max([x for x in maxbonds.values()])
- for nstep, frame_number in enumerate(samples):
+ for _, frame_number in enumerate(samples):
distances = self.internal_distances(
frame_number=frame_number, max_distance=total_max_length
)
@@ -193,59 +194,9 @@ def find_bonds(self, frames: List[int] = None, tolerance: float = 0.2):
self._bond_mapping = bond_mapping
self._unique_bonds = np.unique(np.sort(bonds, axis=1), axis=0)
- def find_molecules(self, tolerance: float = 0.2):
- """Uses the internal list of bonds to find atoms that belong to the same
- molecules. The grouping of atoms is saved internally.
- """
- if self._bond_mapping is None:
- self.find_bonds(tolerance=tolerance)
-
- def recursive_walk(
- number: int, bond_mapping: Dict[int, int], atom_pool: List[int]
- ):
- """Returns a list of atoms connected by bonds to the input atom.
- Called recursively in order to find the entire molecule.
-
- Arguments:
- number -- number (index) of the starting atom on the atom list.
- bond_mapping -- dictionary of the interatomic connections,
- determined using the find_bonds method.
- atom_pool -- a list of all the atom numbers, each atom to be used
- once only. Once an atom number has been assigned to a molecule,
- it will also be removed from this list.
-
- Returns:
- List[int] -- a list of atom numbers (indices)
- """
- connected_atoms = [number]
- for at_number in bond_mapping[number]:
- if at_number in atom_pool:
- connected_atoms.append(at_number)
- atom_pool.pop(atom_pool.index(at_number))
- connected_atoms += recursive_walk(
- at_number, bond_mapping, atom_pool
- )
- return connected_atoms
-
- molecules = []
- atom_pool = list(range(len(self._elements)))
- while len(atom_pool):
- new_molecule = recursive_walk(
- atom_pool.pop(), self._bond_mapping, atom_pool
- )
- molecules.append(list(np.unique(new_molecule)))
- self._molecules = molecules
-
- def add_bond_information(self):
- for bond in self._unique_bonds:
- ind1, ind2 = bond
- at1, at2 = (
- self._chemical_system.atoms[bond[0]],
- self._chemical_system.atoms[bond[1]],
- )
- at1.bonds.append(at2)
- at2.bonds.append(at1)
- self._chemical_system._bonds.append((ind1, ind2))
+ def add_bond_information(self, new_chemical_system: ChemicalSystem):
+ new_chemical_system.add_bonds(self._unique_bonds)
+ new_chemical_system.find_clusters_from_bonds()
def add_point(self, index: int, point: np.ndarray, radius: float) -> bool:
return True
diff --git a/MDANSE/Src/MDANSE/MolecularDynamics/MockTrajectory.py b/MDANSE/Src/MDANSE/MolecularDynamics/MockTrajectory.py
index fdbd8900f3..91c8185939 100644
--- a/MDANSE/Src/MDANSE/MolecularDynamics/MockTrajectory.py
+++ b/MDANSE/Src/MDANSE/MolecularDynamics/MockTrajectory.py
@@ -16,18 +16,19 @@
import math
import json
-from typing import TypeVar
+from typing import TypeVar, List
import numpy as np
from MDANSE.Chemistry import ATOMS_DATABASE
+from MDANSE.Mathematics.Geometry import center_of_mass
from MDANSE.Framework.Units import measure
-from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem
-from MDANSE.Extensions import com_trajectory
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import (
PeriodicRealConfiguration,
RealConfiguration,
_Configuration,
+ contiguous_coordinates_real,
)
from MDANSE.MolecularDynamics.TrajectoryUtils import atomic_trajectory
from MDANSE.MolecularDynamics.UnitCell import UnitCell
@@ -76,9 +77,8 @@ def __init__(
self._variables = {}
self._coordinates = None
- self._chemicalSystem = ChemicalSystem("MockSystem")
- for atom in self._atom_types:
- self._chemicalSystem.add_chemical_entity(Atom(symbol=atom))
+ self._chemical_system = ChemicalSystem("MockSystem")
+ self._chemical_system.initialise_atoms(self._atom_types)
def set_coordinates(self, coords: np.ndarray):
"""Sets the initial (equlibrium) positions of atoms from
@@ -286,16 +286,27 @@ def configuration(self, frame: int) -> "_Configuration":
if self._pbc:
conf = PeriodicRealConfiguration(
- self._chemicalSystem, coordinates, unit_cell, **variables
+ self._chemical_system, coordinates, unit_cell, **variables
)
else:
- conf = RealConfiguration(self._chemicalSystem, coordinates, **variables)
+ conf = RealConfiguration(self._chemical_system, coordinates, **variables)
return conf
def _load_unit_cells(self):
"""Only added for compatibility with Trajectory."""
+ def get_atom_property(self, atom_symbol: str, property: str):
+ return ATOMS_DATABASE.get_atom_property(atom_symbol, property)
+
+ @property
+ def atoms_in_database(self) -> List[str]:
+ return ATOMS_DATABASE.atoms
+
+ @property
+ def properties_in_database(self) -> List[str]:
+ return ATOMS_DATABASE.properties
+
def unit_cell(self, frame: int) -> UnitCell:
"""Returns the UnitCell the size of the system.
@@ -324,12 +335,12 @@ def __len__(self) -> int:
return self._number_of_frames
def read_com_trajectory(
- self, atoms, first=0, last=None, step=1, box_coordinates=False
+ self, indices, first=0, last=None, step=1, box_coordinates=False
):
"""Build the trajectory of the center of mass of a set of atoms.
:param atoms: the atoms for which the center of mass should be computed
- :type atoms: list MDANSE.Chemistry.ChemicalEntity.Atom
+ :type atoms: list MDANSE.Chemistry.ChemicalSystem.Atom
:param first: the index of the first frame
:type first: int
:param last: the index of the last frame
@@ -346,59 +357,45 @@ def read_com_trajectory(
if last is None:
last = len(self)
- indexes = [at.index for at in atoms]
masses = np.array(
[
- ATOMS_DATABASE.get_atom_property(at.symbol, "atomic_weight")
- for at in atoms
+ self.chemical_system.atom_property("atomic_weight")[index]
+ for index in indices
]
)
frames = np.array([self.coordinates(fnum) for fnum in range(first, last, step)])
- coords = frames[:, indexes, :].astype(np.float64)
+ coords = frames[:, indices, :].astype(np.float64)
if coords.ndim == 2:
coords = coords[np.newaxis, :, :]
if self._pbc:
direct_cells = np.array(
- [
- self.unit_cell(fnum).transposed_direct
- for fnum in range(first, last, step)
- ]
+ [self.unit_cell(fnum).direct for fnum in range(first, last, step)]
)
inverse_cells = np.array(
- [
- self.unit_cell(fnum).transposed_inverse
- for fnum in range(first, last, step)
- ]
+ [self.unit_cell(fnum).inverse for fnum in range(first, last, step)]
)
-
- top_lvl_chemical_entities = set(
- [at.top_level_chemical_entity for at in atoms]
- )
- top_lvl_chemical_entities_indexes = [
- [at.index for at in e.atom_list] for e in top_lvl_chemical_entities
- ]
- bonds = {}
- for e in top_lvl_chemical_entities:
- for at in e.atom_list:
- bonds[at.index] = [other_at.index for other_at in at.bonds]
-
- com_traj = com_trajectory.com_trajectory(
+ temp_coords = contiguous_coordinates_real(
coords,
direct_cells,
inverse_cells,
- masses,
- top_lvl_chemical_entities_indexes,
- indexes,
- bonds,
- box_coordinates=box_coordinates,
+ [list(range(len(coords)))],
+ bring_to_centre=True,
)
+ com_coords = np.vstack(
+ [
+ center_of_mass(temp_coords[tstep], masses)
+ for tstep in range(len(temp_coords))
+ ]
+ )
+
+ com_traj = atomic_trajectory(com_coords, direct_cells, inverse_cells)
else:
com_traj = np.sum(
- coords[:, indexes, :] * masses[np.newaxis, :, np.newaxis], axis=1
+ coords[:, indices, :] * masses[np.newaxis, :, np.newaxis], axis=1
)
com_traj /= np.sum(masses)
@@ -518,9 +515,9 @@ def chemical_system(self):
"""Return the chemical system stored in the trajectory.
:return: the chemical system
- :rtype: MDANSE.Chemistry.ChemicalEntity.ChemicalSystem
+ :rtype: MDANSE.Chemistry.ChemicalSystem.ChemicalSystem
"""
- return self._chemicalSystem
+ return self._chemical_system
@property
def file(self) -> str:
diff --git a/MDANSE/Src/MDANSE/MolecularDynamics/Trajectory.py b/MDANSE/Src/MDANSE/MolecularDynamics/Trajectory.py
index a72c7a7e8e..0abda4616c 100644
--- a/MDANSE/Src/MDANSE/MolecularDynamics/Trajectory.py
+++ b/MDANSE/Src/MDANSE/MolecularDynamics/Trajectory.py
@@ -15,7 +15,10 @@
#
import os
from ast import operator
-from typing import Collection
+from typing import Collection, List, Dict, TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+ from MDANSE.Chemistry.Databases import AtomsDatabase
import math
import numpy as np
@@ -25,14 +28,10 @@
from MDANSE.Trajectory.MdanseTrajectory import MdanseTrajectory
from MDANSE.Trajectory.H5MDTrajectory import H5MDTrajectory
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem, _ChemicalEntity
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import (
RealConfiguration,
)
-from MDANSE.MolecularDynamics.TrajectoryUtils import (
- sorted_atoms,
- resolve_undefined_molecules_name,
-)
from MDANSE import PLATFORM
@@ -56,6 +55,7 @@ def __init__(self, filename, trajectory_format=None):
self._trajectory = self.open_trajectory(self._format)
self._min_span = np.zeros(3)
self._max_span = np.zeros(3)
+ self._atom_cache = {}
def guess_correct_format(self):
"""This is a placeholder for now. As the number of
@@ -122,7 +122,7 @@ def coordinates(self, frame):
return self._trajectory.coordinates(frame)
- def configuration(self, frame):
+ def configuration(self, frame: int = 0):
"""Build and return a configuration at a given frame.
:param frame: the frame
@@ -177,12 +177,12 @@ def min_span(self):
return self._min_span
def read_com_trajectory(
- self, atoms, first=0, last=None, step=1, box_coordinates=False
+ self, atom_indices, first=0, last=None, step=1, box_coordinates=False
):
"""Build the trajectory of the center of mass of a set of atoms.
:param atoms: the atoms for which the center of mass should be computed
- :type atoms: list MDANSE.Chemistry.ChemicalEntity.Atom
+ :type atoms: list MDANSE.Chemistry.ChemicalSystem.Atom
:param first: the index of the first frame
:type first: int
:param last: the index of the last frame
@@ -196,7 +196,11 @@ def read_com_trajectory(
:rtype: ndarray
"""
return self._trajectory.read_com_trajectory(
- atoms, first=first, last=last, step=step, box_coordinates=box_coordinates
+ atom_indices,
+ first=first,
+ last=last,
+ step=step,
+ box_coordinates=box_coordinates,
)
def to_real_coordinates(self, box_coordinates, first, last, step):
@@ -219,7 +223,7 @@ def to_real_coordinates(self, box_coordinates, first, last, step):
def read_atomic_trajectory(
self, index, first=0, last=None, step=1, box_coordinates=False
):
- """Read an atomic trajectory. The trajectory is corrected from box jumps.
+ """Read an atomic trajectory. The trajectory is corrected for box jumps.
:param index: the index of the atom
:type index: int
@@ -279,12 +283,48 @@ def has_variable(self, variable: str) -> bool:
"""
return self._trajectory.has_variable(variable)
+ def get_atom_property(self, atom_symbol: str, property: str):
+ if (atom_symbol, property) not in self._atom_cache.keys():
+ self._atom_cache[(atom_symbol, property)] = (
+ self._trajectory.get_atom_property(atom_symbol, property)
+ )
+ return self._atom_cache[(atom_symbol, property)]
+
+ def has_atom(self, symbol: str):
+ return symbol in self.atoms_in_database
+
+ def get_property_dict(self, symbol: str) -> Dict[str, Any]:
+ """Returns a dictionary of all the properties of an atom type.
+
+ Parameters
+ ----------
+ symbol : str
+ Symbol of the atom.
+
+ Returns
+ -------
+ Union[int, float, str]
+ The atom property.
+ """
+ return {
+ property_name: self.get_atom_property(symbol, property_name)
+ for property_name in self.properties_in_database
+ }
+
+ @property
+ def atoms_in_database(self) -> List[str]:
+ return self._trajectory.atoms_in_database()
+
+ @property
+ def properties_in_database(self) -> List[str]:
+ return self._trajectory.properties_in_database()
+
@property
def chemical_system(self):
"""Return the chemical system stored in the trajectory.
:return: the chemical system
- :rtype: MDANSE.Chemistry.ChemicalEntity.ChemicalSystem
+ :rtype: MDANSE.Chemistry.ChemicalSystem.ChemicalSystem
"""
return self._trajectory.chemical_system
@@ -325,6 +365,93 @@ def variables(self):
return self._trajectory.variables()
+additive_atom_properties = [
+ "nucleon",
+ "b_incoherent2",
+ "xray_asf_b4",
+ "proton",
+ "atomic_weight",
+ "ionization_energy",
+ "xs_absorption",
+ "xs_scattering",
+ "b_incoherent",
+ "b_coherent",
+ "charge",
+ "xray_asf_c",
+ "neutron",
+ "xray_asf_a4",
+ "xray_asf_a2",
+ "xray_asf_a3",
+ "xray_asf_a1",
+ "xray_asf_b3",
+ "xray_asf_b2",
+ "xray_asf_b1",
+ "xs_incoherent",
+ "xs_coherent",
+ "nuclear_spin",
+]
+averaged_atom_properties = [
+ "electronegativity",
+ "electroaffinity",
+ "atomic_number",
+ "group",
+ "serie",
+]
+constant_atom_properties = {
+ "equal": 1.0,
+ "abundance": 100.0,
+}
+atom_radii = [
+ "covalent_radius",
+ "vdw_radius",
+ "atomic_radius",
+]
+
+
+def create_average_atom(
+ atom_dictionary: Dict[str, int], database: Trajectory, radius_padding: float = 0.0
+):
+ all_properties = database.properties_in_database
+ values = {}
+ for property in all_properties:
+ temp = []
+ total = 0
+ for element_name, element_count in atom_dictionary.items():
+ temp.append(
+ [database.get_atom_property(element_name, property), element_count]
+ )
+ if property in additive_atom_properties:
+ total = np.sum([float(x[0]) * int(x[1]) for x in temp])
+ elif property in averaged_atom_properties:
+ total = np.sum([float(x[0]) * int(x[1]) for x in temp]) / np.sum(
+ [int(x[1]) for x in temp]
+ )
+ elif property in constant_atom_properties.keys():
+ total = constant_atom_properties[property]
+ elif property in atom_radii:
+ total = (
+ np.sum([float(x[0]) * int(x[1]) for x in temp])
+ / np.sum([int(x[1]) for x in temp])
+ + radius_padding
+ )
+ else:
+ for entry in temp:
+ try:
+ converted = float(entry[0])
+ except TypeError:
+ total = entry
+ except ValueError:
+ total = entry
+ else:
+ total += converted * entry[1]
+ values[property] = total
+ is_dummy = 1
+ for element_name, _ in atom_dictionary.items():
+ is_dummy = is_dummy and database.get_atom_property(element_name, "dummy")
+ values["dummy"] = is_dummy
+ return values
+
+
class TrajectoryWriterError(Exception):
pass
@@ -348,11 +475,11 @@ def __init__(
:param h5_filename: the trajectory filename
:type h5_filename: str
:param chemical_system: the chemical system
- :type h5_filename: MDANSE.Chemistry.ChemicalEntity.ChemicalSystem
+ :type h5_filename: MDANSE.Chemistry.ChemicalSystem.ChemicalSystem
:param h5_filename: the number of steps
:type h5_filename: int
:param selected_atoms: the selected atoms of the chemical system to write
- :type selected_atoms: list of MDANSE.Chemistry.ChemicalEntity.Atom
+ :type selected_atoms: list of MDANSE.Chemistry.ChemicalSystem.Atom
"""
self._h5_filename = h5_filename
@@ -360,23 +487,14 @@ def __init__(
self._h5_file = h5py.File(self._h5_filename, "w")
self._chemical_system = chemical_system
+ self._last_configuration = None
if selected_atoms is None:
- self._selected_atoms = self._chemical_system.atom_list
+ self._selected_atoms = list(self._chemical_system._atom_indices)
else:
- for at in selected_atoms:
- if at.root_chemical_system != chemical_system:
- LOG.error(
- f"atom.chemical_system={at.root_chemical_system} and traj.chemical_system={chemical_system}"
- )
- raise TrajectoryWriterError(
- "One or more atoms of the selection comes from a different chemical system"
- )
- self._selected_atoms = sorted_atoms(selected_atoms)
+ self._selected_atoms = selected_atoms
- self._selected_atoms = [at.index for at in self._selected_atoms]
-
- all_atoms = self._chemical_system.atom_list
+ all_atoms = list(self._chemical_system.atom_list)
for idx in self._selected_atoms:
all_atoms[idx] = False
@@ -410,6 +528,132 @@ def __init__(
else:
self._initial_charges = initial_charges
+ def write_atom_properties(
+ self, symbol: str, properties: Dict[str, Any], ptypes: Dict[str, str] = None
+ ):
+ if "atom_database" not in self._h5_file.keys():
+ group = self._h5_file.create_group("/atom_database")
+ else:
+ group = self._h5_file["/atom_database"]
+ string_dt = h5py.special_dtype(vlen=str)
+ if "property_labels" not in group:
+ label_dataset = group.create_dataset(
+ "property_labels", data=200 * [""], dtype=string_dt
+ )
+ else:
+ label_dataset = self._h5_file["/atom_database/property_labels"]
+ if "property_types" not in group:
+ type_dataset = group.create_dataset(
+ "property_types", data=200 * [""], dtype=string_dt
+ )
+ else:
+ type_dataset = self._h5_file["/atom_database/property_types"]
+ next_index = 0
+ for label in label_dataset[:]:
+ if len(label) > 0:
+ next_index += 1
+ else:
+ break
+ properties["dummy"] = 0
+ if symbol == "Du":
+ properties["dummy"] = 1
+ if "element" in properties.keys():
+ if properties["element"] == "dummy":
+ properties["dummy"] = 1
+ new_labels = [str(x) for x in properties.keys()]
+ if ptypes is None:
+ ptypes = ATOMS_DATABASE._properties
+ ptypes["dummy"] = "int"
+ for label in new_labels:
+ if label.encode("utf-8") not in label_dataset:
+ label_dataset[next_index] = label
+ type_dataset[next_index] = ptypes[label]
+ next_index += 1
+ mapping = {
+ property_label.decode("utf-8"): index
+ for index, property_label in enumerate(label_dataset[:])
+ }
+ atom_dataset = group.create_dataset(symbol, data=200 * [-1.0])
+ for key, value in properties.items():
+ try:
+ float(value)
+ except ValueError:
+ continue
+ except TypeError:
+ continue
+ else:
+ atom_dataset[mapping[key]] = value
+ try:
+ colour = [int(x) for x in properties["color"].split(";")]
+ except AttributeError:
+ colour = [int(x) for x in properties["color"][0].split(";")]
+ atom_dataset[mapping["color"]] = (
+ 0x10000 * colour[0] + 0x100 * colour[1] + colour[2]
+ )
+
+ def write_atom_database(
+ self,
+ symbols: List[str],
+ database: "AtomsDatabase",
+ optional_molecule_radii: Dict[str, float] = None,
+ ):
+ for atom_symbol in symbols:
+ if database.has_atom(atom_symbol):
+ property_dict = database.get_property_dict(atom_symbol)
+ else:
+ atom_dict = {}
+ molecule_radius = 0.0
+ for token in atom_symbol.split("_"):
+ symbol = ""
+ number = ""
+ noletters = True
+ for char in token:
+ if char.isnumeric():
+ if noletters:
+ symbol += char
+ else:
+ number += char
+ else:
+ symbol += char
+ noletters = False
+ atom_dict[symbol] = int(number)
+ if optional_molecule_radii is not None:
+ molecule_radius = optional_molecule_radii.get(atom_symbol, 0.0)
+ property_dict = create_average_atom(
+ atom_dict, database, radius_padding=molecule_radius
+ )
+ if hasattr(database, "_properties"):
+ self.write_atom_properties(
+ atom_symbol, property_dict, database._properties
+ )
+ else:
+ self.write_atom_properties(atom_symbol, property_dict)
+
+ def write_standard_atom_database(self):
+ symbols = list(np.unique(self._chemical_system.atom_list))
+ database = ATOMS_DATABASE
+ for atom_symbol in symbols:
+ if database.has_atom(atom_symbol):
+ property_dict = database.get_property_dict(atom_symbol)
+ else:
+ atom_dict = {}
+ for token in atom_symbol.split("_"):
+ symbol = ""
+ number = ""
+ noletters = True
+ for char in token:
+ if char.isnumeric():
+ if noletters:
+ symbol += char
+ else:
+ number += char
+ else:
+ symbol += char
+ noletters = False
+ atom_dict[symbol] = int(number)
+ property_dict = create_average_atom(atom_dict, database)
+ self.write_atom_properties(atom_symbol, property_dict, database._properties)
+
def _dump_chemical_system(self):
"""Dump the chemical system to the trajectory file."""
@@ -423,11 +667,10 @@ def close(self):
"""Close the trajectory file"""
self.validate_charges()
- configuration = self._chemical_system.configuration
n_atoms = self._chemical_system.total_number_of_atoms
- if configuration is not None:
+ if self._last_configuration is not None:
configuration_grp = self._h5_file["/configuration"]
- for k, v in configuration.variables.items():
+ for k, v in self._last_configuration.variables.items():
dset = configuration_grp.get(k, None)
dset.resize((self._current_index, n_atoms, 3))
try:
@@ -488,7 +731,7 @@ def validate_charges(self):
if variable_charge_dset is not None:
del self._h5_file[variable_charge_dset.name]
- def dump_configuration(self, time, units=None):
+ def dump_configuration(self, configuration, time, units=None):
"""Dump the chemical system configuration at a given time.
:param time: the time
@@ -503,7 +746,6 @@ def dump_configuration(self, time, units=None):
f"The current index {self._current_index} is greater than the actual number of steps of the trajectory {self._n_steps}"
)
- configuration = self._chemical_system.configuration
if configuration is None:
return
@@ -560,6 +802,7 @@ def dump_configuration(self, time, units=None):
time_dset[self._current_index] = time
self._current_index += 1
+ self._last_configuration = configuration
class RigidBodyTrajectoryGenerator:
@@ -575,7 +818,7 @@ class RigidBodyTrajectoryGenerator:
def __init__(
self,
trajectory,
- chemical_entity: _ChemicalEntity,
+ chemical_entity: List[int],
reference,
first=0,
last=None,
@@ -586,7 +829,7 @@ def __init__(
:param trajectory: the input trajectory
:type trajectory: MDANSE.Trajectory.Trajectory
:param chemical_entity: the chemical enitty for which the Rigig-Body trajectory should be computed
- :type chemical_entity: MDANSE.Chemistry.ChemicalEntity.ChemicalEntity
+ :type chemical_entity: MDANSE.Chemistry.ChemicalSystem.ChemicalEntity
:param reference: the reference configuration. Must be continuous.
:type reference: MDANSE.MolecularDynamics.Configuration.Configuration
:param first: the index of the first frame
@@ -604,9 +847,7 @@ def __init__(
atoms = chemical_entity.atom_list
- masses = [
- ATOMS_DATABASE.get_atom_property(at.symbol, "atomic_weight") for at in atoms
- ]
+ masses = [ATOMS_DATABASE.get_atom_property(at, "atomic_weight") for at in atoms]
mass = sum(masses)
@@ -624,7 +865,7 @@ def __init__(
# relative coords of the CONTIGUOUS reference
r_ref = np.zeros((len(atoms), 3), np.float64)
for i, at in enumerate(atoms):
- r_ref[i] = reference["coordinates"][at.index, :] - ref_com
+ r_ref[i] = reference["coordinates"][i, :] - ref_com
unit_cells, inverse_unit_cells = self._trajectory.get_unit_cells()
if unit_cells is not None:
@@ -632,9 +873,7 @@ def __init__(
inverse_unit_cells = inverse_unit_cells[first:last:step, :, :]
for i, at in enumerate(atoms):
- r = self._trajectory.read_atomic_trajectory(
- at.index, first, last, step, True
- )
+ r = self._trajectory.read_atomic_trajectory(i, first, last, step, True)
r = r - rcms
r = r[:, np.newaxis, :]
@@ -745,7 +984,7 @@ def read_atoms_trajectory(
# from MDANSE.MolecularDynamics.Configuration import RealConfiguration
- # from MDANSE.Chemistry.ChemicalEntity import Atom
+ # from MDANSE.Chemistry.ChemicalSystem import Atom
# cs = ChemicalSystem()
# for i in range(768):
# cs.add_chemical_entity(Atom(symbol='H'))
@@ -770,8 +1009,6 @@ def read_atoms_trajectory(
if __name__ == "__main__":
from MDANSE.MolecularDynamics.Configuration import RealConfiguration
- from MDANSE.Chemistry.ChemicalEntity import Atom
-
cs = ChemicalSystem()
for i in range(2):
cs.add_chemical_entity(Atom(symbol="H"))
diff --git a/MDANSE/Src/MDANSE/MolecularDynamics/TrajectoryUtils.py b/MDANSE/Src/MDANSE/MolecularDynamics/TrajectoryUtils.py
index c4ca42d668..3f27c1519b 100644
--- a/MDANSE/Src/MDANSE/MolecularDynamics/TrajectoryUtils.py
+++ b/MDANSE/Src/MDANSE/MolecularDynamics/TrajectoryUtils.py
@@ -15,20 +15,13 @@
#
import operator
-from typing import Union, Iterable
+from typing import Union, Iterable, List
import numpy as np
from MDANSE.Core.Error import Error
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import (
- Atom,
- AtomCluster,
- AtomGroup,
- ChemicalSystem,
- _ChemicalEntity,
-)
-from MDANSE.Extensions import fast_calculation
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
class MolecularDynamicsError(Error):
@@ -53,440 +46,61 @@ def elements_from_masses(masses: Iterable[float], tolerance: float = 0.01):
return result
-def atom_index_to_molecule_index(chemical_system: ChemicalSystem) -> dict[int, int]:
- """
- Maps the indices of all atoms in a chemical system to the indices of their root parent chemical entities and returns
- the lookup table. This can then be used to retrieve the root parent chemical entity of an atom through the
- chemical_entities property of ChemicalSystem.
-
- :param chemical_system: the chemical system whose lookup table is to be generated
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
+def atom_index_to_molecule_index(chemical_system: ChemicalSystem) -> List[int]:
+ """Returns a list of molecule numbers, per atom. Single
+ atoms are assigned the value -1.
- :return: a lookup table mapping atom indices to the indices of their root chemical entity
- :rtype: dict
-
- :Example:
+ Parameters
+ ----------
+ chemical_system : ChemicalSystem
+ Object describing all the atoms and molecules in the system
- >>> from MDANSE.Chemistry.ChemicalEntity import Molecule, ChemicalSystem
- >>>
- >>> # Set up a chemical system
- >>> molecules = [Molecule('WAT', 'w1'), Molecule('WAT', 'w2')]
- >>> cs = ChemicalSystem()
- >>> for molecule in molecules:
- >>> cs.add_chemical_entity(molecule)
- >>>
- >>> atom_index_to_molecule_index(cs)
- {0: 0, 1: 0, 2: 0, 3: 1, 4: 1, 5: 1}
+ Returns
+ -------
+ List[int]
+ list of molecule numbers, per atom.
"""
- lut = {}
- for i, ce in enumerate(chemical_system.chemical_entities):
- for at in ce.atom_list:
- lut[at.index] = i
-
+ lut = [-1] * len(chemical_system.atom_list)
+ last_cluster = 1
+ for cluster_name in chemical_system._clusters:
+ for cluster in chemical_system._clusters[cluster_name]:
+ for atom_index in cluster:
+ lut[atom_index] = last_cluster
+ last_cluster += 1
return lut
-def brute_formula(
- chemical_entity: _ChemicalEntity, sep: str = "_", ignore_ones: bool = False
-) -> str:
- """
- Determine the molecular formula of a given chemical entity.
-
- :param chemical_entity: the chemical entity whose formula is to be determined
- :type chemical_entity: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalEntity`
-
- :param sep: the separator used between elements, i.e. with the default separator a water molecule will return H2_O1
- :type sep: str
-
- :param ignore_ones: determines whether number 1 should be printed, i.e. whether water should be H2_O1 or H2_O
- :type ignore_ones: bool
-
- :return: the molecular formula
- :rtype: str
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Molecule
- >>> m = Molecule('WAT', 'water')
- >>>
- >>> brute_formula(m)
- 'H2_O1'
- >>> brute_formula(m, '')
- 'H2O1'
- >>> brute_formula(m, '', True)
- 'H2O'
- """
-
- contents = {}
-
- for at in chemical_entity.atom_list:
- contents[at.symbol] = str(int(contents.get(at.symbol, 0)) + 1)
-
- formula = sep.join(["".join(v) for v in sorted(contents.items())])
-
- if ignore_ones:
- return formula.replace("1", "")
- else:
- return formula
-
-
-def build_connectivity(
- chemical_system: ChemicalSystem, tolerance: float = 0.05
-) -> None:
- """
- Creates bonds between atoms within each atom cluster as well as between loose atoms. Bonds are created only between
- atoms whose covalent radii overlap, i.e. for whose the sum of their covalent radii plus the tolerance is smaller
- than their distance. Bonds are created only between atoms within a
- :class: `MDANSE.Chemistry.ChemicalEntity.AtomCluster` or between loose atoms (atoms that are not part of another
- chemical entity or which are the only atom in their chemical entity). No bonds are created between atoms of other
- chemical entities (unless it's the only atom in it), and no bonds are created between atoms in different atom
- clusters or between atoms in an entity and loose atoms, regardless of their positions.
-
- NOTE: Periodic boundary conditions are ignored in this function; bonds are not created across PBC, only within.
-
- Please note that the coordinates of atoms are taken from the configuration registered in the provided chemical
- system.
-
- :param chemical_system: the chemical system in which bonds are to be created
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
-
- :param tolerance: the tolerance used for defining whether two atoms are bonded in nm
- :type tolerance: float
-
- :return: None
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Atom, AtomCluster, AtomGroup, Molecule, ChemicalSystem
- >>> from MDANSE.MolecularDynamics.Configuration import RealConfiguration
- >>> import numpy as np
- >>>
- >>> cs = ChemicalSystem()
- >>>
- >>> # Atoms in a Molecule object will not be changed
- >>> molecule = Molecule('WAT', 'water')
- >>>
- >>> # Atoms in atom clusters and loose atoms as well as the atom group as it has only one atom will be bonded
- >>> # if appropriate. All the atoms here are H atoms whose covalent radius is 0.023 in MDANSE atom database
- >>> atom = Atom(name='loose atom')
- >>> cluster = AtomCluster('name', [Atom(name=f'cluster atom {i}') for i in range(4)])
- >>> group = AtomGroup([Atom(name='group atom', parent=cs)])
- >>>
- >>> for entity in [molecule, atom, cluster, group]:
- >>> cs.add_chemical_entity(entity)
- >>>
- >>> # The coordinates of all the previously defined particles, in the order they were added to the chemical system
- >>> coords = np.array([[1, 1.05, 1], [1, 0.98, 1], [1, 1.12, 1],
- [1, 1, 1.02],
- [1, 1, 1], [1.044, 1, 1], [0.95, 1, 1], [1.055, 1, 1],
- [1, 1, 1.06]])
- >>> configuration = RealConfiguration(cs, coords)
- >>> cs.configuration = configuration
- >>>
- >>> build_connectivity(cs, 0.005)
- >>>
- >>> # The bonding of atoms in molecule has not changed even though. by coordinates, some are within bonding distance
- >>> # of some of the other atoms.
- >>> molecule['OW'].bonds
- [Atom(name='HW2'), Atom(name='HW1')]
- >>> molecule['HW2'].bonds
- [Atom(name='OW')]
- >>> molecule['HW1'].bonds
- [Atom(name='OW')]
- >>>
- >>> # The loose atom is within the bonding distance of the first atom in the cluster, but no bond is created between
- >>> # them since bonds are created only in atoms within each cluster and between other atoms separately. A bond is,
- >>> # however created between the loose atom and the atom in the atom group since they are within bonding distance
- >>> # and are considered to be 'other' atoms (not withing a cluster but not within a large structure).
- >>> atom.bonds
- [Atom(name='group atom')]
- >>> group._atoms[0].bonds
- [Atom(name='loose atom')]
- >>>
- >>> # Atoms are bonded purely based on distance (sum of the two atoms' covalent radii + tolerance) regardless of the
- >>> # element, so it is possible to end up in a chemically unfeasible situation such as this chain of 4 H atoms:
- >>> cluster[0].bonds
- [Atom(name='cluster atom 1'), Atom(name='cluster atom 2')]
- >>> cluster[1].bonds
- [Atom(name='cluster atom 0'), Atom(name='cluster atom 3')]
- >>> cluster[2].bonds
- [Atom(name='cluster atom 0')]
- >>> cluster[3].bonds
- [Atom(name='cluster atom 1')]
- """
-
- conf = chemical_system.configuration
-
- atom_clusters = []
- single_atoms_objects = []
-
- # Find all atom clusters, loose atoms, and one-atom objects
- for ce in chemical_system.chemical_entities:
- if isinstance(ce, Atom):
- single_atoms_objects.append(ce)
- elif isinstance(ce, AtomCluster):
- atom_clusters.append(ce)
- else:
- if ce.number_of_atoms == 1:
- single_atoms_objects.extend(ce.atom_list)
-
- if single_atoms_objects:
- atom_clusters.append(AtomCluster("", single_atoms_objects, parentless=True))
-
- for ce in atom_clusters:
- atoms = sorted(ce.atom_list, key=operator.attrgetter("index"))
-
- n_atoms = len(atoms)
- indexes = [at.index for at in atoms]
- coords = conf.to_real_coordinates()[indexes, :]
- cov_radii = np.zeros((n_atoms,), dtype=np.float64)
- for i, at in enumerate(atoms):
- cov_radii[i] = ATOMS_DATABASE.get_atom_property(
- at.symbol.capitalize(), "covalent_radius"
- )
-
- bonds = fast_calculation.cpt_cluster_connectivity_nopbc(
- coords, cov_radii, tolerance
- )
-
- for idx1, idx2 in bonds:
- atoms[idx1].bonds.append(atoms[idx2])
- atoms[idx2].bonds.append(atoms[idx1])
-
-
def find_atoms_in_molecule(
chemical_system: ChemicalSystem,
entity_name: str,
atom_names: list[str],
- indexes: bool = False,
-) -> list[list[Union[Atom, int]]]:
- """
- Finds all chemical entities of the provided name within the chemical system, and then retrieves all atoms from each
- of the found entities whose name matches one of the provided atom names. However, please note that only the chemical
- entities directly registered in the chemical system are searched, i.e. the chemical_entities property of
- :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`. Therefore, for example, if a chemical system consists of a
- Protein with name 'protein' which consists of 2 NucleotideChains 'chain1' and 'chain2', and this function is called
- with the entity_name parameter set to 'chain1', an empty list will be returned.
-
- :param chemical_system: the chemical system to be searched
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
-
- :param entity_name: the name of the chemical entity to match
- :type entity_name: str
-
- :param atom_names: the list of atom names to search
- :type atom_names: list
-
- :param indexes: if True the indexes of the atoms will be returned otherwise the Atom instances will be returned
- :type indexes: bool
-
- :return: the list of indexes or atom instances found
- :rtype: list
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Molecule, ChemicalSystem
- >>>
- >>> cs = ChemicalSystem()
- >>>
- >>> molecules = [Molecule('WAT', 'water'), Molecule('WAT', 'water'), Molecule('WAT', 'totally not water')]
- >>> for molecule in molecules:
- >>> cs.add_chemical_entity(molecule)
- >>>
- >>> # Search for all hydrogen atoms in molecules called water
- >>> find_atoms_in_molecule(cs, 'water', ['HW2', 'HW1'])
- [[Atom(name='HW2'), Atom(name='HW1')], [Atom(name='HW2'), Atom(name='HW1')]]
- >>> # Searching for atoms in molecules that do not exist returns an empty list
- >>> find_atoms_in_molecule(cs, 'INVALID', ['HW1'])
- []
- >>> # Searching for atoms that do not exist in the molecules of the specified name returns a list of empty lists
- >>> find_atoms_in_molecule(cs, 'water', ['INVALID'])
- [[], []]
- >>> # Setting the indexes parameter to True causes indices to be returned instead of atom objects
- >>> find_atoms_in_molecule(cs, 'water', ['HW2', 'HW1'], True)
- [[1, 2], [4, 5]]
- """
-
- # Loop over the chemical entities of the chemical entity and keep only those whose name match |ce_name|
- chemical_entities = []
- for ce in chemical_system.chemical_entities:
- if ce.name == entity_name:
- chemical_entities.append(ce)
-
- match = []
- for ce in chemical_entities:
- atoms = ce.atom_list
- names = [at.name for at in atoms]
- try:
- match.append([atoms[names.index(at_name)] for at_name in atom_names])
- except ValueError:
- match.append([])
-
- if indexes is True:
- match = [[at.index for at in at_list] for at_list in match]
-
- return match
-
-
-def get_chemical_objects_dict(
- chemical_system: ChemicalSystem,
-) -> dict[str, list[_ChemicalEntity]]:
- """
- Maps all chemical entities in a chemical system to their names, and returns this as a dict. Please note that only
- the top level chemical entities (those directly registered in chemical system) are mapped; children entities are not
- mapped.
-
- :param chemical_system: the chemical system whose entities are to be retrieved
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
-
- :return: a dict mapping the names of the entities in a chemical system to a list of entities with that name
- :rtype: dict
-
- :Examples:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Molecule, ChemicalSystem
- >>>
- >>> compounds = [Molecule('WAT', 'water'), Molecule('WAT', 'water'), Molecule('WAT', 'dihydrogen monoxide'), Atom()]
- >>>
- >>> cs = ChemicalSystem()
- >>> for compound in compounds:
- >>> cs.add_chemical_entity(compound)
- >>>
- >>> # The atoms that are part of molecules (and so not registered with the chemical system directly) are not mapped
- >>> get_chemical_objects_dict(cs)
- {'water': [Molecule(name='water'), Molecule(name='water')],
- 'dihydrogen monoxide': [Molecule(name='dihydrogen monoxide')], '': [Atom(name='')]}
- """
-
- d = {}
- for ce in chemical_system.chemical_entities:
- d.setdefault(ce.name, []).append(ce)
-
- return d
-
-
-def group_atoms(
- chemical_system: ChemicalSystem, groups: list[list[int]]
-) -> list[AtomGroup]:
- """
- Groups select atoms into :class: `MDANSE.Chemistry.ChemicalEntity.AtomGroup` objects according to the instructions
- in the 'groups' argument. Please note, however, that the groups are created strictly according to this parameter,
- meaning that not all atoms are necessarily placed into a group and that some atoms may be placed into multiple
- groups, depending on the instructions. The only exception to this is if one of the lists in the 'groups' parameters
- is empty, in which case no group is created for that list, the instruction silently ignored.
-
- :param chemical_system: the chemical system whose atoms are to be grouped
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
-
- :param groups: the nested list of indexes, each sublist defining a group
- :type groups: list
-
- :return: list of atom groups as specified
- :rtype: list
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Atom, Molecule, ChemicalSystem
- >>>
- >>> compounds = [Atom(), Molecule('WAT', ''), Molecule('WAT', ''), Molecule('WAT', '')]
- >>>
- >>> cs = ChemicalSystem()
- >>> for compound in compounds:
- >>> cs.add_chemical_entity(compound)
- >>>
- >>> # An atom group is created for each non-empty list in the provided list of lists
- >>> groups = group_atoms(cs, [[0, 2], [], [3], [5, 7, 9]])
- >>> groups
- [AtomGroup(), AtomGroup(), AtomGroup()]
- >>> groups[0].atom_list
- [Atom(name=''), Atom(name='HW2')]
- >>> groups[1].atom_list
- [Atom(name='HW1')]
- >>> groups[2].atom_list
- [Atom(name='HW2'), Atom(name='OW'), Atom(name='HW1')]
- """
- atoms = chemical_system.atom_list
-
- groups = [AtomGroup([atoms[index] for index in gr]) for gr in groups if gr]
-
- return groups
-
-
-def resolve_undefined_molecules_name(chemical_system: ChemicalSystem) -> None:
- """
- Changes the names of all top-level chemical entities (those directly registered with a chemical system) that have no
- name to their molecular formulae. To be considered to have no name, the molecule's name must be an empty string or a
- string that consists of only spaces. The molecular formula is determined through
- :func: `MDANSE.MolecularDynamics.TrajectoryUtils.resolve_undefined_molecules_name`.
-
- :param chemical_system: the chemical system
- :type chemical_system: :class: `MDANSE.Chemistry.ChemicalEntity.ChemicalSystem`
-
- :return: None
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Atom, Molecule, ChemicalSystem
- >>>
- >>> compounds = [Molecule('WAT', ''), Molecule('WAT', ' water '), Molecule('WAT', ' '), Atom()]
- >>>
- >>> # Alter the name of one of the atoms in a molecule to see that it will not be changed
- >>> compounds[0]['OW'].name = ''
- >>>
- >>> cs = ChemicalSystem()
- >>> for compound in compounds:
- >>> cs.add_chemical_entity(compound)
- >>>
- >>> resolve_undefined_molecules_name(cs)
- >>> cs.chemical_entities
- [Molecule(name='H2O1'), Molecule(name=' water '), Molecule(name='H2O1'), Atom(name='H1')]
- >>> compounds[0]['OW'].name
- ''
- """
- # Is it okay to not do this for children?
- for ce in chemical_system.chemical_entities:
- if not ce.name.strip():
- ce.name = brute_formula(ce, sep="")
-
-
-def sorted_atoms(
- atoms: list[Atom], attribute: str = None
-) -> list[Union[Atom, float, int, str, list]]:
- """
- Sort a list of atoms according to their index, and returns either the sorted list of atoms or the values of the
- specified attribute.
-
- :param atoms: the atom list to be sorted
- :type atoms: list
-
- :param attribute: if not None, return the attribute of the atom instead of the atom instance
- :type attribute: str
-
- :return: the sorted atoms or the value of their specified attributes
- :rtype: list
-
- :Example:
-
- >>> from MDANSE.Chemistry.ChemicalEntity import Atom
- >>>
- >>> atoms = [Atom() for _ in range(4)]
- >>> for i, atom in enumerate(atoms):
- >>> atom.index = i
- >>> atom.name = f'atom{i}'
- >>>
- >>> sorted_atoms([atoms[0], atoms[3], atoms[2], atoms[1]])
- [Atom(name='atom0'), Atom(name='atom3'), Atom(name='atom2'), Atom(name='atom1')]
- >>> sorted_atoms([atoms[0], atoms[3], atoms[2], atoms[1]], 'name')
- ['atom0', 'atom3', 'atom2', 'atom1']
- """
-
- atoms = sorted(atoms, key=operator.attrgetter("index"))
+ indices: bool = False,
+) -> list[list[int]]:
+
+ if entity_name not in chemical_system._clusters:
+ return []
+
+ result = []
+ for index_list in chemical_system._clusters[entity_name]:
+ if indices:
+ result.append(
+ [
+ chemical_system._atom_indices[index]
+ for index in index_list
+ if chemical_system.atom_list[index] in atom_names
+ ]
+ )
+ else:
+ result.append(
+ [
+ chemical_system.atom_list[index]
+ for index in index_list
+ if chemical_system.atom_list[index] in atom_names
+ ]
+ )
- if attribute is None:
- return atoms
- else:
- return [getattr(at, attribute) for at in atoms]
+ return result
def atomic_trajectory(config, cell, rcell, box_coordinates=False):
diff --git a/MDANSE/Src/MDANSE/Trajectory/H5MDTrajectory.py b/MDANSE/Src/MDANSE/Trajectory/H5MDTrajectory.py
index e5d252c84e..2684e54bfe 100644
--- a/MDANSE/Src/MDANSE/Trajectory/H5MDTrajectory.py
+++ b/MDANSE/Src/MDANSE/Trajectory/H5MDTrajectory.py
@@ -14,6 +14,7 @@
# along with this program. If not, see .
#
+from typing import List
import os
import numpy as np
@@ -21,15 +22,15 @@
from MDANSE.MLogging import LOG
from MDANSE.Framework.Units import measure
+from MDANSE.Mathematics.Geometry import center_of_mass
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem
-from MDANSE.Extensions import com_trajectory
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import (
PeriodicRealConfiguration,
RealConfiguration,
+ contiguous_coordinates_real,
)
from MDANSE.MolecularDynamics.TrajectoryUtils import (
- resolve_undefined_molecules_name,
atomic_trajectory,
)
from MDANSE.MolecularDynamics.UnitCell import UnitCell
@@ -62,7 +63,7 @@ def __init__(self, h5_filename):
self._chemical_system = ChemicalSystem(
os.path.splitext(os.path.basename(self._h5_filename))[0]
)
- self._chemical_system.from_element_list(chemical_elements)
+ self._chemical_system.initialise_atoms(chemical_elements)
# Load all the unit cells
self._load_unit_cells()
@@ -78,15 +79,6 @@ def __init__(self, h5_filename):
pos_unit = "ang"
conv_factor = measure(1.0, pos_unit).toval("nm")
coords *= conv_factor
- if self._unit_cells:
- unit_cell = self._unit_cells[0]
- conf = PeriodicRealConfiguration(self._chemical_system, coords, unit_cell)
- else:
- conf = RealConfiguration(self._chemical_system, coords)
- self._chemical_system.configuration = conf
-
- # Define a default name for all chemical entities which have no name
- resolve_undefined_molecules_name(self._chemical_system)
self._variables_to_skip = []
@@ -95,12 +87,12 @@ def file_is_right(self, filename):
result = True
try:
temp = h5py.File(filename)
- except:
+ except FileNotFoundError:
result = False
else:
try:
temp["h5md"]
- except:
+ except KeyError:
result = False
return result
@@ -324,12 +316,12 @@ def __len__(self):
return grp.shape[0]
def read_com_trajectory(
- self, atoms, first=0, last=None, step=1, box_coordinates=False
+ self, atom_indices, first=0, last=None, step=1, box_coordinates=False
):
"""Build the trajectory of the center of mass of a set of atoms.
:param atoms: the atoms for which the center of mass should be computed
- :type atoms: list MDANSE.Chemistry.ChemicalEntity.Atom
+ :type atoms: list MDANSE.Chemistry.ChemicalSystem.Atom
:param first: the index of the first frame
:type first: int
:param last: the index of the last frame
@@ -346,19 +338,33 @@ def read_com_trajectory(
if last is None:
last = len(self)
- indexes = [at.index for at in atoms]
+ if len(atom_indices) == 1:
+ return self.read_atomic_trajectory(
+ atom_indices[0],
+ first=first,
+ last=last,
+ step=step,
+ box_coordinates=box_coordinates,
+ )
+
+ atoms = self.chemical_system.atom_list
+
try:
- masses = self._h5_file["/particles/all/mass/value"][:].astype(np.float64)
+ masses = self._h5_file["/particles/all/mass/value"][atom_indices].astype(
+ np.float64
+ )
except KeyError:
try:
- masses = self._h5_file["/particles/all/mass"][:].astype(np.float64)
+ masses = self._h5_file["/particles/all/mass"][atom_indices].astype(
+ np.float64
+ )
except KeyError:
masses = np.array(
[
- ATOMS_DATABASE.get_atom_property(at.symbol, "atomic_weight")
+ ATOMS_DATABASE.get_atom_property(at, "atomic_weight")
for at in atoms
]
- )
+ )[atom_indices]
grp = self._h5_file["/particles/all/position/value"]
try:
pos_unit = self._h5_file["/particles/all/position/value"].attrs["unit"]
@@ -369,50 +375,37 @@ def read_com_trajectory(
pos_unit = "ang"
conv_factor = measure(1.0, pos_unit).toval("nm")
- coords = grp[first:last:step, :, :].astype(np.float64) * conv_factor
+ coords = grp[first:last:step, atom_indices, :].astype(np.float64) * conv_factor
if coords.ndim == 2:
coords = coords[np.newaxis, :, :]
if self._unit_cells is not None:
direct_cells = np.array(
- [
- self.unit_cell(nf).transposed_direct
- for nf in range(first, last, step)
- ]
+ [self.unit_cell(nf).direct for nf in range(first, last, step)]
)
inverse_cells = np.array(
- [
- self.unit_cell(nf).transposed_inverse
- for nf in range(first, last, step)
- ]
+ [self.unit_cell(nf).inverse for nf in range(first, last, step)]
)
-
- top_lvl_chemical_entities = set(
- [at.top_level_chemical_entity for at in atoms]
- )
- top_lvl_chemical_entities_indexes = [
- [at.index for at in e.atom_list] for e in top_lvl_chemical_entities
- ]
- bonds = {}
- for e in top_lvl_chemical_entities:
- for at in e.atom_list:
- bonds[at.index] = [other_at.index for other_at in at.bonds]
-
- com_traj = com_trajectory.com_trajectory(
+ temp_coords = contiguous_coordinates_real(
coords,
direct_cells,
inverse_cells,
- masses,
- top_lvl_chemical_entities_indexes,
- indexes,
- bonds,
- box_coordinates=box_coordinates,
+ [list(range(len(coords)))],
+ bring_to_centre=True,
+ )
+ com_coords = np.vstack(
+ [
+ center_of_mass(temp_coords[tstep], masses)
+ for tstep in range(len(temp_coords))
+ ]
)
+ com_traj = atomic_trajectory(com_coords, direct_cells, inverse_cells)
+
else:
com_traj = np.sum(
- coords[:, indexes, :] * masses[np.newaxis, :, np.newaxis], axis=1
+ coords[:, atom_indices, :] * masses[np.newaxis, :, np.newaxis], axis=1
)
com_traj /= np.sum(masses)
@@ -553,12 +546,21 @@ def has_variable(self, variable: str) -> bool:
else:
return False
+ def get_atom_property(self, atom_symbol: str, property: str):
+ return ATOMS_DATABASE.get_atom_property(atom_symbol, property)
+
+ def atoms_in_database(self) -> List[str]:
+ return ATOMS_DATABASE.atoms
+
+ def properties_in_database(self) -> List[str]:
+ return ATOMS_DATABASE.properties
+
@property
def chemical_system(self):
"""Return the chemical system stored in the trajectory.
:return: the chemical system
- :rtype: MDANSE.Chemistry.ChemicalEntity.ChemicalSystem
+ :rtype: MDANSE.Chemistry.ChemicalSystem.ChemicalSystem
"""
return self._chemical_system
diff --git a/MDANSE/Src/MDANSE/Trajectory/MdanseTrajectory.py b/MDANSE/Src/MDANSE/Trajectory/MdanseTrajectory.py
index 0dd69910ad..eab9d9dd8e 100644
--- a/MDANSE/Src/MDANSE/Trajectory/MdanseTrajectory.py
+++ b/MDANSE/Src/MDANSE/Trajectory/MdanseTrajectory.py
@@ -14,20 +14,22 @@
# along with this program. If not, see .
#
import os
+from typing import List
+import traceback
import numpy as np
import h5py
from MDANSE.MLogging import LOG
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem
-from MDANSE.Extensions import com_trajectory
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
+from MDANSE.Mathematics.Geometry import center_of_mass
from MDANSE.MolecularDynamics.Configuration import (
PeriodicRealConfiguration,
RealConfiguration,
+ contiguous_coordinates_real,
)
from MDANSE.MolecularDynamics.TrajectoryUtils import (
- resolve_undefined_molecules_name,
atomic_trajectory,
)
from MDANSE.MolecularDynamics.UnitCell import UnitCell
@@ -52,40 +54,32 @@ def __init__(self, h5_filename):
# Load the chemical system
self._chemical_system = ChemicalSystem(
- os.path.splitext(os.path.basename(self._h5_filename))[0]
+ os.path.splitext(os.path.basename(self._h5_filename))[0], self
)
- self._chemical_system.load(self._h5_filename)
+ self._chemical_system.load(self._h5_file)
# Load all the unit cells
self._load_unit_cells()
- # Load the first configuration
- coords = self._h5_file["/configuration/coordinates"][0, :, :]
- if self._unit_cells:
- unit_cell = self._unit_cells[0]
- conf = PeriodicRealConfiguration(self._chemical_system, coords, unit_cell)
- else:
- conf = RealConfiguration(self._chemical_system, coords)
- self._chemical_system.configuration = conf
-
- # Define a default name for all chemical entities which have no name
- resolve_undefined_molecules_name(self._chemical_system)
-
@classmethod
def file_is_right(self, filename):
result = True
try:
- temp = h5py.File(filename)
- except:
+ file_object = h5py.File(filename)
+ except FileNotFoundError:
result = False
else:
try:
temp_cs = ChemicalSystem(
os.path.splitext(os.path.basename(filename))[0]
)
- temp_cs.load(filename)
- except:
+ temp_cs.load(file_object)
+ except Exception:
+ LOG.warning(
+ f"Could not load ChemicalSystem from {filename}. MDANSE will try to read it as H5MD next."
+ )
result = False
+ file_object.close()
return result
def close(self):
@@ -241,12 +235,12 @@ def __len__(self):
return grp["coordinates"].shape[0]
def read_com_trajectory(
- self, atoms, first=0, last=None, step=1, box_coordinates=False
+ self, atom_indices, first=0, last=None, step=1, box_coordinates=False
):
"""Build the trajectory of the center of mass of a set of atoms.
:param atoms: the atoms for which the center of mass should be computed
- :type atoms: list MDANSE.Chemistry.ChemicalEntity.Atom
+ :type atoms: list MDANSE.Chemistry.ChemicalSystem.Atom
:param first: the index of the first frame
:type first: int
:param last: the index of the last frame
@@ -263,49 +257,58 @@ def read_com_trajectory(
if last is None:
last = len(self)
- indexes = [at.index for at in atoms]
- masses = np.array(
- [
- ATOMS_DATABASE.get_atom_property(at.symbol, "atomic_weight")
- for at in atoms
- ]
- )
+ if len(atom_indices) == 1:
+ return self.read_atomic_trajectory(
+ atom_indices[0],
+ first=first,
+ last=last,
+ step=step,
+ box_coordinates=box_coordinates,
+ )
+
+ try:
+ masses = self.chemical_system.atom_property("atomic_weight")
+ except KeyError:
+ masses = np.array(
+ [
+ ATOMS_DATABASE.get_atom_property(at, "atomic_weight")
+ for at in self.chemical_system.atom_list
+ ]
+ )
+ masses = [masses[index] for index in atom_indices]
grp = self._h5_file["/configuration"]
- coords = grp["coordinates"][first:last:step, :, :].astype(np.float64)
+ coords = grp["coordinates"][first:last:step, atom_indices, :].astype(np.float64)
if coords.ndim == 2:
coords = coords[np.newaxis, :, :]
if self._unit_cells is not None:
- direct_cells = np.array([uc.transposed_direct for uc in self._unit_cells])
- inverse_cells = np.array([uc.transposed_inverse for uc in self._unit_cells])
-
- top_lvl_chemical_entities = set(
- [at.top_level_chemical_entity for at in atoms]
+ direct_cells = np.array(
+ [uc.direct for uc in self._unit_cells[first:last:step]]
)
- top_lvl_chemical_entities_indexes = [
- [at.index for at in e.atom_list] for e in top_lvl_chemical_entities
- ]
- bonds = {}
- for e in top_lvl_chemical_entities:
- for at in e.atom_list:
- bonds[at.index] = [other_at.index for other_at in at.bonds]
-
- com_traj = com_trajectory.com_trajectory(
+ inverse_cells = np.array(
+ [uc.inverse for uc in self._unit_cells[first:last:step]]
+ )
+ temp_coords = contiguous_coordinates_real(
coords,
direct_cells,
inverse_cells,
- masses,
- top_lvl_chemical_entities_indexes,
- indexes,
- bonds,
- box_coordinates=box_coordinates,
+ [list(range(len(coords)))],
+ bring_to_centre=True,
)
+ com_coords = np.vstack(
+ [
+ center_of_mass(temp_coords[tstep], masses)
+ for tstep in range(len(temp_coords))
+ ]
+ )
+
+ com_traj = atomic_trajectory(com_coords, direct_cells, inverse_cells)
else:
com_traj = np.sum(
- coords[:, indexes, :] * masses[np.newaxis, :, np.newaxis], axis=1
+ coords[:, atom_indices, :] * masses[np.newaxis, :, np.newaxis], axis=1
)
com_traj /= np.sum(masses)
@@ -438,12 +441,61 @@ def has_variable(self, variable: str) -> bool:
else:
return False
+ def get_atom_property(self, symbol: str, property: str):
+ if "atom_database" not in self._h5_file:
+ return ATOMS_DATABASE.get_atom_property(symbol, property)
+ elif symbol not in self._h5_file["/atom_database"]:
+ return ATOMS_DATABASE.get_atom_property(symbol, property)
+ temp = np.where(
+ self._h5_file["/atom_database/property_labels"][:]
+ == property.encode("utf-8")
+ )[0]
+ if len(temp) == 0:
+ if property == "dummy":
+ try:
+ return ATOMS_DATABASE.get_atom_property(symbol, property)
+ except KeyError:
+ if (
+ "_" in symbol
+ ): # this is most likely an artificial atom from a molecule
+ return 0 # the molecule atoms are not dummy
+ else:
+ raise KeyError(
+ f"Property {property} is not in the trajectory's internal database."
+ )
+ index = temp.flatten()[0]
+ data_type = self._h5_file["/atom_database/property_types"][index]
+ value = self._h5_file[f"/atom_database/{symbol}"][index]
+ if data_type == b"int":
+ return int(value)
+ if property == "color":
+ num1 = round(value // 0x10000)
+ num2 = round((value - num1 * 0x10000) // 0x100)
+ num3 = round((value - num1 * 0x10000 - num2 * 0x100))
+ return ";".join([str(int(x)) for x in [num1, num2, num3]])
+ return value
+
+ def atoms_in_database(self) -> List[str]:
+ if "atom_database" not in self._h5_file:
+ return ATOMS_DATABASE.atoms
+ else:
+ return list(self._h5_file["/atom_database"].keys())
+
+ def properties_in_database(self) -> List[str]:
+ if "atom_database" not in self._h5_file:
+ return ATOMS_DATABASE.properties
+ else:
+ return list(
+ label.decode("utf-8")
+ for label in self._h5_file["/atom_database/property_labels"]
+ )
+
@property
def chemical_system(self):
"""Return the chemical system stored in the trajectory.
:return: the chemical system
- :rtype: MDANSE.Chemistry.ChemicalEntity.ChemicalSystem
+ :rtype: MDANSE.Chemistry.ChemicalSystem.ChemicalSystem
"""
return self._chemical_system
diff --git a/MDANSE/Src/MDANSE/mdtraj/__init__.py b/MDANSE/Src/MDANSE/mdtraj/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/MDANSE/Src/MDANSE/mdtraj/utils.py b/MDANSE/Src/MDANSE/mdtraj/utils.py
deleted file mode 100644
index 75b583f587..0000000000
--- a/MDANSE/Src/MDANSE/mdtraj/utils.py
+++ /dev/null
@@ -1,188 +0,0 @@
-##############################################################################
-# MDTraj: A Python Library for Loading, Saving, and Manipulating
-# Molecular Dynamics Trajectories.
-# Copyright 2012-2013 Stanford University and the Authors
-#
-# Authors: Robert McGibbon
-# Contributors:
-#
-# MDTraj is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 2.1
-# of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with MDTraj. If not, see .
-##############################################################################
-
-
-##############################################################################
-# imports
-##############################################################################
-
-import collections
-import numbers
-import warnings
-from itertools import zip_longest
-
-import numpy as np
-
-
-class TypeCastPerformanceWarning(RuntimeWarning):
- pass
-
-
-def ensure_type(
- val,
- dtype,
- ndim,
- name,
- length=None,
- can_be_none=False,
- shape=None,
- warn_on_cast=True,
- add_newaxis_on_deficient_ndim=False,
-):
- """Typecheck the size, shape and dtype of a numpy array, with optional
- casting.
-
- Parameters
- ----------
- val : {np.ndaraay, None}
- The array to check
- dtype : {nd.dtype, str}
- The dtype you'd like the array to have
- ndim : int
- The number of dimensions you'd like the array to have
- name : str
- name of the array. This is used when throwing exceptions, so that
- we can describe to the user which array is messed up.
- length : int, optional
- How long should the array be?
- can_be_none : bool
- Is ``val == None`` acceptable?
- shape : tuple, optional
- What should be shape of the array be? If the provided tuple has
- Nones in it, those will be semantically interpreted as matching
- any length in that dimension. So, for example, using the shape
- spec ``(None, None, 3)`` will ensure that the last dimension is of
- length three without constraining the first two dimensions
- warn_on_cast : bool, default=True
- Raise a warning when the dtypes don't match and a cast is done.
- add_newaxis_on_deficient_ndim : bool, default=True
- Add a new axis to the beginining of the array if the number of
- dimensions is deficient by one compared to your specification. For
- instance, if you're trying to get out an array of ``ndim == 3``,
- but the user provides an array of ``shape == (10, 10)``, a new axis will
- be created with length 1 in front, so that the return value is of
- shape ``(1, 10, 10)``.
-
- Notes
- -----
- The returned value will always be C-contiguous.
-
- Returns
- -------
- typechecked_val : np.ndarray, None
- If `val=None` and `can_be_none=True`, then this will return None.
- Otherwise, it will return val (or a copy of val). If the dtype wasn't right,
- it'll be casted to the right shape. If the array was not C-contiguous, it'll
- be copied as well.
-
- """
- if can_be_none and val is None:
- return None
-
- if not isinstance(val, np.ndarray):
- if isinstance(val, collections.abc.Iterable):
- # If they give us an iterator, let's try...
- if isinstance(val, collections.abc.Sequence):
- # sequences are easy. these are like lists and stuff
- val = np.array(val, dtype=dtype)
- else:
- # this is a generator...
- val = np.array(list(val), dtype=dtype)
- elif np.isscalar(val) and add_newaxis_on_deficient_ndim and ndim == 1:
- # special case: if the user is looking for a 1d array, and
- # they request newaxis upconversion, and provided a scalar
- # then we should reshape the scalar to be a 1d length-1 array
- val = np.array([val])
- else:
- raise TypeError(
- f"{name} must be numpy array. You supplied type {type(val)}"
- )
-
- if warn_on_cast and val.dtype != dtype:
- warnings.warn(
- f"Casting {name} dtype={val.dtype} to {dtype} ",
- TypeCastPerformanceWarning,
- )
-
- if not val.ndim == ndim:
- if add_newaxis_on_deficient_ndim and val.ndim + 1 == ndim:
- val = val[np.newaxis, ...]
- else:
- raise ValueError(f"{name} must be ndim {ndim}. You supplied {val.ndim}")
-
- val = np.ascontiguousarray(val, dtype=dtype)
-
- if length is not None and len(val) != length:
- raise ValueError(f"{name} must be length {length}. You supplied {len(val)}")
-
- if shape is not None:
- # the shape specified given by the user can look like (None, None 3)
- # which indicates that ANY length is accepted in dimension 0 or
- # dimension 1
- sentenel = object()
- error = ValueError(
- "{} must be shape {}. You supplied "
- "{}".format(name, str(shape).replace("None", "Any"), val.shape),
- )
- for a, b in zip_longest(val.shape, shape, fillvalue=sentenel):
- if a is sentenel or b is sentenel:
- # if the sentenel was reached, it means that the ndim didn't
- # match or something. this really shouldn't happen
- raise error
- if b is None:
- # if the user's shape spec has a None in it, it matches anything
- continue
- if a != b:
- # check for equality
- raise error
-
- return val
-
-
-def cast_indices(indices):
- """Check that ``indices`` are appropriate for indexing an array
-
- Parameters
- ----------
- indices : {None, array_like, slice}
- If indices is None or slice, it'll just pass through. Otherwise, it'll
- be converted to a numpy array and checked to make sure it contains
- unique integers.
-
- Returns
- -------
- value : {slice, np.ndarray}
- Either a slice or an array of integers, depending on the input type
- """
- if indices is None or isinstance(indices, slice):
- return indices
-
- if not len(indices) == len(set(indices)):
- raise ValueError("indices must be unique.")
-
- out = np.asarray(indices)
- if not issubclass(out.dtype.type, np.integer):
- raise ValueError(
- "indices must be of an integer type. %s is not an integer type" % out.dtype
- )
-
- return out
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py b/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py
index ea71193886..23923a54a5 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py
@@ -23,11 +23,12 @@
"Ar_mdmc_h5md.h5",
)
-
-@pytest.fixture(scope="module")
-def trajectory():
- trajectory = HDFTrajectoryInputData(short_traj)
- yield trajectory
+com_traj = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "..",
+ "Data",
+ "com_trajectory.mdt",
+)
@pytest.mark.parametrize(
@@ -41,7 +42,7 @@ def trajectory():
(3, False),
],
)
-def test_vacf(trajectory, interp_order, normalise):
+def test_vacf(interp_order, normalise):
temp_name = tempfile.mktemp()
parameters = {}
parameters["frames"] = (0, 10, 1, 5)
@@ -60,7 +61,7 @@ def test_vacf(trajectory, interp_order, normalise):
os.remove(temp_name + ".log")
-def test_pps(trajectory):
+def test_pps():
temp_name = tempfile.mktemp()
parameters = {}
parameters["frames"] = (0, 10, 1, 5)
@@ -98,7 +99,7 @@ def parameters():
},
)
parameters["q_values"] = (0.0, 10.0, 0.1)
- parameters["r_values"] = (0.0, 1.0, 0.01)
+ parameters["r_values"] = (0.0, 0.5, 0.01)
parameters["per_axis"] = False
parameters["reference_direction"] = (0, 0, 1)
parameters["instrument_resolution"] = ("Gaussian", {"sigma": 1.0, "mu": 0.0})
@@ -112,7 +113,7 @@ def parameters():
total_list = []
-for tp in [short_traj, mdmc_traj]:
+for tp in [short_traj, mdmc_traj, com_traj]:
for jt in [
# "AngularCorrelation",
# "GeneralAutoCorrelationFunction",
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_infrared.py b/MDANSE/Tests/UnitTests/Analysis/test_infrared.py
index b9cfece313..9e74f36a4d 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_infrared.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_infrared.py
@@ -24,7 +24,7 @@ def test_dacf_analysis():
parameters["running_mode"] = ("single-core", 1)
parameters["trajectory"] = short_traj
parameters["atom_charges"] = "{}"
- parameters["molecule_name"] = "InChI=1S/CO2/c2-1-3"
+ parameters["molecule_name"] = "C1_O2"
job = IJob.create("DipoleAutoCorrelationFunction")
job.run(parameters, status=True)
assert path.exists(temp_name + ".mda")
@@ -45,7 +45,7 @@ def test_ir_analysis():
parameters["running_mode"] = ("single-core", 1)
parameters["trajectory"] = short_traj
parameters["atom_charges"] = "{}"
- parameters["molecule_name"] = "InChI=1S/CO2/c2-1-3"
+ parameters["molecule_name"] = "C1_O2"
job = IJob.create("Infrared")
job.run(parameters, status=True)
assert path.exists(temp_name + ".mda")
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_molecule_names.py b/MDANSE/Tests/UnitTests/Analysis/test_molecule_names.py
index 1d80818a6e..3db2e6f5aa 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_molecule_names.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_molecule_names.py
@@ -39,7 +39,7 @@ def parameters():
parameters["q_values"] = (0.0, 10.0, 0.1)
parameters["r_values"] = (0.0, 10.0, 0.1)
parameters["per_axis"] = False
- parameters["molecule_name"] = "InChI=1S/CO2/c2-1-3"
+ parameters["molecule_name"] = "C1_O2"
parameters["axis"] = "ab"
parameters["reference_direction"] = (0, 0, 1)
parameters["instrument_resolution"] = ("Gaussian", {"sigma": 1.0, "mu": 0.0})
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_qvectors.py b/MDANSE/Tests/UnitTests/Analysis/test_qvectors.py
index f6da4b2f35..4f3ed99aa2 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_qvectors.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_qvectors.py
@@ -36,7 +36,7 @@ def test_disf(trajectory):
parameters["trajectory"] = short_traj
parameters["weights"] = "b_incoherent2"
for qvector_generator in IQVectors.indirect_subclasses():
- instance = IQVectors.create(qvector_generator, trajectory.chemical_system)
+ instance = IQVectors.create(qvector_generator, trajectory._data.configuration())
qvector_defaults = {
name: value[1]["default"] for name, value in instance.settings.items()
}
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_scattering.py b/MDANSE/Tests/UnitTests/Analysis/test_scattering.py
index 4c1f15609f..b26d37c00d 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_scattering.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_scattering.py
@@ -16,15 +16,16 @@
"short_trajectory_after_changes.mdt",
)
-
-@pytest.fixture(scope="module")
-def trajectory():
- trajectory = HDFTrajectoryInputData(short_traj)
- yield trajectory
+com_traj = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "..",
+ "Data",
+ "com_trajectory.mdt",
+)
@pytest.fixture(scope="module")
-def qvector_spherical_lattice(trajectory):
+def qvector_spherical_lattice():
return (
"SphericalLatticeQVectors",
{"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0},
@@ -75,6 +76,10 @@ def disf():
os.remove(temp_name + ".mda")
+@pytest.mark.parametrize(
+ "trajectory",
+ [short_traj, com_traj],
+)
def test_dcsf(trajectory, qvector_spherical_lattice):
temp_name = tempfile.mktemp()
parameters = {}
@@ -85,7 +90,7 @@ def test_dcsf(trajectory, qvector_spherical_lattice):
parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO")
parameters["q_vectors"] = qvector_spherical_lattice
parameters["running_mode"] = ("single-core",)
- parameters["trajectory"] = short_traj
+ parameters["trajectory"] = trajectory
parameters["weights"] = "b_coherent"
dcsf = IJob.create("DynamicCoherentStructureFactor")
dcsf.run(parameters, status=True)
@@ -119,6 +124,10 @@ def test_output_axis_preview(qvector_spherical_lattice):
assert len(axes) == 3 # two configurators return valid arrays
+@pytest.mark.parametrize(
+ "trajectory",
+ [short_traj, com_traj],
+)
def test_disf(trajectory, qvector_spherical_lattice):
temp_name = tempfile.mktemp()
parameters = {}
@@ -129,7 +138,7 @@ def test_disf(trajectory, qvector_spherical_lattice):
parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO")
parameters["q_vectors"] = qvector_spherical_lattice
parameters["running_mode"] = ("single-core",)
- parameters["trajectory"] = short_traj
+ parameters["trajectory"] = trajectory
parameters["weights"] = "b_incoherent2"
disf = IJob.create("DynamicIncoherentStructureFactor")
disf.run(parameters, status=True)
@@ -144,6 +153,10 @@ def test_disf(trajectory, qvector_spherical_lattice):
os.remove(temp_name + ".log")
+@pytest.mark.parametrize(
+ "trajectory",
+ [short_traj, com_traj],
+)
def test_eisf(trajectory, qvector_spherical_lattice):
temp_name = tempfile.mktemp()
parameters = {}
@@ -153,7 +166,7 @@ def test_eisf(trajectory, qvector_spherical_lattice):
parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO")
parameters["q_vectors"] = qvector_spherical_lattice
parameters["running_mode"] = ("single-core",)
- parameters["trajectory"] = short_traj
+ parameters["trajectory"] = trajectory
parameters["weights"] = "b_incoherent"
eisf = IJob.create("ElasticIncoherentStructureFactor")
eisf.run(parameters, status=True)
@@ -168,6 +181,10 @@ def test_eisf(trajectory, qvector_spherical_lattice):
os.remove(temp_name + ".log")
+@pytest.mark.parametrize(
+ "trajectory",
+ [short_traj, com_traj],
+)
def test_gdisf(trajectory):
temp_name = tempfile.mktemp()
parameters = {}
@@ -178,7 +195,7 @@ def test_gdisf(trajectory):
parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO")
parameters["q_shells"] = (2.0, 12.2, 2.0)
parameters["running_mode"] = ("single-core",)
- parameters["trajectory"] = short_traj
+ parameters["trajectory"] = trajectory
parameters["weights"] = "b_incoherent2"
gdisf = IJob.create("GaussianDynamicIncoherentStructureFactor")
gdisf.run(parameters, status=True)
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_structure.py b/MDANSE/Tests/UnitTests/Analysis/test_structure.py
index e892a90e26..372ecc6272 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_structure.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_structure.py
@@ -22,6 +22,13 @@
"Ar_mdmc_h5md.h5",
)
+com_traj = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "..",
+ "Data",
+ "com_trajectory.mdt",
+)
+
################################################################
# Job parameters #
@@ -58,21 +65,28 @@ def parameters():
total_list = []
-for tp in (short_traj, mdmc_traj):
+for tp in (short_traj, mdmc_traj, com_traj):
for jt in [
"RadiusOfGyration",
- "SolventAccessibleSurface",
- "RootMeanSquareDeviation",
- "RootMeanSquareFluctuation",
"DensityProfile",
"MolecularTrace",
- "Voronoi",
"Eccentricity",
]:
for rm in [("single-core", 1), ("multicore", -4)]:
for of in ["MDAFormat", "TextFormat"]:
total_list.append((tp, jt, rm, of))
+for tp in (short_traj, mdmc_traj):
+ for jt in [
+ "RootMeanSquareDeviation",
+ "RootMeanSquareFluctuation",
+ "SolventAccessibleSurface",
+ "Voronoi",
+ ]:
+ for rm in [("single-core", 1)]:
+ for of in ["MDAFormat"]:
+ total_list.append((tp, jt, rm, of))
+
@pytest.mark.parametrize("traj_path,job_type,running_mode,output_format", total_list)
def test_structure_analysis(
diff --git a/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py b/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py
index be5cbb00e5..734055a8c9 100644
--- a/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py
+++ b/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py
@@ -17,16 +17,19 @@
"Data",
"short_trajectory_after_changes.mdt",
)
+com_traj = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ "..",
+ "Data",
+ "com_trajectory.mdt",
+)
-@pytest.fixture(scope="module")
-def trajectory():
- trajectory = HDFTrajectoryInputData(short_traj)
- yield trajectory
-
-
-@pytest.mark.parametrize("interp_order", [1, 2, 3])
-def test_temperature(trajectory, interp_order):
+@pytest.mark.parametrize(
+ "trajectory_name,interp_order",
+ [(short_traj, 1), (short_traj, 3), (com_traj, 1), (com_traj, 3)],
+)
+def test_temperature(trajectory_name, interp_order):
temp_name = tempfile.mktemp()
parameters = {}
parameters["frames"] = (0, 10, 1)
@@ -44,8 +47,11 @@ def test_temperature(trajectory, interp_order):
os.remove(temp_name + ".log")
-@pytest.mark.parametrize("interp_order", [1, 2, 3])
-def test_temperature_nonzero(trajectory, interp_order):
+@pytest.mark.parametrize(
+ "trajectory_name,interp_order",
+ [(short_traj, 1), (short_traj, 3), (com_traj, 1), (com_traj, 3)],
+)
+def test_temperature_nonzero(trajectory_name, interp_order):
temp_name = tempfile.mktemp()
parameters = {}
parameters["frames"] = (0, 10, 1)
@@ -62,8 +68,16 @@ def test_temperature_nonzero(trajectory, interp_order):
assert np.all(temperature > 0.0)
-@pytest.mark.parametrize("output_format", ["MDAFormat", "TextFormat"])
-def test_density(trajectory, output_format):
+@pytest.mark.parametrize(
+ "trajectory_name,output_format",
+ [
+ (short_traj, "MDAFormat"),
+ (com_traj, "MDAFormat"),
+ (short_traj, "TextFormat"),
+ (com_traj, "TextFormat"),
+ ],
+)
+def test_density(trajectory_name, output_format):
temp_name = tempfile.mktemp()
parameters = {}
parameters["frames"] = (0, 10, 1)
diff --git a/MDANSE/Tests/UnitTests/AtomMapping/test_atom_mapping.py b/MDANSE/Tests/UnitTests/AtomMapping/test_atom_mapping.py
index 5ab015fcd4..da105638e7 100644
--- a/MDANSE/Tests/UnitTests/AtomMapping/test_atom_mapping.py
+++ b/MDANSE/Tests/UnitTests/AtomMapping/test_atom_mapping.py
@@ -158,7 +158,10 @@ def test_check_mapping_valid_as_elements_are_correct_5():
def test_check_mapping_valid_as_elements_are_correct_6():
- labels = [AtomLabel("label=1", molecule="mol=1"), AtomLabel("C=1", molecule="mol=2")]
+ labels = [
+ AtomLabel("label=1", molecule="mol=1"),
+ AtomLabel("C=1", molecule="mol=2"),
+ ]
mapping = {"molecule=mol1": {"label1": "C"}, "molecule=mol2": {"C1": "C"}}
assert check_mapping_valid(mapping, labels)
diff --git a/MDANSE/Tests/UnitTests/AtomSelector/test_all_selector.py b/MDANSE/Tests/UnitTests/AtomSelector/test_all_selector.py
index 186267d514..51c798b98d 100644
--- a/MDANSE/Tests/UnitTests/AtomSelector/test_all_selector.py
+++ b/MDANSE/Tests/UnitTests/AtomSelector/test_all_selector.py
@@ -1,21 +1,20 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.AtomSelector.all_selector import select_all
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
-def test_select_all_returns_correct_number_of_atoms_matches(protein_chemical_system):
- selection = select_all(protein_chemical_system)
+def test_select_all_returns_correct_number_of_atoms_matches(protein_trajectory):
+ selection = select_all(protein_trajectory)
assert len(selection) == 30714
diff --git a/MDANSE/Tests/UnitTests/AtomSelector/test_atom_selectors.py b/MDANSE/Tests/UnitTests/AtomSelector/test_atom_selectors.py
index f5047c2fb6..0269df8528 100644
--- a/MDANSE/Tests/UnitTests/AtomSelector/test_atom_selectors.py
+++ b/MDANSE/Tests/UnitTests/AtomSelector/test_atom_selectors.py
@@ -1,6 +1,6 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.AtomSelector.atom_selectors import (
select_element,
select_hs_on_heteroatom,
@@ -9,83 +9,82 @@
)
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
def test_select_element_returns_true_as_match_exist(
- protein_chemical_system,
+ protein_trajectory,
):
- exists = select_element(protein_chemical_system, "S", check_exists=True)
+ exists = select_element(protein_trajectory, "S", check_exists=True)
assert exists
def test_select_element_returns_false_as_match_does_not_exist(
- protein_chemical_system,
+ protein_trajectory,
):
- exists = select_element(protein_chemical_system, "Si", check_exists=True)
+ exists = select_element(protein_trajectory, "Si", check_exists=True)
assert not exists
def test_select_element_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_element(protein_chemical_system, "S")
+ selection = select_element(protein_trajectory, "S")
assert len(selection) == 10
def test_select_hs_on_carbon_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_element(protein_chemical_system, "C")
+ selection = select_hs_on_element(protein_trajectory, "C")
assert len(selection) == 696
def test_select_hs_on_nitrogen_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_element(protein_chemical_system, "N")
+ selection = select_hs_on_element(protein_trajectory, "N")
assert len(selection) == 243
def test_select_hs_on_oxygen_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_element(protein_chemical_system, "O")
+ selection = select_hs_on_element(protein_trajectory, "O")
assert len(selection) == 19184
def test_select_hs_on_sulfur_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_element(protein_chemical_system, "S")
+ selection = select_hs_on_element(protein_trajectory, "S")
assert len(selection) == 0
def test_select_hs_on_silicon_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_element(protein_chemical_system, "Si")
+ selection = select_hs_on_element(protein_trajectory, "Si")
assert len(selection) == 0
def test_select_hs_on_heteroatom_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hs_on_heteroatom(protein_chemical_system)
+ selection = select_hs_on_heteroatom(protein_trajectory)
assert len(selection) == 19427
def test_select_dummy_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_dummy(protein_chemical_system)
+ selection = select_dummy(protein_trajectory)
assert len(selection) == 0
diff --git a/MDANSE/Tests/UnitTests/AtomSelector/test_group_selectors.py b/MDANSE/Tests/UnitTests/AtomSelector/test_group_selectors.py
index 38c359b26d..9fb9e9382e 100644
--- a/MDANSE/Tests/UnitTests/AtomSelector/test_group_selectors.py
+++ b/MDANSE/Tests/UnitTests/AtomSelector/test_group_selectors.py
@@ -1,42 +1,40 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.AtomSelector.group_selectors import (
select_primary_amine,
select_hydroxy,
- select_methly,
+ select_methyl,
select_phosphate,
select_sulphate,
select_thiol,
)
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
-pbd_1gip = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "1gip.pdb"
+traj_1gip = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "1gip.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
@pytest.fixture(scope="module")
def nucleic_acid_chemical_system():
- reader = PDBReader(pbd_1gip)
- nucleic_acid_chemical_system = reader.build_chemical_system()
- return nucleic_acid_chemical_system
+ protein_trajectory = HDFTrajectoryInputData(traj_1gip)
+ return protein_trajectory.trajectory
def test_select_primary_amine_returns_true_as_match_exists(
- protein_chemical_system,
+ protein_trajectory,
):
- exists = select_primary_amine(protein_chemical_system, check_exists=True)
+ exists = select_primary_amine(protein_trajectory, check_exists=True)
assert exists
@@ -48,21 +46,21 @@ def test_select_sulphate_returns_false_as_match_does_not_exist(
def test_select_primary_amine_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_primary_amine(protein_chemical_system)
+ selection = select_primary_amine(protein_trajectory)
assert len(selection) == 117
def test_select_hydroxy_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_hydroxy(protein_chemical_system)
+ selection = select_hydroxy(protein_trajectory)
assert len(selection) == 28786
-def test_select_methyl_returns_correct_number_of_atom_matches(protein_chemical_system):
- selection = select_methly(protein_chemical_system)
+def test_select_methyl_returns_correct_number_of_atom_matches(protein_trajectory):
+ selection = select_methyl(protein_trajectory)
assert len(selection) == 244
@@ -80,6 +78,6 @@ def test_select_sulphate_returns_correct_number_of_atom_matches(
assert len(selection) == 0
-def test_select_thiol_returns_correct_number_of_atoms_matches(protein_chemical_system):
- selection = select_thiol(protein_chemical_system)
+def test_select_thiol_returns_correct_number_of_atoms_matches(protein_trajectory):
+ selection = select_thiol(protein_trajectory)
assert len(selection) == 0
diff --git a/MDANSE/Tests/UnitTests/AtomSelector/test_molecule_selectors.py b/MDANSE/Tests/UnitTests/AtomSelector/test_molecule_selectors.py
index c2cdf10e1d..786c41d894 100644
--- a/MDANSE/Tests/UnitTests/AtomSelector/test_molecule_selectors.py
+++ b/MDANSE/Tests/UnitTests/AtomSelector/test_molecule_selectors.py
@@ -1,30 +1,29 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.AtomSelector.molecule_selectors import select_water
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
def test_select_water_returns_true_as_match_exists(
- protein_chemical_system,
+ protein_trajectory,
):
- exists = select_water(protein_chemical_system, check_exists=True)
+ exists = select_water(protein_trajectory, check_exists=True)
assert exists
def test_select_water_returns_correct_number_of_atom_matches(
- protein_chemical_system,
+ protein_trajectory,
):
- selection = select_water(protein_chemical_system)
+ selection = select_water(protein_trajectory)
assert len(selection) == 28746
diff --git a/MDANSE/Tests/UnitTests/AtomSelector/test_selector.py b/MDANSE/Tests/UnitTests/AtomSelector/test_selector.py
index a583af5694..10b09938d8 100644
--- a/MDANSE/Tests/UnitTests/AtomSelector/test_selector.py
+++ b/MDANSE/Tests/UnitTests/AtomSelector/test_selector.py
@@ -1,31 +1,30 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.AtomSelector.selector import Selector
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
-def test_selector_returns_all_atom_idxs(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_all_atom_idxs(protein_trajectory):
+ selector = Selector(protein_trajectory)
atm_idxs = selector.get_idxs()
assert len(atm_idxs) == 30714
def test_selector_returns_all_atom_idxs_with_all_and_sulfurs_selected(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = True
selector.settings["element"] = {"S": True}
atm_idxs = selector.get_idxs()
@@ -33,9 +32,9 @@ def test_selector_returns_all_atom_idxs_with_all_and_sulfurs_selected(
def test_selector_returns_correct_number_of_atom_idxs_when_sulfur_atoms_are_selected(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = False
selector.settings["element"] = {"S": True}
atm_idxs = selector.get_idxs()
@@ -43,9 +42,9 @@ def test_selector_returns_correct_number_of_atom_idxs_when_sulfur_atoms_are_sele
def test_selector_returns_correct_number_of_atom_idxs_when_sulfur_atoms_are_selected_when_get_idxs_is_called_twice(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = False
selector.settings["element"] = {"S": True}
atm_idxs = selector.get_idxs()
@@ -55,9 +54,9 @@ def test_selector_returns_correct_number_of_atom_idxs_when_sulfur_atoms_are_sele
def test_selector_returns_correct_number_of_atom_idxs_when_waters_are_selected(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = False
selector.settings["water"] = True
atm_idxs = selector.get_idxs()
@@ -65,9 +64,9 @@ def test_selector_returns_correct_number_of_atom_idxs_when_waters_are_selected(
def test_selector_returns_correct_number_of_atom_idxs_when_water_is_turned_on_and_off(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = False
selector.settings["water"] = True
atm_idxs = selector.get_idxs()
@@ -78,9 +77,9 @@ def test_selector_returns_correct_number_of_atom_idxs_when_water_is_turned_on_an
def test_selector_returns_correct_number_of_atom_idxs_when_waters_and_sulfurs_are_selected(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.settings["all"] = False
selector.settings["water"] = True
selector.settings["element"] = {"S": True}
@@ -89,37 +88,37 @@ def test_selector_returns_correct_number_of_atom_idxs_when_waters_and_sulfurs_ar
def test_selector_returns_correct_number_of_atom_idxs_when_waters_and_sulfurs_are_selected_with_settings_loaded_as_a_dict(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "element": {"S": True}, "water": True})
atm_idxs = selector.get_idxs()
assert len(atm_idxs) == 28746 + 10
-def test_selector_json_dump_0(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_0(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "element": {"S": True}})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "element": ["S"]}'
-def test_selector_json_dump_1(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_1(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "element": {"S": True}, "water": True})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "water": true, "element": ["S"]}'
-def test_selector_json_dump_2(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_2(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "water": True})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "water": true}'
-def test_selector_json_dump_3(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_3(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings(
{"all": False, "element": {"S": True, "H": True}, "water": True}
)
@@ -127,8 +126,8 @@ def test_selector_json_dump_3(protein_chemical_system):
assert json_dump == '{"all": false, "water": true, "element": ["H", "S"]}'
-def test_selector_json_dump_4(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_4(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings(
{
"all": False,
@@ -144,16 +143,16 @@ def test_selector_json_dump_4(protein_chemical_system):
)
-def test_selector_json_dump_with_second_update(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_with_second_update(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False})
selector.update_settings({"element": {"S": True, "O": True}, "water": True})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "water": true, "element": ["O", "S"]}'
-def test_selector_json_dump_with_third_update(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_with_third_update(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False})
selector.update_settings({"element": {"S": True, "O": True}, "water": True})
selector.update_settings({"element": {"S": False}})
@@ -161,8 +160,8 @@ def test_selector_json_dump_with_third_update(protein_chemical_system):
assert json_dump == '{"all": false, "water": true, "element": ["O"]}'
-def test_selector_json_dump_with_fourth_update(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_with_fourth_update(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False})
selector.update_settings({"element": {"S": True, "O": True}, "water": True})
selector.update_settings({"element": {"S": False}})
@@ -172,9 +171,9 @@ def test_selector_json_dump_with_fourth_update(protein_chemical_system):
def test_selector_returns_correct_number_of_atom_idxs_after_setting_settings_again_with_reset_first(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "element": {"S": True}, "water": True})
atm_idxs = selector.get_idxs()
assert len(atm_idxs) == 28746 + 10
@@ -190,8 +189,8 @@ def test_selector_returns_correct_number_of_atom_idxs_after_setting_settings_aga
assert len(atm_idxs) == 10
-def test_selector_json_dump_and_load_0(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_and_load_0(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "index": {0: True, 1: True}})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "index": [0, 1]}'
@@ -200,8 +199,8 @@ def test_selector_json_dump_and_load_0(protein_chemical_system):
assert len(atm_idxs) == 2
-def test_selector_json_dump_and_load_1(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_json_dump_and_load_1(protein_trajectory):
+ selector = Selector(protein_trajectory)
selector.update_settings({"all": False, "element": {"S": True}, "water": True})
json_dump = selector.settings_to_json()
assert json_dump == '{"all": false, "water": true, "element": ["S"]}'
@@ -211,9 +210,9 @@ def test_selector_json_dump_and_load_1(protein_chemical_system):
def test_selector_returns_correct_number_of_atom_idxs_when_indexes_0_and_1_are_selected(
- protein_chemical_system,
+ protein_trajectory,
):
- selector = Selector(protein_chemical_system)
+ selector = Selector(protein_trajectory)
selector.update_settings(
{
"all": False,
@@ -224,8 +223,8 @@ def test_selector_returns_correct_number_of_atom_idxs_when_indexes_0_and_1_are_s
assert len(atm_idxs) == 2
-def test_selector_returns_true_with_correct_setting_check(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_true_with_correct_setting_check(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert selector.check_valid_setting(
{
"all": False,
@@ -234,8 +233,8 @@ def test_selector_returns_true_with_correct_setting_check(protein_chemical_syste
)
-def test_selector_returns_false_with_incorrect_setting_check_0(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_setting_check_0(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_setting(
{
"alle": False,
@@ -244,8 +243,8 @@ def test_selector_returns_false_with_incorrect_setting_check_0(protein_chemical_
)
-def test_selector_returns_false_with_incorrect_setting_check_1(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_setting_check_1(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_setting(
{
"all": False,
@@ -254,8 +253,8 @@ def test_selector_returns_false_with_incorrect_setting_check_1(protein_chemical_
)
-def test_selector_returns_false_with_incorrect_setting_check_2(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_setting_check_2(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_setting(
{
"all": False,
@@ -265,37 +264,40 @@ def test_selector_returns_false_with_incorrect_setting_check_2(protein_chemical_
)
-def test_selector_returns_true_with_correct_json_setting_0(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_true_with_correct_json_setting_0(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert selector.check_valid_json_settings(
'{"all": false, "water": true, "element": {"S": true}}'
)
-def test_selector_returns_true_with_correct_json_setting_1(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_true_with_correct_json_setting_1(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert selector.check_valid_json_settings('{"all": false, "index": [0, 1]}')
-def test_selector_returns_false_with_incorrect_json_setting_0(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_json_setting_0(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_json_settings(
'{all: false, "water": true, "element": {"S": true}}'
)
-def test_selector_returns_false_with_incorrect_json_setting_1(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_json_setting_1(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_json_settings('{"all": false, "index": [0, "1"]}')
-def test_selector_returns_false_with_incorrect_json_setting_2(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+def test_selector_returns_false_with_incorrect_json_setting_2(protein_trajectory):
+ selector = Selector(protein_trajectory)
assert not selector.check_valid_json_settings('{"all": False, "index": ["0", "1"]}')
-def test_selector_with_atom_fullname(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+@pytest.mark.xfail(reason="see docstring")
+def test_selector_with_atom_fullname(protein_trajectory):
+ """For the moment, full names of atoms are not implemented
+ in the ChemicalSystem."""
+ selector = Selector(protein_trajectory)
selector.update_settings(
{
"all": False,
@@ -306,8 +308,13 @@ def test_selector_with_atom_fullname(protein_chemical_system):
assert len(atm_idxs) == 2
-def test_selector_with_atom_name(protein_chemical_system):
- selector = Selector(protein_chemical_system)
+@pytest.mark.xfail(reason="see docstring")
+def test_selector_with_atom_name(protein_trajectory):
+ """At the moment the oxygen in water has the same
+ atom name as the oxygen in the protein.
+ We will have to decide if this is acceptable.
+ """
+ selector = Selector(protein_trajectory)
selector.update_settings(
{
"all": False,
diff --git a/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py b/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py
index 9296d86228..cb0ee78868 100644
--- a/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py
+++ b/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py
@@ -1,33 +1,32 @@
import os
import pytest
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.Configurators.AtomTransmutationConfigurator import AtomTransmuter
-pbd_2vb1 = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.pdb"
+traj_2vb1 = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), "..", "Data", "2vb1.mdt"
)
@pytest.fixture(scope="module")
-def protein_chemical_system():
- reader = PDBReader(pbd_2vb1)
- protein_chemical_system = reader.build_chemical_system()
- return protein_chemical_system
+def protein_trajectory():
+ protein_trajectory = HDFTrajectoryInputData(traj_2vb1)
+ return protein_trajectory.trajectory
def test_atom_transmutation_returns_empty_dictionary_when_no_transmutations_are_made(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
mapping = atm_transmuter.get_setting()
assert mapping == {}
def test_atom_transmutation_return_dict_with_transmutations_with_incorrect_element_raises_exception(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
with pytest.raises(ValueError):
atm_transmuter.apply_transmutation(
{"all": False, "element": {"S": True}}, "CCC"
@@ -35,9 +34,9 @@ def test_atom_transmutation_return_dict_with_transmutations_with_incorrect_eleme
def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C")
mapping = atm_transmuter.get_setting()
assert mapping == {
@@ -55,9 +54,9 @@ def test_atom_transmutation_return_dict_with_transmutations_with_s_element_trans
def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_0(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C")
atm_transmuter.apply_transmutation({"all": False, "index": {98: True}}, "N")
mapping = atm_transmuter.get_setting()
@@ -76,9 +75,9 @@ def test_atom_transmutation_return_dict_with_transmutations_with_s_element_trans
def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_1(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C")
atm_transmuter.apply_transmutation({"all": False, "index": {98: True}}, "S")
mapping = atm_transmuter.get_setting()
@@ -96,9 +95,9 @@ def test_atom_transmutation_return_dict_with_transmutations_with_s_element_trans
def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_2(
- protein_chemical_system,
+ protein_trajectory,
):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+ atm_transmuter = AtomTransmuter(protein_trajectory)
atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C")
atm_transmuter.apply_transmutation(
{"all": False, "index": {98: True, 99: True}}, "S"
@@ -118,8 +117,8 @@ def test_atom_transmutation_return_dict_with_transmutations_with_s_element_trans
}
-def test_atom_transmutation_return_empty_dict_after_reset(protein_chemical_system):
- atm_transmuter = AtomTransmuter(protein_chemical_system)
+def test_atom_transmutation_return_empty_dict_after_reset(protein_trajectory):
+ atm_transmuter = AtomTransmuter(protein_trajectory)
atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C")
atm_transmuter.apply_transmutation(
{"all": False, "index": {98: True, 99: True}}, "S"
diff --git a/MDANSE/Tests/UnitTests/Data/1gip.mdt b/MDANSE/Tests/UnitTests/Data/1gip.mdt
new file mode 100644
index 0000000000..fb2e14d0bc
Binary files /dev/null and b/MDANSE/Tests/UnitTests/Data/1gip.mdt differ
diff --git a/MDANSE/Tests/UnitTests/Data/2vb1.mdt b/MDANSE/Tests/UnitTests/Data/2vb1.mdt
new file mode 100644
index 0000000000..db5a1f650b
Binary files /dev/null and b/MDANSE/Tests/UnitTests/Data/2vb1.mdt differ
diff --git a/MDANSE/Tests/UnitTests/Data/com_trajectory.mdt b/MDANSE/Tests/UnitTests/Data/com_trajectory.mdt
new file mode 100644
index 0000000000..79de460af7
Binary files /dev/null and b/MDANSE/Tests/UnitTests/Data/com_trajectory.mdt differ
diff --git a/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py b/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py
index 4faef784eb..186e728182 100644
--- a/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py
+++ b/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py
@@ -6,6 +6,7 @@
import numpy as np
import h5py
+from MDANSE.MolecularDynamics.Configuration import remove_jumps
from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.Framework.Jobs.IJob import IJob
@@ -19,6 +20,31 @@
)
+def test_jumps_removed_correctly():
+ input_coords = np.array(
+ [
+ [0.8, 0.2, 0.3],
+ [0.88, 0.22, 0.33],
+ [0.97, 0.2, 0.3],
+ [0.05, 0.22, 0.31],
+ [0.03, 0.2, 0.3],
+ [0.99, 0.22, 0.32],
+ ]
+ )
+ expected_coords = np.array(
+ [
+ [0.8, 0.2, 0.3],
+ [0.88, 0.22, 0.33],
+ [0.97, 0.2, 0.3],
+ [1.05, 0.22, 0.31],
+ [1.03, 0.2, 0.3],
+ [0.99, 0.22, 0.32],
+ ]
+ )
+ corrected_coords = remove_jumps(input_coords)
+ assert np.allclose(corrected_coords, expected_coords)
+
+
def test_editor_null():
temp_name = tempfile.mktemp()
parameters = {}
@@ -153,8 +179,8 @@ def test_editor_transmute():
original.trajectory.chemical_system.number_of_atoms
== changed.trajectory.chemical_system.number_of_atoms
)
- old_symbols = [at.symbol for at in original.trajectory.chemical_system.atom_list]
- new_symbols = [at.symbol for at in changed.trajectory.chemical_system.atom_list]
+ old_symbols = [at for at in original.trajectory.chemical_system.atom_list]
+ new_symbols = [at for at in changed.trajectory.chemical_system.atom_list]
assert old_symbols != new_symbols
assert "B" not in old_symbols
assert "B" in new_symbols
diff --git a/MDANSE/Tests/UnitTests/molecules/test_chemistry.py b/MDANSE/Tests/UnitTests/molecules/test_chemistry.py
index 53f5e4ebf7..c9938c971f 100644
--- a/MDANSE/Tests/UnitTests/molecules/test_chemistry.py
+++ b/MDANSE/Tests/UnitTests/molecules/test_chemistry.py
@@ -1,10 +1,6 @@
import os
import pytest
-import numpy as np
-from rdkit.Chem.rdmolops import SanitizeMol
-from rdkit.Chem.rdmolops import GetMolFrags
from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
-from MDANSE.Chemistry.Structrures import Topology
short_traj = os.path.join(
@@ -19,35 +15,12 @@ def trajectory():
def test_unit_cell(trajectory: HDFTrajectoryInputData):
- chem_system = trajectory.chemical_system
- configuration = chem_system.configuration
+ configuration = trajectory._data.configuration()
unit_cell = configuration.unit_cell
print(unit_cell.abc_and_angles)
def test_molecule_finder(trajectory: HDFTrajectoryInputData):
- chem_system = trajectory.chemical_system
- configuration = chem_system.configuration
+ configuration = trajectory._data.configuration()
coordinates = configuration._variables["coordinates"]
print(coordinates.shape)
-
-
-@pytest.mark.xfail(reason="see docstring")
-def test_molecule_assignment(trajectory: HDFTrajectoryInputData):
- """As of today (17 Oct 2023) this test does not pass.
- Topology class writes out the atom coordinates to a PDB file buffer,
- and RDKit scans it for molecules.
- Apparently RDKit does not apply the periodic boundary conditions,
- and the molecules that were on the edge of the simulation box
- end up in several pieces.
- At the moment we use the Connectivity class instead.
- """
- chem_system = trajectory.chemical_system
- configuration = chem_system.configuration
- topology = Topology(trajectory, chem_system)
- mol = topology.scan_trajectory_frame(0)
- SanitizeMol(mol)
- gas_bits = GetMolFrags(mol, asMols=True)
- all_lengths = np.array([mol.GetNumAtoms() for mol in gas_bits])
- # assert len(gas_bits) == 20
- assert np.all(all_lengths == 3)
diff --git a/MDANSE/Tests/UnitTests/molecules/test_connectivity.py b/MDANSE/Tests/UnitTests/molecules/test_connectivity.py
index 9420c2517e..72e78fb88d 100644
--- a/MDANSE/Tests/UnitTests/molecules/test_connectivity.py
+++ b/MDANSE/Tests/UnitTests/molecules/test_connectivity.py
@@ -1,10 +1,8 @@
import os
import pytest
-import numpy as np
from MDANSE.MolecularDynamics.Connectivity import Connectivity
from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
from MDANSE.MolecularDynamics.Trajectory import Trajectory
-from MDANSE.Chemistry.Structrures import MoleculeTester
short_traj = os.path.join(
@@ -24,45 +22,25 @@ def test_create_connectivity(trajectory: Trajectory):
assert len(conn._unique_elements) == 2
-def test_find_bonds(trajectory: Trajectory):
+def test_find_molecules(trajectory: Trajectory):
conn = Connectivity(trajectory=trajectory)
conn.find_bonds()
assert len(conn._unique_bonds) == 40
-
-
-def test_find_molecules(trajectory: Trajectory):
- conn = Connectivity(trajectory=trajectory)
- conn.find_molecules()
- assert len(conn._molecules) == 20
-
-
-def test_rebuild_molecules(trajectory: Trajectory):
- print(trajectory.chemical_system.atom_list)
- conn = Connectivity(trajectory=trajectory)
- conn.find_molecules()
- atoms_before = int(trajectory.chemical_system.number_of_atoms)
- chemical_system = trajectory.chemical_system
- print(conn._molecules)
- chemical_system.rebuild(conn._molecules)
- atoms_after = int(trajectory.chemical_system.number_of_atoms)
- assert atoms_before == atoms_after
+ conn.add_bond_information(trajectory.chemical_system)
+ molecules_found = 0
+ for name in trajectory.chemical_system.unique_molecules():
+ molecules_found += trajectory.chemical_system.number_of_molecules(name)
+ assert molecules_found == 20
def test_identify_molecules(trajectory: Trajectory):
conn = Connectivity(trajectory=trajectory)
- conn.find_molecules()
+ conn.find_bonds()
chemical_system = trajectory.chemical_system
- chemical_system.rebuild(conn._molecules)
- configuration = chemical_system.configuration
- coords = configuration.contiguous_configuration().coordinates
+ conn.add_bond_information(chemical_system)
molstrings = []
- for entity in chemical_system.chemical_entities:
- moltester = MoleculeTester(entity, coords)
- inchistring = moltester.identify_molecule()
- molstrings.append(inchistring)
- if entity.number_of_atoms > 1:
- entity.name = inchistring
- assert len(molstrings) == 20
+ for molname, mollist in chemical_system._clusters.items():
+ assert len(mollist) == 20
result = True
for ms in molstrings[1:]:
result = result and ms == molstrings[0]
diff --git a/MDANSE/Tests/UnitTests/molecules/test_rdkit.py b/MDANSE/Tests/UnitTests/molecules/test_rdkit.py
index 295c986fa4..7d6913f5a6 100644
--- a/MDANSE/Tests/UnitTests/molecules/test_rdkit.py
+++ b/MDANSE/Tests/UnitTests/molecules/test_rdkit.py
@@ -5,8 +5,8 @@
from rdkit.Chem.rdmolops import SanitizeMol
from rdkit.Chem.rdmolops import GetMolFrags
import pytest
-from MDANSE.IO.PDBReader import PDBReader
-from MDANSE.Chemistry.ChemicalEntity import ChemicalSystem
+from MDANSE.IO.MinimalPDBReader import MinimalPDBReader as PDBReader
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
fname = os.path.join(
@@ -17,8 +17,7 @@
@pytest.fixture()
def chem_from_pdb():
reader = PDBReader(fname)
- chem = reader.build_chemical_system()
- yield chem
+ yield reader._chemical_system
@pytest.fixture()
diff --git a/MDANSE/Tests/UnitTests/test_HDF5Trajectory.py b/MDANSE/Tests/UnitTests/test_HDF5Trajectory.py
index a12045423c..e75ae5904f 100644
--- a/MDANSE/Tests/UnitTests/test_HDF5Trajectory.py
+++ b/MDANSE/Tests/UnitTests/test_HDF5Trajectory.py
@@ -19,7 +19,7 @@
import numpy as np
-from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import RealConfiguration
from MDANSE.MolecularDynamics.Trajectory import Trajectory, TrajectoryWriter
@@ -31,8 +31,7 @@
def chemical_system():
temp = ChemicalSystem("Dummy test system")
nAtoms = N_ATOMS
- for i in range(nAtoms):
- temp.add_chemical_entity(Atom(symbol="H"))
+ temp.initialise_atoms(nAtoms * ["H"])
return temp
@@ -59,8 +58,7 @@ def sample_trajectory(chemical_system, sample_configuration):
os.close(fdesc)
writer = TrajectoryWriter(fname, chemical_system, n_steps=N_TIMESTEPS)
for n, ts in enumerate(np.arange(N_TIMESTEPS)):
- writer.chemical_system.configuration = sample_configuration
- writer.dump_configuration(ts)
+ writer.dump_configuration(sample_configuration, ts)
return fname
@@ -73,8 +71,7 @@ def gzipped_trajectory(chemical_system, sample_configuration):
fname, chemical_system, n_steps=N_TIMESTEPS, compression="gzip"
)
for n, ts in enumerate(np.arange(N_TIMESTEPS)):
- writer.chemical_system.configuration = sample_configuration
- writer.dump_configuration(ts)
+ writer.dump_configuration(sample_configuration, ts)
return fname
@@ -87,16 +84,14 @@ def lzffed_trajectory(chemical_system, sample_configuration):
fname, chemical_system, n_steps=N_TIMESTEPS, compression="lzf"
)
for n, ts in enumerate(np.arange(N_TIMESTEPS)):
- writer.chemical_system.configuration = sample_configuration
- writer.dump_configuration(ts)
+ writer.dump_configuration(sample_configuration, ts)
return fname
def test_identity(chemical_system):
temp = ChemicalSystem("Dummy test system")
nAtoms = N_ATOMS
- for i in range(nAtoms):
- temp.add_chemical_entity(Atom(symbol="H"))
+ temp.initialise_atoms(nAtoms * ["H"])
# assert(temp == chemical_system)
assert chemical_system == chemical_system
@@ -108,7 +103,7 @@ def test_copy(chemical_system):
print(original.number_of_atoms)
print(copied.atom_list)
print(copied.number_of_atoms)
- assert repr(original) == repr(copied)
+ assert original.atom_list == copied.atom_list
def test_compression(sample_trajectory, gzipped_trajectory, lzffed_trajectory):
diff --git a/MDANSE/Tests/UnitTests/test_chemical_entity.py b/MDANSE/Tests/UnitTests/test_chemical_entity.py
deleted file mode 100644
index fc4dfb7ae6..0000000000
--- a/MDANSE/Tests/UnitTests/test_chemical_entity.py
+++ /dev/null
@@ -1,2917 +0,0 @@
-# This file is part of MDANSE_GUI.
-#
-# MDANSE_GUI is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-import collections
-import pickle
-from typing import Union
-import unittest
-import sys
-
-import numpy as np
-
-from MDANSE.Chemistry import MOLECULES_DATABASE, RESIDUES_DATABASE, NUCLEOTIDES_DATABASE
-import MDANSE.Chemistry.ChemicalEntity as ce
-from MDANSE.Mathematics.LinearAlgebra import Quaternion, Vector, Tensor
-from MDANSE.Mathematics.Transformation import RotationTranslation
-
-
-class TestAtom(unittest.TestCase):
- def test_empty_instantiation(self):
- atom = ce.Atom()
-
- self.assertEqual("H", atom.symbol)
- self.assertEqual("H", atom.name)
- self.assertEqual([], atom.bonds)
- self.assertEqual([], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(None, atom.parent)
-
- def test_instantiation_overwriting_default_values(self):
- bond = ce.Atom()
- atom = ce.Atom(
- symbol="C",
- name="carbon12",
- bonds=[bond],
- groups=["backbone"],
- ghost=True,
- index=0,
- parent=bond,
- atomic_mass=12,
- random="12345",
- )
-
- self.assertEqual("C", atom.symbol)
- self.assertEqual("carbon12", atom.name)
- self.assertEqual([bond], atom.bonds)
- self.assertEqual(["backbone"], atom._groups)
- self.assertEqual(True, atom.ghost)
- self.assertEqual(0, atom.index)
- self.assertEqual(bond, atom.parent)
- self.assertEqual(12, atom.atomic_mass)
- self.assertEqual("12345", atom.random)
-
- def test_instantiation_undefined_element(self):
- with self.assertRaises(ce.UnknownAtomError):
- ce.Atom(symbol="CC")
-
- def test_copy(self):
- atom = ce.Atom()
- copy = atom.copy()
- self.assertEqual(repr(atom), repr(copy))
-
- def test_pickling(self):
- atom = ce.Atom()
- pickled = pickle.dumps(atom)
- unpickled = pickle.loads(pickled)
- self.assertEqual(repr(atom), repr(unpickled))
-
- def test_dunder_str(self):
- atom = ce.Atom(name="Hydrogen")
- self.assertEqual("Hydrogen", str(atom))
-
- def test_dunder_repr(self):
- atom = ce.Atom(name="Hydrogen", bonds=[ce.Atom(name="H5")])
- self.assertEqual(
- "MDANSE.Chemistry.ChemicalEntity.Atom(parent=None, name='Hydrogen', symbol='H', "
- "bonds=[Atom(H5)], groups=[], ghost=False, index=None, element='hydrogen')",
- repr(atom),
- )
-
- def test_atom_list_ghost_true(self):
- atom = ce.Atom(ghost=True)
- atom_list = atom.atom_list
- self.assertEqual([], atom_list)
-
- def test_atom_list_ghost_false(self):
- atom = ce.Atom(ghost=False)
- atom_list = atom.atom_list
- self.assertEqual([atom], atom_list)
-
- def test_total_number_of_atoms(self):
- atom = ce.Atom(ghost=False)
- ghost = ce.Atom(ghost=True)
- self.assertEqual(1, atom.total_number_of_atoms)
- self.assertEqual(1, ghost.total_number_of_atoms)
-
- def test_number_of_atoms(self):
- atom = ce.Atom(ghost=False)
- ghost = ce.Atom(ghost=True)
-
- self.assertEqual(0, atom.number_of_atoms)
- self.assertEqual(1, ghost.number_of_atoms)
-
- def test_bonds_setter(self):
- atom = ce.Atom()
- bond = ce.Atom(symbol="C")
- atom.bonds = [bond]
- self.assertEqual([bond], atom.bonds)
-
- def test_ghost_setter(self):
- atom = ce.Atom(ghost=False)
- atom.ghost = True
- self.assertTrue(atom.ghost)
-
- def test_index_setter_index_not_set(self):
- atom = ce.Atom()
- atom.index = 0
- self.assertEqual(0, atom.index)
-
- def test_index_setter_index_set(self):
- atom = ce.Atom(index=0)
- atom.index = 1
- self.assertEqual(0, atom.index)
-
- def test_name_setter(self):
- atom = ce.Atom(name="name")
- atom.name = "Hydrogen"
- self.assertEqual("Hydrogen", atom.name)
-
- def test_symbol_setter(self):
- atom = ce.Atom(symbol="H")
- atom.symbol = "C"
-
- self.assertEqual("C", atom.symbol)
- with self.assertRaises(ce.UnknownAtomError):
- atom.symbol = "CC"
-
- def test_build(self):
- atom = ce.Atom.build(None, "H", "H1", "0", False)
- self.assertEqual(
- repr(ce.Atom(symbol="H", name="H1", ghost=False, index=0)), repr(atom)
- )
-
- def test_serialize(self):
- atom = ce.Atom()
- dictionary = {}
- result = atom.serialize(dictionary)
-
- self.assertEqual(("atoms", 0), result)
- self.assertEqual(
- {"atoms": [[repr("H"), repr("H"), "None", "False"]]}, dictionary
- )
-
-
-class TestAtomGroup(unittest.TestCase):
- def setUp(self):
- self.atom1 = ce.Atom(name="H1")
- self.atom2 = ce.Atom(name="H2")
-
- self.system = ce.ChemicalSystem("name")
- self.system.add_chemical_entity(self.atom1)
- self.system.add_chemical_entity(self.atom2)
-
- self.group = ce.AtomGroup([self.atom1, self.atom2])
-
- def test_instantiation_valid(self):
- self.assertEqual("", self.group.name)
- self.assertEqual(None, self.group.parent)
- self.assertEqual([self.atom1, self.atom2], self.group._atoms)
- self.assertEqual(self.system, self.group._chemical_system)
-
- def test_instantiation_invalid(self):
- system2 = ce.ChemicalSystem("name")
- system2.add_chemical_entity(self.atom2)
-
- with self.assertRaises(ce.ChemicalEntityError):
- ce.AtomGroup([self.atom1, self.atom2])
-
- def test_pickling(self):
- pickled = pickle.dumps(self.group)
- unpickled = pickle.loads(pickled)
-
- self.assertEqual("", unpickled.name)
- self.assertEqual(None, unpickled.parent)
- self.assertEqual(2, len(unpickled._atoms))
- self.assertEqual(repr(self.atom1), repr(unpickled._atoms[0]))
- self.assertEqual(repr(self.atom2), repr(unpickled._atoms[1]))
- self.assertEqual(repr(self.system), repr(unpickled._chemical_system))
-
- def test_duner_repr(self):
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.AtomGroup(parent=None, name='', atoms=[MDANSE."
- "Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.ChemicalSystem(name), "
- "name='H1', symbol='H', bonds=[], groups=[], ghost=False, index=0, element='hydrogen'), MDANSE.Chemistry."
- "ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.ChemicalSystem(name), name='H2', "
- "symbol='H', bonds=[], groups=[], ghost=False, index=1, element='hydrogen')], chemical_system=MDANSE.Chemistry."
- "ChemicalEntity.ChemicalSystem(name))",
- repr(self.group),
- )
-
- def test_dunder_str(self):
- self.assertEqual("AtomGroup consisting of 2 atoms", str(self.group))
-
- def test_atom_list(self):
- self.atom2._ghost = True
- self.assertEqual([self.atom1], self.group.atom_list)
-
- def test_copy(self):
- self.assertEqual(None, self.group.copy())
-
- def test_number_of_atoms(self):
- self.atom2._ghost = True
- self.assertEqual(1, self.group.number_of_atoms)
- self.assertEqual(2, self.group.total_number_of_atoms)
-
- def test_root_chemical_system(self):
- self.assertEqual(repr(self.system), repr(self.group.root_chemical_system))
-
- def test_serialize(self):
- dictionary = {}
- result = self.group.serialize(dictionary)
-
- self.assertEqual(None, result)
- self.assertDictEqual({}, dictionary)
-
-
-class TestAtomCluster(unittest.TestCase):
- def test_valid_instantiation_parentful(self):
- atom1 = ce.Atom()
- atom2 = ce.Atom()
- cluster = ce.AtomCluster("Cluster1", [atom1, atom2])
-
- self.assertEqual(None, cluster.parent)
- self.assertEqual("Cluster1", cluster.name)
- self.assertEqual(False, cluster._parentless)
- self.assertEqual([atom1, atom2], cluster._atoms)
- self.assertEqual(cluster, cluster._atoms[0].parent)
-
- def test_valid_instantiation_parentless(self):
- atom1 = ce.Atom()
- atom2 = ce.Atom()
- cluster = ce.AtomCluster("Cluster1", [atom1, atom2], parentless=True)
-
- self.assertEqual(None, cluster.parent)
- self.assertEqual("Cluster1", cluster.name)
- self.assertEqual(True, cluster._parentless)
- self.assertEqual([atom1, atom2], cluster._atoms)
- self.assertEqual(None, cluster._atoms[0].parent)
-
- def test_pickling(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
-
- pickled = pickle.dumps(cluster)
- unpickled = pickle.loads(pickled)
-
- self.assertEqual(cluster.parent, unpickled.parent)
- self.assertEqual(cluster.name, unpickled.name)
- self.assertEqual(cluster._parentless, unpickled._parentless)
- self.assertEqual(repr(cluster._atoms), repr(unpickled._atoms))
-
- def test_dunder_getitem(self):
- atom = ce.Atom()
- cluster = ce.AtomCluster("Cluster1", [atom, ce.Atom()], parentless=True)
- self.assertEqual(atom, cluster[0])
-
- def test_dunder_repr(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.AtomCluster(parent=None, name='Cluster1', "
- "parentless=True, atoms=[MDANSE.Chemistry.ChemicalEntity.Atom(parent=None, name='H', "
- "symbol='H', bonds=[], groups=[], ghost=False, index=None, element='hydrogen'), MDANSE.Chemistry.ChemicalEntity."
- "Atom(parent=None, name='H', symbol='H', bonds=[], groups=[], ghost=False, index=None, element='hydrogen')])",
- repr(cluster),
- )
-
- def test_dunder_str(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
- self.assertEqual("AtomCluster consisting of 2 atoms", str(cluster))
-
- def test_atom_list(self):
- atom = ce.Atom()
- ghost = ce.Atom(ghost=True)
- cluster = ce.AtomCluster("Cluster1", [atom, ghost], parentless=True)
- self.assertEqual([atom], cluster.atom_list)
-
- def test_copy_parentful(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=False)
- copy = cluster.copy()
- self.assertEqual(repr(cluster), repr(copy))
-
- def test_copy_parentless(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
- copy = cluster.copy()
- self.assertEqual(repr(cluster), repr(copy))
-
- def test_number_of_atoms(self):
- cluster = ce.AtomCluster(
- "Cluster1", [ce.Atom(), ce.Atom(ghost=True)], parentless=True
- )
- self.assertEqual(1, cluster.number_of_atoms)
- self.assertEqual(2, cluster.total_number_of_atoms)
-
- def test_reorder_atoms_exception(self):
- cluster = ce.AtomCluster(
- "Cluster1", [ce.Atom(symbol="H"), ce.Atom(symbol="C")], parentless=True
- )
- with self.assertRaises(ce.InconsistentAtomNamesError):
- cluster.reorder_atoms(["H", "H"])
- with self.assertRaises(ce.InconsistentAtomNamesError):
- cluster.reorder_atoms(["C", "H", "H"])
-
- def test_reorder_atoms_valid(self):
- h = ce.Atom(symbol="H")
- c = ce.Atom(symbol="C")
- cluster = ce.AtomCluster("Cluster1", [h, c], parentless=True)
- cluster.reorder_atoms(["C", "H"])
-
- self.assertEqual([c, h], cluster._atoms)
-
- def test_build(self):
- h5 = {
- "atom_clusters": [[b"[0, 1]", repr("Cluster1").encode("UTF-8")]],
- "atoms": [
- [repr("H").encode("UTF-8"), repr("H").encode("UTF-8"), b"0", b"False"],
- [repr("H").encode("UTF-8"), repr("H").encode("UTF-8"), b"1", b"False"],
- ],
- }
- ac = ce.AtomCluster.build(h5, [0, 1], "Cluster1")
- cs = ce.ChemicalSystem()
- cs.add_chemical_entity(ac)
-
- self.assertEqual(repr(cs.chemical_entities[0]), repr(ac))
-
- def test_serialize_empty_dict(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
- dictionary = {}
- result = cluster.serialize(dictionary)
-
- self.assertEqual(("atom_clusters", 0), result)
- self.assertDictEqual(
- {
- "atom_clusters": [["[0, 1]", repr("Cluster1")]],
- "atoms": [
- [repr("H"), repr("H"), "None", "False"],
- [repr("H"), repr("H"), "None", "False"],
- ],
- },
- dictionary,
- )
-
- def test_serialize_nonempty_dict(self):
- cluster = ce.AtomCluster("Cluster1", [ce.Atom(), ce.Atom()], parentless=True)
- dictionary = {"atom_clusters": [[], [], []], "atoms": [[], [], []]}
- result = cluster.serialize(dictionary)
-
- self.assertEqual(("atom_clusters", 3), result)
- self.assertDictEqual(
- {
- "atom_clusters": [[], [], [], ["[3, 4]", repr("Cluster1")]],
- "atoms": [
- [],
- [],
- [],
- [repr("H"), repr("H"), "None", "False"],
- [repr("H"), repr("H"), "None", "False"],
- ],
- },
- dictionary,
- )
-
-
-class TestMolecule(unittest.TestCase):
- def setUp(self):
- self.molecule = ce.Molecule("WAT", "water")
-
- def compare_two_molecules(self, molecule: ce.Molecule):
- self.assertEqual(None, molecule.parent)
- self.assertEqual("water", molecule.name)
- self.assertEqual("WAT", molecule.code)
-
- for name, reference_name in zip(molecule._atoms.keys(), ["OW", "HW2", "HW1"]):
- self.assertEqual(reference_name, name)
-
- self.compare_atoms(molecule._atoms, molecule)
-
- def compare_atoms(self, atom_list, parent: ce.Molecule):
- try:
- atom = atom_list["OW"]
- except TypeError:
- atom = atom_list[0]
- self.assertEqual("O", atom.symbol)
- self.assertEqual("OW", atom.name)
- self.assertEqual(2, len(atom.bonds))
- self.assertEqual(parent._atoms["HW1"], atom.bonds[0])
- self.assertEqual(parent._atoms["HW2"], atom.bonds[1])
- self.assertEqual([], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["HW1"]
- except TypeError:
- atom = atom_list[2]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("HW1", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["OW"], atom.bonds[0])
- self.assertEqual([], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["HW2"]
- except TypeError:
- atom = atom_list[1]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("HW2", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["OW"], atom.bonds[0])
- self.assertEqual([], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- def test_valid_molecule_instantiation(self):
- self.compare_two_molecules(self.molecule)
-
- def test_unregistered_molecule_instantiation(self):
- with self.assertRaises(ce.UnknownMoleculeError):
- ce.Molecule("000000", "000000")
-
- def test_dunder_getitem(self):
- self.assertEqual(self.molecule._atoms["OW"], self.molecule["OW"])
-
- def test_pickling(self):
- pickled = pickle.dumps(self.molecule)
- unpickled = pickle.loads(pickled)
-
- self.compare_two_molecules(unpickled)
-
- def test_dunder_repr(self):
- if sys.version_info.minor < 12:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Molecule(parent=None, name='water', "
- "atoms=OrderedDict([('OW', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry."
- "ChemicalEntity.Molecule(water), name='OW', symbol='O', bonds=[Atom(HW1), Atom(HW2)], "
- "groups=[], ghost=False, index=None, element='oxygen', alternatives=['O', 'OH2'])), ('HW2', MDANSE.Chemistry."
- "ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(water), name='HW2', "
- "symbol='H', bonds=[Atom(OW)], groups=[], ghost=False, index=None, element='hydrogen', alternatives=['H2'])), "
- "('HW1', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity."
- "Molecule(water), name='HW1', symbol='H', bonds=[Atom(OW)], groups=[], ghost=False, index=None, element='hydrogen'"
- ", alternatives=['H1']))]), code='WAT')",
- repr(self.molecule),
- )
- else:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Molecule(parent=None, name='water', "
- "atoms=OrderedDict({'OW': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry."
- "ChemicalEntity.Molecule(water), name='OW', symbol='O', bonds=[Atom(HW1), Atom(HW2)], "
- "groups=[], ghost=False, index=None, element='oxygen', alternatives=['O', 'OH2']), 'HW2': MDANSE.Chemistry."
- "ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(water), name='HW2', "
- "symbol='H', bonds=[Atom(OW)], groups=[], ghost=False, index=None, element='hydrogen', alternatives=['H2']), "
- "'HW1': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity."
- "Molecule(water), name='HW1', symbol='H', bonds=[Atom(OW)], groups=[], ghost=False, index=None, element='hydrogen'"
- ", alternatives=['H1'])}), code='WAT')",
- repr(self.molecule),
- )
-
- def test_dunder_str(self):
- self.assertEqual('Molecule of water (database code "WAT")', str(self.molecule))
-
- def test_atom_list(self):
- self.assertEqual(3, len(self.molecule.atom_list))
- self.compare_atoms(self.molecule.atom_list, self.molecule)
-
- def test_copy(self):
- copy = self.molecule.copy()
- self.compare_two_molecules(copy)
-
- def test_number_of_atoms(self):
- self.assertEqual(3, self.molecule.number_of_atoms)
-
- def test_total_number_of_atoms(self):
- self.assertEqual(3, self.molecule.total_number_of_atoms)
-
- def test_reorder_atoms_invalid_input(self):
- with self.assertRaises(ce.InconsistentAtomNamesError):
- self.molecule.reorder_atoms(["O", "H", "H"])
-
- def test_reorder_atoms_valid_input(self):
- self.molecule.reorder_atoms(["HW1", "HW2", "OW"])
- self.assertEqual("HW1", self.molecule.atom_list[0].name)
- self.assertEqual("HW2", self.molecule.atom_list[1].name)
- self.assertEqual("OW", self.molecule.atom_list[2].name)
-
- def test_build(self):
- h5 = {
- "molecules": [
- [
- b"[0, 1, 2]",
- repr("WAT").encode("UTF-8"),
- repr("water").encode("UTF-8"),
- ]
- ],
- "atoms": [
- [
- repr("O").encode("UTF-8"),
- repr("OW").encode("UTF-8"),
- "None",
- b"False",
- ],
- [
- repr("H").encode("UTF-8"),
- repr("HW2").encode("UTF-8"),
- "None",
- b"False",
- ],
- [
- repr("H").encode("UTF-8"),
- repr("HW1").encode("UTF-8"),
- "None",
- b"False",
- ],
- ],
- }
- m = ce.Molecule.build(h5, [0, 1, 2], "WAT", "water")
-
- self.assertEqual(repr(ce.Molecule("WAT", "water")), repr(m))
-
- def test_serialize_from_empty_dict(self):
- dictionary = {}
- result = self.molecule.serialize(dictionary)
-
- self.assertEqual(("molecules", 0), result)
- self.assertDictEqual(
- {
- "molecules": [["[0, 1, 2]", repr("WAT"), repr("water")]],
- "atoms": [
- [repr("O"), repr("OW"), "None", "False"],
- [repr("H"), repr("HW2"), "None", "False"],
- [repr("H"), repr("HW1"), "None", "False"],
- ],
- },
- dictionary,
- )
-
- def test_serialize_from_nonempty_dict(self):
- dictionary = {"atoms": [[], []], "molecules": [[], []]}
- result = self.molecule.serialize(dictionary)
-
- self.assertEqual(("molecules", 2), result)
- self.assertDictEqual(
- {
- "atoms": [
- [],
- [],
- [repr("O"), repr("OW"), "None", "False"],
- [repr("H"), repr("HW2"), "None", "False"],
- [repr("H"), repr("HW1"), "None", "False"],
- ],
- "molecules": [[], [], ["[2, 3, 4]", repr("WAT"), repr("water")]],
- },
- dictionary,
- )
-
-
-class TestResidue(unittest.TestCase):
- def test_valid_residue_initialisation_without_variant(self):
- residue = ce.Residue("GLY", "glycine", None)
-
- self.compare_base_residues(residue, True)
-
- def compare_base_residues(self, residue: ce.Residue, compare_atoms: bool):
- self.assertEqual("glycine", residue.name)
- self.assertEqual(None, residue.parent)
- self.assertEqual("GLY", residue.code)
- self.assertEqual(None, residue._variant)
- self.assertEqual(None, residue._selected_variant)
- if compare_atoms:
- self.assertEqual(collections.OrderedDict(), residue._atoms)
-
- def test_valid_residue_initialisation_with_valid_variant(self):
- residue = ce.Residue("GLY", "glycine", "CT1")
-
- self.assertEqual("glycine", residue.name)
- self.assertEqual(None, residue.parent)
- self.assertEqual("GLY", residue.code)
- self.assertEqual("CT1", residue._variant)
- self.assertDictEqual(RESIDUES_DATABASE["CT1"], residue._selected_variant)
- self.assertEqual(collections.OrderedDict(), residue._atoms)
-
- def test_invalid_residue_initialisation(self):
- with self.assertRaises(ce.UnknownResidueError):
- ce.Residue("00000", "00000")
-
- def test_valid_residue_initialisation_with_nonexistent_variant(self):
- with self.assertRaises(ce.InvalidVariantError):
- ce.Residue("GLY", "glycine", "00000")
-
- def test_valid_residue_initialisation_with_invalid_variant(self):
- with self.assertRaises(ce.InvalidVariantError):
- ce.Residue("GLY", "glycine", "GLY")
-
- def test_set_atoms_valid(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
-
- self.assertEqual(7, len(residue._atoms))
- self.compare_atoms(residue._atoms, residue)
-
- def compare_atoms(
- self, atom_list: Union[list, dict, ce.Residue], parent: ce.Residue
- ):
- try:
- atom = atom_list["H"]
- except TypeError:
- atom = atom_list[0]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("H", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["N"], atom.bonds[0])
- self.assertEqual(["backbone", "peptide"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["HA3"]
- except TypeError:
- atom = atom_list[1]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("HA3", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["CA"], atom.bonds[0])
- self.assertEqual(["sidechain"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["O"]
- except TypeError:
- atom = atom_list[2]
- self.assertEqual("O", atom.symbol)
- self.assertEqual("O", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["C"], atom.bonds[0])
- self.assertEqual(["backbone", "peptide"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["N"]
- except TypeError:
- atom = atom_list[3]
- self.assertEqual("N", atom.symbol)
- self.assertEqual("N", atom.name)
- self.assertEqual(3, len(atom.bonds))
- self.assertEqual(parent._atoms["CA"], atom.bonds[0])
- self.assertEqual(parent._atoms["H"], atom.bonds[1])
- self.assertEqual("-R", atom.bonds[2])
- self.assertEqual(["backbone", "peptide"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["CA"]
- except TypeError:
- atom = atom_list[4]
- self.assertEqual("C", atom.symbol)
- self.assertEqual("CA", atom.name)
- self.assertEqual(4, len(atom.bonds))
- self.assertEqual(parent._atoms["C"], atom.bonds[0])
- self.assertEqual(parent._atoms["HA2"], atom.bonds[1])
- self.assertEqual(parent._atoms["HA3"], atom.bonds[2])
- self.assertEqual(parent._atoms["N"], atom.bonds[3])
- self.assertEqual(["backbone"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["HA2"]
- except TypeError:
- atom = atom_list[5]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("HA2", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(parent._atoms["CA"], atom.bonds[0])
- self.assertEqual(["backbone"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- try:
- atom = atom_list["C"]
- except TypeError:
- atom = atom_list[6]
- self.assertEqual("C", atom.symbol)
- self.assertEqual("C", atom.name)
- self.assertEqual(3, len(atom.bonds))
- self.assertEqual(parent._atoms["CA"], atom.bonds[0])
- self.assertEqual(parent._atoms["O"], atom.bonds[1])
- self.assertEqual("+R", atom.bonds[2])
- self.assertEqual(["backbone", "peptide"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(parent, atom.parent)
-
- def test_set_atoms_invalid(self):
- residue = ce.Residue("GLY", "glycine", None)
- with self.assertRaises(ce.InconsistentAtomNamesError):
- residue.set_atoms([])
-
- def test_set_atoms_variant(self):
- residue = ce.Residue("GLY", "glycine", "CT1")
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C", "OXT"])
- selected_variant = RESIDUES_DATABASE["CT1"]
- selected_variant["atoms"]["OXT"]["bonds"] = [residue._atoms["C"]]
-
- self.maxDiff = None
- self.assertEqual("glycine", residue.name)
- self.assertEqual(None, residue.parent)
- self.assertEqual("GLY", residue.code)
- self.assertEqual("CT1", residue._variant)
- self.assertDictEqual(selected_variant, residue._selected_variant)
-
- self.compare_atoms(residue._atoms, residue)
-
- atom = residue._atoms["OXT"]
- self.assertEqual("O", atom.symbol)
- self.assertEqual("OXT", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual(residue._atoms["C"], atom.bonds[0])
- self.assertEqual(["backbone"], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(residue, atom.parent)
-
- def test_pickling(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
-
- pickled = pickle.dumps(residue)
- unpickled = pickle.loads(pickled)
-
- self.compare_base_residues(unpickled, False)
- self.compare_atoms(unpickled._atoms, unpickled)
-
- def test_dunder_getitem(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- self.compare_atoms(residue, residue)
-
- def test_dunder_repr(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- if sys.version_info.minor < 12:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Residue(parent=None, name='glycine', code='GLY', "
- "variant=None, selected_variant=None, atoms=OrderedDict([('H', MDANSE.Chemistry.ChemicalEntity"
- ".Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name='H', symbol='H', bonds="
- "[Atom(N)], groups=['backbone', 'peptide'], ghost=False, index=None, element='hydrogen', alternatives=['HN'])), "
- "('HA3', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue"
- "(glycine), name='HA3', symbol='H', bonds=[Atom(CA)], groups=['sidechain'], ghost=False, "
- "index=None, element='hydrogen', alternatives=['HA1'])), ('O', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE"
- ".Chemistry.ChemicalEntity.Residue(glycine), name='O', symbol='O', bonds=[Atom(C)], groups="
- "['backbone', 'peptide'], ghost=False, index=None, element='oxygen', alternatives=['OT1'])), ('N', MDANSE."
- "Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name="
- "'N', symbol='N', bonds=[Atom(CA), Atom(H), Atom(-R)], groups=['backbone', 'peptide'], ghost="
- "False, index=None, element='nitrogen', alternatives=[])), ('CA', MDANSE.Chemistry.ChemicalEntity.Atom(parent="
- "MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name='CA', symbol='C', bonds=[Atom(C), "
- "Atom(HA2), Atom(HA3), Atom(N)], groups=['backbone'], ghost=False, index=None, element='carbon', alternatives="
- "[])), ('HA2', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity."
- "Residue(glycine), name='HA2', symbol='H', bonds=[Atom(CA)], groups=['backbone'], ghost=False,"
- " index=None, element='hydrogen', alternatives=['HA'])), ('C', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE"
- ".Chemistry.ChemicalEntity.Residue(glycine), name='C', symbol='C', bonds=[Atom(CA), Atom(O), "
- "Atom(+R)], groups=['backbone', 'peptide'], ghost=False, index=None, element='carbon', alternatives=[]))]))",
- repr(residue),
- )
- else:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Residue(parent=None, name='glycine', code='GLY', "
- "variant=None, selected_variant=None, atoms=OrderedDict({'H': MDANSE.Chemistry.ChemicalEntity"
- ".Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name='H', symbol='H', bonds="
- "[Atom(N)], groups=['backbone', 'peptide'], ghost=False, index=None, element='hydrogen', alternatives=['HN']), "
- "'HA3': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue"
- "(glycine), name='HA3', symbol='H', bonds=[Atom(CA)], groups=['sidechain'], ghost=False, "
- "index=None, element='hydrogen', alternatives=['HA1']), 'O': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE"
- ".Chemistry.ChemicalEntity.Residue(glycine), name='O', symbol='O', bonds=[Atom(C)], groups="
- "['backbone', 'peptide'], ghost=False, index=None, element='oxygen', alternatives=['OT1']), 'N': MDANSE."
- "Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name="
- "'N', symbol='N', bonds=[Atom(CA), Atom(H), Atom(-R)], groups=['backbone', 'peptide'], ghost="
- "False, index=None, element='nitrogen', alternatives=[]), 'CA': MDANSE.Chemistry.ChemicalEntity.Atom(parent="
- "MDANSE.Chemistry.ChemicalEntity.Residue(glycine), name='CA', symbol='C', bonds=[Atom(C), "
- "Atom(HA2), Atom(HA3), Atom(N)], groups=['backbone'], ghost=False, index=None, element='carbon', alternatives="
- "[]), 'HA2': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity."
- "Residue(glycine), name='HA2', symbol='H', bonds=[Atom(CA)], groups=['backbone'], ghost=False,"
- " index=None, element='hydrogen', alternatives=['HA']), 'C': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE"
- ".Chemistry.ChemicalEntity.Residue(glycine), name='C', symbol='C', bonds=[Atom(CA), Atom(O), "
- "Atom(+R)], groups=['backbone', 'peptide'], ghost=False, index=None, element='carbon', alternatives=[])}))",
- repr(residue),
- )
-
- def test_dunder_str(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- self.assertEqual(
- 'Amino acid Residue glycine (database code "GLY")', str(residue)
- )
-
- def test_atom_list(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- self.compare_atoms(residue.atom_list, residue)
-
- def test_number_of_atoms(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- self.assertEqual(7, residue.number_of_atoms)
- self.assertEqual(7, residue.total_number_of_atoms)
-
- def test_copy(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- copy = residue.copy()
-
- self.compare_atoms(copy, copy)
-
- def test_build(self):
- h5 = {
- "residues": [
- [
- b"[0, 1, 2, 3, 4, 5, 6]",
- repr("GLY").encode("UTF-8"),
- repr("glycine").encode("UTF-8"),
- b"None",
- ]
- ],
- "atoms": [
- [repr("H").encode("UTF-8"), repr("H").encode("UTF-8"), b"False"],
- [repr("H").encode("UTF-8"), repr("HA3").encode("UTF-8"), b"False"],
- [repr("O").encode("UTF-8"), repr("O").encode("UTF-8"), b"False"],
- [repr("N").encode("UTF-8"), repr("N").encode("UTF-8"), b"False"],
- [repr("C").encode("UTF-8"), repr("CA").encode("UTF-8"), b"False"],
- [repr("H").encode("UTF-8"), repr("HA2").encode("UTF-8"), b"False"],
- [repr("C").encode("UTF-8"), repr("C").encode("UTF-8"), b"False"],
- ],
- }
- r = ce.Residue.build(h5, [0, 1, 2, 3, 4, 5, 6], "GLY", "glycine", None)
-
- expected = ce.Residue("GLY", "glycine", None)
- expected.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
-
- self.assertEqual(repr(expected), repr(r))
-
- def test_serialize_empty_dict(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- dictionary = {}
- result = residue.serialize(dictionary)
-
- self.maxDiff = None
- self.assertEqual(("residues", 0), result)
- self.assertDictEqual(
- {
- "residues": [
- ["[0, 1, 2, 3, 4, 5, 6]", repr("GLY"), repr("glycine"), "None"]
- ],
- "atoms": [
- [repr("H"), repr("H"), "None", "False"],
- [repr("H"), repr("HA3"), "None", "False"],
- [repr("O"), repr("O"), "None", "False"],
- [repr("N"), repr("N"), "None", "False"],
- [repr("C"), repr("CA"), "None", "False"],
- [repr("H"), repr("HA2"), "None", "False"],
- [repr("C"), repr("C"), "None", "False"],
- ],
- },
- dictionary,
- )
-
- def test_serialize_nonempty_dict(self):
- residue = ce.Residue("GLY", "glycine", None)
- residue.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C"])
- dictionary = {"atoms": [[], [], []], "residues": [[], [], []]}
- result = residue.serialize(dictionary)
-
- self.maxDiff = None
- self.assertEqual(("residues", 3), result)
- self.assertDictEqual(
- {
- "residues": [
- [],
- [],
- [],
- ["[3, 4, 5, 6, 7, 8, 9]", repr("GLY"), repr("glycine"), "None"],
- ],
- "atoms": [
- [],
- [],
- [],
- [repr("H"), repr("H"), "None", "False"],
- [repr("H"), repr("HA3"), "None", "False"],
- [repr("O"), repr("O"), "None", "False"],
- [repr("N"), repr("N"), "None", "False"],
- [repr("C"), repr("CA"), "None", "False"],
- [repr("H"), repr("HA2"), "None", "False"],
- [repr("C"), repr("C"), "None", "False"],
- ],
- },
- dictionary,
- )
-
-
-class TestNucleotide(unittest.TestCase):
- def test_valid_residue_initialisation_without_variant(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
-
- self.compare_base_residues(nucleotide, True)
-
- def compare_base_residues(self, nucleotide: ce.Nucleotide, compare_atoms: bool):
- self.assertEqual("5T1", nucleotide.name)
- self.assertEqual(None, nucleotide.parent)
- self.assertEqual("5T1", nucleotide.code)
- self.assertEqual(None, nucleotide._variant)
- self.assertEqual(None, nucleotide._selected_variant)
- if compare_atoms:
- self.assertEqual(collections.OrderedDict(), nucleotide._atoms)
-
- def test_valid_residue_initialisation_with_valid_variant(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", "3T1")
-
- self.assertEqual("5T1", nucleotide.name)
- self.assertEqual(None, nucleotide.parent)
- self.assertEqual("5T1", nucleotide.code)
- self.assertEqual("3T1", nucleotide._variant)
- self.assertDictEqual(NUCLEOTIDES_DATABASE["3T1"], nucleotide._selected_variant)
- self.assertEqual(collections.OrderedDict(), nucleotide._atoms)
-
- def test_invalid_residue_initialisation(self):
- with self.assertRaises(ce.UnknownResidueError):
- ce.Nucleotide("00000", "00000")
-
- def test_valid_residue_initialisation_with_nonexistent_variant(self):
- with self.assertRaises(ce.InvalidVariantError):
- ce.Nucleotide("5T1", "5T1", "00000")
-
- def test_valid_residue_initialisation_with_invalid_variant(self):
- with self.assertRaises(ce.InvalidVariantError):
- ce.Nucleotide("5T1", "5T1", "A")
-
- def test_set_atoms_none(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
-
- self.compare_atoms_in_5t1(nucleotide._atoms, nucleotide)
-
- def compare_atoms_in_5t1(
- self, atom_list: Union[dict, ce.Nucleotide, list], nucleotide: ce.Nucleotide
- ):
- try:
- atom = atom_list["HO5'"]
- except TypeError:
- atom = atom_list[0]
- self.assertEqual("H", atom.symbol)
- self.assertEqual("HO5'", atom.name)
- self.assertEqual(1, len(atom.bonds))
- self.assertEqual("O5'", atom.bonds[0])
- self.assertEqual([], atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(nucleotide, atom.parent)
-
- def test_set_atoms_variant(self):
- nucleotide = ce.Nucleotide("A", "adenine", "5T1")
- names = [
- "C3'",
- "C1'",
- "C5'",
- "H2'",
- "H5'",
- "H3'",
- "O4'",
- "C8",
- "C2",
- "H1'",
- "C6",
- "C5",
- "C4",
- "H5''",
- "HO2'",
- "N9",
- "C4'",
- "C2'",
- "O2'",
- "N1",
- "N3",
- "N6",
- "N7",
- "H4'",
- "H8",
- "H2",
- "O5'",
- "H61",
- "H62",
- "O3'",
- "HO5'",
- ]
- nucleotide.set_atoms(names)
-
- symbols = [
- "C",
- "C",
- "C",
- "H",
- "H",
- "H",
- "O",
- "C",
- "C",
- "H",
- "C",
- "C",
- "C",
- "H",
- "H",
- "N",
- "C",
- "C",
- "O",
- "N",
- "N",
- "N",
- "N",
- "H",
- "H",
- "H",
- "O",
- "H",
- "H",
- "O",
- "H",
- ]
- bond_atoms = [
- ["C2'", "C4'", "H3'", "O3'"],
- ["C2'", "H1'", "N9", "O4'"],
- ["C4'", "H5'", "H5''", "O5'"],
- ["C2'"],
- ["C5'"],
- ["C3'"],
- ["C1'", "C3'"],
- ["H8", "N7", "N9"],
- ["N1", "N3", "H2"],
- ["C1'"],
- ["C5", "N1", "N6"],
- ["C4", "C6", "N7"],
- ["C5", "N3", "N9"],
- ["C5'"],
- ["O2'"],
- ["C1'", "C4", "C8"],
- ["C3'", "C5'", "H4'", "O4'"],
- ["C1'", "C3'", "H2'", "O2'"],
- ["C2'", "HO2'"],
- ["C2", "C6"],
- ["C2", "C4"],
- ["C6", "H61", "H62"],
- ["C5", "C8"],
- ["C4'"],
- ["C8"],
- ["C2"],
- ["C5'"],
- ["N6"],
- ["N6"],
- ["C3'", "+R"],
- ["O5'"],
- ]
- groups = (
- [["sugar"]] * 7
- + [["base"], ["base"], ["sugar"]]
- + [["base"]] * 3
- + [["sugar"], ["sugar"], ["base"]]
- + [["sugar"]] * 3
- + [["base"]] * 4
- + [
- ["sugar"],
- ["base"],
- ["base"],
- ["phosphate"],
- ["base"],
- ["base"],
- ["phosphate"],
- ]
- )
-
- for atom, symbol, name, bonds, group in zip(
- nucleotide._atoms.values(), symbols, names, bond_atoms, groups
- ):
- self.assertEqual(symbol, atom.symbol)
- self.assertEqual(name, atom.name)
- self.assertEqual(len(bonds), len(atom.bonds))
- for i, bond in enumerate(bonds):
- if bond[0] != "+":
- self.assertEqual(nucleotide._atoms[bond], atom.bonds[i])
- else:
- self.assertEqual(bond, atom.bonds[i])
- self.assertEqual(group, atom._groups)
- self.assertEqual(False, atom.ghost)
- self.assertEqual(None, atom.index)
- self.assertEqual(nucleotide, atom.parent)
-
- def test_set_atoms_invalid_input(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- with self.assertRaises(ce.InconsistentAtomNamesError):
- nucleotide.set_atoms(["HO5"])
-
- def test_dunder_getitem(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- self.compare_atoms_in_5t1(nucleotide, nucleotide)
-
- def test_pickling(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
-
- pickled = pickle.dumps(nucleotide)
- unpickled = pickle.loads(pickled)
-
- self.compare_base_residues(unpickled, False)
- self.compare_atoms_in_5t1(unpickled._atoms, unpickled)
-
- def test_dunder_repr(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
-
- if sys.version_info.minor < 12:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Nucleotide(parent=None, name='5T1', resname='5T1'"
- ", code='5T1', variant=None, selected_variant=None, atoms=OrderedDict([(\"HO5'\", MDANSE."
- "Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Nucleotide(5T1), name="
- "\"HO5'\", symbol='H', bonds=[Atom(O5')], groups=[], ghost=False, index=None, element='hydrogen', replaces="
- "['OP1', 'OP2', 'P'], o5prime_connected=True, alternatives=[]))]))",
- repr(nucleotide),
- )
- else:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Nucleotide(parent=None, name='5T1', resname='5T1'"
- ", code='5T1', variant=None, selected_variant=None, atoms=OrderedDict({\"HO5'\": MDANSE."
- "Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Nucleotide(5T1), name="
- "\"HO5'\", symbol='H', bonds=[Atom(O5')], groups=[], ghost=False, index=None, element='hydrogen', replaces="
- "['OP1', 'OP2', 'P'], o5prime_connected=True, alternatives=[])}))",
- repr(nucleotide),
- )
-
- def test_dunder_str(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- self.assertEqual('Nucleotide 5T1 (database code "5T1")', str(nucleotide))
-
- def test_copy(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- copy = nucleotide.copy()
-
- self.compare_base_residues(copy, False)
- self.compare_atoms_in_5t1(copy._atoms, copy)
-
- def test_atom_list(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- self.compare_atoms_in_5t1(nucleotide.atom_list, nucleotide)
-
- def test_number_of_atoms(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- self.assertEqual(1, nucleotide.number_of_atoms)
- self.assertEqual(1, nucleotide.total_number_of_atoms)
-
- def test_build(self):
- h5 = {
- "nucleotides": [
- [
- b"[0]",
- repr("5T1").encode("UTF-8"),
- repr("5T1").encode("UTF-8"),
- b"None",
- ]
- ],
- "atoms": [
- [repr("H").encode("UTF-8"), repr("HO5'").encode("UTF-8"), b"False"]
- ],
- }
- n = ce.Nucleotide.build(h5, [0], "5T1", "5T1", None)
-
- expected = ce.Nucleotide("5T1", "5T1", None)
- expected.set_atoms(["HO5'"])
-
- self.assertEqual(repr(expected), repr(n))
-
- def test_serialize_empty_dict(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- dictionary = {}
- result = nucleotide.serialize(dictionary)
-
- self.assertEqual(("nucleotides", 0), result)
- self.assertDictEqual(
- {
- "nucleotides": [["[0]", repr("5T1"), repr("5T1"), "None"]],
- "atoms": [[repr("H"), repr("HO5'"), "None", "False"]],
- },
- dictionary,
- )
-
- def test_serialize_nonempty_dict(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
- dictionary = {"atoms": [[], [], []], "nucleotides": [[], [], []]}
- result = nucleotide.serialize(dictionary)
-
- self.assertEqual(("nucleotides", 3), result)
- self.assertDictEqual(
- {
- "nucleotides": [[], [], [], ["[3]", repr("5T1"), repr("5T1"), "None"]],
- "atoms": [[], [], [], [repr("H"), repr("HO5'"), "None", "False"]],
- },
- dictionary,
- )
-
-
-class TestNucleotideChain(unittest.TestCase):
- def setUp(self):
- self.chain = ce.NucleotideChain("name")
-
- def test_instantiation(self):
- self.assertEqual("name", self.chain.name)
- self.assertEqual(None, self.chain.parent)
- self.assertEqual([], self.chain._nucleotides)
-
- def test_set_nucleotides(self):
- n1, n2 = self.prepare_nucleotides()
-
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual(2, len(self.chain._nucleotides))
- self.assertEqual(self.chain, self.chain._nucleotides[0].parent)
- self.assertEqual(self.chain, self.chain._nucleotides[1].parent)
-
- self.assertEqual([n1, n2], self.chain._nucleotides)
- self.assertEqual(n2["P"], n1["O3'"].bonds[1])
- self.assertEqual(n1["O3'"], n2["P"].bonds[3])
-
- @staticmethod
- def prepare_nucleotides():
- names5 = [
- "C3'",
- "C1'",
- "C5'",
- "H2'",
- "H5'",
- "H3'",
- "O4'",
- "C8",
- "C2",
- "H1'",
- "C6",
- "C5",
- "C4",
- "H5''",
- "HO2'",
- "N9",
- "C4'",
- "C2'",
- "O2'",
- "N1",
- "N3",
- "N6",
- "N7",
- "H4'",
- "H8",
- "H2",
- "O5'",
- "H61",
- "H62",
- "O3'",
- "HO5'",
- ]
- n1 = ce.Nucleotide("A", "adenine", "5T1")
- n1.set_atoms(names5)
-
- names3 = [
- "C3'",
- "C1'",
- "C5'",
- "H2'",
- "H5'",
- "H3'",
- "O4'",
- "C8",
- "C2",
- "H1'",
- "C6",
- "C5",
- "C4",
- "H5''",
- "HO2'",
- "N9",
- "C4'",
- "C2'",
- "O2'",
- "N1",
- "N3",
- "N6",
- "N7",
- "H4'",
- "H8",
- "H2",
- "O5'",
- "H61",
- "H62",
- "O3'",
- "HO3'",
- "OP1",
- "OP2",
- "P",
- ]
- n2 = ce.Nucleotide("A", "adenine", "3T1")
- n2.set_atoms(names3)
-
- return n1, n2
-
- def test_set_nucleotides_no_atoms_on_5prime_oxygen(self):
- n1, n2 = self.prepare_nucleotides()
-
- with self.assertRaises(ce.InvalidNucleotideChainError) as e:
- self.chain.set_nucleotides([n2, n1])
- self.assertEqual(
- "The first nucleotide in the chain must contain an atom that is connected to the 5' terminal"
- " oxygen (O5').",
- str(e.exception)[:105],
- )
-
- def test_set_nucleotides_first_no_5prime_oxygen(self):
- nucleotide = ce.Nucleotide("5T1", "5T1", None)
- nucleotide.set_atoms(["HO5'"])
-
- with self.assertRaises(ce.InvalidNucleotideChainError) as e:
- self.chain.set_nucleotides([nucleotide, nucleotide])
- self.assertEqual(
- "The first nucleotide in the chain must contain 5' terminal oxygen atom (O5').",
- str(e.exception)[:77],
- )
-
- def test_set_nucleotides_last_no_ho3prime(self):
- names5 = [
- "C3'",
- "C1'",
- "C5'",
- "H2'",
- "H5'",
- "H3'",
- "O4'",
- "C8",
- "C2",
- "H1'",
- "C6",
- "C5",
- "C4",
- "H5''",
- "HO2'",
- "N9",
- "C4'",
- "C2'",
- "O2'",
- "N1",
- "N3",
- "N6",
- "N7",
- "H4'",
- "H8",
- "H2",
- "O5'",
- "H61",
- "H62",
- "O3'",
- "HO5'",
- ]
- n1 = ce.Nucleotide("A", "adenine", "5T1")
- n1.set_atoms(names5)
- n2 = ce.Nucleotide("5T1", "5T1", None)
-
- with self.assertRaises(ce.InvalidNucleotideChainError) as e:
- self.chain.set_nucleotides([n1, n2])
- self.assertEqual(
- "The last nucleotide in the chain must contain an atom that is connected to the 3' terminal"
- " oxygen (O3').",
- str(e.exception)[:104],
- )
-
- def test_set_nucleotides_last_no_o3prime(self):
- names5 = [
- "C3'",
- "C1'",
- "C5'",
- "H2'",
- "H5'",
- "H3'",
- "O4'",
- "C8",
- "C2",
- "H1'",
- "C6",
- "C5",
- "C4",
- "H5''",
- "HO2'",
- "N9",
- "C4'",
- "C2'",
- "O2'",
- "N1",
- "N3",
- "N6",
- "N7",
- "H4'",
- "H8",
- "H2",
- "O5'",
- "H61",
- "H62",
- "O3'",
- "HO5'",
- ]
- n1 = ce.Nucleotide("A", "adenine", "5T1")
- n1.set_atoms(names5)
- n2 = ce.Nucleotide("3T1", "3T1", None)
- n2.set_atoms(["HO3'"])
-
- with self.assertRaises(ce.InvalidNucleotideChainError) as e:
- self.chain.set_nucleotides([n1, n2])
- self.assertEqual(
- "The last nucleotide in the chain must contain 3' terminal oxygen atom (O3').",
- str(e.exception)[:76],
- )
-
- def test_dunder_getitem(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual(n1, self.chain[0])
- self.assertEqual(n2, self.chain[1])
-
- def test_pickling(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- pickled = pickle.dumps(self.chain)
- unpickled = pickle.loads(pickled)
-
- self.assertEqual("name", unpickled.name)
- self.assertEqual(None, unpickled.parent)
-
- self.assertEqual(2, len(unpickled._nucleotides))
- self.assertEqual(unpickled[1]["P"], unpickled[0]["O3'"].bonds[1])
- self.assertEqual(unpickled[0]["O3'"], unpickled[1]["P"].bonds[3])
-
- def test_dunder_str(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual("NucleotideChain of 2 nucleotides", str(self.chain))
-
- def test_dunder_repr(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.maxDiff = None
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.NucleotideChain(parent=None, name='name', "
- "nucleotides=[MDANSE.MolecularDynamics.ChemicalEntity.Nucleotide(parent=MDANSE.Chemistry."
- "ChemicalEntity.NucleotideChain(name=name), name='adenine', resname='A', code='A', "
- "variant='5T1', selected_variant={'is_3ter_terminus': False, 'atoms':",
- repr(self.chain)[:320],
- )
-
- def test_bases(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual(
- [
- n1["C8"],
- n1["C2"],
- n1["C6"],
- n1["C5"],
- n1["C4"],
- n1["N9"],
- n1["N1"],
- n1["N3"],
- n1["N6"],
- n1["N7"],
- n1["H8"],
- n1["H2"],
- n1["H61"],
- n1["H62"],
- n2["C8"],
- n2["C2"],
- n2["C6"],
- n2["C5"],
- n2["C4"],
- n2["N9"],
- n2["N1"],
- n2["N3"],
- n2["N6"],
- n2["N7"],
- n2["H8"],
- n2["H2"],
- n2["H61"],
- n2["H62"],
- ],
- self.chain.bases,
- )
-
- def test_copy(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
- copy = self.chain.copy()
-
- self.assertEqual(repr(self.chain), repr(copy))
-
- def test_residues(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual([n1, n2], self.chain.residues)
-
- def test_number_of_atoms(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual(65, self.chain.number_of_atoms)
- self.assertEqual(65, self.chain.total_number_of_atoms)
-
- def test_build(self):
- h5 = {
- "nucleotides": [
- [
- b"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 2"
- b"8, 29, 30]",
- b"'A'",
- b"'adenine'",
- b"'5T1'",
- ],
- [
- b"[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]",
- b"'A'",
- b"'adenine'",
- b"'3T1'",
- ],
- ],
- "atoms": [
- [b"'C'", b'"C3\'"', b"False"],
- [b"'C'", b'"C1\'"', b"False"],
- [b"'C'", b'"C5\'"', b"False"],
- [b"'H'", b'"H2\'"', b"False"],
- [b"'H'", b'"H5\'"', b"False"],
- [b"'H'", b'"H3\'"', b"False"],
- [b"'O'", b'"O4\'"', b"False"],
- [b"'C'", b"'C8'", b"False"],
- [b"'C'", b"'C2'", b"False"],
- [b"'H'", b'"H1\'"', b"False"],
- [b"'C'", b"'C6'", b"False"],
- [b"'C'", b"'C5'", b"False"],
- [b"'C'", b"'C4'", b"False"],
- [b"'H'", b"\"H5''\"", b"False"],
- [b"'H'", b'"HO2\'"', b"False"],
- [b"'N'", b"'N9'", b"False"],
- [b"'C'", b'"C4\'"', b"False"],
- [b"'C'", b'"C2\'"', b"False"],
- [b"'O'", b'"O2\'"', b"False"],
- [b"'N'", b"'N1'", b"False"],
- [b"'N'", b"'N3'", b"False"],
- [b"'N'", b"'N6'", b"False"],
- [b"'N'", b"'N7'", b"False"],
- [b"'H'", b'"H4\'"', b"False"],
- [b"'H'", b"'H8'", b"False"],
- [b"'H'", b"'H2'", b"False"],
- [b"'O'", b'"O5\'"', b"False"],
- [b"'H'", b"'H61'", b"False"],
- [b"'H'", b"'H62'", b"False"],
- [b"'O'", b'"O3\'"', b"False"],
- [b"'H'", b'"HO5\'"', b"False"],
- [b"'C'", b'"C3\'"', b"False"],
- [b"'C'", b'"C1\'"', b"False"],
- [b"'C'", b'"C5\'"', b"False"],
- [b"'H'", b'"H2\'"', b"False"],
- [b"'H'", b'"H5\'"', b"False"],
- [b"'H'", b'"H3\'"', b"False"],
- [b"'O'", b'"O4\'"', b"False"],
- [b"'C'", b"'C8'", b"False"],
- [b"'C'", b"'C2'", b"False"],
- [b"'H'", b'"H1\'"', b"False"],
- [b"'C'", b"'C6'", b"False"],
- [b"'C'", b"'C5'", b"False"],
- [b"'C'", b"'C4'", b"False"],
- [b"'H'", b"\"H5''\"", b"False"],
- [b"'H'", b'"HO2\'"', b"False"],
- [b"'N'", b"'N9'", b"False"],
- [b"'C'", b'"C4\'"', b"False"],
- [b"'C'", b'"C2\'"', b"False"],
- [b"'O'", b'"O2\'"', b"False"],
- [b"'N'", b"'N1'", b"False"],
- [b"'N'", b"'N3'", b"False"],
- [b"'N'", b"'N6'", b"False"],
- [b"'N'", b"'N7'", b"False"],
- [b"'H'", b'"H4\'"', b"False"],
- [b"'H'", b"'H8'", b"False"],
- [b"'H'", b"'H2'", b"False"],
- [b"'O'", b'"O5\'"', b"False"],
- [b"'H'", b"'H61'", b"False"],
- [b"'H'", b"'H62'", b"False"],
- [b"'O'", b'"O3\'"', b"False"],
- [b"'H'", b'"HO3\'"', b"False"],
- [b"'O'", b"'OP1'", b"False"],
- [b"'O'", b"'OP2'", b"False"],
- [b"'P'", b"'P'", b"False"],
- ],
- "nucleotide_chains": [[b"'name'", b"[0, 1]"]],
- }
-
- nc = ce.NucleotideChain.build(h5, "name", [0, 1])
-
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.maxDiff = None
- self.assertEqual(repr(self.chain), repr(nc))
-
- def test_serialize_empty_dict(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
- dictionary = {}
- result = self.chain.serialize(dictionary)
-
- self.maxDiff = None
- self.assertEqual(("nucleotide_chains", 0), result)
- self.assertEqual(
- ["nucleotides", "atoms", "nucleotide_chains"], list(dictionary.keys())
- )
- self.assertEqual([[repr("name"), "[0, 1]"]], dictionary["nucleotide_chains"])
- self.assertEqual(
- [
- [
- "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, "
- "25, 26, 27, 28, 29, 30]",
- repr("A"),
- repr("adenine"),
- repr("5T1"),
- ],
- [
- "[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, "
- "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]",
- repr("A"),
- repr("adenine"),
- repr("3T1"),
- ],
- ],
- dictionary["nucleotides"],
- )
-
- def test_serialize_nonempty_dict(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
- dictionary = {"nucleotides": [[], [], []], "nucleotide_chains": [[]]}
- result = self.chain.serialize(dictionary)
-
- self.assertEqual(("nucleotide_chains", 1), result)
- self.assertEqual(
- ["nucleotides", "nucleotide_chains", "atoms"], list(dictionary.keys())
- )
- self.assertEqual(
- [[], [repr("name"), "[3, 4]"]], dictionary["nucleotide_chains"]
- )
- self.assertEqual(
- [
- [],
- [],
- [],
- [
- "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, "
- "22, 23, 24, 25, 26, 27, 28, 29, 30]",
- repr("A"),
- repr("adenine"),
- repr("5T1"),
- ],
- [
- "[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, "
- "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]",
- repr("A"),
- repr("adenine"),
- repr("3T1"),
- ],
- ],
- dictionary["nucleotides"],
- )
-
- def test_sugars(self):
- n1, n2 = self.prepare_nucleotides()
- self.chain.set_nucleotides([n1, n2])
-
- self.assertEqual(
- [
- n1["C3'"],
- n1["C1'"],
- n1["C5'"],
- n1["H2'"],
- n1["H5'"],
- n1["H3'"],
- n1["O4'"],
- n1["H1'"],
- n1["H5''"],
- n1["HO2'"],
- n1["C4'"],
- n1["C2'"],
- n1["O2'"],
- n1["H4'"],
- n2["C3'"],
- n2["C1'"],
- n2["C5'"],
- n2["H2'"],
- n2["H5'"],
- n2["H3'"],
- n2["O4'"],
- n2["H1'"],
- n2["H5''"],
- n2["HO2'"],
- n2["C4'"],
- n2["C2'"],
- n2["O2'"],
- n2["H4'"],
- ],
- self.chain.sugars,
- )
-
-
-class TestPeptideChain(unittest.TestCase):
- def setUp(self):
- self.chain = ce.PeptideChain("name")
-
- def test_instantiation(self):
- self.assertEqual("name", self.chain.name)
- self.assertEqual(None, self.chain.parent)
- self.assertEqual([], self.chain._residues)
-
- def test_set_residues_valid(self):
- self.populate_chain()
-
- self.assertEqual(2, len(self.chain._residues))
- self.assertEqual(self.chain, self.chain._residues[0].parent)
- self.assertEqual(self.chain, self.chain._residues[1].parent)
-
- self.assertEqual(
- self.chain._residues[1]["N"], self.chain._residues[0]["C"].bonds[2]
- )
- self.assertEqual(
- self.chain._residues[0]["C"], self.chain._residues[1]["N"].bonds[2]
- )
-
- def populate_chain(self):
- r1 = ce.Residue("GLY", "glycine1", "NT1")
- r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "HT1", "HT2", "HT3"])
-
- r2 = ce.Residue("GLY", "glycine2", "CT1")
- r2.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C", "OXT"])
- self.chain.set_residues([r1, r2])
-
- return r1, r2
-
- def test_set_residues_no_atoms_connected_to_terminal_nitrogen(self):
- r1 = ce.Residue("GLY", "glycine1", None)
- r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "H"])
-
- r2 = ce.Residue("GLY", "glycine2", "CT1")
- r2.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C", "OXT"])
-
- with self.assertRaises(ce.InvalidPeptideChainError) as e:
- self.chain.set_residues([r1, r2])
-
- self.assertEqual(
- "The first residue in the chain must contain an atom that is connected to the terminal "
- "nitrogen.",
- str(e.exception)[:95],
- )
-
- def test_set_residues_no_terminal_nitrogen(self):
- r = ce.Residue("NT1", "NT1", None)
- r.set_atoms(["HT1", "HT2", "HT3"])
-
- with self.assertRaises(ce.InvalidPeptideChainError) as e:
- self.chain.set_residues([r, r])
-
- self.assertEqual(
- "The first residue in the chain must contain the terminal nitrogen atom. ",
- str(e.exception)[:72],
- )
-
- def test_set_residues_no_atoms_connected_to_terminal_carbon(self):
- r1 = ce.Residue("GLY", "glycine1", "NT1")
- r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "HT1", "HT2", "HT3"])
-
- with self.assertRaises(ce.InvalidPeptideChainError) as e:
- self.chain.set_residues([r1, r1])
-
- self.assertEqual(
- "The last residue in the chain must contain an atom that is connected to the terminal carbon.",
- str(e.exception)[:92],
- )
-
- def test_set_residues_no_terminal_carbon(self):
- r1 = ce.Residue("GLY", "glycine1", "NT1")
- r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "HT1", "HT2", "HT3"])
-
- r2 = ce.Residue("CT1", "CT1", "CT1")
- r2.set_atoms(["OXT"])
-
- with self.assertRaises(ce.InvalidPeptideChainError) as e:
- self.chain.set_residues([r1, r2])
-
- self.assertEqual(
- "The last residue in the chain must contain the terminal carbon atom. ",
- str(e.exception)[:69],
- )
-
- def test_dunder_getitem(self):
- r1, r2 = self.populate_chain()
-
- self.assertEqual(r1, self.chain[0])
- self.assertEqual(r2, self.chain[1])
-
- def test_pickling(self):
- self.populate_chain()
-
- pickled = pickle.dumps(self.chain)
- unpickled = pickle.loads(pickled)
-
- self.assertEqual("name", unpickled.name)
- self.assertEqual(None, unpickled.parent)
- self.assertEqual(2, len(unpickled._residues))
-
- def test_dunder_str(self):
- self.populate_chain()
- self.assertEqual("PeptideChain of 2 residues", str(self.chain))
-
- def test_dunder_repr(self):
- self.populate_chain()
-
- self.maxDiff = None
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.PeptideChain(parent=None, name='name', "
- "residues=[MDANSE.MolecularDynamics.ChemicalEntity.Residue(parent=MDANSE.Chemistry."
- "ChemicalEntity.PeptideChain(name), name='glycine1', code='GLY', variant='NT1', "
- "selected_variant={'is_n_terminus': True, ",
- repr(self.chain)[:281],
- )
-
- def test_atom_list(self):
- r1, r2 = self.populate_chain()
-
- self.assertEqual(
- [
- r1["HA3"],
- r1["O"],
- r1["N"],
- r1["CA"],
- r1["HA2"],
- r1["C"],
- r1["HT1"],
- r1["HT2"],
- r1["HT3"],
- r2["H"],
- r2["HA3"],
- r2["O"],
- r2["N"],
- r2["CA"],
- r2["HA2"],
- r2["C"],
- r2["OXT"],
- ],
- self.chain.atom_list,
- )
-
- def test_backbone(self):
- r1, r2 = self.populate_chain()
-
- self.assertEqual(
- [
- r1["O"],
- r1["N"],
- r1["CA"],
- r1["HA2"],
- r1["C"],
- r1["HT1"],
- r1["HT2"],
- r1["HT3"],
- r2["H"],
- r2["O"],
- r2["N"],
- r2["CA"],
- r2["HA2"],
- r2["C"],
- r2["OXT"],
- ],
- self.chain.backbone,
- )
-
- def test_copy(self):
- self.populate_chain()
- copy = self.chain.copy()
-
- self.maxDiff = None
- self.assertEqual(repr(self.chain), repr(copy))
-
- def test_number_of_atoms(self):
- self.populate_chain()
- self.assertEqual(17, self.chain.number_of_atoms)
- self.assertEqual(17, self.chain.total_number_of_atoms)
-
- def test_peptide_chains(self):
- self.populate_chain()
- self.assertEqual([self.chain], self.chain.peptide_chains)
-
- def test_peptides(self):
- r1, r2 = self.populate_chain()
- self.assertEqual(
- [r1["O"], r1["N"], r1["C"], r2["H"], r2["O"], r2["N"], r2["C"]],
- self.chain.peptides,
- )
-
- def test_residues(self):
- r1, r2 = self.populate_chain()
- self.assertEqual([r1, r2], self.chain.residues)
-
- def test_build(self):
- h5 = {
- "residues": [
- [b"[0, 1, 2, 3, 4, 5, 6, 7, 8]", b"'GLY'", b"'glycine1'", b"'NT1'"],
- [b"[9, 10, 11, 12, 13, 14, 15, 16]", b"'GLY'", b"'glycine2'", b"'CT1'"],
- ],
- "atoms": [
- [b"'H'", b"'HA3'", b"False"],
- [b"'O'", b"'O'", b"False"],
- [b"'N'", b"'N'", b"False"],
- [b"'C'", b"'CA'", b"False"],
- [b"'H'", b"'HA2'", b"False"],
- [b"'C'", b"'C'", b"False"],
- [b"'H'", b"'HT1'", b"False"],
- [b"'H'", b"'HT2'", b"False"],
- [b"'H'", b"'HT3'", b"False"],
- [b"'H'", b"'H'", b"False"],
- [b"'H'", b"'HA3'", b"False"],
- [b"'O'", b"'O'", b"False"],
- [b"'N'", b"'N'", b"False"],
- [b"'C'", b"'CA'", b"False"],
- [b"'H'", b"'HA2'", b"False"],
- [b"'C'", b"'C'", b"False"],
- [b"'O'", b"'OXT'", b"False"],
- ],
- "peptide_chains": [[b"'name'", b"[0, 1]"]],
- }
- pc = ce.PeptideChain.build(h5, "name", [0, 1])
-
- self.populate_chain()
-
- self.maxDiff = None
- self.assertEqual(repr(self.chain), repr(pc))
-
- def test_serialize_empty_dict(self):
- self.populate_chain()
- dictionary = {}
- result = self.chain.serialize(dictionary)
-
- self.maxDiff = None
- self.assertEqual(("peptide_chains", 0), result)
- self.assertEqual(
- ["residues", "atoms", "peptide_chains"], list(dictionary.keys())
- )
- self.assertEqual([[repr("name"), "[0, 1]"]], dictionary["peptide_chains"])
- self.assertEqual(
- [
- [
- "[0, 1, 2, 3, 4, 5, 6, 7, 8]",
- repr("GLY"),
- repr("glycine1"),
- repr("NT1"),
- ],
- [
- "[9, 10, 11, 12, 13, 14, 15, 16]",
- repr("GLY"),
- repr("glycine2"),
- repr("CT1"),
- ],
- ],
- dictionary["residues"],
- )
-
- def test_serialize_nonempty_dict(self):
- self.populate_chain()
- dictionary = {"residues": [[], [], []], "peptide_chains": [[], [], []]}
- result = self.chain.serialize(dictionary)
-
- self.assertEqual(("peptide_chains", 3), result)
- self.assertEqual(
- ["residues", "peptide_chains", "atoms"], list(dictionary.keys())
- )
- self.assertEqual(
- [[], [], [], [repr("name"), "[3, 4]"]], dictionary["peptide_chains"]
- )
- self.assertEqual(
- [
- [],
- [],
- [],
- [
- "[0, 1, 2, 3, 4, 5, 6, 7, 8]",
- repr("GLY"),
- repr("glycine1"),
- repr("NT1"),
- ],
- [
- "[9, 10, 11, 12, 13, 14, 15, 16]",
- repr("GLY"),
- repr("glycine2"),
- repr("CT1"),
- ],
- ],
- dictionary["residues"],
- )
-
- def test_sidechains(self):
- r1, r2 = self.populate_chain()
- self.assertEqual([r1["HA3"], r2["HA3"]], self.chain.sidechains)
-
-
-class TestProtein(unittest.TestCase):
- def setUp(self):
- self.protein = ce.Protein("name")
-
- def test_instantiation(self):
- self.assertEqual("name", self.protein.name)
- self.assertEqual(None, self.protein.parent)
- self.assertEqual([], self.protein._peptide_chains)
-
- def test_set_peptide_chains(self):
- chain = self.populate_protein()
-
- self.assertEqual([chain], self.protein._peptide_chains)
- self.assertEqual(self.protein, self.protein._peptide_chains[0].parent)
-
- def populate_protein(self):
- r1 = ce.Residue("GLY", "glycine1", "NT1")
- r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "HT1", "HT2", "HT3"])
-
- r2 = ce.Residue("GLY", "glycine2", "CT1")
- r2.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C", "OXT"])
-
- chain = ce.PeptideChain("name")
- chain.set_residues([r1, r2])
- self.protein.set_peptide_chains([chain])
-
- return chain
-
- def test_pickling(self):
- chain = self.populate_protein()
-
- pickled = pickle.dumps(self.protein)
- unpickled = pickle.loads(pickled)
-
- self.maxDiff = None
- self.assertEqual("name", unpickled.name)
- self.assertEqual(None, unpickled.parent)
- self.assertEqual(1, len(unpickled._peptide_chains))
- self.assertEqual(repr(chain), repr(unpickled._peptide_chains[0]))
-
- def test_dunder_getitem(self):
- chain = self.populate_protein()
- self.assertEqual(chain, self.protein[0])
-
- def test_dunder_repr(self):
- self.populate_protein()
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.Protein(parent=None, name='name', peptide_chains="
- "[MDANSE.MolecularDynamics.ChemicalEntity.PeptideChain(parent=MDANSE.Chemistry.ChemicalEntity."
- "Protein(name=name), name='name'",
- repr(self.protein)[:213],
- )
-
- def test_dunder_str(self):
- self.populate_protein()
- self.assertEqual(
- "Protein name consisting of 1 peptide chains", str(self.protein)
- )
-
- def test_atom_list(self):
- chain = self.populate_protein()
-
- self.assertEqual(
- [
- chain[0]["HA3"],
- chain[0]["O"],
- chain[0]["N"],
- chain[0]["CA"],
- chain[0]["HA2"],
- chain[0]["C"],
- chain[0]["HT1"],
- chain[0]["HT2"],
- chain[0]["HT3"],
- chain[1]["H"],
- chain[1]["HA3"],
- chain[1]["O"],
- chain[1]["N"],
- chain[1]["CA"],
- chain[1]["HA2"],
- chain[1]["C"],
- chain[1]["OXT"],
- ],
- self.protein.atom_list,
- )
-
- def test_backbone(self):
- chain = self.populate_protein()
- self.assertEqual(
- [
- chain[0]["O"],
- chain[0]["N"],
- chain[0]["CA"],
- chain[0]["HA2"],
- chain[0]["C"],
- chain[0]["HT1"],
- chain[0]["HT2"],
- chain[0]["HT3"],
- chain[1]["H"],
- chain[1]["O"],
- chain[1]["N"],
- chain[1]["CA"],
- chain[1]["HA2"],
- chain[1]["C"],
- chain[1]["OXT"],
- ],
- self.protein.backbone,
- )
-
- def test_copy(self):
- chain = self.populate_protein()
- copy = self.protein.copy()
-
- self.maxDiff = None
- self.assertEqual("name", copy.name)
- self.assertEqual(None, copy.parent)
- self.assertEqual(1, len(copy._peptide_chains))
- self.assertEqual(repr(chain), repr(copy._peptide_chains[0]))
-
- def test_number_of_atoms(self):
- self.populate_protein()
-
- self.assertEqual(17, self.protein.number_of_atoms)
- self.assertEqual(17, self.protein.total_number_of_atoms)
-
- def test_peptide_chains(self):
- chain = self.populate_protein()
- self.assertEqual([chain], self.protein.peptide_chains)
-
- def test_peptides(self):
- chain = self.populate_protein()
- self.assertEqual(
- [
- chain[0]["O"],
- chain[0]["N"],
- chain[0]["C"],
- chain[1]["H"],
- chain[1]["O"],
- chain[1]["N"],
- chain[1]["C"],
- ],
- self.protein.peptides,
- )
-
- def test_residues(self):
- chain = self.populate_protein()
- self.assertEqual(chain.residues, self.protein.residues)
-
- def test_build(self):
- h5 = {
- "proteins": [["'name'", "[0]"]],
- "residues": [
- [b"[0, 1, 2, 3, 4, 5, 6, 7, 8]", b"'GLY'", b"'glycine1'", b"'NT1'"],
- [b"[9, 10, 11, 12, 13, 14, 15, 16]", b"'GLY'", b"'glycine2'", b"'CT1'"],
- ],
- "atoms": [
- [b"'H'", b"'HA3'", b"False"],
- [b"'O'", b"'O'", b"False"],
- [b"'N'", b"'N'", b"False"],
- [b"'C'", b"'CA'", b"False"],
- [b"'H'", b"'HA2'", b"False"],
- [b"'C'", b"'C'", b"False"],
- [b"'H'", b"'HT1'", b"False"],
- [b"'H'", b"'HT2'", b"False"],
- [b"'H'", b"'HT3'", b"False"],
- [b"'H'", b"'H'", b"False"],
- [b"'H'", b"'HA3'", b"False"],
- [b"'O'", b"'O'", b"False"],
- [b"'N'", b"'N'", b"False"],
- [b"'C'", b"'CA'", b"False"],
- [b"'H'", b"'HA2'", b"False"],
- [b"'C'", b"'C'", b"False"],
- [b"'O'", b"'OXT'", b"False"],
- ],
- "peptide_chains": [[b"'name'", b"[0, 1]"]],
- }
- p = ce.Protein.build(h5, "name", [0])
-
- self.populate_protein()
-
- self.maxDiff = 0
- self.assertEqual(repr(self.protein), repr(p))
-
- def test_serialize_empty_dict(self):
- self.populate_protein()
- dictionary = {}
- result = self.protein.serialize(dictionary)
-
- self.assertEqual(("proteins", 0), result)
- self.assertEqual(
- ["proteins", "residues", "atoms", "peptide_chains"], list(dictionary.keys())
- )
- self.assertEqual([[repr("name"), "[0]"]], dictionary["proteins"])
- self.assertEqual([[repr("name"), "[0, 1]"]], dictionary["peptide_chains"])
-
- def test_serialize_nonempty_dict(self):
- self.populate_protein()
- dictionary = {"proteins": [[], [], []], "peptide_chains": [[], [], []]}
- result = self.protein.serialize(dictionary)
-
- self.assertEqual(("proteins", 3), result)
- self.assertEqual(
- ["proteins", "peptide_chains", "residues", "atoms"], list(dictionary.keys())
- )
- self.assertEqual([[], [], [], [repr("name"), "[3]"]], dictionary["proteins"])
- self.assertEqual(
- [[], [], [], [repr("name"), "[0, 1]"]], dictionary["peptide_chains"]
- )
-
- def test_sidechains(self):
- chain = self.populate_protein()
- self.assertEqual([chain[0]["HA3"], chain[1]["HA3"]], self.protein.sidechains)
-
-
-class TestTranslateAtomNames(unittest.TestCase):
- def test_valid(self):
- result = ce.translate_atom_names(MOLECULES_DATABASE, "WAT", ["O", "HW2", "H1"])
- self.assertEqual(["OW", "HW2", "HW1"], result)
-
- def test_subset_of_all_atoms(self):
- result = ce.translate_atom_names(MOLECULES_DATABASE, "WAT", ["O", "HW2"])
- self.assertEqual(["OW", "HW2"], result)
-
- def test_multiple_of_one_atom(self):
- result = ce.translate_atom_names(
- MOLECULES_DATABASE, "WAT", ["O", "HW2", "HW2", "HW2", "HW2"]
- )
- self.assertEqual(["OW", "HW2", "HW2", "HW2", "HW2"], result)
-
- def test_invalid_molname(self):
- with self.assertRaises(ce.UnknownMoleculeError):
- ce.translate_atom_names(MOLECULES_DATABASE, "00000", ["OW", "HW1", "HW2"])
-
- def test_invalid_atom(self):
- with self.assertRaises(ce.UnknownAtomError):
- ce.translate_atom_names(MOLECULES_DATABASE, "WAT", [""])
-
-
-class TestChemicalSystem(unittest.TestCase):
- def setUp(self):
- self.system = ce.ChemicalSystem("name")
-
- def test_instantiation(self):
- self.assertEqual("name", self.system.name)
- self.assertEqual(None, self.system.parent)
- self.assertEqual([], self.system.chemical_entities)
- self.assertEqual(None, self.system._configuration)
- self.assertEqual(0, self.system._number_of_atoms)
- self.assertEqual(0, self.system._total_number_of_atoms)
- self.assertEqual(None, self.system._atoms)
-
- def test_add_chemical_entity_valid(self):
- cluster = ce.AtomCluster("name", [ce.Atom(ghost=False), ce.Atom(ghost=True)])
- self.system.add_chemical_entity(cluster)
-
- self.assertEqual(1, self.system._number_of_atoms)
- self.assertEqual(2, self.system._total_number_of_atoms)
- self.assertEqual(self.system, cluster.parent)
- self.assertEqual([cluster], self.system.chemical_entities)
- self.assertEqual(None, self.system._configuration)
- self.assertEqual(None, self.system._atoms)
-
- def test_add_chemical_entity_invalid_input(self):
- with self.assertRaises(ce.InvalidChemicalEntityError):
- self.system.add_chemical_entity([])
-
- def test_pickling(self):
- molecule = ce.Molecule("WAT", "name")
- self.system.add_chemical_entity(molecule)
-
- pickled = pickle.dumps(self.system)
- unpickled = pickle.loads(pickled)
-
- self.assertEqual("name", unpickled.name)
- self.assertEqual(None, unpickled.parent)
- self.assertEqual(3, unpickled._number_of_atoms)
- self.assertEqual(3, unpickled._total_number_of_atoms)
- self.assertEqual(repr(molecule), repr(unpickled.chemical_entities[0]))
- self.assertEqual(None, unpickled._configuration)
- self.assertEqual(None, unpickled._atoms)
-
- def test_dunder_repr(self):
- molecule = ce.Molecule("WAT", "name")
- self.system.add_chemical_entity(molecule)
-
- self.maxDiff = None
- if sys.version_info.minor < 12:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.ChemicalSystem(parent=None, name='name', "
- "chemical_entities=[MDANSE.MolecularDynamics.ChemicalEntity.Molecule(parent=MDANSE.Chemistry."
- "ChemicalEntity.ChemicalSystem(name), name='name', atoms=OrderedDict([('OW', MDANSE.Chemistry."
- "ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(name), name='OW', "
- "symbol='O', bonds=[Atom(HW1), Atom(HW2)], groups=[], ghost=False, index=0, element='oxygen', alternatives="
- "['O', 'OH2'])), ('HW2', MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry."
- "ChemicalEntity.Molecule(name), name='HW2', symbol='H', bonds=[Atom(OW)], groups=[], "
- "ghost=False, index=1, element='hydrogen', alternatives=['H2'])), ('HW1', MDANSE.Chemistry.ChemicalEntity."
- "Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(name), name='HW1', symbol='H', bonds="
- "[Atom(OW)], groups=[], ghost=False, index=2, element='hydrogen', alternatives=['H1']))]), code='WAT')], "
- "configuration=None, number_of_atoms=3, total_number_of_atoms=3, bonds=[], atoms=None)",
- repr(self.system),
- )
- else:
- self.assertEqual(
- "MDANSE.MolecularDynamics.ChemicalEntity.ChemicalSystem(parent=None, name='name', "
- "chemical_entities=[MDANSE.MolecularDynamics.ChemicalEntity.Molecule(parent=MDANSE.Chemistry."
- "ChemicalEntity.ChemicalSystem(name), name='name', atoms=OrderedDict({'OW': MDANSE.Chemistry."
- "ChemicalEntity.Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(name), name='OW', "
- "symbol='O', bonds=[Atom(HW1), Atom(HW2)], groups=[], ghost=False, index=0, element='oxygen', alternatives="
- "['O', 'OH2']), 'HW2': MDANSE.Chemistry.ChemicalEntity.Atom(parent=MDANSE.Chemistry."
- "ChemicalEntity.Molecule(name), name='HW2', symbol='H', bonds=[Atom(OW)], groups=[], "
- "ghost=False, index=1, element='hydrogen', alternatives=['H2']), 'HW1': MDANSE.Chemistry.ChemicalEntity."
- "Atom(parent=MDANSE.Chemistry.ChemicalEntity.Molecule(name), name='HW1', symbol='H', bonds="
- "[Atom(OW)], groups=[], ghost=False, index=2, element='hydrogen', alternatives=['H1'])}), code='WAT')], "
- "configuration=None, number_of_atoms=3, total_number_of_atoms=3, bonds=[], atoms=None)",
- repr(self.system),
- )
-
- def test_dunder_str(self):
- atom1 = ce.Atom(ghost=False)
- atom2 = ce.Atom(ghost=False)
- cluster = ce.AtomCluster("name", [atom1, atom2])
- self.system.add_chemical_entity(cluster)
- self.assertEqual(
- "ChemicalSystem name consisting of 1 chemical entities", str(self.system)
- )
-
- def test_atom_list(self):
- atom1 = ce.Atom(ghost=False)
- atom2 = ce.Atom(ghost=False)
- cluster = ce.AtomCluster("name", [atom1, atom2])
- self.system.add_chemical_entity(cluster)
-
- self.assertEqual([atom1, atom2], self.system.atom_list)
-
- def test_atoms(self):
- atom1 = ce.Atom(ghost=False)
- atom2 = ce.Atom(ghost=False)
- cluster = ce.AtomCluster("name", [atom1, atom2])
- self.system.add_chemical_entity(cluster)
-
- atom1._index = 1
- atom2._index = 0
-
- self.maxDiff = None
- self.assertEqual([atom2, atom1], self.system.atoms)
-
- def test_configuration_setter_valid(self):
- config = DummyConfiguration(self.system)
- self.system.configuration = config
-
- self.assertEqual(config, self.system.configuration)
-
- def test_configuration_setter_invalid(self):
- other_system = ce.ChemicalSystem("another_name")
- config = DummyConfiguration(self.system)
-
- with self.assertRaises(ce.InconsistentChemicalSystemError):
- other_system.configuration = config
-
- def test_copy(self):
- molecule = ce.Molecule("WAT", "name")
- self.system.add_chemical_entity(molecule)
- copy = self.system.copy()
-
- self.assertEqual("name", copy.name)
- self.assertEqual(None, copy.parent)
- self.assertEqual(repr(molecule), repr(copy.chemical_entities[0]))
- self.assertEqual(None, copy._configuration)
- self.assertEqual(3, copy._number_of_atoms)
- self.assertEqual(3, copy._total_number_of_atoms)
- self.assertEqual(self.system.atoms, copy.atoms)
-
- def test_load_valid(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("atoms".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [
- [repr("H").encode("UTF-8"), repr("H1").encode("UTF-8"), b"0", b"False"]
- ]
- self.system.load(file)
-
- self.assertEqual(None, self.system._h5_file)
- self.assertEqual("new", self.system.name)
- self.assertEqual(None, self.system.parent)
- self.assertEqual(
- repr(ce.Atom(name="H1", parent=self.system, index=0)),
- repr(self.system.chemical_entities[0]),
- )
- self.assertEqual(None, self.system._configuration)
- self.assertEqual(1, self.system._number_of_atoms)
- self.assertEqual(1, self.system._total_number_of_atoms)
- self.assertEqual(None, self.system._atoms)
-
- def test_load_corrupt_file_skeleton_invalid_entity_type(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("INVALID".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [[b"H", b"H1", b"0", b"False"]]
-
- with self.assertRaises(ce.CorruptedFileError):
- self.system.load(file)
-
- def test_load_corrupt_file_skeleton_entity_not_in_system(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("atoms".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["INVALID"] = [[b"H", b"H1", b"0", b"False"]]
-
- with self.assertRaises(ce.CorruptedFileError):
- self.system.load(file)
-
- def test_load_corrupt_file_skeleton_index_out_of_range(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("atoms".encode(encoding="UTF-8", errors="strict"), 1)
- ]
- file["/chemical_system"]["atoms"] = [[b"H", b"H1", b"0", b"False"]]
-
- with self.assertRaises(ce.CorruptedFileError):
- self.system.load(file)
-
- def test_load_corrupt_file_ast_error(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("atoms".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [[b'"', b"H1", b"0", b"False"]]
-
- with self.assertRaises(ce.CorruptedFileError):
- self.system.load(file)
-
- def test_load_corrupt_file_inconsistent_atoms(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("molecules".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [
- [
- repr("H").encode("UTF-8"),
- repr("H1").encode("UTF-8"),
- str(i).encode("UTF-8"),
- b"False",
- ]
- for i in range(3)
- ]
- file["/chemical_system"]["molecules"] = [
- [b"[0, 1, 2]", repr("WAT").encode("UTF-8"), repr("water").encode("UTF-8")]
- ]
-
- with self.assertRaises(ce.CorruptedFileError) as e:
- self.system.load(file)
- self.assertEqual(
- "Could not reconstruct from the HDF5 "
- "Trajectory because its constituent atoms recorded in the trajectory are different",
- str(e.exception)[:168],
- )
-
- def test_load_corrupt_file_index_out_of_bounds(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("molecules".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [
- [repr("H").encode("UTF-8"), repr("H1").encode("UTF-8"), b"0", b"False"]
- ]
- file["/chemical_system"]["molecules"] = [
- [b"[0, 1, 2]", repr("WAT").encode("UTF-8"), repr("water").encode("UTF-8")]
- ]
-
- with self.assertRaises(ce.CorruptedFileError) as e:
- self.system.load(file)
- self.assertEqual(
- "Could not reconstruct from the HDF5 "
- "Trajectory because one or more of its constituent atoms are missing",
- str(e.exception)[:154],
- )
-
- def test_load_corrupt_file_missing_entity(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("molecules".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["molecules"] = [
- [b"[0, 1, 2]", repr("WAT").encode("UTF-8"), repr("water").encode("UTF-8")]
- ]
-
- with self.assertRaises(ce.CorruptedFileError) as e:
- self.system.load(file)
- self.assertEqual(
- "Could not reconstruct from the HDF5 "
- "Trajectory because one of its constituent parts could not be found in the trajectory",
- str(e.exception)[:171],
- )
-
- def test_load_corrupt_file_incorrect_arguments(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("proteins".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["peptide_chains"] = [
- [
- repr("name").encode("UTF-8"),
- b"[0, 1]",
- repr("INVALID_ARGUMENT").encode("UTF-8"),
- ],
- ]
- file["/chemical_system"]["proteins"] = [
- [repr("protein").encode("UTF-8"), b"[0, 1, 2]"]
- ]
-
- with self.assertRaises(ce.CorruptedFileError) as e:
- self.system.load(file)
- self.assertEqual(
- "Could not reconstruct from the HDF5 "
- "Trajectory because the data associated with it does not match the expected arguments",
- str(e.exception)[:170],
- )
-
- def test_load_corrupt_file_ast_error_when_building(self):
- file = StubHDFFile()
- file["/chemical_system"] = StubHDFFile()
- file["/chemical_system"].attrs["name"] = "new"
-
- file["/chemical_system/contents"] = [
- ("molecules".encode(encoding="UTF-8", errors="strict"), 0)
- ]
- file["/chemical_system"]["atoms"] = [
- [repr("H").encode("UTF-8"), b"H1", b"0", b"False"]
- ]
- file["/chemical_system"]["molecules"] = [
- [b"[0, 1, 2]", repr("WAT").encode("UTF-8"), repr("water").encode("UTF-8")]
- ]
-
- with self.assertRaises(ce.CorruptedFileError) as e:
- self.system.load(file)
- self.assertEqual(
- "Could not reconstruct from the HDF5 "
- "Trajectory because the data associated with it is in an incorrect format.",
- str(e.exception)[:160],
- )
-
- def test_serialize(self):
- molecule = ce.Molecule("WAT", "water")
- self.system.add_chemical_entity(molecule)
- file = StubHDFFile()
- self.system.serialize(file)
-
- self.assertEqual("name", file["/chemical_system"].attrs["name"])
- self.assertEqual(
- [["[0, 1, 2]", repr("WAT"), repr("water")]],
- file["/chemical_system"]["molecules"],
- )
- self.assertEqual(
- [
- [repr("O"), repr("OW"), "0", "False"],
- [repr("H"), repr("HW2"), "1", "False"],
- [repr("H"), repr("HW1"), "2", "False"],
- ],
- file["/chemical_system"]["atoms"],
- )
- self.assertEqual([("molecules", "0")], file["/chemical_system"]["contents"])
-
-
-class DummyConfiguration:
- def __init__(self, system: ce.ChemicalSystem):
- self.chemical_system = system
-
-
-class StubHDFFile(dict):
- attrs = {}
-
- def close(self):
- pass
-
- def create_group(self, value: str):
- self[value] = StubHDFFile()
- return self[value]
-
- def create_dataset(self, name: str, data, dtype):
- self[name] = data
-
-
-class TestChemicalEntity(unittest.TestCase):
- def setUp(self):
- self.r1 = ce.Residue("GLY", "glycine1", "NT1")
- self.r1.set_atoms(["HA3", "O", "N", "CA", "HA2", "C", "HT1", "HT2", "HT3"])
-
- self.r2 = ce.Residue("GLY", "glycine2", "CT1")
- self.r2.set_atoms(["H", "HA3", "O", "N", "CA", "HA2", "C", "OXT"])
-
- self.chain = ce.PeptideChain("chain")
- self.chain.set_residues([self.r1, self.r2])
-
- self.protein = ce.Protein("protein")
- self.protein.set_peptide_chains([self.chain])
-
- def test_full_name(self):
- self.assertEqual("protein.chain.glycine1.N", self.r1["N"].full_name)
- self.assertEqual("protein.chain.glycine2", self.r2.full_name)
-
- def test_group(self):
- self.assertEqual(
- [self.r1["HA3"], self.r2["HA3"]], self.protein.group("sidechain")
- )
-
- def test_center_of_mass(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- group = ce.AtomGroup([self.r1["HT3"], self.r1["HA2"], self.r2["O"]])
-
- configuration = {"coordinates": np.ones((17, 3))}
- self.assertTrue(
- np.allclose(np.array([1, 1, 1]), self.protein.center_of_mass(configuration))
- )
- self.assertTrue(
- np.allclose(np.array([1, 1, 1]), group.center_of_mass(configuration))
- )
-
- def test_mass(self):
- self.assertAlmostEqual(132.1176, self.protein.mass)
- self.assertAlmostEqual(1.0079, self.r1["HA3"].mass)
-
- def test_masses(self):
- for i, j in zip(
- [
- 1.0079,
- 15.9994,
- 14.0067,
- 12.0107,
- 1.0079,
- 12.0107,
- 1.0079,
- 1.0079,
- 1.0079,
- 1.0079,
- 1.0079,
- 15.9994,
- 14.0067,
- 12.0107,
- 1.0079,
- 12.0107,
- 15.9994,
- ],
- self.protein.masses,
- ):
- self.assertAlmostEqual(i, j)
-
- for i, j in zip([1.0079], self.r1["HA3"].masses):
- self.assertAlmostEqual(i, j)
-
- def test_find_transformation_as_quaternion_valid(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- conf = StubConfiguration(False, system, coordinates=np.ones((17, 3)))
- system.configuration = conf
-
- self.assertTupleEqual(
- (
- Quaternion([1.0, 0.0, 0.0, 0.0]),
- Vector(1.0, 1.0, 1.0),
- Vector(1.0, 1.0, 1.0),
- 0.0,
- ),
- self.protein.find_transformation_as_quaternion(conf),
- )
-
- def test_find_transformation_as_quaternion_entity_not_part_of_system(self):
- conf = StubConfiguration(False, None, coordinates=np.ones((17, 3)))
- with self.assertRaises(ce.ChemicalEntityError):
- self.protein.find_transformation_as_quaternion(conf)
-
- def test_find_transformation_as_quaternion_periodic_configuration(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- conf = StubConfiguration(True, system)
- system.configuration = conf
-
- with self.assertRaises(ValueError) as e:
- self.protein.find_transformation_as_quaternion(conf)
- self.assertEqual(
- "superposition in periodic configurations is not defined, therefore the configuration of the "
- "root chemical system of this chemical entity must not be periodic.",
- str(e.exception),
- )
-
- def test_find_transformation_as_quaternion_conf1_incompatible(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- conf = StubConfiguration(False, system)
- system.configuration = conf
-
- conf.chemical_system = ce.ChemicalSystem("different system")
- with self.assertRaises(ValueError) as e:
- self.protein.find_transformation_as_quaternion(conf)
- self.assertEqual(
- "conformations come from different chemical systems: the root chemical system of this "
- 'chemical entity is "name" but the chemical system registered with the provided configuration '
- '(conf1) is "different system".',
- str(e.exception)[:208],
- )
-
- def test_find_transformation_as_quaternion_conf2_incompatible(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- conf = StubConfiguration(False, system)
- system.configuration = conf
-
- with self.assertRaises(ValueError) as e:
- self.protein.find_transformation_as_quaternion(
- conf, StubConfiguration(False, ce.ChemicalSystem("diff"))
- )
- self.assertEqual(
- "conformations come from different chemical systems: the root chemical system of this "
- 'chemical entity is "name" but the chemical system registered with the provided configuration '
- '(conf2) is "diff".',
- str(e.exception)[:196],
- )
-
- def test_find_transformation(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- conf = StubConfiguration(False, system, coordinates=np.ones((17, 3)))
- system.configuration = conf
-
- transformation, rms = self.protein.find_transformation(conf)
- self.assertTrue(isinstance(transformation, RotationTranslation))
- self.assertEqual(
- Tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], False),
- transformation.tensor,
- )
- self.assertEqual(Vector([0.0, 0.0, 0.0]), transformation.vector)
- self.assertEqual(0, rms)
-
- def test_center_and_moment_of_inertia(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- group = ce.AtomGroup([self.r1["HT3"], self.r1["HA2"], self.r2["O"]])
-
- configuration = {"coordinates": np.ones((50, 3))}
- self.assertEqual(
- (
- Vector(1.0, 1.0, 1.0),
- Tensor([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]),
- ),
- self.protein.center_and_moment_of_inertia(configuration),
- )
- self.assertEqual(
- (
- Vector(1.0, 1.0, 1.0),
- Tensor([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]),
- ),
- self.protein.centre_and_moment_of_inertia(configuration),
- )
- self.assertEqual(
- (
- Vector(1.0, 1.0, 1.0),
- Tensor([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]),
- ),
- group.center_and_moment_of_inertia(configuration),
- )
-
- def test_normalizing_transformation_valid(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- configuration = {"coordinates": np.ones((50, 3))}
-
- no_representation = self.protein.normalizing_transformation(configuration, None)
- ir = self.protein.normalizing_transformation(configuration, "Ir")
- iir = self.protein.normalizing_transformation(configuration, "IIr")
- iiir = self.protein.normalizing_transformation(configuration, "IIIr")
- il = self.protein.normalizing_transformation(configuration, "Il")
- iil = self.protein.normalizing_transformation(configuration, "IIl")
- iiil = self.protein.normalizing_transformation(configuration, "IIIl")
-
- tensors = [
- [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
- [0.0, 0.0, 1.0],
- [0, 1, 0],
- [1, 0, 0],
- [0, 0, 1],
- [1, 0, 0],
- [0, 1, 0],
- ]
- vectors = [
- Vector([-1.0, -1.0, -1.0]),
- Tensor(-1),
- Tensor(-1),
- Tensor(-1),
- Tensor(-1),
- Tensor(-1),
- Tensor(-1),
- ]
- self.assertTrue(isinstance(no_representation, RotationTranslation))
- for expected_tensor, expected_vector, result in zip(
- tensors, vectors, [no_representation, ir, iir, iiir, il, iil, iiil]
- ):
- self.assertEqual(Tensor(expected_tensor), result.tensor)
- self.assertEqual(expected_vector, result.vector)
-
- def test_normalizing_transformation_invalid_representation(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- configuration = {"coordinates": np.ones((50, 3))}
- with self.assertRaises(ValueError):
- self.protein.normalizing_transformation(configuration, "INVALID INPUT")
-
- def test_root_chemical_system(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- atom = ce.Atom()
-
- self.assertEqual(system, self.protein.root_chemical_system)
- self.assertEqual(system, self.r1["O"].root_chemical_system)
- self.assertEqual(None, atom.root_chemical_system)
-
- def test_top_level_chemical_entity(self):
- system = ce.ChemicalSystem("name")
- system.add_chemical_entity(self.protein)
- atom = ce.Atom()
- self.assertEqual(self.protein, self.protein.top_level_chemical_entity)
- self.assertEqual(self.protein, self.r1["O"].top_level_chemical_entity)
- self.assertEqual(atom, atom.top_level_chemical_entity)
-
-
-class StubConfiguration(dict):
- def __init__(self, is_periodic: bool, chemical_system, **kwargs):
- self.is_periodic = is_periodic
- self.chemical_system = chemical_system
- super().__init__(**kwargs)
diff --git a/MDANSE/Tests/UnitTests/test_configuration.py b/MDANSE/Tests/UnitTests/test_configuration.py
index 945bb3de5c..bd39310c4d 100644
--- a/MDANSE/Tests/UnitTests/test_configuration.py
+++ b/MDANSE/Tests/UnitTests/test_configuration.py
@@ -17,7 +17,7 @@
import numpy as np
-from MDANSE.Chemistry.ChemicalEntity import Atom, AtomCluster, ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.Mathematics.Transformation import Translation, Rotation
from MDANSE.Mathematics.LinearAlgebra import Vector
from MDANSE.MolecularDynamics.Configuration import (
@@ -40,11 +40,12 @@ def setUp(self):
self._nAtoms = 4
atoms = []
+ cluster = []
for i in range(self._nAtoms):
- atoms.append(Atom(symbol="H"))
- ac = AtomCluster("", atoms)
-
- self.chem_system.add_chemical_entity(ac)
+ atoms.append("H")
+ cluster.append(i)
+ self.chem_system.initialise_atoms(atoms)
+ self.chem_system.add_clusters([cluster])
def test_dunder_init_valid(self):
coords = np.random.uniform(0, 1, (self._nAtoms, 3))
@@ -182,11 +183,12 @@ def setUp(self):
self._nAtoms = 4
atoms = []
+ cluster = []
for i in range(self._nAtoms):
- atoms.append(Atom(symbol="H"))
- ac = AtomCluster("", atoms)
-
- self.chem_system.add_chemical_entity(ac)
+ atoms.append("H")
+ cluster.append(i)
+ self.chem_system.initialise_atoms(atoms)
+ self.chem_system.add_clusters([cluster])
self.coords = np.random.uniform(0, 1, (self._nAtoms, 3))
self.unit_cell = UnitCell(np.random.uniform(0, 1, (3, 3)))
@@ -229,11 +231,12 @@ def setUp(self):
self._nAtoms = 4
atoms = []
+ cluster = []
for i in range(self._nAtoms):
- atoms.append(Atom(symbol="H"))
- ac = AtomCluster("", atoms)
-
- self.chem_system.add_chemical_entity(ac)
+ atoms.append("H")
+ cluster.append(i)
+ self.chem_system.initialise_atoms(atoms)
+ self.chem_system.add_clusters([cluster])
def test_fold_coordinates(self):
coords = np.array(
@@ -320,16 +323,6 @@ def test_to_real_configuration(self):
)
self.assertEqual(unit_cell, real._unit_cell)
- def test_atoms_in_shell(self):
- unit_cell = UnitCell(np.array([[10, 0, 0], [0, 10, 0], [0, 0, 10]]))
- coords = np.array(
- ([0.1, 0.1, 0.1], [0.2, 0.1, 0.1], [0.5, 0.1, 0.1], [0.9, 0.1, 0.1])
- )
- conf = PeriodicBoxConfiguration(self.chem_system, coords, unit_cell)
- atoms = conf.atoms_in_shell(0, 0.0, 0.3)
-
- self.assertEqual([1, 3], [at.index for at in atoms])
-
def test_contiguous_configuration(self):
unit_cell = UnitCell(np.array([[2, 1, 0], [-3, 2, 0], [2, 1, -4]]))
coords = [[0.1, 0.1, 0.1], [0.3, 0.2, 0.4], [-1.3, -1.1, -1.3], [1.9, 1.5, 1.9]]
@@ -343,76 +336,15 @@ def test_contiguous_configuration(self):
np.allclose(
[
[0.1, 0.1, 0.1],
- [0.8, 1.1, -1.6],
- [-0.9, -0.8, 1.2],
- [-1.9, 0.8, 0.4],
+ [0.3, 0.2, 0.4],
+ [-0.3, -0.1, -0.3],
+ [-0.1, 0.5, -0.1],
],
contiguous_conf["coordinates"],
),
f'\nactual = {contiguous_conf["coordinates"]}',
)
- def test_contiguous_offsets_valid_no_input(self):
- self.chem_system.add_chemical_entity(AtomCluster("2", [Atom(), Atom()]))
-
- unit_cell = UnitCell(np.array([[2, 1, 0], [-3, 2, 0], [2, 1, -4]]))
- coords = [
- [0.1, 0.1, 0.1],
- [0.3, 0.2, 0.4],
- [-1.3, -1.1, -1.3],
- [1.9, 1.5, 1.9],
- [1, 1.5, 1],
- [0.1, 1.5, 1.1],
- ]
- conf = PeriodicBoxConfiguration(self.chem_system, coords, unit_cell)
- offsets = conf.contiguous_offsets()
-
- self.assertTrue(
- np.allclose(
- [
- [0, 0, 0],
- [0, 0, 0],
- [1, 1, 1],
- [-2, -1, -2],
- [0, 0, 0],
- [1, 0, 0],
- ],
- offsets,
- ),
- f"\nactual = {offsets}",
- )
-
- def test_contiguous_offsets_valid_specified_list(self):
- self.chem_system.add_chemical_entity(AtomCluster("2", [Atom(), Atom()]))
-
- unit_cell = UnitCell(np.array([[2, 1, 0], [-3, 2, 0], [2, 1, -4]]))
- coords = [
- [0.1, 0.1, 0.1],
- [0.3, 0.2, 0.4],
- [-1.3, -1.1, -1.3],
- [1.9, 1.5, 1.9],
- [1, 1.5, 1],
- [0.1, 1.5, 1.1],
- ]
- conf = PeriodicBoxConfiguration(self.chem_system, coords, unit_cell)
- offsets = conf.contiguous_offsets([self.chem_system.chemical_entities[0]])
-
- self.assertTrue(
- np.allclose(
- [[0, 0, 0], [0, 0, 0], [1, 1, 1], [-2, -1, -2]],
- offsets,
- ),
- f"\nactual = {offsets}",
- )
-
- def test_contiguous_offsets_invalid(self):
- unit_cell = UnitCell(np.array([[2, 1, 0], [-3, 2, 0], [2, 1, -4]]))
- coords = [[0.1, 0.1, 0.1], [0.3, 0.2, 0.4], [-1.3, -1.1, -1.3], [1.9, 1.5, 1.9]]
- conf = PeriodicBoxConfiguration(self.chem_system, coords, unit_cell)
-
- with self.assertRaises(ConfigurationError):
- conf.contiguous_offsets([Atom(parent=ChemicalSystem())])
-
class TestPeriodicRealConfiguration(unittest.TestCase):
def setUp(self):
@@ -420,11 +352,12 @@ def setUp(self):
self._nAtoms = 4
atoms = []
+ cluster = []
for i in range(self._nAtoms):
- atoms.append(Atom(symbol="H"))
- ac = AtomCluster("", atoms)
-
- self.chem_system.add_chemical_entity(ac)
+ atoms.append("H")
+ cluster.append(i)
+ self.chem_system.initialise_atoms(atoms)
+ self.chem_system.add_clusters([cluster])
def test_fold_coordinates(self):
coords = np.array(
@@ -516,14 +449,6 @@ def test_to_real_coordinates(self):
real = conf.to_real_coordinates()
self.assertTrue(np.allclose(coords, real), f"\nactual = {real}")
- def test_atoms_in_shell(self):
- coords = np.array([[1, 1, 1], [2, 1, 1], [5, 1, 1], [9, 1, 1]])
- unit_cell = UnitCell(np.array([[10, 0, 0], [0, 10, 0], [0, 0, 10]]))
- conf = PeriodicRealConfiguration(self.chem_system, coords, unit_cell)
- atoms = conf.atoms_in_shell(0, 0, 3)
-
- self.assertEqual([1, 3], [at.index for at in atoms])
-
def test_contiguous_configuration(self):
coords = np.array(
[
@@ -556,7 +481,30 @@ def test_contiguous_configuration(self):
)
self.assertEqual(unit_cell, result._unit_cell)
- def test_continuous_configuration(self):
+ def test_contiguous_configuration_does_not_move_atoms_to_edges(self):
+ unit_cell = UnitCell(
+ np.array(
+ [
+ [4.15821342e00, 0.00000000e00, 0.00000000e00],
+ [2.54617138e-16, 4.15821342e00, 0.00000000e00],
+ [2.85252415e-16, 2.85252415e-16, 4.65852547e00],
+ ]
+ )
+ )
+ coords = np.array(
+ [
+ [-1.8630077362060546, -0.4748522758483886, -0.5351669311523437],
+ [-1.9116626739501952, -0.4739928722381591, -0.6350426197052002],
+ [-1.7785566329956053, -0.5469871520996094, -0.5323768615722656],
+ [-1.8123033523559569, -0.3780877590179443, -0.5149454593658447],
+ ]
+ )
+ conf = PeriodicRealConfiguration(self.chem_system, coords.copy(), unit_cell)
+ result = conf.contiguous_configuration()
+ new_coords = result.coordinates
+ assert np.allclose(coords, new_coords)
+
+ def test_continuous_configuration_without_bonds(self):
coords = np.array(
[
[14.0, 3.0, 6.0],
@@ -588,82 +536,38 @@ def test_continuous_configuration(self):
)
self.assertEqual(unit_cell, result._unit_cell)
- def test_contiguous_offsets_valid_no_input(self):
- coords = np.array(
- [
- [14.0, 3.0, 6.0],
- [32.0, 9.0, 15.0],
- [50.0, 15.0, 24.0],
- [68.0, 21.0, 33.0],
- ]
- )
- unit_cell = UnitCell(
- np.array([[1.0, 2.0, 1.0], [2.0, -1.0, 1.0], [3.0, 1.0, 1.0]])
- )
- conf = PeriodicRealConfiguration(self.chem_system, coords, unit_cell)
-
- offsets = conf.contiguous_offsets()
- self.assertTrue(
- np.allclose(
- [
- [0.0, 0.0, 0.0],
- [-3.0, -3.0, -3.0],
- [-6.0, -6.0, -6.0],
- [-9.0, -9.0, -9.0],
- ],
- offsets,
- ),
- f"\nactual = {offsets}",
- )
-
- def test_contiguous_offsets_valid_specified_list(self):
- self.chem_system.add_chemical_entity(AtomCluster("2", [Atom(), Atom()]))
-
+ def test_continuous_configuration_with_bonds(self):
coords = np.array(
[
[14.0, 3.0, 6.0],
[32.0, 9.0, 15.0],
[50.0, 15.0, 24.0],
[68.0, 21.0, 33.0],
- [15.0, 15.0, 15.0],
- [10.0, 10.0, 10.0],
]
)
unit_cell = UnitCell(
np.array([[1.0, 2.0, 1.0], [2.0, -1.0, 1.0], [3.0, 1.0, 1.0]])
)
+ self.chem_system.add_bonds([(0, 1), (2, 3)])
conf = PeriodicRealConfiguration(self.chem_system, coords, unit_cell)
- offsets = conf.contiguous_offsets([self.chem_system.chemical_entities[0]])
+ result = conf.continuous_configuration()
+ self.assertTrue(isinstance(result, PeriodicRealConfiguration))
+ self.assertEqual(repr(self.chem_system), repr(result._chemical_system))
+ self.assertEqual(["coordinates"], list(result._variables.keys()))
self.assertTrue(
np.allclose(
[
- [0.0, 0.0, 0.0],
- [-3.0, -3.0, -3.0],
- [-6.0, -6.0, -6.0],
- [-9.0, -9.0, -9.0],
+ [14.0, 3.0, 6.0],
+ [14.0, 3.0, 6.0],
+ [50.0, 15.0, 24.0],
+ [50.0, 15.0, 24.0],
],
- offsets,
+ result["coordinates"],
),
- f"\nactual = {offsets}",
- )
-
- def test_contiguous_offsets_invalid(self):
- coords = np.array(
- [
- [14.0, 3.0, 6.0],
- [32.0, 9.0, 15.0],
- [50.0, 15.0, 24.0],
- [68.0, 21.0, 33.0],
- ]
- )
- unit_cell = UnitCell(
- np.array([[1.0, 2.0, 1.0], [2.0, -1.0, 1.0], [3.0, 1.0, 1.0]])
+ f'\nactual = {result["coordinates"]}',
)
- conf = PeriodicRealConfiguration(self.chem_system, coords, unit_cell)
-
- with self.assertRaises(ConfigurationError):
- conf.contiguous_offsets([Atom(parent=ChemicalSystem())])
+ self.assertEqual(unit_cell, result._unit_cell)
class TestRealConfiguration(unittest.TestCase):
@@ -672,11 +576,12 @@ def setUp(self):
self._nAtoms = 4
atoms = []
+ cluster = []
for i in range(self._nAtoms):
- atoms.append(Atom(symbol="H"))
- ac = AtomCluster("", atoms)
-
- self.chem_system.add_chemical_entity(ac)
+ atoms.append("H")
+ cluster.append(i)
+ self.chem_system.initialise_atoms(atoms)
+ self.chem_system.add_clusters([cluster])
def test_clone_valid_no_input(self):
coordinates = np.random.uniform(0, 1, (self._nAtoms, 3))
@@ -727,13 +632,6 @@ def test_to_real_coordinates(self):
self.assertTrue(np.allclose(coordinates, real), f"\nactual = {real}")
- def test_atoms_in_shell(self):
- coords = np.array([[1, 1, 1], [2, 1, 1], [5, 1, 1], [9, 1, 1]])
- conf = RealConfiguration(self.chem_system, coords)
- atoms = conf.atoms_in_shell(0, 0, 5)
-
- self.assertEqual([1, 2], [at.index for at in atoms])
-
def test_contiguous_configuration(self):
coords = np.random.uniform(0, 1, (self._nAtoms, 3))
conf = RealConfiguration(self.chem_system, coords)
@@ -745,26 +643,3 @@ def test_continuous_configuration(self):
conf = RealConfiguration(self.chem_system, coords)
self.assertEqual(conf, conf.continuous_configuration())
-
- def test_contiguous_offsets_valid_none(self):
- self.chem_system.add_chemical_entity(AtomCluster("", [Atom(), Atom()]))
- coords = np.random.uniform(0, 1, (self._nAtoms + 2, 3))
- conf = RealConfiguration(self.chem_system, coords)
-
- offsets = conf.contiguous_offsets()
- self.assertTrue(np.allclose(np.zeros((6, 3)), offsets), f"\nactual = {offsets}")
-
- def test_contiguous_offsets_valid_system_input(self):
- self.chem_system.add_chemical_entity(AtomCluster("", [Atom(), Atom()]))
- coords = np.random.uniform(0, 1, (self._nAtoms + 2, 3))
- conf = RealConfiguration(self.chem_system, coords)
-
- offsets = conf.contiguous_offsets(self.chem_system.chemical_entities[0])
- self.assertTrue(np.allclose(np.zeros((4, 3)), offsets), f"\nactual = {offsets}")
-
- def test_contiguous_offsets_invalid_system(self):
- coords = np.random.uniform(0, 1, (self._nAtoms, 3))
- conf = RealConfiguration(self.chem_system, coords)
-
- with self.assertRaises(ConfigurationError):
- conf.contiguous_offsets([Atom(parent=ChemicalSystem())])
diff --git a/MDANSE/Tests/UnitTests/test_converter.py b/MDANSE/Tests/UnitTests/test_converter.py
index 7baf3f27b6..06fc085b26 100644
--- a/MDANSE/Tests/UnitTests/test_converter.py
+++ b/MDANSE/Tests/UnitTests/test_converter.py
@@ -57,7 +57,10 @@ def test_lammps_mdt_conversion_file_exists_and_loads_up_successfully(compression
lammps = Converter.create("LAMMPS")
lammps.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -86,7 +89,10 @@ def test_lammps_mdt_conversion_unit_system(unit_system):
lammps = Converter.create("LAMMPS")
lammps.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -117,7 +123,10 @@ def test_lammps_mdt_conversion_trajectory_format(trajectory_file, trajectory_for
lammps = Converter.create("LAMMPS")
lammps.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -157,7 +166,10 @@ def test_vasp_mdt_conversion_file_exists_and_loads_up_successfully(compression):
vasp = Converter.create("VASP")
vasp.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -181,7 +193,10 @@ def test_discover_mdt_conversion_file_exists_and_loads_up_successfully(compressi
vasp = Converter.create("discover")
vasp.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -205,7 +220,10 @@ def test_cp2k_mdt_conversion_file_exists_and_loads_up_successfully(velocity):
vasp = Converter.create("cp2k")
vasp.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -230,7 +248,10 @@ def test_charmm_mdt_conversion_file_exists_and_loads_up_successfully(compression
vasp = Converter.create("charmm")
vasp.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -256,7 +277,10 @@ def test_ase_mdt_conversion_file_exists_and_loads_up_successfully(compression):
ase_conv = Converter.create("ase")
ase_conv.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -282,7 +306,10 @@ def test_improvedase_mdt_conversion_file_exists_and_loads_up_successfully(trajec
ase_conv = Converter.create("improvedase")
ase_conv.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -309,7 +336,10 @@ def test_improvedase_lammps_two_files():
ase_conv = Converter.create("improvedase")
ase_conv.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -335,7 +365,10 @@ def test_xyz_mdt_conversion_file_exists_and_loads_up_successfully(compression):
ase_conv = Converter.create("ase")
ase_conv.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -361,7 +394,10 @@ def test_dlp_mdt_conversion_file_exists_and_loads_up_successfully_with_dlp_versi
dl_poly = Converter.create("DL_POLY")
dl_poly.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -387,7 +423,10 @@ def test_dlp_mdt_conversion_file_exists_and_loads_up_successfully_with_dlp_versi
dl_poly = Converter.create("DL_POLY")
dl_poly.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -468,7 +507,10 @@ def test_castep_md_conversion_file_exists_and_loads_up_successfully(compression)
castep = Converter.create("CASTEP")
castep.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -493,7 +535,10 @@ def test_dftb_conversion_file_exists_and_loads_up_successfully(compression):
dftb = Converter.create("DFTB")
dftb.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -518,7 +563,10 @@ def test_forcite_conversion_file_exists_and_loads_up_successfully(compression):
forcite = Converter.create("Forcite")
forcite.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -542,7 +590,10 @@ def test_gromacs_conversion_file_exists_and_loads_up_successfully(compression):
gromacs = Converter.create("Gromacs")
gromacs.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
@@ -565,7 +616,10 @@ def test_mdanalysis_conversion_file_exists_and_loads_up_successfully(compression
mdanalysis = Converter.create("MDAnalysis")
mdanalysis.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
# remove offset files generated by mdanalysis
os.remove(os.path.join(file_wd, "Data", ".md.xtc_offsets.lock"))
@@ -592,7 +646,10 @@ def test_mdtraj_conversion_file_exists_and_loads_up_successfully(compression):
mdanalysis = Converter.create("MDTraj")
mdanalysis.run(parameters, status=True)
- HDFTrajectoryConfigurator("trajectory").configure(temp_name + ".mdt")
+ traj_conf = HDFTrajectoryConfigurator("trajectory")
+ traj_conf.configure(temp_name + ".mdt")
+ traj_conf.get_information()
+ traj_conf["hdf_trajectory"].close()
assert os.path.exists(temp_name + ".mdt")
assert os.path.isfile(temp_name + ".mdt")
diff --git a/MDANSE/Tests/UnitTests/test_databases.py b/MDANSE/Tests/UnitTests/test_databases.py
index f7c52de3d1..c508e255a6 100644
--- a/MDANSE/Tests/UnitTests/test_databases.py
+++ b/MDANSE/Tests/UnitTests/test_databases.py
@@ -20,16 +20,10 @@
from MDANSE.Chemistry import (
ATOMS_DATABASE,
- MOLECULES_DATABASE,
- RESIDUES_DATABASE,
- NUCLEOTIDES_DATABASE,
)
import MDANSE.Chemistry.Databases as Databases
from MDANSE.Chemistry.Databases import (
AtomsDatabaseError,
- MoleculesDatabaseError,
- ResiduesDatabaseError,
- NucleotidesDatabaseError,
)
@@ -335,360 +329,3 @@ def test_save(self):
dump.assert_called_with(
{"properties": self.properties, "atoms": self.data}, ANY
)
-
-
-class TestMoleculesDatabase(unittest.TestCase):
- def setUp(self):
- self.data = {
- "WAT": {
- "alternatives": ["H2O", "water", "TIP3"],
- "atoms": {
- "OW": {
- "symbol": "O",
- "alternatives": ["O", "OH2"],
- "groups": [],
- "bonds": ["HW1", "HW2"],
- },
- "HW2": {
- "symbol": "H",
- "alternatives": ["H2"],
- "groups": [],
- "bonds": ["OW"],
- },
- },
- }
- }
- self.overwrite_database()
-
- @classmethod
- def tearDownClass(cls):
- MOLECULES_DATABASE._load()
-
- def overwrite_database(self):
- MOLECULES_DATABASE._data = self.data
-
- def test__load_default_database(self):
- with patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m:
- MOLECULES_DATABASE._load("INVALID.json", "molecules.json")
- m.assert_called_with("molecules.json", "r")
- self.assertDictEqual(self.data, MOLECULES_DATABASE._data)
-
- def test__load_user_database(self):
- with (
- patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m,
- patch("os.path.exists", spec=True),
- ):
- MOLECULES_DATABASE._load("user.json", "default.json")
- m.assert_called_with("user.json", "r")
- self.assertDictEqual(self.data, MOLECULES_DATABASE._data)
-
- def test___contains__(self):
- self.assertFalse("fhsdjfsd" in MOLECULES_DATABASE)
- self.assertTrue("WAT" in MOLECULES_DATABASE)
- self.assertTrue("H2O" in MOLECULES_DATABASE)
-
- def test___getitem__(self):
- self.assertDictEqual(self.data["WAT"], MOLECULES_DATABASE["WAT"])
- with self.assertRaises(MoleculesDatabaseError):
- a = MOLECULES_DATABASE["INVALID"]
- # TODO: Look into the not implemented description of __getitem__
-
- def test___iter__(self):
- generator = iter(MOLECULES_DATABASE)
- self.assertDictEqual(self.data["WAT"], next(generator))
-
- def test_add_molecule_existing_molecule(self):
- with self.assertRaises(MoleculesDatabaseError):
- MOLECULES_DATABASE.add_molecule("WAT")
-
- def test_add_molecule_valid(self):
- with (
- patch("json.dump") as m,
- patch("MDANSE.Chemistry.Databases.MoleculesDatabase.save") as n,
- ):
- MOLECULES_DATABASE.add_molecule("new_molecule")
- self.assertDictEqual(
- {"alternatives": [], "atoms": {}}, MOLECULES_DATABASE["new_molecule"]
- )
- assert not m.called
- assert not n.called
-
- def test_items(self):
- for (expected_atom, expected_data), (atom, data) in zip(
- self.data.items(), MOLECULES_DATABASE.items()
- ):
- self.assertEqual(expected_atom, atom)
- self.assertDictEqual(expected_data, data)
-
- def test_molecules(self):
- self.assertEqual(["WAT"], MOLECULES_DATABASE.molecules)
-
- def test_n_molecules(self):
- self.assertEqual(1, MOLECULES_DATABASE.n_molecules)
-
- def test__reset(self):
- MOLECULES_DATABASE._reset()
- self.assertDictEqual({}, MOLECULES_DATABASE._data)
-
- def test_save(self):
- with (
- patch("builtins.open", new_callable=mock_open) as op,
- patch("json.dump") as dump,
- ):
- MOLECULES_DATABASE.save()
- op.assert_called_with(MOLECULES_DATABASE._USER_DATABASE, "w")
- dump.assert_called_with(self.data, ANY)
-
-
-class TestNucleotidesDatabase(unittest.TestCase):
- def setUp(self):
- self.data = {
- "5T1": {
- "is_3ter_terminus": False,
- "atoms": {
- "HO5'": {
- "replaces": ["OP1", "OP2", "P"],
- "o5prime_connected": True,
- "groups": [],
- "bonds": ["O5'"],
- "symbol": "H",
- "alternatives": [],
- }
- },
- "alternatives": ["5-terminus", "5T"],
- "is_5ter_terminus": True,
- }
- }
- NUCLEOTIDES_DATABASE._data = self.data
- NUCLEOTIDES_DATABASE._residue_map = {
- "5T1": "5T1",
- "5-terminus": "5T1",
- "5T": "5T1",
- }
-
- @classmethod
- def tearDownClass(cls):
- NUCLEOTIDES_DATABASE._load()
-
- def test__load_default_database(self):
- with patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m:
- NUCLEOTIDES_DATABASE._load("INVALID.json", "molecules.json")
- m.assert_called_with("molecules.json", "r")
- self.assertDictEqual(self.data, NUCLEOTIDES_DATABASE._data)
- self.assertDictEqual(
- {"5T1": "5T1", "5-terminus": "5T1", "5T": "5T1"},
- NUCLEOTIDES_DATABASE._residue_map,
- )
-
- def test__load_user_database(self):
- with (
- patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m,
- patch("os.path.exists", spec=True),
- ):
- NUCLEOTIDES_DATABASE._load("user.json", "default.json")
- m.assert_called_with("user.json", "r")
- self.assertDictEqual(self.data, NUCLEOTIDES_DATABASE._data)
- self.assertDictEqual(
- {"5T1": "5T1", "5-terminus": "5T1", "5T": "5T1"},
- NUCLEOTIDES_DATABASE._residue_map,
- )
-
- def test___contains__(self):
- self.assertFalse("fhsdjfsd" in NUCLEOTIDES_DATABASE)
- self.assertTrue("5T1" in NUCLEOTIDES_DATABASE)
- self.assertTrue("5T" in NUCLEOTIDES_DATABASE)
-
- def test___getitem__(self):
- self.assertDictEqual(self.data["5T1"], NUCLEOTIDES_DATABASE["5T1"])
- self.assertDictEqual(self.data["5T1"], NUCLEOTIDES_DATABASE["5T"])
- with self.assertRaises(NucleotidesDatabaseError):
- a = NUCLEOTIDES_DATABASE["INVALID"]
- # TODO: Look into the not implemented description of __getitem__
-
- def test___iter__(self):
- generator = iter(NUCLEOTIDES_DATABASE)
- self.assertDictEqual(self.data["5T1"], next(generator))
-
- def test_add_nucleotide_existing_nucleotide(self):
- with self.assertRaises(NucleotidesDatabaseError):
- NUCLEOTIDES_DATABASE.add_nucleotide("5T")
-
- def test_add_nucleotide_valid(self):
- with (
- patch("json.dump") as m,
- patch("MDANSE.Chemistry.Databases.NucleotidesDatabase.save") as n,
- ):
- NUCLEOTIDES_DATABASE.add_nucleotide("new_nucleotide", True, True)
- self.assertDictEqual(
- {
- "alternatives": [],
- "atoms": {},
- "is_5ter_terminus": True,
- "is_3ter_terminus": True,
- },
- NUCLEOTIDES_DATABASE["new_nucleotide"],
- )
- assert not m.called
- assert not n.called
-
- def test_items(self):
- for (expected_atom, expected_data), (atom, data) in zip(
- self.data.items(), NUCLEOTIDES_DATABASE.items()
- ):
- self.assertEqual(expected_atom, atom)
- self.assertDictEqual(expected_data, data)
-
- def test_nucleotides(self):
- self.assertEqual(["5T1"], NUCLEOTIDES_DATABASE.nucleotides)
-
- def test_n_nucleotides(self):
- self.assertEqual(1, NUCLEOTIDES_DATABASE.n_nucleotides)
-
- def test__reset(self):
- NUCLEOTIDES_DATABASE._reset()
- self.assertDictEqual({}, NUCLEOTIDES_DATABASE._data)
-
- def test_save(self):
- with (
- patch("builtins.open", new_callable=mock_open) as op,
- patch("json.dump") as dump,
- ):
- NUCLEOTIDES_DATABASE.save()
- op.assert_called_with(NUCLEOTIDES_DATABASE._USER_DATABASE, "w")
- dump.assert_called_with(self.data, ANY)
-
-
-class TestResiduesDatabase(unittest.TestCase):
- def setUp(self):
- self.data = {
- "GLY": {
- "is_n_terminus": False,
- "atoms": {
- "C": {
- "symbol": "C",
- "alternatives": [],
- "groups": ["backbone", "peptide"],
- "bonds": ["CA", "O", "+R"],
- },
- "H": {
- "symbol": "H",
- "alternatives": ["HN"],
- "groups": ["backbone", "peptide"],
- "bonds": ["N"],
- },
- "CA": {
- "symbol": "C",
- "alternatives": [],
- "groups": ["backbone"],
- "bonds": ["C", "HA2", "HA3", "N"],
- },
- },
- "alternatives": ["glycine", "G"],
- "is_c_terminus": False,
- }
- }
- RESIDUES_DATABASE._data = self.data
- RESIDUES_DATABASE._residue_map = {"GLY": "GLY", "glycine": "GLY", "G": "GLY"}
-
- @classmethod
- def tearDownClass(cls):
- RESIDUES_DATABASE._load()
-
- def test__load_default_database(self):
- with patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m:
- RESIDUES_DATABASE._load("INVALID.json", "residues.json")
- m.assert_called_with("residues.json", "r")
- self.assertDictEqual(self.data, RESIDUES_DATABASE._data)
- self.assertDictEqual(
- {"GLY": "GLY", "glycine": "GLY", "G": "GLY"},
- RESIDUES_DATABASE._residue_map,
- )
-
- def test__load_user_database(self):
- with (
- patch(
- "builtins.open", new_callable=mock_open, read_data=json.dumps(self.data)
- ) as m,
- patch("os.path.exists", spec=True),
- ):
- RESIDUES_DATABASE._load("user.json", "default.json")
- m.assert_called_with("user.json", "r")
- self.assertDictEqual(self.data, RESIDUES_DATABASE._data)
- self.assertDictEqual(
- {"GLY": "GLY", "glycine": "GLY", "G": "GLY"},
- RESIDUES_DATABASE._residue_map,
- )
-
- def test___contains__(self):
- self.assertFalse("fhsdjfsd" in RESIDUES_DATABASE)
- self.assertTrue("GLY" in RESIDUES_DATABASE)
- self.assertTrue("G" in RESIDUES_DATABASE)
-
- def test___getitem__(self):
- self.assertDictEqual(self.data["GLY"], RESIDUES_DATABASE["GLY"])
- self.assertDictEqual(self.data["GLY"], RESIDUES_DATABASE["G"])
- with self.assertRaises(ResiduesDatabaseError):
- a = RESIDUES_DATABASE["INVALID"]
- # TODO: Look into the not implemented description of __getitem__
-
- def test___iter__(self):
- generator = iter(RESIDUES_DATABASE)
- self.assertDictEqual(self.data["GLY"], next(generator))
-
- def test_add_residue_existing_nucleotide(self):
- with self.assertRaises(ResiduesDatabaseError):
- RESIDUES_DATABASE.add_residue("G")
-
- def test_add_residue_valid(self):
- with (
- patch("json.dump") as m,
- patch("MDANSE.Chemistry.Databases.ResiduesDatabase.save") as n,
- ):
- RESIDUES_DATABASE.add_residue("new_residues", True, True)
- self.assertDictEqual(
- {
- "alternatives": [],
- "atoms": {},
- "is_c_terminus": True,
- "is_n_terminus": True,
- },
- RESIDUES_DATABASE["new_residues"],
- )
- assert not m.called
- assert not n.called
-
- def test_items(self):
- for (expected_atom, expected_data), (atom, data) in zip(
- self.data.items(), RESIDUES_DATABASE.items()
- ):
- self.assertEqual(expected_atom, atom)
- self.assertDictEqual(expected_data, data)
-
- def test_residues(self):
- self.assertEqual(["GLY"], RESIDUES_DATABASE.residues)
-
- def test_n_residues(self):
- self.assertEqual(1, RESIDUES_DATABASE.n_residues)
-
- def test__reset(self):
- RESIDUES_DATABASE._reset()
- self.assertDictEqual({}, RESIDUES_DATABASE._data)
-
- def test_save(self):
- with (
- patch("builtins.open", new_callable=mock_open) as op,
- patch("json.dump") as dump,
- ):
- RESIDUES_DATABASE.save()
- op.assert_called_with(RESIDUES_DATABASE._USER_DATABASE, "w")
- dump.assert_called_with(self.data, ANY)
diff --git a/MDANSE/Tests/UnitTests/test_ijob.py b/MDANSE/Tests/UnitTests/test_ijob.py
index 598ecfaf3a..d7fb081a99 100644
--- a/MDANSE/Tests/UnitTests/test_ijob.py
+++ b/MDANSE/Tests/UnitTests/test_ijob.py
@@ -27,7 +27,6 @@
"McStasVirtualInstrument",
"MeanSquareDisplacement",
"MolecularTrace",
- "MoleculeFinder",
"NeutronDynamicTotalStructureFactor",
"OrderParameter",
"PositionAutoCorrelationFunction",
diff --git a/MDANSE/Tests/UnitTests/test_mock_trajectory.py b/MDANSE/Tests/UnitTests/test_mock_trajectory.py
index b6263d3353..82e8e2aa5c 100644
--- a/MDANSE/Tests/UnitTests/test_mock_trajectory.py
+++ b/MDANSE/Tests/UnitTests/test_mock_trajectory.py
@@ -14,7 +14,6 @@
# along with this program. If not, see .
#
import os
-import tempfile
import pytest
import numpy as np
@@ -72,7 +71,7 @@ def test_com_trajectory(static_trajectory):
"""Centre of Mass (COM) trajectory should be identical
to the static trajectory, since the atoms never moved"""
com_trajectory = static_trajectory.read_com_trajectory(
- static_trajectory._chemicalSystem.atoms, 0, 10, 1
+ list(range(static_trajectory._num_atoms_in_box)), 0, 10, 1
)
conf_static = static_trajectory[3]
conf_com = com_trajectory[3]
diff --git a/MDANSE/Tests/UnitTests/test_pdb_reader.py b/MDANSE/Tests/UnitTests/test_pdb_reader.py
index 14756c6cd8..6ba3bd1659 100644
--- a/MDANSE/Tests/UnitTests/test_pdb_reader.py
+++ b/MDANSE/Tests/UnitTests/test_pdb_reader.py
@@ -15,8 +15,7 @@
#
import os
import unittest
-import numpy
-from MDANSE.IO.PDBReader import PDBReader
+from MDANSE.IO.MinimalPDBReader import MinimalPDBReader as PDBReader
pbd_2vb1 = os.path.join(os.path.dirname(os.path.realpath(__file__)), "Data", "2vb1.pdb")
@@ -33,21 +32,13 @@ def test_reader(self):
reader = PDBReader(pbd_2vb1)
- chemicalSystem = reader.build_chemical_system()
+ chemical_system = reader._chemical_system
- atomList = chemicalSystem.atom_list
+ atomList = chemical_system.atom_list
- self.assertEqual(atomList[4].symbol, "C")
- self.assertEqual(atomList[7].name, "HB2")
- self.assertEqual(atomList[10].full_name, "...LYS1.HG2")
- self.assertEqual(atomList[28].parent.name, "VAL2")
-
- conf = chemicalSystem.configuration
-
- self.assertAlmostEqual(conf.variables["coordinates"][0, 0], 4.6382)
- self.assertAlmostEqual(conf.variables["coordinates"][0, 1], 3.0423)
- self.assertAlmostEqual(conf.variables["coordinates"][0, 2], 2.6918)
-
- self.assertAlmostEqual(conf.variables["coordinates"][-1, 0], 2.4937)
- self.assertAlmostEqual(conf.variables["coordinates"][-1, 1], 3.9669)
- self.assertAlmostEqual(conf.variables["coordinates"][-1, 2], -0.5209)
+ self.assertEqual(atomList[4], "C")
+ print(chemical_system._labels.keys())
+ self.assertTrue(10 in chemical_system._labels["LYS"])
+ self.assertEqual(chemical_system.name_list[7], "HB2")
+ # self.assertEqual(atomList[10].full_name, "...LYS1.HG2")
+ # self.assertEqual(atomList[28].parent.name, "VAL2")
diff --git a/MDANSE/Tests/UnitTests/test_trajectory.py b/MDANSE/Tests/UnitTests/test_trajectory.py
index 5272969968..b5025e56e9 100644
--- a/MDANSE/Tests/UnitTests/test_trajectory.py
+++ b/MDANSE/Tests/UnitTests/test_trajectory.py
@@ -16,7 +16,7 @@
import tempfile
import unittest
import numpy as np
-from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import PeriodicRealConfiguration
from MDANSE.MolecularDynamics.Trajectory import Trajectory, TrajectoryWriter
from MDANSE.MolecularDynamics.UnitCell import UnitCell
@@ -26,15 +26,13 @@ class TestTrajectory(unittest.TestCase):
""" """
def setUp(self):
- self._chemicalSystem = ChemicalSystem()
+ self._chemical_system = ChemicalSystem()
self._nAtoms = 4
-
- for i in range(self._nAtoms):
- self._chemicalSystem.add_chemical_entity(Atom(symbol="H"))
+ self._chemical_system.initialise_atoms(self._nAtoms * ["H"])
def test_write_trajectory(self):
tf = tempfile.NamedTemporaryFile().name
- tw = TrajectoryWriter(tf, self._chemicalSystem, 10)
+ tw = TrajectoryWriter(tf, self._chemical_system, 10)
allCoordinates = []
allUnitCells = []
@@ -44,10 +42,9 @@ def test_write_trajectory(self):
allUnitCells.append(np.random.uniform(0, 10, (3, 3)))
allCoordinates.append(np.random.uniform(0, 10, (self._nAtoms, 3)))
conf = PeriodicRealConfiguration(
- self._chemicalSystem, allCoordinates[-1], UnitCell(allUnitCells[-1])
+ self._chemical_system, allCoordinates[-1], UnitCell(allUnitCells[-1])
)
- tw.chemical_system.configuration = conf
- tw.dump_configuration(i)
+ tw.dump_configuration(conf, i)
tw.close()
@@ -66,7 +63,7 @@ def test_write_trajectory(self):
def test_write_trajectory_with_velocities(self):
tf = tempfile.NamedTemporaryFile().name
- tw = TrajectoryWriter(tf, self._chemicalSystem, 10)
+ tw = TrajectoryWriter(tf, self._chemical_system, 10)
allCoordinates = []
allUnitCells = []
@@ -78,11 +75,10 @@ def test_write_trajectory_with_velocities(self):
allCoordinates.append(np.random.uniform(0, 10, (self._nAtoms, 3)))
allVelocities.append(np.random.uniform(0, 10, (self._nAtoms, 3)))
conf = PeriodicRealConfiguration(
- self._chemicalSystem, allCoordinates[-1], UnitCell(allUnitCells[-1])
+ self._chemical_system, allCoordinates[-1], UnitCell(allUnitCells[-1])
)
conf.variables["velocities"] = allVelocities[-1]
- self._chemicalSystem.configuration = conf
- tw.dump_configuration(i)
+ tw.dump_configuration(conf, i)
tw.close()
@@ -104,7 +100,7 @@ def test_write_trajectory_with_velocities(self):
def test_write_trajectory_with_gradients(self):
tf = tempfile.NamedTemporaryFile().name
- tw = TrajectoryWriter(tf, self._chemicalSystem, 10)
+ tw = TrajectoryWriter(tf, self._chemical_system, 10)
allCoordinates = []
allUnitCells = []
@@ -118,12 +114,11 @@ def test_write_trajectory_with_gradients(self):
allVelocities.append(np.random.uniform(0, 10, (self._nAtoms, 3)))
allGradients.append(np.random.uniform(0, 10, (self._nAtoms, 3)))
conf = PeriodicRealConfiguration(
- self._chemicalSystem, allCoordinates[-1], UnitCell(allUnitCells[-1])
+ self._chemical_system, allCoordinates[-1], UnitCell(allUnitCells[-1])
)
conf.variables["velocities"] = allVelocities[-1]
conf.variables["gradients"] = allGradients[-1]
- self._chemicalSystem.configuration = conf
- tw.dump_configuration(i)
+ tw.dump_configuration(conf, i)
tw.close()
@@ -148,7 +143,7 @@ def test_write_trajectory_with_gradients(self):
def test_read_com_trajectory(self):
tf = tempfile.NamedTemporaryFile().name
- tw = TrajectoryWriter(tf, self._chemicalSystem, 1)
+ tw = TrajectoryWriter(tf, self._chemical_system, 1)
allCoordinates = []
allUnitCells = []
@@ -160,14 +155,16 @@ def test_read_com_trajectory(self):
[[0.0, 0.0, 0.0], [8.0, 8.0, 8.0], [4.0, 4.0, 4.0], [2.0, 2.0, 2.0]]
)
conf = PeriodicRealConfiguration(
- self._chemicalSystem, allCoordinates[-1], UnitCell(allUnitCells[-1])
+ self._chemical_system, allCoordinates[-1], UnitCell(allUnitCells[-1])
)
- self._chemicalSystem.configuration = conf
- tw.dump_configuration(i)
+ tw.dump_configuration(conf, i)
tw.close()
t = Trajectory(tf)
- com_trajectory = t.read_com_trajectory(self._chemicalSystem.atoms, 0, 1, 1)
+ com_trajectory = t.read_com_trajectory(
+ list(range(self._chemical_system.total_number_of_atoms)), 0, 1, 1
+ )
+ print(com_trajectory)
self.assertTrue(np.allclose(com_trajectory, [[3.5, 3.5, 3.5]], rtol=1.0e-6))
t.close()
diff --git a/MDANSE/Tests/UnitTests/test_trajectory_utils.py b/MDANSE/Tests/UnitTests/test_trajectory_utils.py
deleted file mode 100644
index ca24bcc0b8..0000000000
--- a/MDANSE/Tests/UnitTests/test_trajectory_utils.py
+++ /dev/null
@@ -1,199 +0,0 @@
-import unittest
-
-from MDANSE.Chemistry.ChemicalEntity import Molecule, Protein, ChemicalSystem
-from MDANSE.MolecularDynamics.Configuration import RealConfiguration
-from MDANSE.MolecularDynamics.TrajectoryUtils import *
-
-
-class TestTrajectoryUtils(unittest.TestCase):
- def test_atom_index_to_molecule_index(self):
- m1 = Molecule("WAT", "w1")
- m2 = Molecule("WAT", "w2")
- cs = ChemicalSystem()
- cs.add_chemical_entity(m1)
- cs.add_chemical_entity(m2)
-
- result = atom_index_to_molecule_index(cs)
- self.assertDictEqual({0: 0, 1: 0, 2: 0, 3: 1, 4: 1, 5: 1}, result)
-
- def test_brute_formula(self):
- m = Molecule("WAT", "w1")
- self.assertEqual("H2_O1", brute_formula(m))
- self.assertEqual("H2O1", brute_formula(m, ""))
- self.assertEqual("H2O", brute_formula(m, "", True))
-
- def test_build_connectivity(self):
- cs = ChemicalSystem()
-
- m = Molecule("WAT", "w")
- ac = AtomCluster("ac", [Atom(), Atom(), Atom(), Atom()])
- a = Atom()
- ag = AtomGroup([Atom(parent=cs)])
-
- for ce in [m, ac, a, ag]:
- cs.add_chemical_entity(ce)
-
- coords = np.array(
- [
- [1, 1.05, 1],
- [1, 0.98, 1],
- [1, 1.12, 1],
- [1, 1, 1],
- [1.044, 1, 1],
- [0.95, 1, 1],
- [1.055, 1, 1],
- [1, 1, 1.02],
- [1, 1, 1.06],
- ]
- )
- conf = RealConfiguration(cs, coords)
- cs.configuration = conf
-
- build_connectivity(cs, 0.005)
-
- self.assertEqual([m["OW"]], m["HW1"].bonds)
- self.assertEqual([m["HW1"], m["HW2"]], m["OW"].bonds)
- self.assertEqual([m["OW"]], m["HW2"].bonds)
-
- self.assertEqual([ac[1].index, ac[2].index], [at.index for at in ac[0].bonds])
- self.assertEqual([ac[0].index, ac[3].index], [at.index for at in ac[1].bonds])
- self.assertEqual([ac[0].index], [at.index for at in ac[2].bonds])
- self.assertEqual([ac[1].index], [at.index for at in ac[3].bonds])
-
- self.assertEqual([ag._atoms[0].index], [at.index for at in a.bonds])
- self.assertEqual([a.index], [at.index for at in ag._atoms[0].bonds])
-
- def test_find_atoms_in_molecule(self):
- m1 = Molecule("WAT", "water")
- m2 = Molecule("WAT", "water")
- m3 = Molecule("WAT", "water")
- p = Protein("protein")
- p.set_peptide_chains([m3])
-
- cs = ChemicalSystem()
- for ce in [m1, m2, p]:
- cs.add_chemical_entity(ce)
-
- water_hydrogens = find_atoms_in_molecule(cs, "water", ["HW2", "HW1"])
- protein_oxygens = find_atoms_in_molecule(cs, "protein", ["OW"])
- empty = find_atoms_in_molecule(cs, "INVALID", ["OW"])
- empty2 = find_atoms_in_molecule(cs, "water", ["INVALID"])
- water_hydrogen_indices = find_atoms_in_molecule(
- cs, "water", ["HW2", "HW1"], True
- )
-
- self.assertEqual(
- [[m1["HW2"], m1["HW1"]], [m2["HW2"], m2["HW1"]]], water_hydrogens
- )
- self.assertEqual([[m3["OW"]]], protein_oxygens)
- self.assertEqual([], empty)
- self.assertEqual([[], []], empty2)
- self.assertEqual([[1, 2], [4, 5]], water_hydrogen_indices)
-
- def test_get_chemical_objects_dict(self):
- m1 = Molecule("WAT", "water")
- m2 = Molecule("WAT", "water")
- m4 = Molecule("WAT", "dihydrogen oxide")
-
- m3 = Molecule("WAT", "water")
- p = Protein("protein")
- p.set_peptide_chains([m3])
-
- cs = ChemicalSystem()
- for ce in [m1, m2, m4, p]:
- cs.add_chemical_entity(ce)
-
- self.assertDictEqual(
- {"water": [m1, m2], "dihydrogen oxide": [m4], "protein": [p]},
- get_chemical_objects_dict(cs),
- )
-
- def test_group_atoms(self):
- atoms = [Atom() for _ in range(10)]
- molecules = [Molecule("WAT", "") for _ in range(5)]
- atoms.extend(molecules)
-
- cs = ChemicalSystem()
- for ce in atoms:
- cs.add_chemical_entity(ce)
-
- groups = group_atoms(cs, [[0, 1, 2], [], [1, 5], [10], [11, 12, 13, 11, 20]])
-
- self.assertEqual(4, len(groups))
- self.assertEqual([atoms[0], atoms[1], atoms[2]], groups[0]._atoms)
- self.assertEqual([atoms[1], atoms[5]], groups[1]._atoms)
- self.assertEqual([molecules[0]["OW"]], groups[2]._atoms)
- self.assertEqual(
- [
- molecules[0]["HW2"],
- molecules[0]["HW1"],
- molecules[1]["OW"],
- molecules[0]["HW2"],
- molecules[3]["HW2"],
- ],
- groups[3]._atoms,
- )
-
- def test_resolve_undefined_molecules_name(self):
- m1 = Molecule("WAT", "")
- m2 = Molecule("WAT", " water ")
- m4 = Molecule("WAT", " ")
-
- m3 = Molecule("WAT", "")
- p = Protein("protein")
- p.set_peptide_chains([m3])
-
- cs = ChemicalSystem()
- for ce in [m1, m2, m4, p]:
- cs.add_chemical_entity(ce)
-
- resolve_undefined_molecules_name(cs)
-
- self.assertEqual("H2O1", m1.name)
- self.assertEqual(" water ", m2.name)
- self.assertEqual("H2O1", m4.name)
- self.assertEqual("", m3.name)
- self.assertEqual("protein", p.name)
-
- def test_sorted_atoms_normal(self):
- atoms = [Atom() for _ in range(10)]
- for i, atom in enumerate(atoms):
- atom.index = i
-
- result = sorted_atoms(
- [
- atoms[1],
- atoms[2],
- atoms[5],
- atoms[9],
- atoms[0],
- atoms[3],
- atoms[8],
- atoms[4],
- atoms[7],
- atoms[6],
- ]
- )
- self.assertEqual(atoms, result)
-
- def test_sorted_atoms_return_names(self):
- atoms = [Atom() for _ in range(10)]
- for i, atom in enumerate(atoms):
- atom.index = i
-
- result = sorted_atoms(
- [
- atoms[1],
- atoms[2],
- atoms[5],
- atoms[9],
- atoms[0],
- atoms[3],
- atoms[8],
- atoms[4],
- atoms[7],
- atoms[6],
- ],
- "name",
- )
- self.assertEqual([at.name for at in atoms], result)
diff --git a/MDANSE/pyproject.toml b/MDANSE/pyproject.toml
index 34a2d630fa..661ba00e82 100644
--- a/MDANSE/pyproject.toml
+++ b/MDANSE/pyproject.toml
@@ -1,10 +1,10 @@
[build-system]
-requires = ["setuptools", "cython", "numpy", "wheel"]
+requires = ["setuptools", "numpy", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "MDANSE"
-version = "2.0.0b2"
+version = "2.0.0b3"
description = 'MDANSE Core package - Molecular Dynamics trajectory handling and analysis code'
readme = "README.md"
requires-python = ">=3.9"
@@ -36,7 +36,8 @@ dependencies = [
"ase",
"rdkit",
"MDAnalysis",
- "mdtraj"
+ "mdtraj",
+ "networkx"
]
# dynamic = ["version", "description"]
diff --git a/MDANSE/setup.py b/MDANSE/setup.py
index 9958bb922b..4b6c7e87b0 100644
--- a/MDANSE/setup.py
+++ b/MDANSE/setup.py
@@ -1,323 +1,258 @@
-import fnmatch
-import glob
-import os
-import sys
-
-import numpy
-
-from setuptools import setup, Extension, find_packages
-from Cython.Distutils import build_ext as cython_build_ext
-
-from distutils.sysconfig import get_config_vars
-from distutils.util import convert_path
-
-try:
- import sphinx
-except ImportError:
- sphinx = None
-
-
-#################################
-# Modules variables
-#################################
-EXCLUDE = ["*.py", "*.pyc", "*$py.class", "*~", ".*", "*.bak", "*.so", "*.pyd"]
-
-EXCLUDE_DIRECTORIES = (
- ".*",
- "CVS",
- "_darcs",
- "./build",
- "*svn",
- "./dist",
- "EGG-INFO",
- "*.egg-info",
-)
-
-EXTENSIONS_PATH = "Extensions"
-
-INCLUDE_DIR = [numpy.get_include()]
-
-#################################
-# Helper function
-#################################
-
-
-def is_package(path):
- return os.path.isdir(path) and os.path.isfile(os.path.join(path, "__init__.py"))
-
-
-def find_package_data(
- where=".",
- package="",
- exclude=EXCLUDE,
- exclude_directories=EXCLUDE_DIRECTORIES,
- only_in_packages=True,
- show_ignored=False,
-):
- out = {}
- stack = [(convert_path(where), "", package, only_in_packages)]
- while stack:
- where, prefix, package, only_in_packages = stack.pop(0)
- for name in os.listdir(where):
- fn = os.path.join(where, name)
- if os.path.isdir(fn):
- bad_name = False
- for pattern in exclude_directories:
- if (
- fnmatch.fnmatchcase(name, pattern)
- or fn.lower() == pattern.lower()
- ):
- bad_name = True
- if show_ignored:
- print >> sys.stderr, (
- "Directory %s ignored by pattern %s" % (fn, pattern)
- )
- break
- if bad_name:
- continue
- if os.path.isfile(os.path.join(fn, "__init__.py")) and not prefix:
- if not package:
- new_package = name
- else:
- new_package = package + "." + name
- stack.append((fn, "", new_package, False))
- else:
- stack.append((fn, prefix + name + "/", package, only_in_packages))
- elif package or not only_in_packages:
- # is a file
- bad_name = False
- for pattern in exclude:
- if (
- fnmatch.fnmatchcase(name, pattern)
- or fn.lower() == pattern.lower()
- ):
- bad_name = True
- if show_ignored:
- print >> sys.stderr, (
- "File %s ignored by pattern %s" % (fn, pattern)
- )
- break
- if bad_name:
- continue
- out.setdefault(package, []).append(prefix + name)
-
- return out
-
-
-def find_data(
- where=".", exclude=EXCLUDE, exclude_directories=EXCLUDE_DIRECTORIES, prefix=""
-):
- out = {}
- stack = [convert_path(where)]
- while stack:
- where = stack.pop(0)
- for name in os.listdir(where):
- fn = os.path.join(where, name)
- d = os.path.join(prefix, os.path.dirname(fn))
- if os.path.isdir(fn):
- stack.append(fn)
- else:
- bad_name = False
- for pattern in exclude:
- if (
- fnmatch.fnmatchcase(name, pattern)
- or fn.lower() == pattern.lower()
- ):
- bad_name = True
- break
- if bad_name:
- continue
- out.setdefault(d, []).append(fn)
-
- out = [(k, v) for k, v in out.items()]
-
- return out
-
-
-#################################
-# User data section
-#################################
-
-DATA_FILES = []
-
-
-#################################
-# Documentation
-#################################
-
-if sphinx:
- try:
- from sphinx.ext.apidoc import main as sphinx_apidoc_main
- except ImportError:
- from sphinx.apidoc import main as sphinx_apidoc_main
-
- # class mdanse_build_doc(sphinx.setup_command.BuildDoc):
- class mdanse_build_doc:
- def run(self):
- build = self.get_finalized_command("build")
-
- buildDir = os.path.abspath(build.build_lib)
-
- if not os.path.exists(buildDir):
- raise IOError("build command must be performed prior building the doc")
-
- sys.path.insert(0, buildDir)
-
- sphinxDir = os.path.abspath(
- os.path.join(build.build_base, "sphinx", self.doctype)
- )
-
- if not os.path.exists(sphinxDir):
- os.makedirs(sphinxDir)
-
- metadata = self.distribution.metadata
- args = [
- "-F",
- "--separate",
- "-H%s" % metadata.name,
- "-A%s" % metadata.author,
- "-R%s" % metadata.version,
- "-o%s" % sphinxDir,
- os.path.join(buildDir, "MDANSE"),
- os.path.join(buildDir, "MDANSE", "Externals"),
- ]
-
- # /!\ apidoc.main is deprecated. The API has been broken in sphinx 1.7.0, see https://github.com/sphinx-doc/sphinx/issues/4615
- if int(sphinx.__version__.split(".")[1]) <= 6:
- args.insert(0, "")
-
- sphinx_apidoc_main(args)
-
- currentDirectory = os.getcwd()
-
- import shutil
-
- shutil.copy(
- os.path.join(currentDirectory, "Doc", "conf_%s.py" % self.doctype),
- os.path.join(sphinxDir, "conf.py"),
- )
- shutil.copy(
- os.path.join(currentDirectory, "Doc", "mdanse_logo.png"),
- os.path.join(sphinxDir, "_static"),
- )
- shutil.copy(
- os.path.join(currentDirectory, "Doc", "layout.html"),
- os.path.join(sphinxDir, "_templates"),
- )
-
- # The directory where the rst files are located.
- self.source_dir = sphinxDir
- # The directory where the conf.py file is located.
- self.config_dir = self.source_dir
-
- # The directory where the documentation will be built
- self.build_dir = os.path.join(buildDir, "MDANSE", "Doc", self.doctype)
-
- if isinstance(self.builder, str):
- builders = [self.builder]
- else:
- builders = self.builder
-
- for builder in builders:
- self.builder_target_dir = os.path.join(self.build_dir, builder)
- sphinx.setup_command.BuildDoc.finalize_options(self)
- sphinx.setup_command.BuildDoc.run(self)
-
- sys.path.pop(0)
-
- class mdanse_build_help(mdanse_build_doc):
- doctype = "help"
-
- class mdanse_build_api(mdanse_build_doc):
- doctype = "api"
-
-
-#################################
-# Extensions section
-#################################
-
-if "linux" in sys.platform:
- (opt,) = get_config_vars("OPT")
- os.environ["OPT"] = " ".join(
- flag for flag in opt.split() if flag != "-Wstrict-prototypes"
- )
-
-EXTENSIONS = [
- Extension(
- "MDANSE.Extensions.atoms_in_shell",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "atoms_in_shell.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.com_trajectory",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "com_trajectory.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.contiguous_coordinates",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "contiguous_coordinates.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.van_hove",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "van_hove.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.fast_calculation",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "fast_calculation.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.sas_fast_calc",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "sas_fast_calc.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.mic_fast_calc",
- include_dirs=INCLUDE_DIR,
- sources=[os.path.join("Extensions", "mic_fast_calc.pyx")],
- language="c++",
- ),
- Extension(
- "MDANSE.Extensions.xtc",
- include_dirs=[
- numpy.get_include(),
- os.path.join("Extensions", "xtc", "include"),
- ],
- sources=glob.glob(os.path.join("Extensions", "xtc", "src", "*.c"))
- + [os.path.join("Extensions", "xtc", "xtc.pyx")],
- ),
- Extension(
- "MDANSE.Extensions.trr",
- include_dirs=[
- numpy.get_include(),
- os.path.join("Extensions", "xtc", "include"),
- ],
- sources=glob.glob(os.path.join("Extensions", "xtc", "src", "*.c"))
- + [os.path.join("Extensions", "xtc", "trr.pyx")],
- ),
-]
-
-for ext in EXTENSIONS:
- ext.cython_directives = {"language_level": "3"}
-
-CMDCLASS = {"build_ext": cython_build_ext}
-
-if sphinx:
- CMDCLASS["build_api"] = mdanse_build_api
- CMDCLASS["build_help"] = mdanse_build_help
-
-#################################
-# The setup section
-#################################
-
-setup(
- name="MDANSE",
- packages=find_packages("Src"),
- package_dir={"": "Src"},
- data_files=DATA_FILES,
- platforms=["Unix", "Windows"],
- ext_modules=EXTENSIONS,
- cmdclass=CMDCLASS,
-)
+import fnmatch
+import os
+import sys
+
+import numpy
+
+from setuptools import setup, find_packages
+
+from distutils.sysconfig import get_config_vars
+from distutils.util import convert_path
+
+try:
+ import sphinx
+except ImportError:
+ sphinx = None
+
+
+#################################
+# Modules variables
+#################################
+EXCLUDE = ["*.py", "*.pyc", "*$py.class", "*~", ".*", "*.bak", "*.so", "*.pyd"]
+
+EXCLUDE_DIRECTORIES = (
+ ".*",
+ "CVS",
+ "_darcs",
+ "./build",
+ "*svn",
+ "./dist",
+ "EGG-INFO",
+ "*.egg-info",
+)
+
+INCLUDE_DIR = [numpy.get_include()]
+
+#################################
+# Helper function
+#################################
+
+
+def is_package(path):
+ return os.path.isdir(path) and os.path.isfile(os.path.join(path, "__init__.py"))
+
+
+def find_package_data(
+ where=".",
+ package="",
+ exclude=EXCLUDE,
+ exclude_directories=EXCLUDE_DIRECTORIES,
+ only_in_packages=True,
+ show_ignored=False,
+):
+ out = {}
+ stack = [(convert_path(where), "", package, only_in_packages)]
+ while stack:
+ where, prefix, package, only_in_packages = stack.pop(0)
+ for name in os.listdir(where):
+ fn = os.path.join(where, name)
+ if os.path.isdir(fn):
+ bad_name = False
+ for pattern in exclude_directories:
+ if (
+ fnmatch.fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()
+ ):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "Directory %s ignored by pattern %s" % (fn, pattern)
+ )
+ break
+ if bad_name:
+ continue
+ if os.path.isfile(os.path.join(fn, "__init__.py")) and not prefix:
+ if not package:
+ new_package = name
+ else:
+ new_package = package + "." + name
+ stack.append((fn, "", new_package, False))
+ else:
+ stack.append((fn, prefix + name + "/", package, only_in_packages))
+ elif package or not only_in_packages:
+ # is a file
+ bad_name = False
+ for pattern in exclude:
+ if (
+ fnmatch.fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()
+ ):
+ bad_name = True
+ if show_ignored:
+ print >> sys.stderr, (
+ "File %s ignored by pattern %s" % (fn, pattern)
+ )
+ break
+ if bad_name:
+ continue
+ out.setdefault(package, []).append(prefix + name)
+
+ return out
+
+
+def find_data(
+ where=".", exclude=EXCLUDE, exclude_directories=EXCLUDE_DIRECTORIES, prefix=""
+):
+ out = {}
+ stack = [convert_path(where)]
+ while stack:
+ where = stack.pop(0)
+ for name in os.listdir(where):
+ fn = os.path.join(where, name)
+ d = os.path.join(prefix, os.path.dirname(fn))
+ if os.path.isdir(fn):
+ stack.append(fn)
+ else:
+ bad_name = False
+ for pattern in exclude:
+ if (
+ fnmatch.fnmatchcase(name, pattern)
+ or fn.lower() == pattern.lower()
+ ):
+ bad_name = True
+ break
+ if bad_name:
+ continue
+ out.setdefault(d, []).append(fn)
+
+ out = [(k, v) for k, v in out.items()]
+
+ return out
+
+
+#################################
+# User data section
+#################################
+
+DATA_FILES = []
+
+
+#################################
+# Documentation
+#################################
+
+if sphinx:
+ try:
+ from sphinx.ext.apidoc import main as sphinx_apidoc_main
+ except ImportError:
+ from sphinx.apidoc import main as sphinx_apidoc_main
+
+ # class mdanse_build_doc(sphinx.setup_command.BuildDoc):
+ class mdanse_build_doc:
+ def run(self):
+ build = self.get_finalized_command("build")
+
+ buildDir = os.path.abspath(build.build_lib)
+
+ if not os.path.exists(buildDir):
+ raise IOError("build command must be performed prior building the doc")
+
+ sys.path.insert(0, buildDir)
+
+ sphinxDir = os.path.abspath(
+ os.path.join(build.build_base, "sphinx", self.doctype)
+ )
+
+ if not os.path.exists(sphinxDir):
+ os.makedirs(sphinxDir)
+
+ metadata = self.distribution.metadata
+ args = [
+ "-F",
+ "--separate",
+ "-H%s" % metadata.name,
+ "-A%s" % metadata.author,
+ "-R%s" % metadata.version,
+ "-o%s" % sphinxDir,
+ os.path.join(buildDir, "MDANSE"),
+ os.path.join(buildDir, "MDANSE", "Externals"),
+ ]
+
+ # /!\ apidoc.main is deprecated. The API has been broken in sphinx 1.7.0, see https://github.com/sphinx-doc/sphinx/issues/4615
+ if int(sphinx.__version__.split(".")[1]) <= 6:
+ args.insert(0, "")
+
+ sphinx_apidoc_main(args)
+
+ currentDirectory = os.getcwd()
+
+ import shutil
+
+ shutil.copy(
+ os.path.join(currentDirectory, "Doc", "conf_%s.py" % self.doctype),
+ os.path.join(sphinxDir, "conf.py"),
+ )
+ shutil.copy(
+ os.path.join(currentDirectory, "Doc", "mdanse_logo.png"),
+ os.path.join(sphinxDir, "_static"),
+ )
+ shutil.copy(
+ os.path.join(currentDirectory, "Doc", "layout.html"),
+ os.path.join(sphinxDir, "_templates"),
+ )
+
+ # The directory where the rst files are located.
+ self.source_dir = sphinxDir
+ # The directory where the conf.py file is located.
+ self.config_dir = self.source_dir
+
+ # The directory where the documentation will be built
+ self.build_dir = os.path.join(buildDir, "MDANSE", "Doc", self.doctype)
+
+ if isinstance(self.builder, str):
+ builders = [self.builder]
+ else:
+ builders = self.builder
+
+ for builder in builders:
+ self.builder_target_dir = os.path.join(self.build_dir, builder)
+ sphinx.setup_command.BuildDoc.finalize_options(self)
+ sphinx.setup_command.BuildDoc.run(self)
+
+ sys.path.pop(0)
+
+ class mdanse_build_help(mdanse_build_doc):
+ doctype = "help"
+
+ class mdanse_build_api(mdanse_build_doc):
+ doctype = "api"
+
+
+#################################
+# Extensions section
+#################################
+
+if "linux" in sys.platform:
+ (opt,) = get_config_vars("OPT")
+ os.environ["OPT"] = " ".join(
+ flag for flag in opt.split() if flag != "-Wstrict-prototypes"
+ )
+
+CMDCLASS = {}
+
+if sphinx:
+ CMDCLASS["build_api"] = mdanse_build_api
+ CMDCLASS["build_help"] = mdanse_build_help
+
+#################################
+# The setup section
+#################################
+
+setup(
+ name="MDANSE",
+ packages=find_packages("Src"),
+ package_dir={"": "Src"},
+ data_files=DATA_FILES,
+ platforms=["Unix", "Windows"],
+ cmdclass=CMDCLASS,
+)
diff --git a/MDANSE_GUI/CHANGELOG b/MDANSE_GUI/CHANGELOG
index 62253943fc..42eac234be 100644
--- a/MDANSE_GUI/CHANGELOG
+++ b/MDANSE_GUI/CHANGELOG
@@ -1,240 +1,12 @@
-version 1.5.2
---------------
-* CHANGED issue #191 Extended and improved the text output of Analysis
-* FIXED issues #178 #182 minor GUI problems have been removed
-* CHANGED issue #157 DISABLED 3D viewer on ARM (Apple Silicon) MacOS; this will only be fixed in MDANSE 2
-* ADDED issue #167 CP2K Trajectory Converter with example files have been added to MDANSE
-* CHANGED issue #165 The Trajectory Viewer functionality can now be opened without having to open the Molecular Viewer first
-* FIXED issue #158 Molecular Viewer and Elevation, Iso-Surface, and Scalar-Field plotters no longer crash MDANSE on Ubuntu 22
-* FIXED issue #152 MDANSE API documentation that comes with released installers now has class inheritance diagrams displayed properly
-* FIXED issue #151 MDANSE should no longer interfere with system functionalities such as nano on Ubuntu 22
-* FIXED issue #148 The python2 script that comes with MacOS installer can now be used to run scripts
-* FIXED issue #147 MDANSE installed with the installer can now be started on MacOS 11 and MacOS 12. However, Molecular Viewer, Animation, and the Elevation, Iso-Surface, and Scalar-Field plotters continue to crash MDANSE, which will not be fixed until MDANSE 2.0.0
-* CHANGED (internal) issue #136 MDANSE is now tested only on MacOS 11 and MacOS 12 (for MacOS)
-
-
-version 1.5.1
---------------
-* ADDED issue #129 Installers for Ubuntu 22.x are now automatically generated and available for download
-* FIXED issue #131 Importing MDANSE and other installed packages no longer raises exceptions
-* FIXED issue #126 The error messages are now helpful when incorrect input is provided in fields like DL_POLY's 'aliases' that take Python object-like input
-* CHANGED issue #127 The minimum size of Quick View in 2D/3D Plotter is now much smaller, allowing for resizing downwards
-
-version 1.5.0
---------------
-* ADDED issue #93 HDF5 format can now be used as output format of analyses as well as input for plotters
-* ADDED issue #75 Added a new Units Editor window for handling unit definitions and expanded the range of unit conversions in plotters. The internal unit handling has been also rewritten
-* ADDED issue #71 Trajectory files generated by MDANSE now contain units
-* ADDED (internal) issue #68 The data used by plotters is now abstracted, allowing for easier implementation of different data format inputs
-* ADDED issue #62 A new MDANSE script, mdanse_job, has been added which can be used to directly open the GUI window for a job
-* ADDED issue #58 2 new plotters for visualising trajectory variables (configuration, velocities, and gradients) have been added
-* ADDED issue #49 The new MDANSE User Guide is now accessible from the Help menu
-* ADDED issue #45 Data Info now also lists the variables present in the trajectory
-* ADDED issue #43 Gromacs converter can now be used to also convert TRR files. This creates a trajectory with velocities and gradients if present
-* ADDED issue #26 Added velocity interpolation to Current Correlation Function
-* ADDED issue #25 The Pair Distribution Function analysis now also calculates Radial Distribution Function and Total Correlation Function
-* FIXED issue #100 The Atoms List Selection now displays the correct number in the 'Number of atoms' field and prevents its change when opened from an analysis
-* FIXED issue #98 Centre of masses option in the Eccentricity analysis now works correctly
-* FIXED issue #95 MaterialsStudio converters (such as Forcite, Discover, DFTB) now create atom clusters correctly
-* FIXED issue #69 Fixed the variables generated by the Rigid Body Trajectory job
-* FIXED issue #48 The 'Toggle toolbar' button now works correctly on Windows
-* FIXED issue #46 Trajectory files generated by MDANSE no longer include temperature and kinetic energy variables
-* FIXED issue #31 Gromacs converter is now able to process files of any size
-* FIXED issue #30 Scalar Field Plotter now works on Windows
-* FIXED issue #29 Elements Database GUI now works properly
-* FIXED issue #22 Normalisation now works correctly in Position Autocorrelation Function and General Autocorrelation Function
-* FIXED issue #21 Opening an analysis that implements Atom Selection or Reference Basis no longer causes other analyses' GUI windows to crash when opened
-* FIXED issue #17 MDANSE can now be opened on all recent versions of MacOS, including computers with the M1 chip
-* FIXED issue #15 CASTEP converter now works on MD files with headers of any size
-* CHANGED issue #42 The 'variable' box in 2D/3D Plotter is now larger and resizeable
-* CHANGED issue #41 Improved the default names of output files of analyses and conversions. A number is also appended to prevent overwriting
-* CHANGED (internal) issue #67 Where possible Scientific.IO.NetCDF has been replaced with netCDF4 package
-* CHANGED issue #28 Simple Help is now formatted nicely
-* CHANGED issue #24 Plotters no longer show variables which contain non-numeric values
-* CHANGED (internal) issue #19 The CI/CD has been migrated to use GitHub Actions and GitHub-hosted runners
-* CHANGED (internal) MDANSE is now maintained by the ISIS Neutron and Muon Source. Licensing and other documents now reflect this
-
-version 1.5.0.ill (unreleased)
---------------
-* ADDED issue #59 Added smart_association in LAMMPS converter. When two or more masses are matching in a LAMMPS trajectory, and smart_association is set to True, we select the nearest one.
-* FIXED issue #58 Some LAMMPS files could not be converted with MDANSE
-* FIXED issue #57 On macOS, MDANSE did not use the embedded python
-* CHANGED LAMMPS converter accepts now "0" as the number of steps (=> automatic detection of the steps number)
-* CHANGED Default mass tolerance in LAMMPS converter in now 10^-3 instead of 10^-5
-* CHANGED (internal) netCDF version has been updated on macOS
-
-version 1.4.0
---------------
-* FIXED issue #56 Layout on Windows differed from macOS and Linux (we keep Windows Layout: "Data" on top, "Plugins" below)
-* FIXED issue #55 Plotter (1D, 2D, Plotter, NetCDF Plotter) had several issues (see https://code.ill.fr/scientific-software/mdanse/issues/55)
-* FIXED issue #54 Some Gromacs trajectories cannot be opened (due to the presence of "M" dummy atoms)
-* FIXED issue #53 VASP NPT trajectories could not be opened
-* FIXED issue #52 QVector circular lattice generator created an error
-* FIXED issue #51 SFFSF job was accessible from MMTK trajectory and molecular viewer
-* FIXED issue #50 Some results could be inconsistent when using multiple atom selections
-* FIXED issue #49 Some LAMMPS files could not be converted
-* FIXED issue #48 There was an error in NDTSF analysis
-* FIXED issue #47 GUI converter did not close
-* CHANGED (internal) Docker build has been changed
-* CHANGED (internal) macOS build has been changed
-
-version 1.3.1
---------------
-* FIXED issue #46 There was an error message when closign converter plugins. The error is no more here but the converter still does not close.
-
-version 1.3.0
---------------
-* ADDED Neutron Dynamic Total Structure Factor analysis
-* ADDED User can now launch a script with qvector parameters instead of saved qvector definition
-* FIXED issue #45 MSD computing on non-orthorombic universe was wrong (fixed with new mmtk version) /!\ Modifies MSD, VACF and DoS, and maybe others... /!\ Units in MMTK have slightly changed
-* FIXED issue #44 An error message appeared when display, close and reopen molecular viewer and animation plugins
-* FIXED issue #43 The weights are no more normalized with absolute sum /!\ Modifies at least CCF, DCSF and SSF job behavior
-* FIXED issue #42 Plotter units could be inconsistent
-* FIXED issue #41 Instrument resolution window froze GUI on macOS
-* FIXED issue #40 MDANSE could not be used on Ubuntu Bionic systems (due to vtk dependency name)
-* FIXED issue #38 Interface was frozen when jobs were launched. A delay of 2s is added at the end of jobs before suppressing the status file
-
-version 1.2.1
---------------
-* FIXED issue #39 Time scale in Gromacs converter was incorrect
-
-version 1.2.0
---------------
-* ADDED issue #27 Better error handling when an error occurs when running an analysis from the GUI
-* ADDED issue #10 Implemented Gromacs trajectory converter
-* FIXED issue #36 Jobs could not be launched on Windows machines
-* FIXED issue #35 Result of RBT was incorrect /!\ Modifies API (removes stepwise parameter) /!\ Modifies job behavior
-* FIXED issue #32 Result of DCSF was incorrect (the QVectors changed over frames) /!\ Modifies job behavior
-* FIXED issue #31 Result of RMSD was incorrect (the sqrt was not applied) /!\ Modifies job behavior
-* FIXED issue #30 Normalization of VACF total value was incorrect /!\ Modifies job behavior
-* FIXED issue #29 Some jobs (AC, CCF, DOS, DACF, DCSF, DISF, GACF, GDISF, MSD, PACF, RMSD, VACF) did not behave properly if first time of the MD is not zero /!\ Modifies jobs behaviors
-* FIXED issue #28 The time step is now part of the settings for DCD based converters /!\ Modifies API (with default value) /!\ Modifies jobs CHARMM, NAMD and XPLOR behaviors
-* FIXED issue #26 Data can be deleted from the GUI
-* FIXED issue #25 The plotter is now compliant with all matplotlib versions (was crashing on ubuntu-xenial)
-* FIXED issue #24 Q vectors in CCF Job were incorrect /!\ Modifies job behavior
-* FIXED issue #21 "Save a template for new analysis" button produced an error
-* FIXED issue #20 Opening the theoretical help on MacOS is now OK
-* FIXED issue #18 The items of the checkable combobox are now checkable on Windows
-* FIXED issue #16 The file filter combo box is now available from the input file dialog on MacOS
-* CHANGED (internal) issue #34 source code is moved to Src/ instead of MDANSE/
-* CHANGED (internal) MDANSE can now be built without documentation
-* CHANGED (internal) issue #33 The macOS dmg is now ligher than before
-* CHANGED (internal) MDANSE is now built with system python on macOS (2.7.10)
-
-version 1.1.3
---------------
-* FIXED issue #19 Users could not display user definitions
-* FIXED issue #17 The plotter crashed when user was clicking on "plot in new window"
-
-version 1.1.2
---------------
-* ADDED issue #15 An automatic mode for data loading is added to compel with the fact that data filter does not appear in data loading popup on macOS
-
-version 1.1.1
---------------
-* FIXED issue #14 Package name was not valid for debian package in 1.1.0 version
-* CHANGED Moving artifacts for more convenient user downloading
-
-version 1.1.0
---------------
-* ADDED issue #12 MDANSE has now three different development phases (beta, rc, release)
-* ADDED issue #11 MDANSE is now compliant with 16.04 and 18.04 Ubuntu systems
-* CHANGED Replacing all "output_file" occurences by "output_files" /!\ Modifies API /!\
-* FIXED issue #13 The changelog was not updated in the windows installer
-* FIXED issue #9 updated the macos build scripts in order to have an universal dmg
-* FIXED issue #7 suppression of the appearance of an error dialog when closing widgets
-* ADDED (internal) Reference data files integrated in functional tests
-* CHANGED (internal) MDANSE is now build on new build servers (2018)
-* CHANGED (internal) Complete refactoring of build scripts
-
-version 1.0.11
--------------
-* bug fix when converting MS trajectories due to a too small value for recursionlimit parameter
-
-version 1.0.10
--------------
-* bug fix due to missing import in ElementsDatabaseEditor
-* bug fix when loading trajectory with missing unknown MMTK atoms
-
-version 1.0.9
--------------
-* use the short git commit id instead of long
-
-version 1.0.8
--------------
-* bug fix when getting git commit id in long format
-
-version 1.0.7
--------------
-* = 1.0.6.a
-
-version 1.0.6.a
-----------------
-* bug fix when setting the commit id in __pkginfo__
-
-version 1.0.6
-----------------
-* the bug report button opens now the default mail client for sending bug report
-* the __pkginfo__ is now updated with the commit id when MDANSE is built
-
-version 1.0.5
-----------------
-* bug fix on macos when closing the application from the Finder: the jobs manager thread was not properly closed
-* the macos dmg file was corrupted due to the use of pkg_resources module for storing resources
-
-version 1.0.4.rc4
-----------------
-* bug fix in coordination number analysis: some pairs were never taken into account
-* bug fix when transmutating atoms from an atom selection different to 'all'
-
-version 1.0.4.rc3
-----------------
-* bug fix in debian packager: add the python-setuptools dependency
-* improved LAMMPS converter: the parsing of the config file is more tolerance in term of required keyword format
-
-version 1.0.4.rc2
-----------------
-* added support for gitflow bugfix branch to gitlab config file
-* the DL_POLY converter is now compliant with DL_POLY 4
-* added the mass tolerance to LAMMP converter
-* updated the LAMMP example trajectory with more accurate masses
-
-version 1.0.4.rc1
-----------------
-* bug fix in IWidget: the label of the configurator was not taken into account
-* bug fix path_to_module function: the list of directories has to be parsed backwards
-* raise an error when none or more than atom matches the mass stored in the LAMMPS config file
-* modified the label for r value
-
-version 1.0.3.e:
-----------------
-* bug fix relative to REGISTRY update
-
-version 1.0.3.d:
-----------------
-* redirected the sys.stdout and sys.stderr to the LOGGER
-* implemented a write method so as ConsoleHandler behaves as a file-like object
-* the job short name appears now explicitely in the saved job files
-* small refactoring of MDANSE __init__
-* small refactoring of ClassRegistry
-* removed the explicit imports of the framework classes
-* the plotter show the last loaded data now
-* bug fix in rmsd job: the PBC were not applied to the calculation
-* bug fix in AtomSelectionConfigurator::get_indexes
-* bug fix when saving user definitions
-* bug fix with the initial size of the user definitions plugins
-* updated the job template writing
-* small refactoring of the save job template command line option
-* removed unused imports
-* removed white spaces
-
-version 1.0.3.c:
-----------------
-* bug fix with JobControllerPanel in case of crashing jobs
-* regression fixed due to trials to get rid of relative imports MDANSE/Externals/pubsub package
-
-version 1.0.3.a:
-----------------
-* updated `MDANSE/__pkginfo__.py` module
-
+version 0.1.0a3
+---------------
+* CHANGED plotting interface to a new 2-tab design
+* ADDED user settings connected to every tab
+* ADDED instrument definitions as a separate tab
+
+version 0.1.0a1
+---------------
+* ADDED a new interface based on qtpy
+* ADDED a VTK 3D viewer adapted from E. Pellegrini's Waterstay project
+* ADDED a plotting mechanism based on E. Pellegrini's implementation
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py
index e4e9eafcf6..c7c6c784dc 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomSelectionWidget.py
@@ -92,7 +92,7 @@ def __init__(
self.selector = selector
self._field = field
self.settings = self.selector.settings
- self.atm_full_names = [atm.full_name for atm in self.selector.system.atom_list]
+ self.atm_full_names = self.selector.system.name_list
self.selection_textbox = QPlainTextEdit()
self.selection_textbox.setReadOnly(True)
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py
index 82dec8a880..901c846a50 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/AtomTransmutationWidget.py
@@ -139,9 +139,7 @@ def update_transmutation_textbox(self) -> None:
text = [f"Number of atoms transmuted:\n{len(map)}\n\nTransmuted atoms:\n"]
atoms = self.selector.system.atom_list
for idx, symbol in map.items():
- text.append(
- f"{idx} ({atoms[idx].full_name}): {atoms[idx].symbol} -> {symbol}\n"
- )
+ text.append(f"{idx} {atoms[idx]} -> {symbol}\n")
self.transmutation_textbox.setText("".join(text))
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/PartialChargeWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/PartialChargeWidget.py
index da85f47d87..d9d9b97703 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/PartialChargeWidget.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/PartialChargeWidget.py
@@ -134,7 +134,7 @@ def update_charge_textbox(self) -> None:
text = [f"Partial charge mapping:\n"]
atoms = self.selector.system.atom_list
for idx, charge in map.items():
- text.append(f"{idx} ({atoms[idx].full_name}) -> {charge}\n")
+ text.append(f"{idx} ({atoms[idx]}) -> {charge}\n")
self.charge_textbox.setText("".join(text))
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py
index 3b4893709d..b61d868b58 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/InputWidgets/QVectorsWidget.py
@@ -28,17 +28,19 @@ class VectorModel(QStandardItemModel):
type_changed = Signal()
input_is_valid = Signal(bool)
- def __init__(self, *args, chemical_system=None, **kwargs):
+ def __init__(self, *args, trajectory=None, **kwargs):
super().__init__(*args, **kwargs)
self._generator = None
self._defaults = []
- self._chemical_system = chemical_system
+ self._trajectory = trajectory
@Slot(str)
def switch_qvector_type(self, vector_type: str, optional_settings: dict = None):
self.clear()
self._defaults = []
- self._generator = IQVectors.create(vector_type, self._chemical_system)
+ self._generator = IQVectors.create(
+ vector_type, self._trajectory.configuration(0)
+ )
settings = self._generator.settings
for kv in settings.items():
name = kv[0] # dictionary key
@@ -111,12 +113,12 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._relative_size = 3
trajectory_configurator = kwargs.get("trajectory_configurator", None)
- chemical_system = None
+ trajectory = None
if trajectory_configurator is not None:
- chemical_system = trajectory_configurator["instance"].chemical_system
+ trajectory = trajectory_configurator["instance"]
self._selector = QComboBox(self._base)
self._selector.addItems(IQVectors.indirect_subclasses())
- self._model = VectorModel(self._base, chemical_system=chemical_system)
+ self._model = VectorModel(self._base, trajectory=trajectory)
self._view = QTableView(self._base)
self._layout.addWidget(self._selector)
self._layout.addWidget(self._view)
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py
index cd38488484..f6e52d86a6 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/AtomProperties.py
@@ -22,7 +22,7 @@
from qtpy.QtGui import QStandardItemModel, QStandardItem, QColor
from qtpy.QtCore import Signal, Slot, QObject, Qt
-from MDANSE.Chemistry.Databases import AtomsDatabase
+from MDANSE.MolecularDynamics.Trajectory import Trajectory
RGB_COLOURS = []
RGB_COLOURS.append((1.00, 0.20, 1.00)) # selection
@@ -149,7 +149,7 @@ def add_colour(self, rgb: tuple[int, int, int]) -> int:
def reinitialise_from_database(
self,
atoms: list[str],
- element_database: AtomsDatabase,
+ element_database: Trajectory,
dummy_size: Optional[float] = None,
) -> list[int]:
"""Puts colours into the list based on chemical elements list
@@ -189,9 +189,12 @@ def reinitialise_from_database(
):
size = dummy_size
else:
- size = round(element_database[atom]["vdw_radius"], 2)
+ size = round(element_database.get_atom_property(atom, "vdw_radius"), 2)
atom_entry = AtomEntry()
- rgb = [int(x) for x in element_database[atom]["color"].split(";")]
+ rgb = [
+ int(x)
+ for x in element_database.get_atom_property(atom, "color").split(";")
+ ]
colour_index_list.append(self.add_colour(rgb))
item_row = atom_entry.set_values(
atom,
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py
index e3d0bdc0b2..49518e1aa8 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/Controls.py
@@ -236,7 +236,7 @@ def createSidePanel(self):
layout4 = QHBoxLayout(wrapper4)
size_factor = QDoubleSpinBox(base)
size_factor.setToolTip("Scaling factor for atom size")
- size_factor.setValue(0.8)
+ size_factor.setValue(0.4)
size_factor.setMinimum(0.0)
size_factor.setMaximum(50.0)
size_factor.setSingleStep(0.05)
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py
index 0450f67201..7f48c6a2fd 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/MolecularViewer.py
@@ -28,7 +28,6 @@
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
-from MDANSE.Chemistry import ATOMS_DATABASE as CHEMICAL_ELEMENTS
from MDANSE.MLogging import LOG
from MDANSE_GUI.MolecularViewer.readers import hdf5wrapper
@@ -71,9 +70,10 @@ class MolecularViewer(QtWidgets.QWidget):
def __init__(self):
super(MolecularViewer, self).__init__()
- self._scale_factor = 0.8
+ self._scale_factor = 0.4
self._datamodel = None
+ self._element_database = None
self._iren = QVTKRenderWindowInteractor(self)
@@ -309,7 +309,7 @@ def create_traj_actors(self, polydata, line_opacity=1.0, ball_opacity=1.0):
else:
glyph.SetInputData(polydata)
- temp_scale = float(0.2 * self._scale_factor)
+ temp_scale = float(1.0 * self._scale_factor)
glyph.SetScaleModeToScaleByScalar()
glyph.SetColorModeToColorByScalar()
glyph.SetScaleFactor(temp_scale)
@@ -618,6 +618,7 @@ def set_reader(self, reader):
self._reader = reader
+ self._element_database = self._reader._trajectory
self._n_atoms = self._reader.n_atoms
self._n_frames = self._reader.n_frames
self._current_frame = min(self._current_frame, self._n_frames - 1)
@@ -630,19 +631,19 @@ def set_reader(self, reader):
self._resolution = 4 if self._resolution < 4 else self._resolution
self._atom_colours = self._colour_manager.reinitialise_from_database(
- self._atoms, CHEMICAL_ELEMENTS, self.dummy_size
+ self._atoms, self._element_database, self.dummy_size
)
# this returns a list of indices, mapping colours to atoms
self._atom_scales = np.array(
[
- CHEMICAL_ELEMENTS.get_atom_property(at, "vdw_radius")
+ self._element_database.get_atom_property(at, "vdw_radius")
for at in self._atoms
]
).astype(np.float32)
self.du_log = np.array(
[
- CHEMICAL_ELEMENTS.get_atom_property(at, "element") != "dummy"
+ self._element_database.get_atom_property(at, "dummy") == 0
for at in self._reader.atom_types
]
)
@@ -650,12 +651,12 @@ def set_reader(self, reader):
[
i
for i, at in enumerate(self._reader.atom_types)
- if CHEMICAL_ELEMENTS.get_atom_property(at, "element") != "dummy"
+ if self._element_database.get_atom_property(at, "dummy") == 0
]
)
self.covs = np.array(
[
- CHEMICAL_ELEMENTS.get_atom_property(at, "covalent_radius")
+ self._element_database.get_atom_property(at, "covalent_radius")
for at in self._reader.atom_types
]
)
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py
index c0c403c915..4d352801dc 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/hdf5wrapper.py
@@ -14,26 +14,31 @@
# along with this program. If not, see .
#
+import typing
import numpy as np
from MDANSE.MolecularDynamics.UnitCell import UnitCell
+if typing.TYPE_CHECKING:
+ from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
+ from MDANSE.MolecularDynamics.Trajectory import Trajectory
+
from MDANSE_GUI.MolecularViewer.readers.i_reader import IReader
class HDF5Wrapper(IReader):
- def __init__(self, fname, trajectory, chemical):
+ def __init__(self, fname, trajectory: "Trajectory", chemical: "ChemicalSystem"):
super(HDF5Wrapper, self).__init__(fname)
- self._n_atoms = chemical._number_of_atoms
+ self._n_atoms = chemical.number_of_atoms
self._n_frames = len(trajectory)
self._trajectory = trajectory
self._chemical_system = chemical
self._filename = fname
- self._atom_ids = [atom.index for atom in chemical.atoms]
- self._atom_types = [atom.symbol for atom in chemical.atoms]
+ self._atom_ids = chemical._atom_indices
+ self._atom_types = chemical.atom_list
self._atom_names = [
- "_".join([str(x) for x in [atom.symbol, atom.index]])
- for atom in chemical.atoms
+ str(element) + "_" + str(index)
+ for element, index in zip(chemical.atom_list, chemical._atom_indices)
]
def read_frame(self, frame: int) -> "np.array":
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py
index dfe481a184..39c073d2c0 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/MolecularViewer/readers/i_reader.py
@@ -20,7 +20,6 @@
from MDANSE.MLogging import LOG
from MDANSE.Chemistry import ATOMS_DATABASE
-from MDANSE.Chemistry import RESIDUES_DATABASE
class InvalidFileError(Exception):
@@ -143,7 +142,6 @@ def guess_atom_types(self):
self._atom_types = []
for i in range(self._n_atoms):
atom_name = self._atom_names[i]
- residue_name = self._residue_names[i]
# Remove the trailing and initial digits from the upperized atom names
upper_atom_name = atom_name.upper()
@@ -152,29 +150,16 @@ def guess_atom_types(self):
# Case of the an atom that belongs to a standard residue
# Guess the atom type by the starting from the first alpha letter from the left,
# increasing the word by one letter if there was no success in guessing the atom type
- if residue_name in RESIDUES_DATABASE:
- start = 1
- while True:
- upper_atom_name = upper_atom_name[:start]
- if upper_atom_name in symbols:
- self._atom_types.append(upper_atom_name.capitalize())
- break
- if start > len(atom_name):
- raise ValueError("Unknown atom type: {}".format(atom_name))
- start += 1
- # Case of the an atom that does not belong to a standard residue
- # Guess the atom type by the starting from whole atom name,
- # decreasing the word by one letter from the right if there was no success in guessing the atom type
- else:
- start = len(upper_atom_name)
- while True:
- upper_atom_name = upper_atom_name[:start]
- if upper_atom_name in symbols:
- self._atom_types.append(upper_atom_name.capitalize())
- break
- if start == 0:
- raise ValueError("Unknown atom type: {}".format(atom_name))
- start -= 1
+
+ start = len(upper_atom_name)
+ while True:
+ upper_atom_name = upper_atom_name[:start]
+ if upper_atom_name in symbols:
+ self._atom_types.append(upper_atom_name.capitalize())
+ break
+ if start == 0:
+ raise ValueError("Unknown atom type: {}".format(atom_name))
+ start -= 1
def read_atom_trajectory(self, index):
"""Read the trajectory of a single atom with a given index
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Views/TrajectoryView.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Views/TrajectoryView.py
index 5837aa6cc7..a97932e770 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Views/TrajectoryView.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Views/TrajectoryView.py
@@ -55,7 +55,8 @@ def deleteNode(self):
model = self.model()
index = self.currentIndex()
node_number = model.itemFromIndex(index).data()
- trajectory = model._nodes[node_number][0]
+ trajectory, instance = model._nodes[node_number]
+ instance.close()
self.free_name.emit(str(trajectory))
model.removeRow(index.row())
self.item_details.emit(("", None))
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/PlotDataInfo.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/PlotDataInfo.py
index 36df9d6a4b..e8bac120ac 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/PlotDataInfo.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/PlotDataInfo.py
@@ -14,10 +14,15 @@
# along with this program. If not, see .
#
from collections import defaultdict
+from typing import TYPE_CHECKING
+import numpy as np
from qtpy.QtCore import Slot, Signal
from qtpy.QtWidgets import QTextBrowser
+if TYPE_CHECKING:
+ from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
+
class PlotDataInfo(QTextBrowser):
error = Signal(str)
@@ -37,13 +42,13 @@ def update_panel(self, input_text):
filtered = self.filter(text)
self.setHtml(filtered)
- def summarise_chemical_system(self, cs):
+ def summarise_chemical_system(self, cs: "ChemicalSystem"):
text = "\n ==== Chemical System summary ==== \n"
- counter = defaultdict(int)
- for atom in cs.atom_list:
- counter[(atom.full_name, atom.symbol)] += 1
- for key, value in counter.items():
- text += f"Full Name: {key[0]}; Element: {key[1]}; Count: {value}\n"
+ atoms, counts = np.unique(cs.atom_list, return_counts=True)
+ for ind in range(len(atoms)):
+ text += f"Element: {atoms[ind]}; Count: {counts[ind]}\n"
+ for molname, mollist in cs._clusters.items():
+ text += f"Molecule: {molname}; Count: {len(mollist)}"
text += " ===== \n"
return text
diff --git a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py
index 765e30023f..3ada21f5d8 100644
--- a/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py
+++ b/MDANSE_GUI/Src/MDANSE_GUI/Tabs/Visualisers/TrajectoryInfo.py
@@ -13,11 +13,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from collections import defaultdict
+from typing import TYPE_CHECKING
+
+import numpy as np
from qtpy.QtCore import Slot, Signal
from qtpy.QtWidgets import QTextBrowser
+if TYPE_CHECKING:
+ from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
+
class TrajectoryInfo(QTextBrowser):
error = Signal(str)
@@ -46,13 +51,13 @@ def update_panel(self, data: tuple):
filtered = self.filter(text)
self.setHtml(filtered)
- def summarise_chemical_system(self, cs):
+ def summarise_chemical_system(self, cs: "ChemicalSystem"):
text = "\n ==== Chemical System summary ==== \n"
- counter = defaultdict(int)
- for atom in cs.atom_list:
- counter[(atom.full_name, atom.symbol)] += 1
- for key, value in counter.items():
- text += f"Full Name: {key[0]}; Element: {key[1]}; Count: {value}\n"
+ atoms, counts = np.unique(cs.atom_list, return_counts=True)
+ for ind in range(len(atoms)):
+ text += f"Element: {atoms[ind]}; Count: {counts[ind]}\n"
+ for molname, mollist in cs._clusters.items():
+ text += f"Molecule: {molname}; Count: {len(mollist)}\n"
text += " ===== \n"
return text
diff --git a/MDANSE_GUI/Tests/UnitTests/test_PlottingContext.py b/MDANSE_GUI/Tests/UnitTests/test_PlottingContext.py
index 0d51fa8ede..7e98515da5 100644
--- a/MDANSE_GUI/Tests/UnitTests/test_PlottingContext.py
+++ b/MDANSE_GUI/Tests/UnitTests/test_PlottingContext.py
@@ -40,7 +40,8 @@ def test_single_dataset_2d(file_2d):
def test_available_x_axes_1d(file_1d):
temp = SingleDataset("dos_total", file_1d)
axes = temp.available_x_axes()
- assert axes == ["rad/ps"]
+ assert axes == ["omega"]
+ assert temp._axes_units[axes[0]] == "rad/ps"
longest = temp.longest_axis()
assert longest[0] == "rad/ps"
@@ -49,7 +50,7 @@ def test_available_x_axes_2d(file_2d):
temp = SingleDataset("f(q,t)_total", file_2d)
axes = temp.available_x_axes()
print(axes)
- assert axes == ["1/nm", "ps"]
+ assert [temp._axes_units[axis] for axis in axes] == ["1/nm", "ps"]
longest = temp.longest_axis()
print(longest)
assert longest[0] == "ps"
diff --git a/MDANSE_GUI/Tests/UnitTests/test_hdf5wrapper.py b/MDANSE_GUI/Tests/UnitTests/test_hdf5wrapper.py
index 7bf86fe2fc..0dec67270a 100644
--- a/MDANSE_GUI/Tests/UnitTests/test_hdf5wrapper.py
+++ b/MDANSE_GUI/Tests/UnitTests/test_hdf5wrapper.py
@@ -19,7 +19,7 @@
import numpy as np
-from MDANSE.Chemistry.ChemicalEntity import Atom, ChemicalSystem
+from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem
from MDANSE.MolecularDynamics.Configuration import RealConfiguration
from MDANSE.MolecularDynamics.Trajectory import Trajectory, TrajectoryWriter
from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData
@@ -34,8 +34,7 @@
def chemical_system():
temp = ChemicalSystem("Dummy test system")
nAtoms = N_ATOMS
- for i in range(nAtoms):
- temp.add_chemical_entity(Atom(symbol="H"))
+ temp.initialise_atoms(nAtoms * ["H"])
return temp
@@ -62,8 +61,7 @@ def sample_trajectory(chemical_system, sample_configuration):
os.close(fdesc)
writer = TrajectoryWriter(fname, chemical_system, n_steps=N_TIMESTEPS)
for n, ts in enumerate(np.arange(N_TIMESTEPS)):
- writer.chemical_system.configuration = sample_configuration
- writer.dump_configuration(ts)
+ writer.dump_configuration(sample_configuration, ts)
return fname
diff --git a/MDANSE_GUI/pyproject.toml b/MDANSE_GUI/pyproject.toml
index 274a259c1a..37f30ae1f0 100644
--- a/MDANSE_GUI/pyproject.toml
+++ b/MDANSE_GUI/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "MDANSE_GUI"
-version = "0.1.0b3"
+version = "0.1.0b4"
description = 'MDANSE GUI package - the graphical interface for MDANSE'
readme = "README.md"
requires-python = ">=3.9"
diff --git a/MDANSE_GUI/setup.py b/MDANSE_GUI/setup.py
index 7ed51e9d17..65295c04be 100644
--- a/MDANSE_GUI/setup.py
+++ b/MDANSE_GUI/setup.py
@@ -30,19 +30,8 @@
"*.egg-info",
)
-EXTENSIONS_PATH = "Extensions"
-
INCLUDE_DIR = [numpy.get_include()]
-QHULL_DIR = os.path.join("Extensions", "qhull_lib")
-
-QHULL_INCLUDE_DIR = (
- INCLUDE_DIR
- + [EXTENSIONS_PATH]
- + [os.path.join(QHULL_DIR, "ext")]
- + [os.path.join(QHULL_DIR, "src")]
-)
-
#################################
# Helper function
#################################