Esempio n. 1
0
 def testVec3Addition(self):
     vec1 = Vec3(1, 2, 3)
     vec2 = Vec3(4, 5, 6)
     vec2_tup = (4, 5, 6)
     result = Vec3(5, 7, 9)
     self.assertEqual(vec1 + vec2, result)
     self.assertEqual(vec1 + vec2_tup, result)
Esempio n. 2
0
 def testVec3Division(self):
     vec1 = Vec3(4, 5, 6)
     factor = 2
     result = Vec3(2, 2.5, 3)
     self.assertEqual(vec1 / factor, result)
     with self.assertRaises(TypeError):
         2 / vec1
Esempio n. 3
0
 def testVec3Subtraction(self):
     vec1 = Vec3(1, 2, 3)
     vec2 = Vec3(3, 2, 1)
     vec2_tup = (3, 2, 1)
     result = Vec3(-2, 0, 2)
     self.assertEqual(vec1 - vec2, result)
     self.assertEqual(vec1 - vec2_tup, result)
     self.assertEqual(vec2_tup - vec1, -result)
Esempio n. 4
0
def reducePeriodicBoxVectors(periodicBoxVectors):
    """ Reduces the representation of the PBC. periodicBoxVectors is expected to
    be an unpackable iterable of length-3 iterables
    """
    if is_quantity(periodicBoxVectors):
        a, b, c = periodicBoxVectors.value_in_unit(nanometers)
    else:
        a, b, c = periodicBoxVectors
    a = Vec3(*a)
    b = Vec3(*b)
    c = Vec3(*c)

    c = c - b * round(c[1] / b[1])
    c = c - a * round(c[0] / a[0])
    b = b - a * round(b[0] / a[0])

    return (a, b, c) * nanometers
Esempio n. 5
0
    def testReducePBCVectors(self):
        """ Checks that reducePeriodicBoxVectors properly reduces vectors """
        a = Vec3(4.24388485, 0.0, 0.0)
        b = Vec3(-1.4146281691908937, 4.001173048368583, 0.0)
        c = Vec3(-1.4146281691908937, -2.0005862820516203, 3.4651176446201674)
        vecs = reducePeriodicBoxVectors((a, b, c)*nanometers)
        vecs2 = computePeriodicBoxVectors(4.24388485, 4.24388485, 4.24388485,
                109.4712190*degrees, 109.4712190*degrees, 109.4712190*degrees)

        # Check that the vectors are the same
        a1, a2, a3 = vecs
        b1, b2, b3 = vecs2
        for x, y in zip(a1, b1):
            self.assertAlmostEqual(strip_units(x), strip_units(y))
        for x, y in zip(a2, b2):
            self.assertAlmostEqual(strip_units(x), strip_units(y))
        for x, y in zip(a3, b3):
            self.assertAlmostEqual(strip_units(x), strip_units(y))
Esempio n. 6
0
def computePeriodicBoxVectors(a_length, b_length, c_length, alpha, beta,
                              gamma):
    """Convert lengths and angles to periodic box vectors.
    
    Lengths should be given in nanometers and angles in radians (or as Quantity
    instances)
    """

    if is_quantity(a_length): a_length = a_length.value_in_unit(nanometers)
    if is_quantity(b_length): b_length = b_length.value_in_unit(nanometers)
    if is_quantity(c_length): c_length = c_length.value_in_unit(nanometers)
    if is_quantity(alpha): alpha = alpha.value_in_unit(radians)
    if is_quantity(beta): beta = beta.value_in_unit(radians)
    if is_quantity(gamma): gamma = gamma.value_in_unit(radians)

    # Compute the vectors.

    a = [a_length, 0, 0]
    b = [b_length * math.cos(gamma), b_length * math.sin(gamma), 0]
    cx = c_length * math.cos(beta)
    cy = c_length * (math.cos(alpha) -
                     math.cos(beta) * math.cos(gamma)) / math.sin(gamma)
    cz = math.sqrt(c_length * c_length - cx * cx - cy * cy)
    c = [cx, cy, cz]

    # If any elements are very close to 0, set them to exactly 0.

    for i in range(3):
        if abs(a[i]) < 1e-6:
            a[i] = 0.0
        if abs(b[i]) < 1e-6:
            b[i] = 0.0
        if abs(c[i]) < 1e-6:
            c[i] = 0.0
    a = Vec3(*a)
    b = Vec3(*b)
    c = Vec3(*c)

    # Make sure they're in the reduced form required by OpenMM.

    c = c - b * round(c[1] / b[1])
    c = c - a * round(c[0] / a[0])
    b = b - a * round(b[0] / a[0])
    return (a, b, c) * nanometers
Esempio n. 7
0
    def _prep_sim(self, coords, external_forces=[]):

        try:
            from openmm import Platform, LangevinIntegrator, Vec3
            from openmm.app import Modeller, ForceField, \
                CutoffNonPeriodic, PME, Simulation, HBonds
            from openmm.unit import angstrom, nanometers, picosecond, \
                kelvin, Quantity, molar
        except ImportError:
            raise ImportError('Please install PDBFixer and OpenMM 7.6 in order to use ClustENM.')

        positions = Quantity([Vec3(*xyz) for xyz in coords], angstrom)
        modeller = Modeller(self._topology, positions)

        if self._sol == 'imp':
            forcefield = ForceField(*self._force_field)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=CutoffNonPeriodic,
                                             nonbondedCutoff=1.0*nanometers,
                                             constraints=HBonds)

        if self._sol == 'exp':
            forcefield = ForceField(*self._force_field)

            modeller.addSolvent(forcefield,
                                padding=self._padding*nanometers,
                                ionicStrength=self._ionicStrength*molar)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=PME,
                                             nonbondedCutoff=1.0*nanometers,
                                             constraints=HBonds)

        for force in external_forces:
            system.addForce(force)

        integrator = LangevinIntegrator(self._temp*kelvin,
                                        1/picosecond,
                                        0.002*picosecond)

        # precision could be mixed, but single is okay.
        platform = self._platform if self._platform is None else Platform.getPlatformByName(self._platform)
        properties = None

        if self._platform is None:
            properties = {'Precision': 'single'}
        elif self._platform in ['CUDA', 'OpenCL']:
            properties = {'Precision': 'single'}

        simulation = Simulation(modeller.topology, system, integrator,
                                platform, properties)

        simulation.context.setPositions(modeller.positions)

        return simulation
Esempio n. 8
0
    def getUnitCellDimensions(self, frame=0):
        """Get the dimensions of the crystallographic unit cell.

        Parameters
        ----------
        frame : int=0
            the index of the frame for which to get the unit cell dimensions
        """
        xsize = self._periodicBoxVectors[frame][0][0].value_in_unit(nanometers)
        ysize = self._periodicBoxVectors[frame][1][1].value_in_unit(nanometers)
        zsize = self._periodicBoxVectors[frame][2][2].value_in_unit(nanometers)
        return Vec3(xsize, ysize, zsize) * nanometers
Esempio n. 9
0
def _construct_box_vectors(line):
    """Create the periodic box vectors based on the values stored in the file.

    @param[in] line The line containing the description
    """

    sline = line.split()
    values = [float(i) for i in sline]
    if len(sline) == 3:
        return (Vec3(values[0], 0, 0), Vec3(
            0, values[1], 0), Vec3(0, 0, values[2])) * nanometers
    return reducePeriodicBoxVectors(
        (Vec3(values[0], values[3],
              values[4]), Vec3(values[5], values[1], values[6]),
         Vec3(values[7], values[8], values[2])) * nanometers)
Esempio n. 10
0
 def testVec3Attributes(self):
     vec1 = Vec3(1, 2, 3)
     self.assertEqual(vec1.x, 1)
     self.assertEqual(vec1.y, 2)
     self.assertEqual(vec1.z, 3)
Esempio n. 11
0
    def __init__(self, file):
        """Load a PDBx/mmCIF file.

        The atom positions and Topology can be retrieved by calling
        getPositions() and getTopology().

        Parameters
        ----------
        file : string
            the name of the file to load.  Alternatively you can pass an open
            file object.
        """
        top = Topology()
        ## The Topology read from the PDBx/mmCIF file
        self.topology = top
        self._positions = []
        PDBFile._loadNameReplacementTables()

        # Load the file.

        inputFile = file
        ownHandle = False
        if isinstance(file, str):
            inputFile = open(file)
            ownHandle = True
        reader = PdbxReader(inputFile)
        data = []
        reader.read(data)
        if ownHandle:
            inputFile.close()
        block = data[0]

        # Build the topology.

        atomData = block.getObj('atom_site')
        atomNameCol = atomData.getAttributeIndex('auth_atom_id')
        if atomNameCol == -1:
            atomNameCol = atomData.getAttributeIndex('label_atom_id')
        atomIdCol = atomData.getAttributeIndex('id')
        resNameCol = atomData.getAttributeIndex('auth_comp_id')
        if resNameCol == -1:
            resNameCol = atomData.getAttributeIndex('label_comp_id')
        resNumCol = atomData.getAttributeIndex('auth_seq_id')
        if resNumCol == -1:
            resNumCol = atomData.getAttributeIndex('label_seq_id')
        resInsertionCol = atomData.getAttributeIndex('pdbx_PDB_ins_code')
        chainIdCol = atomData.getAttributeIndex('auth_asym_id')
        if chainIdCol == -1:
            chainIdCol = atomData.getAttributeIndex('label_asym_id')
            altChainIdCol = -1
        else:
            altChainIdCol = atomData.getAttributeIndex('label_asym_id')
        if altChainIdCol != -1:
            # Figure out which column is best to use for chain IDs.

            idSet = set(row[chainIdCol] for row in atomData.getRowList())
            altIdSet = set(row[altChainIdCol] for row in atomData.getRowList())
            if len(altIdSet) > len(idSet):
                chainIdCol, altChainIdCol = (altChainIdCol, chainIdCol)
        elementCol = atomData.getAttributeIndex('type_symbol')
        altIdCol = atomData.getAttributeIndex('label_alt_id')
        modelCol = atomData.getAttributeIndex('pdbx_PDB_model_num')
        xCol = atomData.getAttributeIndex('Cartn_x')
        yCol = atomData.getAttributeIndex('Cartn_y')
        zCol = atomData.getAttributeIndex('Cartn_z')
        lastChainId = None
        lastAltChainId = None
        lastResId = None
        lastInsertionCode = ''
        atomTable = {}
        atomsInResidue = set()
        models = []
        for row in atomData.getRowList():
            atomKey = ((row[resNumCol], row[chainIdCol], row[atomNameCol]))
            model = ('1' if modelCol == -1 else row[modelCol])
            if model not in models:
                models.append(model)
                self._positions.append([])
            modelIndex = models.index(model)
            if row[altIdCol] != '.' and atomKey in atomTable and len(
                    self._positions[modelIndex]) > atomTable[atomKey].index:
                # This row is an alternate position for an existing atom, so ignore it.

                continue
            if modelIndex == 0:
                # This row defines a new atom.

                if resInsertionCol == -1:
                    insertionCode = ''
                else:
                    insertionCode = row[resInsertionCol]
                if insertionCode in ('.', '?'):
                    insertionCode = ''
                if lastChainId != row[chainIdCol] or (
                        altChainIdCol != -1
                        and lastAltChainId != row[altChainIdCol]):
                    # The start of a new chain.
                    chain = top.addChain(row[chainIdCol])
                    lastChainId = row[chainIdCol]
                    lastResId = None
                    if altChainIdCol != -1:
                        lastAltChainId = row[altChainIdCol]
                if lastResId != row[resNumCol] or lastChainId != row[
                        chainIdCol] or lastInsertionCode != insertionCode or (
                            lastResId == '.'
                            and row[atomNameCol] in atomsInResidue):
                    # The start of a new residue.
                    resId = (None if resNumCol == -1 else row[resNumCol])
                    resIC = insertionCode
                    resName = row[resNameCol]
                    if resName in PDBFile._residueNameReplacements:
                        resName = PDBFile._residueNameReplacements[resName]
                    res = top.addResidue(resName, chain, resId, resIC)
                    if resName in PDBFile._atomNameReplacements:
                        atomReplacements = PDBFile._atomNameReplacements[
                            resName]
                    else:
                        atomReplacements = {}
                    lastResId = row[resNumCol]
                    lastInsertionCode = insertionCode
                    atomsInResidue.clear()
                element = None
                try:
                    element = elem.get_by_symbol(row[elementCol])
                except KeyError:
                    pass
                atomName = row[atomNameCol]
                if atomName in atomReplacements:
                    atomName = atomReplacements[atomName]
                atom = top.addAtom(atomName, element, res, row[atomIdCol])
                atomTable[atomKey] = atom
                atomsInResidue.add(atomName)
            else:
                # This row defines coordinates for an existing atom in one of the later models.

                try:
                    atom = atomTable[atomKey]
                except KeyError:
                    raise ValueError(
                        'Unknown atom %s in residue %s %s for model %s' %
                        (row[atomNameCol], row[resNameCol], row[resNumCol],
                         model))
                if atom.index != len(self._positions[modelIndex]):
                    raise ValueError(
                        'Atom %s for model %s does not match the order of atoms for model %s'
                        % (row[atomIdCol], model, models[0]))
            self._positions[modelIndex].append(
                Vec3(float(row[xCol]), float(row[yCol]), float(row[zCol])) *
                0.1)
        for i in range(len(self._positions)):
            self._positions[i] = self._positions[i] * nanometers
        ## The atom positions read from the PDBx/mmCIF file.  If the file contains multiple frames, these are the positions in the first frame.
        self.positions = self._positions[0]
        self.topology.createStandardBonds()
        self._numpyPositions = None

        # Record unit cell information, if present.

        cell = block.getObj('cell')
        if cell is not None and cell.getRowCount() > 0:
            row = cell.getRow(0)
            (a, b, c) = [
                float(row[cell.getAttributeIndex(attribute)]) * 0.1
                for attribute in ('length_a', 'length_b', 'length_c')
            ]
            (alpha, beta, gamma) = [
                float(row[cell.getAttributeIndex(attribute)]) * math.pi / 180.0
                for attribute in ('angle_alpha', 'angle_beta', 'angle_gamma')
            ]
            self.topology.setPeriodicBoxVectors(
                computePeriodicBoxVectors(a, b, c, alpha, beta, gamma))

        # Add bonds based on struct_conn records.

        connectData = block.getObj('struct_conn')
        if connectData is not None:
            res1Col = connectData.getAttributeIndex('ptnr1_label_seq_id')
            res2Col = connectData.getAttributeIndex('ptnr2_label_seq_id')
            atom1Col = connectData.getAttributeIndex('ptnr1_label_atom_id')
            atom2Col = connectData.getAttributeIndex('ptnr2_label_atom_id')
            asym1Col = connectData.getAttributeIndex('ptnr1_label_asym_id')
            asym2Col = connectData.getAttributeIndex('ptnr2_label_asym_id')
            typeCol = connectData.getAttributeIndex('conn_type_id')
            connectBonds = []
            for row in connectData.getRowList():
                type = row[typeCol][:6]
                if type in ('covale', 'disulf', 'modres'):
                    key1 = (row[res1Col], row[asym1Col], row[atom1Col])
                    key2 = (row[res2Col], row[asym2Col], row[atom2Col])
                    if key1 in atomTable and key2 in atomTable:
                        connectBonds.append((atomTable[key1], atomTable[key2]))
            if len(connectBonds) > 0:
                # Only add bonds that don't already exist.
                existingBonds = set(top.bonds())
                for bond in connectBonds:
                    if bond not in existingBonds and (
                            bond[1], bond[0]) not in existingBonds:
                        top.addBond(bond[0], bond[1])
                        existingBonds.add(bond)
Esempio n. 12
0
    def __init__(self, file, extraParticleIdentifier='EP'):
        """Load a PDB file.

        The atom positions and Topology can be retrieved by calling getPositions() and getTopology().

        Parameters
        ----------
        file : string or file
            the name of the file to load.  Alternatively you can pass an open file object.
        extraParticleIdentifier : string='EP'
            if this value appears in the element column for an ATOM record, the Atom's element will be set to None to mark it as an extra particle
        """

        metalElements = [
            'Al', 'As', 'Ba', 'Ca', 'Cd', 'Ce', 'Co', 'Cs', 'Cu', 'Dy', 'Fe',
            'Gd', 'Hg', 'Ho', 'In', 'Ir', 'K', 'Li', 'Mg', 'Mn', 'Mo', 'Na',
            'Ni', 'Pb', 'Pd', 'Pt', 'Rb', 'Rh', 'Sm', 'Sr', 'Te', 'Tl', 'V',
            'W', 'Yb', 'Zn'
        ]

        top = Topology()
        ## The Topology read from the PDB file
        self.topology = top

        # Load the PDB file

        if isinstance(file, PdbStructure):
            pdb = file
        else:
            inputfile = file
            own_handle = False
            if isinstance(file, str):
                inputfile = open(file)
                own_handle = True
            pdb = PdbStructure(inputfile,
                               load_all_models=True,
                               extraParticleIdentifier=extraParticleIdentifier)
            if own_handle:
                inputfile.close()
        PDBFile._loadNameReplacementTables()

        # Build the topology

        atomByNumber = {}
        for chain in pdb.iter_chains():
            c = top.addChain(chain.chain_id)
            for residue in chain.iter_residues():
                resName = residue.get_name()
                if resName in PDBFile._residueNameReplacements:
                    resName = PDBFile._residueNameReplacements[resName]
                r = top.addResidue(resName, c, str(residue.number),
                                   residue.insertion_code)
                if resName in PDBFile._atomNameReplacements:
                    atomReplacements = PDBFile._atomNameReplacements[resName]
                else:
                    atomReplacements = {}
                for atom in residue.iter_atoms():
                    atomName = atom.get_name()
                    if atomName in atomReplacements:
                        atomName = atomReplacements[atomName]
                    atomName = atomName.strip()
                    element = atom.element
                    if element == 'EP':
                        element = None
                    elif element is None:
                        # Try to guess the element.

                        upper = atomName.upper()
                        while len(upper) > 1 and upper[0].isdigit():
                            upper = upper[1:]
                        if upper.startswith('CL'):
                            element = elem.chlorine
                        elif upper.startswith('NA'):
                            element = elem.sodium
                        elif upper.startswith('MG'):
                            element = elem.magnesium
                        elif upper.startswith('BE'):
                            element = elem.beryllium
                        elif upper.startswith('LI'):
                            element = elem.lithium
                        elif upper.startswith('K'):
                            element = elem.potassium
                        elif upper.startswith('ZN'):
                            element = elem.zinc
                        elif len(residue) == 1 and upper.startswith('CA'):
                            element = elem.calcium
                        elif upper.startswith('D') and any(
                                a.name == atomName[1:]
                                for a in residue.iter_atoms()):
                            pass  # A Drude particle
                        else:
                            try:
                                element = elem.get_by_symbol(upper[0])
                            except KeyError:
                                pass
                    newAtom = top.addAtom(atomName, element, r,
                                          str(atom.serial_number))
                    atomByNumber[atom.serial_number] = newAtom
        self._positions = []
        for model in pdb.iter_models(True):
            coords = []
            for chain in model.iter_chains():
                for residue in chain.iter_residues():
                    for atom in residue.iter_atoms():
                        pos = atom.get_position().value_in_unit(nanometers)
                        coords.append(Vec3(pos[0], pos[1], pos[2]))
            self._positions.append(coords * nanometers)
        ## The atom positions read from the PDB file.  If the file contains multiple frames, these are the positions in the first frame.
        self.positions = self._positions[0]
        self.topology.setPeriodicBoxVectors(pdb.get_periodic_box_vectors())
        self.topology.createStandardBonds()
        self.topology.createDisulfideBonds(self.positions)
        self._numpyPositions = None

        # Add bonds based on CONECT records. Bonds between metals of elements specified in metalElements and residues in standardResidues are not added.

        connectBonds = []
        for connect in pdb.models[-1].connects:
            i = connect[0]
            for j in connect[1:]:
                if i in atomByNumber and j in atomByNumber:
                    if atomByNumber[i].element is not None and atomByNumber[
                            j].element is not None:
                        if atomByNumber[
                                i].element.symbol not in metalElements and atomByNumber[
                                    j].element.symbol not in metalElements:
                            connectBonds.append(
                                (atomByNumber[i], atomByNumber[j]))
                        elif atomByNumber[
                                i].element.symbol in metalElements and atomByNumber[
                                    j].residue.name not in PDBFile._standardResidues:
                            connectBonds.append(
                                (atomByNumber[i], atomByNumber[j]))
                        elif atomByNumber[
                                j].element.symbol in metalElements and atomByNumber[
                                    i].residue.name not in PDBFile._standardResidues:
                            connectBonds.append(
                                (atomByNumber[i], atomByNumber[j]))
                    else:
                        connectBonds.append((atomByNumber[i], atomByNumber[j]))
        if len(connectBonds) > 0:
            # Only add bonds that don't already exist.
            existingBonds = set(top.bonds())
            for bond in connectBonds:
                if bond not in existingBonds and (
                        bond[1], bond[0]) not in existingBonds:
                    top.addBond(bond[0], bond[1])
                    existingBonds.add(bond)
Esempio n. 13
0
    def __init__(self, file):
        """Load a .gro file.

        The atom positions can be retrieved by calling getPositions().

        Parameters
        ----------
        file : string
            the name of the file to load
        """
        xyzs = []
        elements = [
        ]  # The element, most useful for quantum chemistry calculations
        atomname = []  # The atom name, for instance 'HW1'
        comms = []
        resid = []
        resname = []
        boxes = []
        xyz = []
        ln = 0
        frame = 0
        with open(file) as grofile:
            for line in grofile:
                if ln == 0:
                    comms.append(line.strip())
                elif ln == 1:
                    na = int(line.strip())
                elif _is_gro_coord(line):
                    if frame == 0:  # Create the list of residues, atom names etc. only if it's the first frame.
                        (thisresnum, thisresname, thisatomname) = [
                            line[i * 5:i * 5 + 5].strip() for i in range(3)
                        ]
                        resname.append(thisresname)
                        resid.append(int(thisresnum))
                        atomname.append(thisatomname)
                        thiselem = thisatomname
                        if len(thiselem) > 1:
                            thiselem = thiselem[0] + sub(
                                '[A-Z0-9]', '', thiselem[1:])
                            try:
                                elements.append(elem.get_by_symbol(thiselem))
                            except KeyError:
                                elements.append(None)
                    firstDecimalPos = line.index('.', 20)
                    secondDecimalPos = line.index('.', firstDecimalPos + 1)
                    digits = secondDecimalPos - firstDecimalPos
                    pos = [
                        float(line[20 + i * digits:20 + (i + 1) * digits])
                        for i in range(3)
                    ]
                    xyz.append(Vec3(pos[0], pos[1], pos[2]))
                elif _is_gro_box(line) and ln == na + 2:
                    boxes.append(_construct_box_vectors(line))
                    xyzs.append(xyz * nanometers)
                    xyz = []
                    ln = -1
                    frame += 1
                else:
                    raise Exception("Unexpected line in .gro file: " + line)
                ln += 1

        ## The atom positions read from the file.  If the file contains multiple frames, these are the positions in the first frame.
        self.positions = xyzs[0]
        ## A list containing the element of each atom stored in the file
        self.elements = elements
        ## A list containing the name of each atom stored in the file
        self.atomNames = atomname
        ## A list containing the ID of the residue that each atom belongs to
        self.residueIds = resid
        ## A list containing the name of the residue that each atom belongs to
        self.residueNames = resname
        self._positions = xyzs
        self._periodicBoxVectors = boxes
        self._numpyPositions = None
Esempio n. 14
0
    def writeModel(self, positions, unitCellDimensions=None, periodicBoxVectors=None):
        """Write out a model to the DCD file.

        The periodic box can be specified either by the unit cell dimensions
        (for a rectangular box), or the full set of box vectors (for an
        arbitrary triclinic box).  If neither is specified, the box vectors
        specified in the Topology will be used. Regardless of the value
        specified, no dimensions will be written if the Topology does not
        represent a periodic system.

        Parameters
        ----------
        positions : list
            The list of atomic positions to write
        unitCellDimensions : Vec3=None
            The dimensions of the crystallographic unit cell.
        periodicBoxVectors : tuple of Vec3=None
            The vectors defining the periodic box.
        """
        if len(list(self._topology.atoms())) != len(positions):
            raise ValueError('The number of positions must match the number of atoms')
        if is_quantity(positions):
            positions = positions.value_in_unit(nanometers)
        if any(math.isnan(norm(pos)) for pos in positions):
            raise ValueError('Particle position is NaN')
        if any(math.isinf(norm(pos)) for pos in positions):
            raise ValueError('Particle position is infinite')
        file = self._file

        self._modelCount += 1
        if self._interval > 1 and self._firstStep+self._modelCount*self._interval > 1<<31:
            # This will exceed the range of a 32 bit integer.  To avoid crashing or producing a corrupt file,
            # update the header to say the trajectory consisted of a smaller number of larger steps (so the
            # total trajectory length remains correct).
            self._firstStep //= self._interval
            self._dt *= self._interval
            self._interval = 1
            file.seek(0, os.SEEK_SET)
            file.write(struct.pack('<i4c9if', 84, b'C', b'O', b'R', b'D', 0, self._firstStep, self._interval, 0, 0, 0, 0, 0, 0, self._dt))

        # Update the header.

        file.seek(8, os.SEEK_SET)
        file.write(struct.pack('<i', self._modelCount))
        file.seek(20, os.SEEK_SET)
        file.write(struct.pack('<i', self._firstStep+self._modelCount*self._interval))

        # Write the data.

        file.seek(0, os.SEEK_END)
        boxVectors = self._topology.getPeriodicBoxVectors()
        if boxVectors is not None:
            if periodicBoxVectors is not None:
                boxVectors = periodicBoxVectors
            elif unitCellDimensions is not None:
                if is_quantity(unitCellDimensions):
                    unitCellDimensions = unitCellDimensions.value_in_unit(nanometers)
                boxVectors = (Vec3(unitCellDimensions[0], 0, 0), Vec3(0, unitCellDimensions[1], 0), Vec3(0, 0, unitCellDimensions[2]))*nanometers
            (a_length, b_length, c_length, alpha, beta, gamma) = computeLengthsAndAngles(boxVectors)
            a_length = a_length * 10.  # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
            b_length = b_length * 10.  # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
            c_length = c_length * 10.  # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
            angle1 = math.sin(math.pi/2-gamma)
            angle2 = math.sin(math.pi/2-beta)
            angle3 = math.sin(math.pi/2-alpha)
            file.write(struct.pack('<i6di', 48, a_length, angle1, b_length, angle2, angle3, c_length, 48))
        length = struct.pack('<i', 4*len(positions))
        for i in range(3):
            file.write(length)
            data = array.array('f', (10*x[i] for x in positions))
            data.tofile(file)
            file.write(length)
        try:
            file.flush()
        except AttributeError:
            pass
Esempio n. 15
0
def solvate(molecular_system,
            box_geometry="truncated octahedral",
            clearance='14.0 angstroms',
            anion='Cl-',
            num_anions="neutralize",
            cation='Na+',
            num_cations="neutralize",
            ionic_strength='0.0 molar',
            engine="LEaP",
            to_form=None,
            logfile=False,
            verbose=False):
    """solvate(item, geometry=None, water=None, engine=None)
    Methods and wrappers to create and solvate boxes
    Parameters
    ----------
    anion: 'Cl-', 'Br-', 'F-', and 'I-'
    num_anions: number of cations to add. integer or "neutralize"
    cation: "NA"  'Cs+', 'K+', 'Li+', 'Na+', and 'Rb+'
    num_cations: number of cations to add. integer or "neutralize"
    box_geometry: "cubic", "truncated_octahedral" or "rhombic_dodecahedron" (Default: "truncated_octahedral")
    Returns
    -------
    item : bla bla
        bla bla
    Examples
    --------
    See Also
    --------
    Notes
    -----
    """

    from molsysmt.basic import get_form, convert

    engine = digest_engine(engine)
    to_form = digest_to_form(to_form)
    if to_form is None:
        to_form = get_form(molecular_system)

    if engine == "OpenMM":

        from openmm import Vec3

        clearance = puw.convert(clearance, to_form='openmm.unit')
        ionic_strength = puw.convert(ionic_strength, to_form='openmm.unit')

        modeller = convert(molecular_system, to_form='openmm.Modeller')
        molecular_mechanics = convert(molecular_system,
                                      to_form='molsysmt.MolecularMechanics')
        parameters = molecular_mechanics.get_openmm_System_parameters()
        forcefield = molecular_mechanics.to_openmm_ForceField()

        solvent_model = None
        if molecular_mechanics.water_model == 'SPC':
            solvent_model = 'tip3p'
        elif molecular_mechanics.water_model in [
                'TIP3P', 'TIP3PFB', 'SPCE', 'TIP4PEW', 'TIP4PFB', 'TIP5P'
        ]:
            solvent_model = molecular_mechanics.water_model.lower()
        else:
            raise NotImplementedError()

        if box_geometry == "truncated octahedral":

            max_size = max(
                max((pos[i] for pos in modeller.positions)) -
                min((pos[i] for pos in modeller.positions)) for i in range(3))
            vectors = Vec3(1.0, 0,
                           0), Vec3(1.0 / 3.0, 2.0 * np.sqrt(2.0) / 3.0,
                                    0.0), Vec3(-1.0 / 3.0,
                                               np.sqrt(2.0) / 3.0,
                                               np.sqrt(6.0) / 3.0)
            box_vectors = [(max_size + clearance) * v for v in vectors]

            modeller.addSolvent(forcefield,
                                model=solvent_model,
                                boxVectors=box_vectors,
                                ionicStrength=ionic_strength,
                                positiveIon=cation,
                                negativeIon=anion)

        elif box_geometry == "rhombic dodecahedral":

            max_size = max(
                max((pos[i] for pos in modeller.positions)) -
                min((pos[i] for pos in modeller.positions)) for i in range(3))
            vectors = Vec3(1.0, 0.0,
                           0.0), Vec3(0.0, 1.0,
                                      0.0), Vec3(0.5, 0.5,
                                                 np.sqrt(2) / 2)
            box_vectors = [(max_size + clearance) * v for v in vectors]

            modeller.addSolvent(forcefield,
                                model=solvent_model,
                                boxVectors=box_vectors,
                                ionicStrength=ionic_strength,
                                positiveIon=cation,
                                negativeIon=anion)

        else:

            modeller.addSolvent(forcefield,
                                model=solvent_model,
                                padding=clearance,
                                ionicStrength=ionic_strength,
                                positiveIon=cation,
                                negativeIon=anion)

        tmp_item = convert(modeller, to_form=to_form)

        del (modeller)

        return tmp_item

    elif engine == "PDBFixer":

        from openmm import Vec3

        clearance = puw.convert(clearance, to_form='openmm.unit')
        ionic_strength = puw.convert(ionic_strength, to_form='openmm.unit')

        pdbfixer = convert(molecular_system, to_form='pdbfixer.PDBFixer')
        max_size = max(
            max((pos[i] for pos in pdbfixer.positions)) -
            min((pos[i] for pos in pdbfixer.positions)) for i in range(3))

        box_size = None
        box_vectors = None

        if box_geometry == "truncated octahedral":

            vectors = Vec3(1.0, 0,
                           0), Vec3(1.0 / 3.0, 2.0 * np.sqrt(2.0) / 3.0,
                                    0.0), Vec3(-1.0 / 3.0,
                                               np.sqrt(2.0) / 3.0,
                                               np.sqrt(6.0) / 3.0)

        elif box_geometry == "rhombic dodecahedral":

            vectors = Vec3(1.0, 0.0,
                           0.0), Vec3(0.0, 1.0,
                                      0.0), Vec3(0.5, 0.5,
                                                 np.sqrt(2) / 2)

        elif box_geometry == "cubic":

            vectors = Vec3(1.0, 0.0, 0.0), Vec3(0.0, 1.0,
                                                0.0), Vec3(0.0, 0.0, 1.0)

        box_vectors = [(max_size + clearance) * v for v in vectors]

        pdbfixer.addSolvent(boxVectors=box_vectors,
                            ionicStrength=ionic_strength,
                            positiveIon=cation,
                            negativeIon=anion)

        tmp_item = convert(pdbfixer, to_form=to_form)

        del (pdbfixer)

        return tmp_item

    elif engine == "LEaP":

        from molsysmt.thirds.tleap import TLeap
        from molsysmt._private.files_and_directories import temp_directory, temp_filename
        from molsysmt.tools.file_pdb import replace_HETATM_by_ATOM_in_terminal_cappings
        from shutil import rmtree, copyfile
        from os import getcwd, chdir
        from molsysmt.basic import set as _set, select
        from molsysmt.build import has_hydrogens, remove_hydrogens

        if has_hydrogens(molecular_system):
            raise ValueError(
                "A molecular system without hydrogen atoms is needed.")
            #molecular_system = remove_hydrogens(molecular_system)
            #if verbose:
            #    print("All Hydrogen atoms were removed to be added by LEaP\n\n")

        indices_NME_C = select(
            molecular_system,
            target='atom',
            selection='group_name=="NME" and atom_name=="C"')
        with_NME_C = (len(indices_NME_C) > 0)

        if with_NME_C:
            _set(molecular_system,
                 target='atom',
                 selection='group_name=="NME" and atom_name=="C"',
                 atom_name='CH3')

        current_directory = getcwd()
        working_directory = temp_directory()
        pdbfile_in = temp_filename(dir=working_directory, extension='pdb')
        _ = convert(molecular_system, to_form=pdbfile_in)
        #replace_HETATM_from_capping_atoms(pdbfile_in)

        tmp_prmtop = temp_filename(dir=working_directory, extension='prmtop')
        tmp_inpcrd = tmp_prmtop.replace('prmtop', 'inpcrd')
        tmp_logfile = tmp_prmtop.replace('prmtop', 'leap.log')

        molecular_mechanics = convert(molecular_system,
                                      to_form='molsysmt.MolecularMechanics')
        parameters = molecular_mechanics.get_leap_parameters()
        forcefield = parameters['forcefield']
        water = parameters['water_model']

        solvent_model = None
        if water == 'SPC':
            solvent_model = 'SPCBOX'
        elif water == 'TIP3P':
            solvent_model = 'TIP3PBOX'
        elif water == 'TIP4P':
            solvent_model = 'TIP4PBOX'

        if verbose:
            print('Working directory:', working_directory)

        tleap = TLeap()
        tleap.load_parameters(*forcefield)
        tleap.load_unit('MolecularSystem', pdbfile_in)
        tleap.check_unit('MolecularSystem')
        tleap.get_total_charge('MolecularSystem')
        tleap.solvate('MolecularSystem',
                      solvent_model,
                      clearance,
                      box_geometry=box_geometry)

        if num_anions != 0:
            if num_anions == 'neutralize':
                num_anions = 0
            tleap.add_ions('MolecularSystem',
                           anion,
                           num_ions=num_anions,
                           replace_solvent=True)

        if num_cations != 0:
            if num_cations == 'neutralize':
                num_cations = 0
            tleap.add_ions('MolecularSystem',
                           cation,
                           num_ions=num_cations,
                           replace_solvent=True)

        tleap.save_unit('MolecularSystem', tmp_prmtop)
        errors = tleap.run(working_directory=working_directory,
                           verbose=verbose)

        del (tleap)

        if logfile:
            copyfile(tmp_logfile, current_directory + '/build_peptide.log')

        tmp_item = convert([tmp_prmtop, tmp_inpcrd], to_form=to_form)

        if with_NME_C:
            _set(tmp_item,
                 target='atom',
                 selection='group_name=="NME" and atom_name=="CH3"',
                 atom_name='C')

        rmtree(working_directory)

        return tmp_item

    else:

        raise NotImplementedError
Esempio n. 16
0
 def testNegation(self):
     vec1 = Vec3(1, 2, 3)
     vec1_neg = Vec3(-1, -2, -3)
     self.assertEqual(-vec1, vec1_neg)
Esempio n. 17
0
 def testVec3Equality(self):
     vec1 = Vec3(1, 2, 3)
     vec2 = Vec3(1, 2, 3)
     self.assertEqual(vec1, vec2)
Esempio n. 18
0
 def testVec3Multiplication(self):
     vec1 = Vec3(1, 2, 3)
     factor = 2
     result = Vec3(2, 4, 6)
     self.assertEqual(vec1 * factor, result)
     self.assertEqual(factor * vec1, result)