def mol_to_parmed(mol): """ Convert MDT Molecule to parmed Structure Args: mol (moldesign.Molecule): Returns: parmed.Structure """ struc = parmed.Structure() struc.title = mol.name pmedatoms = [] for atom in mol.atoms: pmedatm = parmed.Atom(atomic_number=atom.atomic_number, name=atom.name, mass=atom.mass.value_in(u.dalton), number=utils.if_not_none(atom.pdbindex, -1)) pmedatm.xx, pmedatm.xy, pmedatm.xz = atom.position.value_in(u.angstrom) pmedatoms.append(pmedatm) struc.add_atom(pmedatm, resname=utils.if_not_none(atom.residue.resname, 'UNL'), resnum=utils.if_not_none(atom.residue.pdbindex, -1), chain=utils.if_not_none(atom.chain.name, '')) for bond in mol.bonds: struc.bonds.append(parmed.Bond(pmedatoms[bond.a1.index], pmedatoms[bond.a2.index], order=bond.order)) return struc
def mol_to_parmed(mol): """ Convert MDT Molecule to parmed Structure Args: mol (moldesign.Molecule): Returns: parmed.Structure """ struc = parmed.Structure() struc.title = mol.name pmedatoms = [] for atom in mol.atoms: pmedatm = parmed.Atom(atomic_number=atom.atomic_number, name=atom.name, mass=atom.mass.value_in(u.dalton), number=utils.if_not_none(atom.pdbindex, -1)) pmedatm.xx, pmedatm.xy, pmedatm.xz = atom.position.value_in(u.angstrom) pmedatoms.append(pmedatm) struc.add_atom(pmedatm, resname=utils.if_not_none(atom.residue.resname, 'UNL'), resnum=utils.if_not_none(atom.residue.pdbindex, -1), chain=utils.if_not_none(atom.chain.name, '')) for bond in mol.bonds: struc.bonds.append( parmed.Bond(pmedatoms[bond.a1.index], pmedatoms[bond.a2.index], order=bond.order)) return struc
def run_job(job, engine=None, image=None, wait=True, jobname=None, display=True, _return_result=False): """ Helper for running jobs. Args: job (pyccc.Job): The job to run engine (pyccc.Engine): Engine to run this job on (default: ``moldesign.compute.get_engine()``) image (str): URL for the docker image wait (bool): if True, block until this function completes and return the function's return value. Otherwise, return a job object immediately that can be queried later. display (bool): if True, show logging output for this job Returns: pyccc job object OR function's return value """ engine = utils.if_not_none(engine, mdt.compute.get_engine()) if engine is None: raise ValueError('No compute engine configured! Configure MDT using ' 'moldesign.compute.config') engine.submit(job) jobname = utils.if_not_none(jobname, job.name) if display: mdt.uibase.display_log(job.get_display_object(), jobname) if wait: job.wait() if _return_result: return job.result return job
def wrapper(*args, **kwargs): """ Wraps a python function so that it will be executed remotely using a compute engine Note: At runtime, this documentation should be replaced with that of the wrapped function """ # If the wrapper is not enabled, just run the wrapped function as normal. f = func # keeps a reference to the original function in this closure if not wrapper.enabled: return f(*args, **kwargs) wait = kwargs.get('wait', True) # Bind instance methods to their objects if self.is_imethod: f, args = _bind_instance_method(f, args) # Submit job to remote engine python_call = bpy.PythonCall(f, *args, **kwargs) image = utils.if_not_none(self.image, configuration.config.default_python_image) engine = utils.if_not_none(self.engine, mdt.compute.get_engine()) job = bpy.PythonJob(engine, image, python_call, name=self.jobname, sendsource=self.sendsource) if self.display: uibase.display_log(job.get_display_object(), title=f.__name__) if wait: job.wait() return job.result else: return job
def __init__(self, name, short_description=None, type=None, default=None, choices=None, select_multiple=False, help_url=None): """ A method's parameter :param default: the default value. If this does not match any spec in choices, it must be set. :param choices: A list of allowable values for the parameter :param types: a list of types for the parameter (does not check choices if parameter is one of these types) :param number: Number of values (>1 should be passed in list). '+' indicates arbitrary list size :return: """ self.name = name self.displayname = if_not_none(short_description, name) self.value = None self.default = default self.choices = if_not_none(choices, []) self.type = type self.help_url = help_url if isinstance(type, u.MdtQuantity): type = type.units if isinstance(type, u.MdtUnit): self.type = float self.units = type else: self.units = None self.select_multiple = select_multiple
def __init__(self, name=None, atnum=None, mass=None, chain=None, residue=None, formal_charge=None, pdbname=None, pdbindex=None, element=None, metadata=None): # Allow user to instantiate an atom as Atom(6) or Atom('C') if atnum is None and element is None: if isinstance(name, int): atnum = name name = None else: element = name if element: self.atnum = data.ATOMIC_NUMBERS[element] else: self.atnum = atnum self.name = utils.if_not_none(name, self.elem) self.pdbname = utils.if_not_none(pdbname, self.name) self.pdbindex = pdbindex if mass is None: self.mass = data.ATOMIC_MASSES[self.atnum] else: self.mass = mass self.formal_charge = utils.if_not_none(formal_charge, 0.0 * u.q_e) self.residue = residue self.chain = chain self.molecule = None self.index = None self._position = np.zeros(3) * u.default.length self._momentum = np.zeros(3) * (u.default.length* u.default.mass/u.default.time) self._bond_graph = {} self.metadata = mdt.utils.DotDict() if metadata: self.metadata.update(metadata)
def __init__(self, mol, unit_system=None, first_frame=False, name=None): self._init = True self.info = "Trajectory" self.frames = [] self.mol = mol self.unit_system = utils.if_not_none(unit_system, mdt.units.default) self.properties = utils.DotDict() self._reset() self._tempmol.dynamic_dof = self.mol.dynamic_dof self.name = utils.if_not_none(name, 'untitled') if first_frame: self.new_frame()
def __init__(self, mol, unit_system=None, first_frame=False, name=None): self._init = True self.info = "Trajectory" self.frames = [] self.mol = mol self.unit_system = utils.if_not_none(unit_system, mdt.units.default) self.properties = utils.DotDict() self._tempmol = mdt.Molecule(self.mol.atoms, copy_atoms=True) self._tempmol.dynamic_dof = self.mol.dynamic_dof self._viz = None self._atoms = None self.name = utils.if_not_none(name, 'untitled') if first_frame: self.new_frame()
def _antechamber_calc_charges(mol, ambname, chargename, kwargs): charge = utils.if_not_none(mol.charge, 0) command = 'antechamber -fi mol2 -i mol.mol2 -fo mol2 -o out.mol2 -c %s -an n'%ambname if charge != 0: command += ' -nc %d' % charge.value_in(u.q_e) def finish_job(job): """Callback to complete the job""" lines = iter(job.get_output('out.mol2').read().split('\n')) charges = utils.DotDict(type='atomic') line = lines.next() while line.strip()[:len('@<TRIPOS>ATOM')] != '@<TRIPOS>ATOM': line = lines.next() line = lines.next() while line.strip()[:len('@<TRIPOS>BOND')] != '@<TRIPOS>BOND': fields = line.split() idx = int(fields[0])-1 assert mol.atoms[idx].name == fields[1] charges[mol.atoms[idx]] = u.q_e*float(fields[-1]) line = lines.next() mol.properties[chargename] = charges return charges job = pyccc.Job(image=mdt.compute.get_image_path(IMAGE), command=command, name="%s, %s" % (chargename, mol.name), inputs={'mol.mol2': mol.write(format='mol2')}, when_finished=finish_job) return compute.run_job(job, _return_result=True, **kwargs)
def run_nbo(mol, requests=('nlmo', 'nbo'), image='nbo', engine=None): wfn = mol.wfn inputs = {'in.47': make_nbo_input_file(mol, requests)} command = 'gennbo.i4.exe in.47' engine = utils.if_not_none(engine, mdt.compute.config.get_engine()) imagename = mdt.compute.get_image_path(image) job = engine.launch(imagename, command, inputs=inputs, name="nbo, %s" % mol.name) moldesign.uibase.display_log(job.get_display_object(), "nbo, %s" % mol.name) job.wait() parsed_data = parse_nbo(job.get_output('FILE.10'), len(mol.wfn.aobasis)) for orbtype, data in parsed_data.iteritems(): if orbtype[0] == 'P': # copy data from the orthogonal orbitals orthdata = parsed_data[orbtype[1:]] for key in 'bond_names iatom jatom stars bondnums num_bonded_atoms'.split( ): data[key] = orthdata[key] data.occupations = [None for orb in data.coeffs] add_orbitals(mol, wfn, data, orbtype) wfn._nbo_job = job
def __init__(self, paramlist, paramdefs, title=None): super(Configurator, self).__init__(layout=ipy.Layout(display='flex', flex_flow='column', align_self='flex-start', align_items='stretch', max_width='100%')) self.paramlist = paramlist self.paramdefs = paramdefs self.apply_button = ipy.Button(description='Apply') self.apply_button.on_click(self.apply_values) self.reset_button = ipy.Button(description='Reset') self.reset_button.on_click(self.reset_values) self.buttons = ipy.Box([self.reset_button, self.apply_button], layout=ipy.Layout(align_self='center')) self.selectors = collections.OrderedDict([(p.name, ParamSelector(p)) for p in paramdefs]) self.reset_values() title = utils.if_not_none(title, 'Configuration') self.title = ipy.HTML('<center><h4>%s</h4></center><hr>' % title, align_self='center') self.currentconfig = ipy.Textarea(description='Current params:', disabled=True, value=str(paramlist).replace(', ', ',\n '), width='350px') self.middle = ipy.HBox([ipy.VBox(self.selectors.values()), self.currentconfig]) self.children = [self.title, self.middle, self.buttons]
def __init__(self, paramlist, paramdefs, title=None): super(Configurator, self).__init__(layout=ipy.Layout(display='flex', flex_flow='column', align_self='flex-start', align_items='stretch', max_width='100%')) self.paramlist = paramlist self.paramdefs = paramdefs self.apply_button = ipy.Button(description='Apply') self.apply_button.on_click(self.apply_values) self.reset_button = ipy.Button(description='Reset') self.reset_button.on_click(self.reset_values) self.buttons = ipy.Box([self.reset_button, self.apply_button], layout=ipy.Layout(align_self='center')) self.selectors = collections.OrderedDict([(p.name, ParamSelector(p)) for p in paramdefs]) self.reset_values() title = utils.if_not_none(title, 'Configuration') self.title = ipy.HTML('<center><h4>%s</h4></center><hr>' % title, align_self='center') self.currentconfig = ipy.Textarea(description='<i>Current params</i>', disabled=True, value=self._pretty_print_config(), layout=ipy.Layout(width='350px', min_height='300px', max_height='500px', display='flex', flex_flow='column')) self.middle = HBox([VBox(list(self.selectors.values())), self.currentconfig]) self.children = [self.title, self.middle, self.buttons]
def run_nbo(mol, requests=('nlmo', 'nbo'), image='nbo', engine=None): wfn = mol.wfn inputs = {'in.47': make_nbo_input_file(mol, requests)} command = 'gennbo.i4.exe in.47' engine = utils.if_not_none(engine, mdt.compute.config.get_engine()) imagename = mdt.compute.get_image_path(image) job = engine.launch(imagename, command, inputs=inputs, name="nbo, %s" % mol.name) moldesign.uibase.display_log(job.get_display_object(), "nbo, %s"%mol.name) job.wait() parsed_data = parse_nbo(job.get_output('FILE.10'), len(mol.wfn.aobasis)) for orbtype, data in parsed_data.iteritems(): if orbtype[0] == 'P': # copy data from the orthogonal orbitals orthdata = parsed_data[orbtype[1:]] for key in 'bond_names iatom jatom stars bondnums num_bonded_atoms'.split(): data[key] = orthdata[key] data.occupations = [None for orb in data.coeffs] add_orbitals(mol, wfn, data, orbtype) wfn._nbo_job = job
def am1_bcc_charges(mol, minsteps=None, wait=True): """ Doesn't work yet ...""" charge = utils.if_not_none(mol.charge, 0) engine = mdt.compute.get_engine() image = compute.get_image_path(IMAGE, engine) command = 'antechamber -fi pdb -i mol.pdb -fo mol2 -o out.mol2 -c bcc -an n' if charge != 0: command += ' -nc %d' % charge if minsteps is not None: command += ' -ek "maxcyc=%d"' % minsteps def parse_mol2(job): """Callback to complete the job""" atom_info = utils.DotDict(job=job) lines = iter(job.get_output('out.mol2').read().split('\n')) while True: line = lines.next() fields = line.split() if fields[0] == 'ATOM': idx = int(fields[1]) - 1 name = fields[2] assert mol.atoms[idx].name == name atom_info[mol.atoms[idx]] = utils.DotDict(partialcharge=u.q_e * float(fields[-2]), atomtype=fields[-1]) return atom_info job = engine.launch(image, command=command, name="am1-bcc, %s" % mol.name, inputs={'mol.pdb': mol.write(format='pdb')}, when_finished=parse_mol2) uibase.display_log(job.get_display_object(), job.name) if not wait: return job() else: job.wait()
def _highlight_atoms(self, atoms, color=None): color = utils.if_not_none(color, self.viewer.HIGHLIGHT_COLOR) self._highlighted_atoms += atoms self.viewer.add_style('vdw', atoms=atoms, radius=self.viewer.ATOMRADIUS * 1.1, color=color, opacity=self.HIGHLIGHTOPACITY)
def _antechamber_calc_charges(mol, ambname, chargename, kwargs): charge = utils.if_not_none(mol.charge, 0) command = 'antechamber -fi mol2 -i mol.mol2 -fo mol2 -o out.mol2 -c %s -an n' % ambname if charge != 0: command += ' -nc %d' % charge.value_in(u.q_e) def finish_job(job): """Callback to complete the job""" lines = iter(job.get_output('out.mol2').read().split('\n')) charges = utils.DotDict(type='atomic') line = lines.next() while line.strip()[:len('@<TRIPOS>ATOM')] != '@<TRIPOS>ATOM': line = lines.next() line = lines.next() while line.strip()[:len('@<TRIPOS>BOND')] != '@<TRIPOS>BOND': fields = line.split() idx = int(fields[0]) - 1 assert mol.atoms[idx].name == fields[1] charges[mol.atoms[idx]] = u.q_e * float(fields[-1]) line = lines.next() mol.properties[chargename] = charges return charges job = pyccc.Job(image=mdt.compute.get_image_path(IMAGE), command=command, name="%s, %s" % (chargename, mol.name), inputs={'mol.mol2': mol.write(format='mol2')}, when_finished=finish_job) return compute.run_job(job, _return_result=True, **kwargs)
def unset_color(self, atoms=None, _store=True): if _store: for atom in utils.if_not_none(atoms, self.mol.atoms): self._colored_as.pop(atom, None) result = super(GeometryViewer, self).unset_color(atoms=atoms) if self.atom_highlights: self._redraw_highlights() return result
def unset_color(self, atoms=None, _store=True): if _store: for atom in utils.if_not_none(atoms, self.mol.atoms): self._colored_as.pop(atom, None) result = super(GeometryViewer, self).unset_color(atoms=atoms) if self.atom_highlights: self._redraw_highlights() return result
def _highlight_atoms(self, atoms, color=None): color = utils.if_not_none(color, self.viewer.HIGHLIGHT_COLOR) self._highlighted_atoms += atoms self.viewer.add_style('vdw', atoms=atoms, radius=self.viewer.ATOMRADIUS * 1.1, color=color, opacity=self.HIGHLIGHTOPACITY)
def __init__(self, atomcontainer, name=None, bond_graph=None, copy_atoms=False, pdbname=None, charge=0): # NEW_FEATURE: deal with random number generators per-geometry # NEW_FEATURE: per-geometry output logging super(Molecule, self).__init__() # copy atoms from another object (i.e., a molecule) oldatoms = helpers.get_all_atoms(atomcontainer) if copy_atoms or (oldatoms[0].molecule is not None): #print 'INFO: Copying atoms into new molecule' atoms = oldatoms.copy() if name is None: # Figure out a reasonable name if oldatoms[0].molecule is not None: name = oldatoms[0].molecule.name + ' copy' elif hasattr(atomcontainer, 'name') and isinstance( atomcontainer.name, str): name = utils.if_not_none(name, atomcontainer.name + ' copy') else: name = 'unnamed' else: atoms = oldatoms self.atoms = atoms self.time = 0.0 * u.default.time self.name = 'uninitialized molecule' self._defres = None self._defchain = None self.pdbname = pdbname self.charge = charge self.constraints = [] self.energy_model = None self.integrator = None # Builds the internal memory structures self.chains = Instance(molecule=self) self.residues = [] self._rebuild_topology(bond_graph=bond_graph) if name is not None: self.name = name elif not self.is_small_molecule: self.name = 'unnamed macromolecule' else: self.name = self.get_stoichiometry() self._properties = MolecularProperties(self) self.ff = utils.DotDict()
def __init__(self, mol, unit_system=None, first_frame=False): self._init = True self.info = "Trajectory" self.frames = [] self.mol = mol self.unit_system = utils.if_not_none(unit_system, mdt.units.default) self._property_keys = None self._tempmol = mdt.Molecule(self.mol.atoms, copy_atoms=True) self._tempmol.dynamic_dof = self.mol.dynamic_dof self._viz = None self.atoms = [_TrajAtom(self, i) for i in xrange(self.mol.num_atoms)] if first_frame: self.new_frame()
def run_job(job, engine=None, image=None, wait=True, jobname=None, display=True, _return_result=False): """ Helper for running jobs. Args: job (pyccc.Job): The job to run engine (pyccc.Engine): Engine to run this job on (default: ``moldesign.compute.get_engine()``) image (str): URL for the docker image wait (bool): if True, block until this function completes and return the function's return value. Otherwise, return a job object immediately that can be queried later. display (bool): if True, show logging output for this job Returns: pyccc job object OR function's return value """ engine = utils.if_not_none(engine, mdt.compute.get_engine()) if engine is None: raise ValueError('No compute engine configured! Configure MDT using ' 'moldesign.compute.config') engine.submit(job) jobname = utils.if_not_none(jobname, job.name) if display: mdt.uibase.display_log(job.get_display_object(), jobname) if wait: job.wait() if _return_result: return job.result return job
def __init__(self, name, short_description=None, type=None, default=None, choices=None, help_url=None, relevance=None): self.name = name self.displayname = utils.if_not_none(short_description, name) self.value = None self.default = default self.choices = utils.if_not_none(choices, []) self.type = type self.help_url = help_url if isinstance(type, u.MdtQuantity): type = type.units if isinstance(type, u.MdtUnit): self.type = float self.units = type else: self.units = None self.relevance = relevance
def rotate(self, angle, axis, center=None): """Rotate this object in 3D space Args: angle (u.Scalar[angle]): angle to rotate by axis (u.Vector[length]): axis to rotate about (len=3) center (u.Vector[length]): center of rotation (len=3) (default: origin) """ center = utils.if_not_none(center, self.com) if hasattr(angle, 'units'): angle = angle.value_in(u.radians) rotmat = external.transformations.rotation_matrix(angle, axis, point=center) self.transform(rotmat)
def __init__(self, name=None, atnum=None, mass=None, chain=None, residue=None, formal_charge=None, pdbname=None, pdbindex=None, element=None): # Allow user to instantiate an atom as Atom(6) or Atom('C') if atnum is None and element is None: if isinstance(name, int): atnum = name name = None else: element = name if element: self.atnum = data.ATOMIC_NUMBERS[element] else: self.atnum = atnum self.name = utils.if_not_none(name, self.elem) self.pdbname = utils.if_not_none(pdbname, self.name) self.pdbindex = pdbindex if mass is None: self.mass = data.ATOMIC_MASSES[self.atnum] else: self.mass = mass self.formal_charge = utils.if_not_none(formal_charge, 0.0 * u.q_e) self.residue = residue self.chain = chain self.molecule = None self.index = None self._position = np.zeros(3) * u.default.length self._momentum = np.zeros(3) * (u.default.length * u.default.mass / u.default.time) self._bond_graph = {}
def rotate(self, angle, axis, center=None): """Rotate this object in 3D space Args: angle (u.Scalar[angle]): angle to rotate by axis (u.Vector[length]): axis to rotate about (len=3) center (u.Vector[length]): center of rotation (len=3) (default: origin) """ center = utils.if_not_none(center, self.com) if hasattr(angle, 'units'): angle = angle.value_in(u.radians) rotmat = external.transformations.rotation_matrix(angle, axis, point=center) self.transform(rotmat)
def name_to_smiles(name, image='opsin', engine=None): command = 'opsin -osmi input.txt output.txt' # TODO: this boilerplate has to go engine = utils.if_not_none(engine, mdt.compute.get_engine()) imagename = mdt.compute.get_image_path(image) job = engine.launch(imagename, command, inputs={'input.txt': name + '\n'}, name="opsin, %s" % name) mdt.uibase.display_log(job.get_display_object(), "opsin, %s"%name) job.wait() return job.get_output('output.txt').read().strip()
def _get_initializing_atoms(self, atomcontainer, name, copy_atoms): """ Make a copy of the passed atoms as necessary, return the name of the molecule """ # copy atoms from another object (i.e., a molecule) oldatoms = helpers.get_all_atoms(atomcontainer) if copy_atoms or (oldatoms[0].molecule is not None): atoms = oldatoms.copy_atoms() if name is None: # Figure out a reasonable name if oldatoms[0].molecule is not None: name = oldatoms[0].molecule.name+' copy' elif hasattr(atomcontainer, 'name') and isinstance(atomcontainer.name, str): name = utils.if_not_none(name, atomcontainer.name+' copy') else: name = 'unnamed' else: atoms = oldatoms return atoms, name
def _get_initializing_atoms(self, atomcontainer, name, copy_atoms): """ Make a copy of the passed atoms as necessary, return the name of the molecule """ # copy atoms from another object (i.e., a molecule) oldatoms = helpers.get_all_atoms(atomcontainer) if copy_atoms or (oldatoms[0].molecule is not None): atoms = oldatoms.copy() if name is None: # Figure out a reasonable name if oldatoms[0].molecule is not None: name = oldatoms[0].molecule.name+' copy' elif hasattr(atomcontainer, 'name') and isinstance(atomcontainer.name, str): name = utils.if_not_none(name, atomcontainer.name+' copy') else: name = 'unnamed' else: atoms = oldatoms return atoms, name
def colormap(self, atomvalues, atoms=None, mplmap='auto', categorical=None, save=True): """ Color atoms according to categorical or numeric data Args: atomvalues (callable OR list or str): Either: - a callable that takes an atom and the data, - a list of values of each atom - the name of an atomic property (e.g., 'residue' or 'mass') atoms (moldesign.molecules.AtomContainer): atoms to color (default: self.mol.atoms) mplmap (str): name of the matplotlib colormap to use if colors aren't explicitly specified) categorical (bool): If None (the default), automatically detect whether the data is categorical or numerical. Otherwise, use this flag to force interpretation of the data as categorical (True) or numerical (False) save (bool): permanently color theses atoms this way (until self.unset_color is called) Returns: dict: mapping of categories to colors """ atoms = utils.if_not_none(atoms, self.mol.atoms) if isinstance(atomvalues, basestring): # shortcut to use strings to access atom attributes, i.e. "ff.partial_charge" attrs = atomvalues.split('.') atomvalues = [] for atom in atoms: obj = atom for attr in attrs: obj = getattr(obj, attr) atomvalues.append(obj) elif callable(atomvalues): atomvalues = list(map(atomvalues, atoms)) colors = colormaps.colormap(atomvalues, mplmap=mplmap, categorical=categorical) self.set_colors(colors, atoms=atoms, save=save) return {v: c for v, c in zip(atomvalues, colors)}
def _build_theories(self): if self.params.theory in self.NEEDS_REFERENCE: scf_ref = if_not_none(self.params.scf_reference, 'rhf') reference = self.THEORIES[scf_ref](self.pyscfmol) if 'scf_cycles' in self.params: reference.max_cycle = self.params.scf_cycles reference.callback = StatusLogger( '%s/%s reference procedure:' % (scf_ref, self.params.basis), ['cycle', 'e_tot'], self.logger) else: reference = None theory = self.THEORIES[self.params.theory](self.pyscfmol) theory.callback = StatusLogger( '%s/%s procedure:' % (self.params.theory, self.params.basis), ['cycle', 'e_tot'], self.logger) if 'scf_cycles' in self.params: theory.max_cycle = self.params.scf_cycles return theory, reference
def mol_to_pyscf(mol, basis, symmetry=None, charge=0, positions=None): """Convert an MDT molecule to a PySCF "Mole" object""" pyscfmol = gto.Mole() positions = if_not_none(positions, mol.atoms.position) pyscfmol.atom = [[atom.elem, pos.value_in(u.angstrom)] for atom, pos in zip(mol.atoms, positions)] pyscfmol.basis = basis pyscfmol.charge = charge if symmetry is not None: pyscfmol.symmetry = symmetry with redirect_stderr(StringIO()) as builderr: pyscfmol.build() builderr.seek(0) for line in builderr: if line.strip() == 'Warn: Ipython shell catchs sys.args': continue else: print 'PYSCF: ' + line return pyscfmol
def calc_distance_array(self, other=None): """ Calculate an array of pairwise distance between all atoms in self and other Args: other (AtomContainer): object to calculate distances to (default: self) Returns: u.Array[length]: 2D array of pairwise distances between the two objects Example: >>> dists = self.calc_distance_array(other) >>> dists[i, j] == self.atoms[i].distance(other.atoms[j]) """ other = utils.if_not_none(other, self) try: other_positions = other.positions.value_in(u.ang) except AttributeError: other_positions = np.array([other.position.value_in(u.ang)]) distances = spd.cdist(self.position.value_in(u.ang), other_positions) return distances * u.ang
def highlight_atoms(self, atoms=None): """ Args: atoms (list[Atoms]): list of atoms to highlight. If None, remove all highlights """ # TODO: Need to handle style changes if self.atom_highlights: # first, unhighlight old highlights to_unset = [] for atom in self.atom_highlights: if atom in self._colored_as: self.set_color(atoms=[atom], color=self._colored_as[atom], _store=False) else: to_unset.append(atom) if to_unset: self.atom_highlights = [] self.unset_color(to_unset, _store=False) self.atom_highlights = utils.if_not_none(atoms, []) self._redraw_highlights()
def colormap(self, atomvalues, atoms=None, mplmap='auto', categorical=None, save=True): """ Color atoms according to categorical or numeric data Args: atomvalues (callable OR list or str): Either: - a callable that takes an atom and the data, - a list of values of each atom - the name of an atomic property (e.g., 'residue' or 'mass') atoms (moldesign.molecules.AtomContainer): atoms to color (default: self.mol.atoms) mplmap (str): name of the matplotlib colormap to use if colors aren't explicitly specified) categorical (bool): If None (the default), automatically detect whether the data is categorical or numerical. Otherwise, use this flag to force interpretation of the data as categorical (True) or numerical (False) save (bool): permanently color theses atoms this way (until self.unset_color is called) Returns: dict: mapping of categories to colors """ atoms = utils.if_not_none(atoms, self.mol.atoms) if isinstance(atomvalues, basestring): # shortcut to use strings to access atom attributes, i.e. "ff.partial_charge" attrs = atomvalues.split('.') atomvalues = [] for atom in atoms: obj = atom for attr in attrs: obj = getattr(obj, attr) atomvalues.append(obj) elif callable(atomvalues): atomvalues = list(map(atomvalues, atoms)) colors = colormaps.colormap(atomvalues, mplmap=mplmap, categorical=categorical) self.set_colors(colors, atoms=atoms, save=save) return {v:c for v,c in zip(atomvalues, colors)}
def calc_distance_array(self, other=None): """ Calculate an array of pairwise distance between all atoms in self and other Args: other (AtomContainer): object to calculate distances to (default: self) Returns: u.Array[length]: 2D array of pairwise distances between the two objects Example: >>> dists = self.calc_distance_array(other) >>> dists[i, j] == self.atoms[i].distance(other.atoms[j]) """ from scipy.spatial.distance import cdist other = utils.if_not_none(other, self) try: other_positions = other.positions.defunits_value() except AttributeError: other_positions = np.array([other.position.defunits_value()]) distances = cdist(self.positions.defunits_value(), other_positions) return distances * u.default.length
def highlight_atoms(self, atoms=None): """ Highlight a subset of atoms in the system Args: atoms (list[Atoms]): list of atoms to highlight. If None, remove all highlights """ # TODO: Need to handle style changes if self.atom_highlights: # first, unhighlight old highlights to_unset = [] for atom in self.atom_highlights: if atom in self._colored_as: self.set_color(atoms=[atom], color=self._colored_as[atom], _store=False) else: to_unset.append(atom) if to_unset: self.atom_highlights = [] self.unset_color(to_unset, _store=False) self.atom_highlights = utils.if_not_none(atoms, []) self._redraw_highlights()
def run_symmol(mol, tolerance=0.1 * u.angstrom, image='symmol', engine=None): infile = ['1.0 1.0 1.0 90.0 90.0 90.0', # line 1: indicates XYZ coordinates # line 2: numbers indicate: mass weighted moment of inertia, # tolerance interpretation, tolerance value, # larger tolerance value (not used) '1 0 %f 0.0' % tolerance.value_in(u.angstrom)] for atom in mol.atoms: infile.append(line_writer.write((atom.element, 1, atom.x.value_in(u.angstrom), atom.y.value_in(u.angstrom), atom.z.value_in(u.angstrom), 0.0, 0.0, 0.0))) infile.append('') command = 'symmol < sym.in' inputs = {'sym.in': '\n'.join(infile)} # TODO: this boilerplate has to go engine = utils.if_not_none(engine, mdt.compute.get_engine()) imagename = mdt.compute.get_image_path(image) job = engine.launch(imagename, command, inputs=inputs, name="symmol, %s" % mol.name) mdt.uibase.display_log(job.get_display_object(), "symmol, %s"%mol.name) job.wait() data = parse_output(job.get_output('symmol.out')) symm = mdt.geom.MolecularSymmetry( mol, data.symbol, data.rms, orientation=get_aligned_coords(mol, data), elems=data.elems, job=job) return symm
def highlight_atoms(self, atoms=None, render=True): """ Args: atoms (list[Atoms]): list of atoms to highlight. If None, remove all highlights render (bool): render this change immediately """ # TODO: Need to handle style changes if self.atom_highlights: # first, unhighlight old highlights to_unset = [] for atom in self.atom_highlights: if atom in self._colored_as: self.set_color(atoms=[atom], color=self._colored_as[atom], _store=False, render=False) else: to_unset.append(atom) if to_unset: self.atom_highlights = [] self.unset_color(to_unset, _store=False, render=False) self.atom_highlights = utils.if_not_none(atoms, []) self._redraw_highlights(render=render)
def run_symmol(mol, tolerance=0.1 * u.angstrom, image='symmol', engine=None): infile = [ '1.0 1.0 1.0 90.0 90.0 90.0', # line 1: indicates XYZ coordinates # line 2: numbers indicate: mass weighted moment of inertia, # tolerance interpretation, tolerance value, # larger tolerance value (not used) '1 0 %f 0.0' % tolerance.value_in(u.angstrom) ] for atom in mol.atoms: infile.append( line_writer.write((atom.element, 1, atom.x.value_in(u.angstrom), atom.y.value_in(u.angstrom), atom.z.value_in(u.angstrom), 0.0, 0.0, 0.0))) infile.append('') command = 'symmol < sym.in' inputs = {'sym.in': '\n'.join(infile)} # TODO: this boilerplate has to go engine = utils.if_not_none(engine, mdt.compute.get_engine()) imagename = mdt.compute.get_image_path(image) job = engine.launch(imagename, command, inputs=inputs, name="symmol, %s" % mol.name) mdt.uibase.display_log(job.get_display_object(), "symmol, %s" % mol.name) job.wait() data = parse_output(job.get_output('symmol.out')) symm = mdt.geom.MolecularSymmetry(mol, data.symbol, data.rms, orientation=get_aligned_coords( mol, data), elems=data.elems, job=job) return symm
def _parse_tleap_errors(job, molin): from moldesign.widgets.parameterization import (UnusualBond, UnknownAtom, UnknownResidue, MissingTerms) # TODO: special messages for known problems (e.g. histidine) msg = [] unknown_res = set() # so we can print only one error per unkonwn residue lineiter = iter(job.stdout.split('\n')) offset = utils.if_not_none(molin.residues[0].pdbindex, 1) reslookup = {str(i + offset): r for i, r in enumerate(molin.residues)} def _atom_from_re(s): resname, residx, atomname, atomidx = s r = reslookup[residx] a = r[atomname] return a def unusual_bond(l): atomre1, atomre2 = ATOMSPEC.findall(l) try: a1, a2 = _atom_from_re(atomre1), _atom_from_re(atomre2) except KeyError: a1 = a2 = None r1 = reslookup[atomre1[1]] r2 = reslookup[atomre2[1]] return UnusualBond(l, (a1, a2), (r1, r2)) while True: try: line = lineiter.next() except StopIteration: break fields = line.split() if fields[0:2] == ['Unknown', 'residue:']: # EX: "Unknown residue: 3TE number: 499 type: Terminal/beginning" res = molin.residues[int(fields[4])] unknown_res.add(res) msg.append(UnknownResidue(line, res)) elif fields[:4] == 'Warning: Close contact of'.split(): # EX: "Warning: Close contact of 1.028366 angstroms between .R<DC5 1>.A<HO5' 1> and .R<DC5 81>.A<P 9>" msg.append(unusual_bond(line)) elif fields[:6] == 'WARNING: There is a bond of'.split(): # Matches two lines, EX: # "WARNING: There is a bond of 34.397700 angstroms between:" # "------- .R<DG 92>.A<O3' 33> and .R<DG 93>.A<P 1>" nextline = lineiter.next() msg.append(unusual_bond(line + nextline)) elif fields[:5] == 'Created a new atom named:'.split(): # EX: "Created a new atom named: P within residue: .R<DC5 81>" residue = reslookup[fields[-1][:-1]] if residue in unknown_res: continue # suppress atoms from an unknown res ... atom = residue[fields[5]] msg.append(UnknownAtom(line, residue, atom)) elif (fields[:5] == '** No torsion terms for'.split() or fields[:5] == 'Could not find angle parameter:'.split()): # EX: " ** No torsion terms for ca-ce-c3-hc" msg.append(MissingTerms(line.strip())) return msg
def _parse_tleap_errors(job, molin): from moldesign.widgets.parameterization import (UnusualBond, UnknownAtom, UnknownResidue, MissingTerms) # TODO: special messages for known problems (e.g. histidine) msg = [] unknown_res = set() # so we can print only one error per unkonwn residue lineiter = iter(job.stdout.split('\n')) offset = utils.if_not_none(molin.residues[0].pdbindex, 1) reslookup = {str(i+offset): r for i,r in enumerate(molin.residues)} def _atom_from_re(s): resname, residx, atomname, atomidx = s r = reslookup[residx] a = r[atomname] return a def unusual_bond(l): atomre1, atomre2 = ATOMSPEC.findall(l) try: a1, a2 = _atom_from_re(atomre1), _atom_from_re(atomre2) except KeyError: a1 = a2 = None r1 = reslookup[atomre1[1]] r2 = reslookup[atomre2[1]] return UnusualBond(l, (a1, a2), (r1, r2)) while True: try: line = lineiter.next() except StopIteration: break fields = line.split() if fields[0:2] == ['Unknown', 'residue:']: # EX: "Unknown residue: 3TE number: 499 type: Terminal/beginning" res = molin.residues[int(fields[4])] unknown_res.add(res) msg.append(UnknownResidue(line, res)) elif fields[:4] == 'Warning: Close contact of'.split(): # EX: "Warning: Close contact of 1.028366 angstroms between .R<DC5 1>.A<HO5' 1> and .R<DC5 81>.A<P 9>" msg.append(unusual_bond(line)) elif fields[:6] == 'WARNING: There is a bond of'.split(): # Matches two lines, EX: # "WARNING: There is a bond of 34.397700 angstroms between:" # "------- .R<DG 92>.A<O3' 33> and .R<DG 93>.A<P 1>" nextline = lineiter.next() msg.append(unusual_bond(line + nextline)) elif fields[:5] == 'Created a new atom named:'.split(): # EX: "Created a new atom named: P within residue: .R<DC5 81>" residue = reslookup[fields[-1][:-1]] if residue in unknown_res: continue # suppress atoms from an unknown res ... atom = residue[fields[5]] msg.append(UnknownAtom(line, residue, atom)) elif (fields[:5] == '** No torsion terms for'.split() or fields[:5] == 'Could not find angle parameter:'.split()): # EX: " ** No torsion terms for ca-ce-c3-hc" msg.append(MissingTerms(line.strip())) return msg
def set_color(self, color, atoms=None, _store=True): if _store: for atom in utils.if_not_none(atoms, self.mol.atoms): self._colored_as[atom] = color return super(GeometryViewer, self).set_color(color, atoms=atoms)
def color_by(self, atom_callback, atoms=None, mplmap='auto', force_cmap=False): """ Color atoms according to either: * an atomic attribute (e.g., 'chain', 'residue', 'mass') * a callback function that accepts an atom and returns a color or a category Args: atom_callback (callable OR str): callable f(atom) returns color OR category OR an atom attribute (e.g., ``atnum, mass, residue.type``) atoms (moldesign.molecules.AtomContainer): atoms to color (default: self.atoms) mplmap (str): name of the matplotlib colormap to use if colors aren't explicitly specified) force_cmap (bool): force the use of a colormap Notes: If you'd like to explicitly specify colors, the callback can return color specifications as an HTML string (``'#1234AB'``), a hexadecimal integer ( ``0x12345AB``), or a CSS3 color keyword (``'green'``, ``'purple'``, etc., see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) If the callback returns an integer, it may be interpreted as a color spec (since RGB colors are just hexadecimal integers). Use ``force_cmap=True`` to force the creation of a colormap. Returns: dict: mapping of categories to colors """ atoms = utils.if_not_none(atoms, self.mol.atoms) if isinstance(atom_callback, basestring): # shortcut to use strings to access atom attributes, i.e. "ff.partial_charge" attrs = atom_callback.split('.') # make sure that whatever value is returned doesn't get interpreted as a color force_cmap = True def atom_callback(atom): obj = atom for attr in attrs: obj = getattr(obj, attr) return obj colors = utils.Categorizer(atom_callback, atoms) if force_cmap: name_is_color = [False] else: name_is_color = map(utils.is_color, colors.keys()) if len(colors) <= 1: colors = {'gray': atoms} elif not all(name_is_color): assert not any(name_is_color), \ "callback function returned a mix of colors and categories" categories = colors cats = categories.keys() # If there are >256 categories, this is a many-to-one mapping colornames = colormap(cats, mplmap=mplmap) colors = {c: [] for c in colornames} for cat, color in zip(cats, colornames): colors[color].extend(categories[cat]) self.set_colors(colors)
def color_by(self, atom_callback, atoms=None, mplmap='auto', force_cmap=False): """ Color atoms according to either: * an atomic attribute (e.g., 'chain', 'residue', 'mass') * a callback function that accepts an atom and returns a color or a category Args: atom_callback (callable OR str): callable f(atom) returns color OR category OR an atom attribute (e.g., ``atnum, mass, residue.type``) atoms (moldesign.molecules.AtomContainer): atoms to color (default: self.atoms) mplmap (str): name of the matplotlib colormap to use if colors aren't explicitly specified) force_cmap (bool): force the use of a colormap Notes: If you'd like to explicitly specify colors, the callback can return color specifications as an HTML string (``'#1234AB'``), a hexadecimal integer ( ``0x12345AB``), or a CSS3 color keyword (``'green'``, ``'purple'``, etc., see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) If the callback returns an integer, it may be interpreted as a color spec (since RGB colors are just hexadecimal integers). Use ``force_cmap=True`` to force the creation of a colormap. Returns: dict: mapping of categories to colors """ atoms = utils.if_not_none(atoms, self.mol.atoms) if isinstance(atom_callback, basestring): # shortcut to use strings to access atom attributes, i.e. "ff.partial_charge" attrs = atom_callback.split('.') # make sure that whatever value is returned doesn't get interpreted as a color force_cmap = True def atom_callback(atom): obj = atom for attr in attrs: obj = getattr(obj, attr) return obj colors = utils.Categorizer(atom_callback, atoms) if force_cmap: name_is_color = [False] else: name_is_color = map(utils.is_color, colors.keys()) if len(colors) <= 1: colors = {'gray': atoms} elif not all(name_is_color): assert not any(name_is_color), \ "callback function returned a mix of colors and categories" categories = colors cats = categories.keys() # If there are >256 categories, this is a many-to-one mapping colornames = colormap(cats, mplmap=mplmap) colors = {c: [] for c in colornames} for cat, color in zip(cats, colornames): colors[color].extend(categories[cat]) self.set_colors(colors)
def set_color(self, color, atoms=None, _store=True): if _store: for atom in utils.if_not_none(atoms, self.mol.atoms): self._colored_as[atom] = color return super(GeometryViewer, self).set_color(color, atoms=atoms)