def create_wrapper_mol_from_atoms_and_bonds(species, coords, bonds, charge=0, free_energy=None, identifier=None): """ Create a :class:`MoleculeWrapper` from atoms and bonds. Args: species (list of str): atom species str coords (2D array): positions of atoms bonds (list of tuple): each tuple is a bond (atom indices) charge (int): chare of the molecule free_energy (float): free energy of the molecule identifier (str): (unique) identifier of the molecule Returns: MoleculeWrapper instance """ pymatgen_mol = pymatgen.Molecule(species, coords, charge) bonds = {tuple(sorted(b)): None for b in bonds} mol_graph = MoleculeGraph.with_edges(pymatgen_mol, bonds) return MoleculeWrapper(mol_graph, free_energy, identifier)
def readStructures(sfile, central, ligand, radius=3.): """ Read structure from file sfile and look for environments of all central atoms in the structure. Only neighbors of type ligand are taken into account. Returns a list of mg.Molecule in which the first atom is the central atom and the following atoms are the neighbors of type ligand of this central atom. """ struct = mg.Structure.from_file(sfile) central_sites = [ site for site in struct if site.specie == mg.Element(central) ] envs = list() print("Identified sites:") for site in central_sites: mol = mg.Molecule([site.specie], [site.coords]) neighbors = struct.get_neighbors(site, radius) for neighbor, d in neighbors: if neighbor.specie == mg.Element(ligand): mol.append(neighbor.specie, neighbor.coords) envs.append(mol) print("%2s[%2d] : #ligand = %d (%s)" % (site.specie, struct.index(site), len(mol[1:]), " ".join( [at.specie.symbol for at in mol[1:]]))) return envs
def write_gau_input(species, coords, iframe, jobname="run_gau", **kwargs): """ write a gaussian input file """ path = kwargs["path"] functional = kwargs["functional"] basis_set = kwargs["basis_set"] nprocs = kwargs["nprocs"] # get first letter of atom name => element species = [specie[0] for specie in species] # convert nm to angstrom coords = np.array(coords) * 10 # build Molecule and Gaussian object mol = mg.Molecule(species, coords, validate_proximity=True) ginp = GaussianInput( mol, charge=0, title="Written by gro2qm - snapshot %d" % iframe, functional=functional, basis_set=basis_set, route_parameters={"pop": "(MK, MBS)"}, link0_parameters={"%nprocs": nprocs}, dieze_tag="#" ) basename = "gau_%05d" % iframe ginp.write_file(os.path.join(path, basename + ".com"), cart_coords=True) mol.to(fmt="xyz", filename=os.path.join(path, basename + ".xyz")) return "sbatch -J snap_%05d %s %s.com" % (iframe, jobname, basename)
def cif_to_charged_cluster_within_radius(file, bondmap, radius, centeratom=False, supercell=None, oxid='guess', clobber=False): '''Heads up, supercell needs to be large enough to cover the radius requested''' assert file[-4:] == '.cif', 'Only works with cif files' if oxid == 'guess': mol = make_molecular_cluster_from_cif(file, supercell=supercell, guessoxid=True) else: mol = make_molecular_cluster_from_cif(file, supercell=supercell, guessoxid=False) mol.add_oxidation_state_by_element(oxid) center_cluster_on_atom(mol, centeratom) sites = mol.get_sites_in_sphere([0, 0, 0], radius) mol = mg.Molecule([s[0].species_string for s in sites], [s[0].coords for s in sites]) assign_nearest_neighbors(mol) missing = calculate_missing_bonds(mol, bondmap) charge, bondcharges = calculate_charge_for_cluster(missing, bondmap) outfilename = file[:-4]+'.xyz' if not clobber: assert not os.path.exists(outfilename), 'Output file with name {} already exists!'.format(outfilename) mol.add_oxidation_state_by_element(dict.fromkeys(mol.symbol_set)) mol.to('xyz', outfilename) with open(outfilename, 'r+') as file: lines = file.readlines() lines[1] = '{}; charge for DFT cluster calculation: {}; based on bondchargemap: {};\n'.format(lines[1][:-1], charge, bondcharges) file.seek(0) file.writelines(lines) dumb_rename_center_atom(outfilename, mol)
def make_molecular_cluster_from_cif(file, supercell=None, guessoxid=False): structure = mg.Structure.from_file(file) if guessoxid: structure.add_oxidation_state_by_guess() if supercell is not None: structure.make_supercell(supercell) molecule = mg.Molecule(structure.species, structure.cart_coords) return molecule
def get_pointgroup(atoms: ase.Atoms) -> str: """ uses pymatgen.symmetry.analyzer """ atoms.center() symbs = atoms.get_chemical_symbols() pos = atoms.get_positions() mol = pmg.Molecule(symbs, pos) return pysym.PointGroupAnalyzer(mol).sch_symbol
def getPointgroup(kind, storagepath): if kind != 'molecule': return None import pymatgen import pymatgen.io.ase as pmgase import pymatgen.symmetry.analyzer as psa atoms = getAtoms(storagepath) cm = atoms.get_center_of_mass() m = pymatgen.Molecule(atoms.get_chemical_symbols(), atoms.get_positions() - cm) return psa.PointGroupAnalyzer(m).sch_symbol
def symmetry_information(self): """ Returns symmetry information of the molecule as for example its point group :return info: a dictionary with symmetry informations """ mol = mg.Molecule(self.atoms[:, 3], self.atoms[:, :3]) analyzer = PointGroupAnalyzer(mol) info = {'point group': analyzer.get_pointgroup()} return info
def getPointgroup(kind,inittraj): if kind == 'molecule': atoms = pickle.loads(inittraj) cm = atoms.get_center_of_mass() m = pymatgen.Molecule(atoms.get_chemical_symbols(),atoms.get_positions()-cm) try: return psa.PointGroupAnalyzer(m).sch_symbol except ValueError: viz.view(atoms) sys.exit() else: return None
def make_constrain_ordered_xyz(file, neighbor0='P', neighbor1='H'): mol = mg.Molecule.from_file(file) assign_nearest_neighbors(mol) edge = mg.Molecule(['Zr'], [[0,0,0]]) #dummy Zr to let me instantiate the molecule edge.pop(0) #discard dummy poplist = [] for i, site in enumerate(mol): if site.specie.name == neighbor0: for n in site.nearests: if n.specie.name == neighbor1: poplist.append(i) edge.append(site.specie, site.coords) continue mol.remove_sites(poplist) poplist = [] for i, site in enumerate(mol): if site.specie.name == neighbor1: for n in site.nearests: if n.specie.name == neighbor0: poplist.append(i) edge.append(site.specie, site.coords) continue mol.remove_sites(poplist) filename = file.split('.xyz')[0].split('/')[-1] #oops only works on linux... # unconstrainf = '{}_Unconstrain.xyz'.format(filename) # mol.to('xyz', unconstrainf) # constrainf = '{}_Constrain.xyz'.format(filename) # edge.to('xyz', constrainf) # unca, uncc = read_xyz(unconstrainf) # ca, cc = read_xyz(constrainf) unca, uncc = mol.species, mol.cart_coords ca, cc = edge.species, edge.cart_coords print('Saving new file as: {}'.format('{}_Reordered'.format(filename))) write_xyz_from_atoms_coords('{}_Reordered'.format(filename), atoms=unca + ca, coords=np.concatenate([uncc, cc]), comment='Unconstrained {}; Constrained {}; Fix atoms {}:{}'.format( len(unca), len(ca), len(unca) + 1, len(unca) + len(ca) ))
def mol_Oh(central, ligand, scale): """ Return a perfect octahedra as a mg.Molecule object. Args: central: (string) Name of the central atom ligand: (string) Name of ligand atoms scale: (float) length of central-ligand distance Returns mg.Molecule object """ species = [mg.Element(central)] + 6 * [mg.Element(ligand)] template = [[0., 0., 0.], [1., 0., 0.], [-1., 0., 0.], [0., 1., 0.], [0., -1., 0.], [0., 0., 1.], [0., 0., -1.]] coords = [[scale * xi for xi in coord] for coord in template] return mg.Molecule(species, coords)
def boxed_molecule(cls, pseudos, cart_coords, acell=3 * (10, )): """ Creates a molecule in a periodic box of lengths acell [Bohr] Args: pseudos: List of pseudopotentials cart_coords: Cartesian coordinates acell: Lengths of the box in *Bohr* """ cart_coords = np.atleast_2d(cart_coords) molecule = pymatgen.Molecule([p.symbol for p in pseudos], cart_coords) l = ArrayWithUnit(acell, "bohr").to("ang") structure = molecule.get_boxed_structure(l[0], l[1], l[2]) return cls(structure)
def rdkit_mol_to_wrapper_mol(m, charge=None, free_energy=None, identifier=None): """ Convert an rdkit molecule to a :class:`MoleculeWrapper` molecule. This constructs a molecule graph from the rdkit mol and assigns the rdkit mol to the molecule wrapper. Args: m (Chem.Mol): rdkit molecule charge (int): charge of the molecule. If None, inferred from the rdkit mol; otherwise, the provided charge will override the inferred. free_energy (float): free energy of the molecule identifier (str): (unique) identifier of the molecule Returns: MoleculeWrapper instance """ species = [a.GetSymbol() for a in m.GetAtoms()] # coords = m.GetConformer().GetPositions() # NOTE, the above way to get coords results in segfault on linux, so we use the # below workaround conformer = m.GetConformer() coords = [[x for x in conformer.GetAtomPosition(i)] for i in range(m.GetNumAtoms())] bonds = [[b.GetBeginAtomIdx(), b.GetEndAtomIdx()] for b in m.GetBonds()] bonds = {tuple(sorted(b)): None for b in bonds} charge = Chem.GetFormalCharge(m) if charge is None else charge pymatgen_mol = pymatgen.Molecule(species, coords, charge) mol_graph = MoleculeGraph.with_edges(pymatgen_mol, bonds) if identifier is None: identifier = m.GetProp("_Name") mw = MoleculeWrapper(mol_graph, free_energy, identifier) mw.rdkit_mol = m return mw
def mol_D4h(central, ligand, d1, d2): """ Return a D4h molecule as a mg.Molecule object. Args: central: (string) Name of the central atom ligand: (string) Name of ligand atoms d1: (float) length of central-ligand axial distance d2: (float) length of central-ligand equatorial distance Returns mg.Molecule object """ species = [mg.Element(central)] + 6 * [mg.Element(ligand)] template = [[0., 0., 0.], [1., 0., 0.], [-1., 0., 0.], [0., 1., 0.], [0., -1., 0.], [0., 0., 1.], [0., 0., -1.]] coords = [template[0]] \ + [[d1 * xi for xi in coord] for coord in template[1:5]] \ + [[d2 * xi for xi in coord] for coord in template[5:]] return mg.Molecule(species, coords)
def getSymmetry(ids, xyz): mol = PointGroupAnalyzer(mg.Molecule(ids, xyz)) return mol.sch_symbol
def make_hydrogen_capped_cluster_from_cif_3(outfilename, ciffile, numnearest, cappingdistances, bqchargemap, centeratom, sphereradius=6, supercell=6, bondlengthcutoff=2.5): '''Make hydrogen-capped cluster. Note: 3 means that this version is trying to accommodate inequivalent sites Supercell needs to be big enough that all atoms in sphere and neighbors thereof have full neighbors.''' print('Importing structure') struct = mg.Structure.from_file(ciffile) struct.make_supercell(supercell) # mol = mg.Molecule(struct.species, struct.cart_coords) mol = tag_sites_by_equivalency(struct) center_cluster_on_atom(mol, centeratom) # fixed 3.23.19 to add centeratom arg remove_oxidation_state_from_species(mol) print('Finding site inside/outside sphere.') innersites = mol.get_sites_in_sphere([0, 0, 0], sphereradius) inner = mg.Molecule.from_sites([s[0] for s in innersites]) neighboringmol = mg.Molecule([], []) for isite in inner: print('Checking neighbors of site {}'.format(mol.index(isite)), end='\r') neighbors = mol.get_neighbors(isite, bondlengthcutoff) for s, _ in neighbors: if s not in inner: if s not in neighboringmol: neighboringmol.append(s.specie, s.coords) try: neighboringmol[neighboringmol.index(s)].innerneighbors.append(isite) except AttributeError: neighboringmol[neighboringmol.index(s)].innerneighbors = [isite] hydrcoords = [] hydrneighbors = [] hydrreplace = [] for ns in neighboringmol: for n in ns.innerneighbors: hydrcoords.append(np.mean([ns.coords, n.coords], axis=0)) # create hydrogen halfway along bond hydrneighbors.append(n) # keep track of neighbor identity hydrreplace.append(ns) # keep track of identitiy of atom being replaced hydrsites = [mg.Site('H', c) for c in hydrcoords] hydr = mg.Molecule.from_sites(hydrsites) # add hydrogen neighbors and adjust bond lengths accordingly for hs, hn, hr in zip(hydrsites, hydrneighbors, hydrreplace): hydr[hydr.index(hs)].innerneighbor = hn hydr[hydr.index(hs)].replacing = hr for s in hydr: adjust_bond_length(s, s.innerneighbor, cappingdistances[str(s.innerneighbor.specie)]) capped = mg.Molecule.from_sites(hydr.sites + inner.sites) print('Writing capped cluster file: ', '{}.xyz'.format(outfilename)) capped.to('xyz', '{}.xyz'.format(outfilename)) print('Writing bq charge file: ', '{}.bq'.format(outfilename)) totalbqcharge = 0 with open('{}.bq'.format(outfilename), 'w') as file: for s in hydr: file.write('Bq {:>15.8f}{:>15.8f}{:>15.8f}{:>10.4f}\n'.format( *s.coords, bqchargemap[str(s.replacing.specie)][str(s.innerneighbor.specie)])) totalbqcharge += bqchargemap[str(s.replacing.specie)][str(s.innerneighbor.specie)] with open('{}.xyz'.format(outfilename), 'r') as file: oldlines = file.readlines() oldlines[1] = oldlines[1].strip() + '; Total bqcharge for capped cluster: {}\n'.format(totalbqcharge) with open('{}.xyz'.format(outfilename), 'w') as file: for line in oldlines: file.write(line) slightly_less_dumb_rename_center_atom('{}.xyz'.format(outfilename))
def make_hydrogen_capped_cluster_from_cif_old_logic(outfilename, ciffile, numnearest, cappingdistances, bqchargemap, centeratom, sphereradius=6, supercell=6): '''Make hydrogen-capped cluster. Supercell needs to be big enough that all atoms in sphere and neighbors thereof have full neighbors.''' print('Importing structure') struct = mg.Structure.from_file(ciffile) struct.make_supercell(6) mol = mg.Molecule(struct.species, struct.cart_coords) center_cluster_on_atom(mol, centeratom) # fixed 3.23.19 to add centeratom arg print('Finding site inside/outside sphere.') innersites = mol.get_sites_in_sphere([0, 0, 0], sphereradius) inner = mg.Molecule.from_sites([s[0] for s in innersites]) SHELLDIST = 4 outersites = mol.get_neighbors_in_shell([0, 0, 0], sphereradius + SHELLDIST / 2, SHELLDIST / 2) outersiteindices = [] for site, _ in outersites: outersiteindices.append(mol.index(site)) neighboringsites = [] for osi in outersiteindices: print('Checking neighbors of site {}'.format(osi), end='\r') neighbors = get_nearest_sites_by_num_neighbors(mol, mol[osi], numnearest) for s, _ in neighbors: if s in inner: try: mol[osi].innerneighbors.append(s) except AttributeError: mol[osi].innerneighbors = [s] if osi not in neighboringsites: neighboringsites.append(osi) hydrcoords = [] hydrneighbors = [] hydrreplace = [] for ns in neighboringsites: ocoords = mol[ns].coords for n in mol[ns].innerneighbors: hydrcoords.append(np.mean([ocoords, n.coords], axis=0)) hydrneighbors.append(n) hydrreplace.append(mol[ns]) hydrsites = [mg.Site('H', c) for c in hydrcoords] hydr = mg.Molecule.from_sites(hydrsites) # add hydrogen neighbors and adjust bond lengths accordingly for hs, hn, hr in zip(hydrsites, hydrneighbors, hydrreplace): hydr[hydr.index(hs)].innerneighbor = hn hydr[hydr.index(hs)].replacing = hr for s in hydr: adjust_bond_length(s, s.innerneighbor, cappingdistances[str(s.innerneighbor.specie)]) capped = mg.Molecule.from_sites(hydr.sites + inner.sites) print('Writing capped cluster file: ', '{}.xyz'.format(outfilename)) capped.to('xyz', '{}.xyz'.format(outfilename)) print('Writing bq charge file: ', '{}.bq'.format(outfilename)) with open('{}.bq'.format(outfilename), 'w') as file: for s in hydr: file.write('Bq {:>15.8f}{:>15.8f}{:>15.8f}{:>10.4f}\n'.format( *s.coords, bqchargemap[str(s.replacing.specie)]))