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)
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
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)
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
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))
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
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
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
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)
def testVec3Attributes(self): vec1 = Vec3(1, 2, 3) self.assertEqual(vec1.x, 1) self.assertEqual(vec1.y, 2) self.assertEqual(vec1.z, 3)
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)
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)
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
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
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
def testNegation(self): vec1 = Vec3(1, 2, 3) vec1_neg = Vec3(-1, -2, -3) self.assertEqual(-vec1, vec1_neg)
def testVec3Equality(self): vec1 = Vec3(1, 2, 3) vec2 = Vec3(1, 2, 3) self.assertEqual(vec1, vec2)
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)