def addSolvent(universe, solvent, density, scale_factor=4.): """ Scales up the universe and adds as many solvent molecules as are necessary to obtain the specified solvent density, taking account of the solute molecules that are already present in the universe. The molecules are placed at random positions in the scaled-up universe, but without overlaps between any two molecules. :param universe: a finite universe :type universe: :class:~MMTK.Universe.Universe :param solvent: a molecule, or the name of a molecule in the database :type solvent: :class:~MMTK.ChemicalObjects.Molecule or str :param density: the density of the solvent (amu/nm**3) :type density: float :param scale_factor: the factor by which the initial universe is expanded before adding the solvent molecules :type scale_factor: float """ # Calculate number of solvent molecules and universe size if isinstance(solvent, basestring): solvent = ChemicalObjects.Molecule(solvent) cell_volume = universe.cellVolume() if cell_volume is None: raise TypeError("universe volume is undefined") solute = copy.copy(universe._objects) solute_volume = 0. excluded_regions = [] for o in solute: solute_volume = solute_volume + surfaceAndVolume(o)[1] excluded_regions.append(o.boundingSphere()) n_solvent = int( round(density * (cell_volume - solute_volume) / solvent.mass())) solvent_volume = n_solvent * solvent.mass() / density cell_volume = solvent_volume + solute_volume universe.translateBy(-solute.position()) universe.scaleSize((cell_volume / universe.cellVolume())**(1. / 3.)) # Scale up the universe and add solvent molecules at random positions universe.scaleSize(scale_factor) universe.scale_factor = scale_factor for i in range(n_solvent): m = copy.copy(solvent) m.translateTo(universe.randomPoint()) while True: s = m.boundingSphere() collision = False for region in excluded_regions: if (s.center - region.center).length() < s.radius + region.radius: collision = True break if not collision: break m.translateTo(universe.randomPoint()) universe.addObject(m) excluded_regions.append(s)
def write(self, object, configuration = None, tag = None): """ Write an object to the file :param object: the object to be written :type object: :class:~MMTK.Collections.GroupOfAtoms :param configuration: the configuration from which the coordinates are taken (default: current configuration) :type configuration: :class:~MMTK.ParticleProperties.Configuration """ if not ChemicalObjects.isChemicalObject(object): for o in object: self.write(o, configuration) else: toplevel = tag is None if toplevel: tag = Utility.uniqueAttribute() if hasattr(object, 'pdbmap'): for residue in object.pdbmap: self.file.nextResidue(residue[0], ) sorted_atoms = residue[1].items() sorted_atoms.sort(lambda x, y: cmp(x[1].number, y[1].number)) for atom_name, atom in sorted_atoms: atom = object.getAtom(atom) p = atom.position(configuration) if Utility.isDefinedPosition(p): try: occ = atom.occupancy except AttributeError: occ = 0. try: temp = atom.temperature_factor except AttributeError: temp = 0. self.file.writeAtom(atom_name, p/Units.Ang, occ, temp, atom.type.symbol) self.atom_sequence.append(atom) else: self.warning = True setattr(atom, tag, None) else: if hasattr(object, 'is_protein'): for chain in object: self.write(chain, configuration, tag) elif hasattr(object, 'is_chain'): self.file.nextChain(None, object.name) for residue in object: self.write(residue, configuration, tag) self.file.terminateChain() elif hasattr(object, 'molecules'): for m in object.molecules: self.write(m, configuration, tag) elif hasattr(object, 'groups'): for g in object.groups: self.write(g, configuration, tag) if toplevel: for a in object.atomList(): if not hasattr(a, tag): self.write(a, configuration, tag) delattr(a, tag)
def write(self, object, configuration = None, tag = None): """ Write an object to the file :param object: the object to be written :type object: :class:`~MMTK.Collections.GroupOfAtoms` :param configuration: the configuration from which the coordinates are taken (default: current configuration) :type configuration: :class:`~MMTK.ParticleProperties.Configuration` """ if not ChemicalObjects.isChemicalObject(object): for o in object: self.write(o, configuration) else: toplevel = tag is None if toplevel: tag = Utility.uniqueAttribute() if hasattr(object, 'pdbmap'): for residue in object.pdbmap: self.file.nextResidue(residue[0], ) sorted_atoms = residue[1].items() sorted_atoms.sort(lambda x, y: cmp(x[1].number, y[1].number)) for atom_name, atom in sorted_atoms: atom = object.getAtom(atom) p = atom.position(configuration) if Utility.isDefinedPosition(p): try: occ = atom.occupancy except AttributeError: occ = 0. try: temp = atom.temperature_factor except AttributeError: temp = 0. self.file.writeAtom(atom_name, p/Units.Ang, occ, temp, atom.type.symbol) self.atom_sequence.append(atom) else: self.warning = True setattr(atom, tag, None) else: if hasattr(object, 'is_protein'): for chain in object: self.write(chain, configuration, tag) elif hasattr(object, 'is_chain'): self.file.nextChain(None, object.name) for residue in object: self.write(residue, configuration, tag) self.file.terminateChain() elif hasattr(object, 'molecules'): for m in object.molecules: self.write(m, configuration, tag) elif hasattr(object, 'groups'): for g in object.groups: self.write(g, configuration, tag) if toplevel: for a in object.atomList(): if not hasattr(a, tag): self.write(a, configuration, tag) delattr(a, tag)
def createGroups(self, mapping): groups = [] for name in self.molecules.keys(): full_name = mapping.get(name, None) if full_name is not None: for molecule in self.molecules[name]: g = ChemicalObjects.Group(full_name) setConfiguration(g, [molecule], toplevel=0) groups.append(g) return groups
def makeChemicalObjects(self, template, top_level): self.groups[template.name].locked = True if top_level: if template.attributes.has_key('sequence'): object = ChemicalObjects.ChainMolecule(None) else: object = ChemicalObjects.Molecule(None) else: object = ChemicalObjects.Group(None) object.atoms = [] object.bonds = Bonds.BondList([]) object.groups = [] object.type = self.groups[template.name] object.parent = None child_objects = [] for child in template.children: if isinstance(child, GroupTemplate): group = self.makeChemicalObjects(child, False) object.groups.append(group) object.atoms.extend(group.atoms) object.bonds.extend(group.bonds) group.parent = object child_objects.append(group) else: atom = ChemicalObjects.Atom(child.element) object.atoms.append(atom) atom.parent = object child_objects.append(atom) for name, index in template.names.items(): setattr(object, name, child_objects[index]) child_objects[index].name = name for name, value in template.attributes.items(): path = name.split('.') setattr(self.namePath(object, path[:-1]), path[-1], value) for atom1, atom2 in template.bonds: atom1 = self.namePath(object, atom1) atom2 = self.namePath(object, atom2) object.bonds.append(Bonds.Bond((atom1, atom2))) for name, vector in template.positions.items(): path = name.split('.') self.namePath(object, path).setPosition(vector) return object
def createMolecule(self, name=None): """ :returns: a :class:~MMTK.ChemicalObjects.Molecule object corresponding to the molecule in the PDB file. The parameter name specifies the molecule name as defined in the chemical database. It can be left out for known molecules (currently only water). :rtype: :class:~MMTK.ChemicalObjects.Molecule """ if name is None: name = molecule_names[self.name] m = ChemicalObjects.Molecule(name) setConfiguration(m, [self]) return m
def numberOfSolventMolecules(universe, solvent, density): """ :param universe: a finite universe :type universe: :class:`~MMTK.Universe.Universe` :param solvent: a molecule, or the name of a molecule in the database :type solvent: :class:`~MMTK.ChemicalObjects.Molecule` or str :param density: the density of the solvent (amu/nm**3) :type density: float :returns: the number of solvent molecules that must be added to the universe, in addition to whatever it already contains, to obtain the given solvent density. :rtype: int """ if isinstance(solvent, basestring): solvent = ChemicalObjects.Molecule(solvent) cell_volume = universe.cellVolume() if cell_volume is None: raise TypeError("universe volume is undefined") solute_volume = 0. for o in universe._objects: solute_volume = solute_volume + surfaceAndVolume(o)[1] return int(round(density*(cell_volume-solute_volume)/solvent.mass()))
def __init__(self, *items, **properties): """ :param items: either a sequence of peptide chain objects, or a string, which is interpreted as the name of a database definition for a protein. If that definition does not exist, the string is taken to be the name of a PDB file, from which all peptide chains are constructed and assembled into a protein. :keyword model: one of "all" (all-atom), "no_hydrogens" or "none" (no hydrogens),"polar_hydrogens" or "polar" (united-atom with only polar hydrogens), "polar_charmm" (like "polar", but defining polar hydrogens like in the CHARMM force field), "polar_opls" (like "polar", but defining polar hydrogens like in the latest OPLS force field), "calpha" (only the |C_alpha| atom of each residue). Default is "all". :type model: str :keyword position: the center-of-mass position of the protein :type position: Scientific.Geometry.Vector :keyword name: a name for the protein :type name: str """ if items == (None,): return self.name = '' if len(items) == 1 and type(items[0]) == type(''): try: filename = Database.databasePath(items[0], 'Proteins') found = 1 except IOError: found = 0 if found: blueprint = Database.BlueprintProtein(items[0]) items = blueprint.chains for attr, value in vars(blueprint).items(): if attr not in ['type', 'chains']: setattr(self, attr, value) else: import PDB conf = PDB.PDBConfiguration(items[0]) model = properties.get('model', 'all') items = conf.createPeptideChains(model) molecules = [] for i in items: if ChemicalObjects.isChemicalObject(i): molecules.append(i) else: molecules = molecules + list(i) for m, i in zip(molecules, range(len(molecules))): m._numbers = [i] if not m.name: m.name = 'chain'+`i` ss = self._findSSBridges(molecules) new_mol = {} for m in molecules: new_mol[m] = ([m],[]) for bond in ss: m1 = new_mol[bond[0].topLevelChemicalObject()] m2 = new_mol[bond[1].topLevelChemicalObject()] if m1 == m2: m1[1].append(bond) else: combined = (m1[0] + m2[0], m1[1] + m2[1] + [bond]) for m in combined[0]: new_mol[m] = combined self.molecules = [] while new_mol: m = new_mol.values()[0] for i in m[0]: del new_mol[i] bonds = m[1] if len(m[0]) == 1: m = m[0][0] m._addSSBridges(bonds) else: numbers = sum((i._numbers for i in m[0]), []) m = ConnectedChains(m[0]) m._numbers = numbers m._addSSBridges(bonds) m._finalize() for c in m: c.parent = self m.parent = self self.molecules.append(m) self.atoms = [] self.chains = [] for m in self.molecules: self.atoms.extend(m.atoms) if hasattr(m, 'is_connected_chains'): for c, name, i in zip(range(len(m)), m.chain_names, m._numbers): self.chains.append((m, c, name, i)) else: try: name = m.name except AttributeError: name = '' self.chains.append((m, None, name, m._numbers[0])) self.chains.sort(lambda c1, c2: cmp(c1[3], c2[3])) self.chains = map(lambda c: c[:3], self.chains) self.parent = None self.type = None self.configurations = {} try: self.name = properties['name'] del properties['name'] except KeyError: pass if properties.has_key('position'): self.translateTo(properties['position']) del properties['position'] self.addProperties(properties) undefined = 0 for a in self.atoms: if a.position() is None: undefined += 1 if undefined > 0 and undefined != len(self.atoms): Utility.warning('Some atoms in a protein ' + 'have undefined positions.')
def createMolecules(self, names = None, permit_undefined=True): """ :param names: If a list of molecule names (as defined in the chemical database) and/or PDB residue names, only molecules mentioned in this list will be constructed. If a dictionary, it is used to map PDB residue names to molecule names. With the default (None), only water molecules are built. :type names: list :param permit_undefined: If False, an exception is raised when a PDB residue is encountered for which no molecule name is supplied in names. If True, an AtomCluster object is constructed for each unknown molecule. :returns: a collection of :class:~MMTK.ChemicalObjects.Molecule objects, one for each molecule in the PDB file. Each PDB residue not describing an amino acid or nucleotide residue is considered a molecule. :rtype: :class:~MMTK.Collections.Collection """ collection = Collections.Collection() mol_dicts = [molecule_names] if type(names) == type({}): mol_dicts.append(names) names = None for name in self.molecules.keys(): full_name = None for dict in mol_dicts: full_name = dict.get(name, None) if names is None or name in names or full_name in names: if full_name is None and not permit_undefined: raise ValueError("no definition for molecule " + name) for molecule in self.molecules[name]: if full_name: m = ChemicalObjects.Molecule(full_name) setConfiguration(m, [molecule]) else: pdbdict = {} atoms = [] i = 0 for atom in molecule: aname = atom.name while aname[0] in string.digits: aname = aname[1:] + aname[0] try: element = atom['element'].strip() a = ChemicalObjects.Atom(element, name = aname) except KeyError: try: a = ChemicalObjects.Atom(aname[:2].strip(), name = aname) except IOError: a = ChemicalObjects.Atom(aname[:1], name = aname) a.setPosition(atom.position) atoms.append(a) pdbdict[atom.name] = Database.AtomReference(i) i += 1 m = ChemicalObjects.AtomCluster(atoms, name = name) if len(pdbdict) == len(molecule): # pdbmap is correct only if the AtomCluster has # unique atom names m.pdbmap = [(name, pdbdict)] setConfiguration(m, [molecule]) collection.addObject(m) return collection