Skip to content

Commit

Permalink
Update getBox and setBox for triclinic box support. [ref #193]
Browse files Browse the repository at this point in the history
  • Loading branch information
lohedges committed Apr 30, 2021
1 parent 208ade1 commit 9f8e504
Showing 1 changed file with 66 additions and 18 deletions.
84 changes: 66 additions & 18 deletions python/BioSimSpace/_SireWrappers/_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
from Sire import Maths as _SireMaths
from Sire import Mol as _SireMol
from Sire import System as _SireSystem
from Sire import Units as _SireUnits
from Sire import Vol as _SireVol

from BioSimSpace import _isVerbose
from BioSimSpace._Exceptions import IncompatibleError as _IncompatibleError
from BioSimSpace.Types import Angle as _Angle
from BioSimSpace.Types import Length as _Length
from BioSimSpace import Units as _Units

Expand Down Expand Up @@ -851,14 +853,17 @@ def getIndex(self, item):
else:
return indices

def setBox(self, size, property_map={}):
def setBox(self, box, angles=3*[_Angle(90, "degree")], property_map={}):
"""Set the size of the periodic simulation box.
Parameters
----------
size : [:class:`Length <BioSimSpace.Types.Length>`]
The size of the box in each dimension.
box : [:class:`Length <BioSimSpace.Types.Length>`]
The box vector magnitudes in each dimension.
angles : [:class:`Angle <BioSimSpace.Types.Angle>`]
The box vector angles: yz, xz, and xy.
property_map : dict
A dictionary that maps system "properties" to their user defined
Expand All @@ -867,25 +872,51 @@ def setBox(self, size, property_map={}):
"""

# Convert tuple to list.
if type(size) is tuple:
size = list(size)
# Convert tuples to lists.
if type(box) is tuple:
box = list(box)
if type(angles) is tuple:
angles = list(angles)

# Validate input.
if type(size) is not list or not all(isinstance(x, _Length) for x in size):
raise TypeError("'size' must be a list of 'BioSimSpace.Types.Length' objects.")
if type(box) is not list or not all(isinstance(x, _Length) for x in box):
raise TypeError("'box' must be a list of 'BioSimSpace.Types.Length' objects.")

if type(angles) is not list or not all(isinstance(x, _Angle) for x in angles):
raise TypeError("'angles' must be a list of 'BioSimSpace.Types.Angle' objects.")

if len(box) != 3:
raise ValueError("'box' must contain three items.")

if len(size) != 3:
raise ValueError("'size' must contain three items.")
if len(box) != 3:
raise ValueError("'angles' must contain three items.")

# Convert sizes to Anstrom.
vec = [x.angstroms().magnitude() for x in size]
vec = [x.angstroms().magnitude() for x in box]

# Whether the box is triclinic.
is_triclinic = False

# If any angle isn't 90 degrees, then the box is triclinic.
for x in angles:
if abs(x.degrees().magnitude() - 90) > 1e-6:
is_triclinic = True
break

# Create a periodic box object.
box = _SireVol.PeriodicBox(_SireMaths.Vector(vec))
if is_triclinic:
# Convert angles to Sire units.
ang = [x.degrees().magnitude()*_SireUnits.degree for x in angles]

# Create a triclinic box object.
space = _SireVol.TriclinicBox(vec[0], vec[1], vec[2],
ang[0], ang[1], ang[2])

else:
# Create a periodic box object.
space = _SireVol.PeriodicBox(_SireMaths.Vector(vec))

# Set the "space" property.
self._sire_object.setProperty(property_map.get("space", "space"), box)
self._sire_object.setProperty(property_map.get("space", "space"), space)

def getBox(self, property_map={}):
"""Get the size of the periodic simulation box.
Expand All @@ -902,18 +933,35 @@ def getBox(self, property_map={}):
-------
box_size : [:class:`Length <BioSimSpace.Types.Length>`]
The size of the box in each dimension.
The box vector magnitudes in each dimension.
angles : [:class:`Angle <BioSimSpace.Types.Angle>`]
The box vector angles: yz, xz, and xy.
"""

# Get the "space" property and convert to a list of BioSimSpace.Type.Length
# objects.
try:
box = self._sire_object.property(property_map.get("space", "space"))
box = [ _Length(x, "Angstrom") for x in box.dimensions() ]
space = self._sire_object.property(property_map.get("space", "space"))

# Periodic box.
if type(space) is _SireVol.PeriodicBox:
box = [ _Length(x, "Angstrom") for x in space.dimensions() ]
angles = 3*[_Angle(90, "degrees")]

# TriclinicBox box.
elif type(space) is _SireVol.TriclinicBox:
box = [_Length(space.vector0().magnitude(), "Angstrom"),
_Length(space.vector1().magnitude(), "Angstrom"),
_Length(space.vector2().magnitude(), "Angstrom")]
angles = [_Angle(space.alpha(), "degree"),
_Angle(space.beta(), "degree"),
_Angle(space.gamma(), "degree")]
except:
box = None
angles = None

return box
return box, angles

def translate(self, vector, property_map={}):
"""Translate the system.
Expand Down

0 comments on commit 9f8e504

Please sign in to comment.