def getBox(self, property_map={}): """Get the size of the periodic simulation box. Parameters ---------- property_map : dict A dictionary that maps system "properties" to their user defined values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } Returns ------- box_size : [:class:`Length <BioSimSpace.Types.Length>`] The size of the box in each dimension. """ # 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() ] except: box = None return box
def _check_box_size(molecule, box, property_map={}): """Internal function to check that box is big enough for the molecule. Parameters ---------- molecule : :class:`Molecule <BioSimSpace._SireWrappers.Molecule>`, \ :class:`System <BioSimSpace._SireWrappers.System>` A molecule, or system of molecules. box : [:class:`Length <BioSimSpace.Types.Length>`] A list containing the box size in each dimension. property_map : dict A dictionary that maps system "properties" to their user defined values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } Returns ------- is_okay : True Whether the box is large enough. """ # Get the axis-aligned bounding box of the molecule/system. aabox = molecule._getAABox(property_map) # Calculate the box size in each dimension, storing each component as a # length in Angstroms. mol_box = [_Length(2 * x, " A") for x in aabox.halfExtents()] # Make sure the box is big enough in each dimension. for len1, len2 in zip(box, mol_box): if len1 < len2: return False # We made it this far, all dimensions are large enough. return True
def _validate_input(molecule, box, shell, ion_conc, is_neutral, work_dir, property_map): """Internal function to validate function arguments. Parameters ---------- molecule : :class:`Molecule <BioSimSpace._SireWrappers.Molecule>`, \ :class:`Molecule <BioSimSpace._SireWrappers.Molecules>`, \ :class:`System <BioSimSpace._SireWrappers.System>` A molecule, or container/system of molecules. box : [:class:`Length <BioSimSpace.Types.Length>`] A list containing the box size in each dimension. shell : :class:`Length` <BioSimSpace.Types.Length>` Thickness of the water shell around the solute. Note that the base length of the resulting box must be at least twice as large as the cutoff used by the chosen molecular dynamics engine. As such, the shell option is often unsuitable for small molecules. ion_conc : float The ion concentration in (mol per litre). is_neutral : bool Whether to neutralise the system. work_dir : str The working directory for the process. property_map : dict A dictionary that maps system "properties" to their user defined values. This allows the user to refer to properties with their own naming scheme, e.g. { "charge" : "my-charge" } Returns ------- (molecule, box, shell, work_dir, property_map) : tuple The validated input arguments. """ # Whether to check the box size. check_box = True # Validate the molecule and create a local copy called _molecule to ensure # that the passed molecule is preserved. if molecule is not None: if type(molecule) is _Molecule: _molecule = _Molecule(molecule) elif type(molecule) is _Molecules: _molecule = molecule.toSystem() elif type(molecule) is _System: _molecule = _System(molecule) else: raise TypeError( "'molecule' must be of type 'BioSimSpace._SireWrappers.Molecule' " "'BioSimSpace._SireWrappers.Molecules', or 'BioSimSpace._SireWrappers.System'" ) # Try to extract the box dimensions from the system. if type(molecule) is _System and box is None and shell is None: try: check_box = False prop = property_map.get("space", "space") box = molecule._sire_object.property(prop).dimensions() # Convert to a list of Length objects. box = [ _Length(box[0], "A"), _Length(box[1], "A"), _Length(box[2], "A") ] except: raise ValueError( "The system has no box information. Please use " "the 'box' keyword argument.") else: if box is None and shell is None: raise ValueError("Missing 'box' keyword argument!") else: _molecule = None if box is None: raise ValueError("Missing 'box' keyword argument!") if shell is not None: _warnings.warn( "Ignoring 'shell' keyword argument as solute is missing.") shell = None if box is not None: # Convert tuple to list. if type(box) is tuple: box = list(box) # Convert Coordinate to list. if type(box) is _Coordinate: box = [box.x(), box.y(), box.z()] # Validate. if len(box) != 3: raise ValueError( "The 'box' must have x, y, and z size information.") else: if not all(isinstance(x, _Length) for x in box): raise ValueError( "The box dimensions must be of type 'BioSimSpace.Types.Length'" ) if shell is not None: if type(shell) is not _Length: raise ValueError( "'shell' must must be of type 'BioSimSpace.Types.Length'") if box is not None: _warnings.warn( "Ignoring 'box' keyword argument as 'shell' takes precendence." ) # Work out the box size based on axis-aligned bounding box. # We take the maximum dimension as the base length of our box. base_length = max(2 * molecule._getAABox().halfExtents()) # Now add the shell thickness. base_length = _Length(base_length, "A") + shell # If we need to add ions, make sure the box is at least 2.54 nanometers # wide, i.e. twice the rlist cutoff used by GROMACS protocols. if base_length < _Length(2.54, "nm"): base_length = _Length(2.54, "nm") # Create the dimensions for a cubic box. box = 3 * [base_length] # Check that the ion concentration is valid. if type(ion_conc) is not float and type(ion_conc) is not int: raise TypeError("'ion_conc' must be of type 'int' or 'float'.") elif ion_conc < 0: raise ValueError("'ion_conc' cannot be negative!") if type(is_neutral) is not bool: raise TypeError("'is_neutral' must be of type 'bool'.") # Check that the working directory is valid. if work_dir is not None and type(work_dir) is not str: raise TypeError("'work_dir' must be of type 'str'") # Check that the property map is valid. if type(property_map) is not dict: raise TypeError("'property_map' must be of type 'dict'") # Check that the box is large enough to hold the molecule. if check_box: if molecule is not None and shell is None and not _check_box_size( molecule, box, property_map): raise ValueError( "The 'box' is not large enough to hold the 'molecule'") return (_molecule, box, shell, work_dir, property_map)
# the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # BioSimSpace 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 BioSimSpace. If not, see <http://www.gnu.org/licenses/>. ##################################################################### """ Length units. """ __author__ = "Lester Hedges" __email_ = "*****@*****.**" __all__ = [ "meter", "centimeter", "millimeter", "nanometer", "angstrom", "picometer" ] from BioSimSpace.Types import Length as _Length meter = _Length(1, "meter") centimeter = _Length(1, "centimeter") millimeter = _Length(1, "millimeter") nanometer = _Length(1, "nanometer") angstrom = _Length(1, "angstrom") picometer = _Length(1, "picometer")