def position_mols(self): """ position the center of masses of the molecules wrt each other first movement is in the x direction """ new_mol = self.mols[0] mov_vec = np.array([1, 0, 0]) for i in range(len(self.mols) - 1): # cm1 = new_mol.center_of_mass new_cm = new_mol.center_of_mass # cm2 = self.mols[i+1].center_of_mass new_cm = new_cm + self.cm_dist[i] * mov_vec mov_vec = self.get_perp_vec(self.mol_vecs[i], mov_vec) mov_vec = mov_vec / np.linalg.norm(mov_vec) new_coords = self.mols[i + 1].cart_coords + new_cm self.mols[i + 1] = Molecule( self.mols[i + 1].species_and_occu, new_coords, charge=self.mols[i + 1]._charge, spin_multiplicity=self.mols[i + 1]._spin_multiplicity, site_properties=self.mols[i + 1].site_properties) new_mol = Molecule.from_sites(self.mols[i].sites + self.mols[i + 1].sites, validate_proximity=True)
def visualize(cg, zoom=None, vis=None, myfactor=1.0, view_index=True, faces_color_override=None): """ Visualizing a coordination geometry :param cg: :param zoom: :param vis: :param myfactor: :param view_index: :param faces_color_override: :return: """ if vis is None: vis = StructureVis(show_polyhedron=False, show_unit_cell=False) myspecies = ["O"] * (cg.coordination_number + 1) myspecies[0] = "Cu" coords = [np.zeros(3, np.float_) + cg.central_site] for pp in cg.points: coords.append(np.array(pp) + cg.central_site) coords = [cc * myfactor for cc in coords] structure = Molecule(species=myspecies, coords=coords) vis.set_structure(structure=structure, reset_camera=True) # neighbors_list = coords[1:] draw_cg( vis, site=structure[0], neighbors=structure[1:], cg=cg, faces_color_override=faces_color_override, ) if view_index: for ineighbor, neighbor in enumerate(structure[1:]): vis.add_text(neighbor.coords, "{}".format(ineighbor), color=(0, 0, 0)) if zoom is not None: vis.zoom(zoom) return vis
def reoriented_molecule(mol, nested=False): """ Reorient a molecule so that its principal axes are aligned with the identity matrix. Args: mol: a Molecule object nested: keep track of how many times the function has been called recursively Returns: new_mol: a reoriented copy of the original molecule. P: the 3x3 rotation matrix used to obtain it. """ coords = mol.cart_coords numbers = mol.atomic_numbers coords -= np.mean(coords, axis=0) A = get_inertia_tensor(coords) # Store the eigenvectors of the inertia tensor P = np.linalg.eigh(A)[1] if np.linalg.det(P) < 0: P[0] *= -1 coords = np.dot(coords, P) return Molecule(numbers, coords), P
def match(self): """ Check the two molecular graphs are isomorphic """ match, mapping = compare_mol_connectivity(self.ref_mol, self.molecule) if not match: print(self.ref_mol.to("xyz")) print(self.molecule.to("xyz")) import pickle with open('wrong.pkl', "wb") as f: pickle.dump([self.ref_mol, self.molecule], f) return False else: # resort the atomic number for molecule 1 order = [mapping[i] for i in range(len(self.ref_mol))] numbers = np.array(self.molecule.atomic_numbers) numbers = numbers[order].tolist() coords = self.molecule.cart_coords[order] position = np.mean(coords, axis=0).dot(self.lattice.inv_matrix) position -= np.floor(position) # check if molecule is on the special wyckoff position if len(self.pmg_struc) / len(self.molecule) < len(self.wyc): if self.diag: #Transform it to the conventional representation position = np.dot(self.perm, position).T position, wp, _ = WP_merge(position, self.lattice.matrix, self.wyc, 2.0) #print("After Mergey:---------------") #print(position) #print(wp) self.wyc = wp self.position = position self.molecule = Molecule(numbers, coords - np.mean(coords, axis=0)) #self.align() return True
def from_string(contents): """ Creates XYZ object from a string. Args: contents: String representing an XYZ file. Returns: XYZ object """ lines = contents.split("\n") num_sites = int(lines[0]) coords = [] sp = [] coord_patt = re.compile( "(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)" ) for i in xrange(2, 2 + num_sites): m = coord_patt.search(lines[i]) if m: sp.append(m.group(1)) # this is 1-indexed coords.append(map(float, m.groups()[1:4])) # this is 0-indexed return XYZ(Molecule(sp, coords))
def configuration_space_from_molecule(molecule, subset=None, atol=1e-5): """ Generate a ``ConfigurationSpace`` object from a `pymatgen` ``Molecule``. Args: molecule (pymatgen ``Molecule``): molecule to be used to define the :any:`ConfigurationSpace`. subset (Optional [list]): list of atom indices to be used for generating the configuration space. atol (Optional [float]): tolerance factor for the ``pymatgen`` `coordinate mapping`_ under each symmetry operation. Returns: a new :any:`ConfigurationSpace` instance. .. _coordinate mapping: http://pymatgen.org/pymatgen.util.coord_utils.html#pymatgen.util.coord_utils.coord_list_mapping """ molecule = Molecule(molecule.species, molecule.cart_coords - molecule.center_of_mass) point_group = point_group_from_molecule(molecule, subset=subset, atol=atol) if subset is None: subset = list(range(1, len(molecule) + 1)) config_space = ConfigurationSpace(objects=subset, symmetry_group=point_group) return config_space
# test if __name__ == '__main__': # the following example require: # acetic_acid.xyz and POSCAR.mp-21276_PbS # create lead acetate ligand # from 3 molecules: 2 acetic acid + 1 Pb import os PACKAGE_PATH = os.path.dirname(__file__) mol0 = Molecule.from_file( os.path.join(PACKAGE_PATH, "test_files", "acetic_acid.xyz")) mol1 = Molecule.from_file( os.path.join(PACKAGE_PATH, "test_files", "acetic_acid.xyz")) mol2 = Molecule(["Pb"], [[0, 0, 0]]) mols = [mol0, mol1, mol2] # center of mass distances in angstrom # example: 3 molecules and cm_dist = [4,2], # center of mass of mol1 is moved from mol0 in 1,0,0 direction by 4 A # mol2 is moved from the center of mass of the combined mol0+mol1 molecule by 2 A # in a direction that is perpendicular to the first moving direction and the # molecule vector of one of the molecules # for n molecules the size of cm_dist must be n-1 cm_dist = [1, 2] # optional parmater # example: angle={'0':{}, '1':{'0':90}, '2':{} } # rotate mol1 with respect to mol0 by 90 degreeen around and axis that is normal # to the plane containing the molecule vectors of mol0 and mol1 angle = {'0': {}, '1': {'0': 90}, '2': {}}
0.001).get_space_group_operations() def test_are_symmetrically_equivalent(self): sites1 = [self.structure[i] for i in [0, 1]] sites2 = [self.structure[i] for i in [2, 3]] self.assertTrue( self.sg1.are_symmetrically_equivalent(sites1, sites2, 1e-3)) sites1 = [self.structure[i] for i in [0, 1]] sites2 = [self.structure[i] for i in [0, 2]] self.assertFalse( self.sg1.are_symmetrically_equivalent(sites1, sites2, 1e-3)) H2O2 = Molecule( ["O", "O", "H", "H"], [[0, 0.727403, -0.050147], [0, -0.727403, -0.050147], [0.83459, 0.897642, 0.401175], [-0.83459, -0.897642, 0.401175]]) C2H2F2Br2 = Molecule( ["C", "C", "F", "Br", "H", "F", "H", "Br"], [[-0.752000, 0.001000, -0.141000], [0.752000, -0.001000, 0.141000], [-1.158000, 0.991000, 0.070000], [-1.240000, -0.737000, 0.496000], [-0.924000, -0.249000, -1.188000], [1.158000, -0.991000, -0.070000], [0.924000, 0.249000, 1.188000], [1.240000, 0.737000, -0.496000]]) H2O = Molecule( ["H", "O", "H"], [[0, 0.780362, -.456316], [0, 0, .114079], [0, -.780362, -.456316]]) C2H4 = Molecule(["C", "C", "H", "H", "H", "H"], [[0.0000, 0.0000, 0.6695], [0.0000, 0.0000, -0.6695],
def from_string(cls, string_input): """ Read an NwInput from a string. Currently tested to work with files generated from this class itself. Args: string_input: string_input to parse. Returns: NwInput object """ directives = [] tasks = [] charge = None spin_multiplicity = None title = None basis_set = None basis_set_option = None theory_directives = {} geom_options = None symmetry_options = None memory_options = None lines = string_input.strip().split("\n") while len(lines) > 0: l = lines.pop(0).strip() if l == "": continue toks = l.split() if toks[0].lower() == "geometry": geom_options = toks[1:] l = lines.pop(0).strip() toks = l.split() if toks[0].lower() == "symmetry": symmetry_options = toks[1:] l = lines.pop(0).strip() # Parse geometry species = [] coords = [] while l.lower() != "end": toks = l.split() species.append(toks[0]) coords.append([float(i) for i in toks[1:]]) l = lines.pop(0).strip() mol = Molecule(species, coords) elif toks[0].lower() == "charge": charge = int(toks[1]) elif toks[0].lower() == "title": title = l[5:].strip().strip("\"") elif toks[0].lower() == "basis": # Parse basis sets l = lines.pop(0).strip() basis_set = {} while l.lower() != "end": toks = l.split() basis_set[toks[0]] = toks[-1].strip("\"") l = lines.pop(0).strip() elif toks[0].lower() in NwTask.theories: # read the basis_set_option if len(toks) > 1: basis_set_option = toks[1] # Parse theory directives. theory = toks[0].lower() l = lines.pop(0).strip() theory_directives[theory] = {} while l.lower() != "end": toks = l.split() theory_directives[theory][toks[0]] = toks[-1] if toks[0] == "mult": spin_multiplicity = float(toks[1]) l = lines.pop(0).strip() elif toks[0].lower() == "task": tasks.append( NwTask(charge=charge, spin_multiplicity=spin_multiplicity, title=title, theory=toks[1], operation=toks[2], basis_set=basis_set, basis_set_option=basis_set_option, theory_directives=theory_directives.get(toks[1]))) elif toks[0].lower() == "memory": memory_options = ' '.join(toks[1:]) else: directives.append(l.strip().split()) return NwInput(mol, tasks=tasks, directives=directives, geometry_options=geom_options, symmetry_options=symmetry_options, memory_options=memory_options)
def test_multi_job_string(self): species = [ "S", "C", "H", "C", "H", "C", "H", "C", "C", "C", "H", "C", "H", "C", "H", "S", ] coords = [ [-0.00250959, -0.05817469, -0.02921636], [1.70755408, -0.03033788, -0.01382912], [2.24317221, -0.05215019, 0.92026728], [2.21976393, 0.01718014, -1.27293235], [3.27786220, 0.04082146, -1.48539646], [1.20867399, 0.04478540, -2.27007793], [1.40292257, 0.10591684, -3.33110912], [-0.05341046, 0.01577217, -1.74839343], [-1.32843436, 0.03545064, -2.45531187], [-1.55195156, 0.08743920, -3.80184635], [-0.75245172, 0.10267657, -4.52817967], [-2.93293778, 0.08408786, -4.13352169], [-3.31125108, 0.11340328, -5.14405819], [-3.73173288, 0.02741365, -3.03412864], [-4.80776535, 0.00535688, -2.99564645], [-2.81590978, -0.00516172, -1.58990580], ] molecule_1 = Molecule(species, coords) rem_1 = { "jobtype": "opt", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": "75", "max_scf_cycles": "300", "scf_algorithm": "diis", "scf_guess": "sad", "sym_ignore": "true", "symmetry": "false", "thresh": "14", } opt_1 = {"CONSTRAINT": ["tors 6 8 9 10 0.0"]} job_1 = QCInput(molecule=molecule_1, rem=rem_1, opt=opt_1) molecule_2 = "read" rem_2 = { "jobtype": "sp", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": "75", "max_scf_cycles": "300", "scf_algorithm": "diis", "scf_guess": "read", "sym_ignore": "true", "symmetry": "false", "thresh": "14", } job_2 = QCInput(molecule=molecule_2, rem=rem_2) job_list = [job_1, job_2] multi_job_str_test = QCInput.multi_job_string( job_list=job_list).split("\n") multi_job_str_actual_list = [ "$molecule", " 0 1", " S -0.0025095900 -0.0581746900 -0.0292163600", " C 1.7075540800 -0.0303378800 -0.0138291200", " H 2.2431722100 -0.0521501900 0.9202672800", " C 2.2197639300 0.0171801400 -1.2729323500", " H 3.2778622000 0.0408214600 -1.4853964600", " C 1.2086739900 0.0447854000 -2.2700779300", " H 1.4029225700 0.1059168400 -3.3311091200", " C -0.0534104600 0.0157721700 -1.7483934300", " C -1.3284343600 0.0354506400 -2.4553118700", " C -1.5519515600 0.0874392000 -3.8018463500", " H -0.7524517200 0.1026765700 -4.5281796700", " C -2.9329377800 0.0840878600 -4.1335216900", " H -3.3112510800 0.1134032800 -5.1440581900", " C -3.7317328800 0.0274136500 -3.0341286400", " H -4.8077653500 0.0053568800 -2.9956464500", " S -2.8159097800 -0.0051617200 -1.5899058000", "$end", "$rem", " job_type = opt", " method = wb97m-v", " basis = def2-tzvppd", " gen_scfman = true", " geom_opt_max_cycles = 75", " max_scf_cycles = 300", " scf_algorithm = diis", " scf_guess = sad", " sym_ignore = true", " symmetry = false", " thresh = 14", "$end", "$opt", "CONSTRAINT", " tors 6 8 9 10 0.0", "ENDCONSTRAINT", "$end", "@@@", "$molecule", " read", "$end", "$rem", " job_type = opt", " method = wb97m-v", " basis = def2-tzvppd", " gen_scfman = true", " geom_opt_max_cycles = 75", " max_scf_cycles = 300", " scf_algorithm = diis", " scf_guess = sad", " sym_ignore = true", " symmetry = false", " thresh = 14", "$end", ] for i_str in multi_job_str_actual_list: self.assertIn(i_str, multi_job_str_test)
def from_string(cls, string_input): """ Read an FiestaInput from a string. Currently tested to work with files generated from this class itself. Args: string_input: string_input to parse. Returns: FiestaInput object """ correlation_grid = {} Exc_DFT_option = {} COHSEX_options = {} GW_options = {} BSE_TDDFT_options = {} lines = string_input.strip().split("\n") # number of atoms and species lines.pop(0) l = lines.pop(0).strip() toks = l.split() nat = toks[0] nsp = toks[1] # number of valence bands lines.pop(0) l = lines.pop(0).strip() toks = l.split() nvbands = toks[0] # correlation_grid # number of points and spacing in eV for correlation grid lines.pop(0) l = lines.pop(0).strip() toks = l.split() correlation_grid['n_grid'] = toks[0] correlation_grid['dE_grid'] = toks[1] # Exc DFT # relire=1 ou recalculer=0 Exc DFT lines.pop(0) l = lines.pop(0).strip() toks = l.split() Exc_DFT_option['rdVxcpsi'] = toks[0] # COHSEX # number of COHSEX corrected occp and unoccp bands: C=COHSEX H=HF lines.pop(0) l = lines.pop(0).strip() toks = l.split() COHSEX_options['nv_cohsex'] = toks[0] COHSEX_options['nc_cohsex'] = toks[1] COHSEX_options['eigMethod'] = toks[2] # number of COHSEX iter, scf on wfns, mixing coeff; V=RI-V I=RI-D lines.pop(0) l = lines.pop(0).strip() toks = l.split() COHSEX_options['nit_cohsex'] = toks[0] COHSEX_options['resMethod'] = toks[1] COHSEX_options['scf_cohsex_wf'] = toks[2] COHSEX_options['mix_cohsex'] = toks[3] # GW # number of GW corrected occp and unoccp bands lines.pop(0) l = lines.pop(0).strip() toks = l.split() GW_options['nv_corr'] = toks[0] GW_options['nc_corr'] = toks[1] # number of GW iterations lines.pop(0) l = lines.pop(0).strip() toks = l.split() GW_options['nit_gw'] = toks[0] # BSE # dumping for BSE and TDDFT lines.pop(0) l = lines.pop(0).strip() toks = l.split() BSE_TDDFT_options['do_bse'] = toks[0] BSE_TDDFT_options['do_tddft'] = toks[1] # number of occp. and virtual bands fo BSE: nocore and up to 40 eVs lines.pop(0) l = lines.pop(0).strip() toks = l.split() BSE_TDDFT_options['nv_bse'] = toks[0] BSE_TDDFT_options['nc_bse'] = toks[1] # number of excitations needed and number of iterations lines.pop(0) l = lines.pop(0).strip() toks = l.split() BSE_TDDFT_options['npsi_bse'] = toks[0] BSE_TDDFT_options['nit_bse'] = toks[1] # Molecule # list of symbols in order lines.pop(0) atname = [] i = int(nsp) while i != 0: l = lines.pop(0).strip() toks = l.split() atname.append(toks[0]) i -= 1 # scaling factor lines.pop(0) l = lines.pop(0).strip() toks = l.split() scale = toks[0] # atoms x,y,z cartesian .. will be multiplied by scale lines.pop(0) # Parse geometry species = [] coords = [] i = int(nat) while i != 0: l = lines.pop(0).strip() toks = l.split() coords.append([float(j) for j in toks[0:3]]) species.append(atname[int(toks[3]) - 1]) i -= 1 mol = Molecule(species, coords) return FiestaInput(mol=mol, correlation_grid=correlation_grid, Exc_DFT_option=Exc_DFT_option, COHSEX_options=COHSEX_options, GW_options=GW_options, BSE_TDDFT_options=BSE_TDDFT_options)
import openbabel as ob except ImportError: ob = None __author__ = "Evan Spotte-Smith" __version__ = "0.1" __maintainer__ = "Evan Spotte-Smith" __email__ = "*****@*****.**" __status__ = "Alpha" __date__ = "September 2019" module_dir = os.path.join(os.path.dirname(os.path.abspath(__file__))) # Not real molecules; just place-holders # We're only interested in the math mol_placeholder = Molecule(["H"], [[0.0, 0.0, 0.0]]) class ReactionRateCalculatorTest(unittest.TestCase): def setUp(self) -> None: if ob: self.energies = [ -271.553636516598, -78.5918513462683, -350.105998350078 ] self.enthalpies = [13.917, 34.596, 49.515] self.entropies = [67.357, 55.047, 84.265] self.rct_1 = MoleculeEntry( mol_placeholder, self.energies[0], enthalpy=self.enthalpies[0],
def _parse_molecule(cls, contents): """ Helper method to parse coordinates of Molecule. Copied from GaussianInput class. """ paras = {} var_pattern = re.compile("^([A-Za-z]+\S*)[\s=,]+([\d\-\.]+)$") for l in contents: m = var_pattern.match(l.strip()) if m: paras[m.group(1)] = float(m.group(2)) species = [] coords = [] # Stores whether a Zmatrix format is detected. Once a zmatrix format # is detected, it is assumed for the remaining of the parsing. zmode = False for l in contents: l = l.strip() if not l: break if (not zmode) and cls.xyz_patt.match(l): m = cls.xyz_patt.match(l) species.append(m.group(1)) toks = re.split("[,\s]+", l.strip()) if len(toks) > 4: coords.append(list(map(float, toks[2:5]))) else: coords.append(list(map(float, toks[1:4]))) elif cls.zmat_patt.match(l): zmode = True toks = re.split("[,\s]+", l.strip()) species.append(toks[0]) toks.pop(0) if len(toks) == 0: coords.append(np.array([0.0, 0.0, 0.0])) else: nn = [] parameters = [] while len(toks) > 1: ind = toks.pop(0) data = toks.pop(0) try: nn.append(int(ind)) except ValueError: nn.append(species.index(ind) + 1) try: val = float(data) parameters.append(val) except ValueError: if data.startswith("-"): parameters.append(-paras[data[1:]]) else: parameters.append(paras[data]) if len(nn) == 1: coords.append(np.array( [0.0, 0.0, float(parameters[0])])) elif len(nn) == 2: coords1 = coords[nn[0] - 1] coords2 = coords[nn[1] - 1] bl = parameters[0] angle = parameters[1] axis = [0, 1, 0] op = SymmOp.from_origin_axis_angle(coords1, axis, angle, False) coord = op.operate(coords2) vec = coord - coords1 coord = vec * bl / np.linalg.norm(vec) + coords1 coords.append(coord) elif len(nn) == 3: coords1 = coords[nn[0] - 1] coords2 = coords[nn[1] - 1] coords3 = coords[nn[2] - 1] bl = parameters[0] angle = parameters[1] dih = parameters[2] v1 = coords3 - coords2 v2 = coords1 - coords2 axis = np.cross(v1, v2) op = SymmOp.from_origin_axis_angle( coords1, axis, angle, False) coord = op.operate(coords2) v1 = coord - coords1 v2 = coords1 - coords2 v3 = np.cross(v1, v2) adj = get_angle(v3, axis) axis = coords1 - coords2 op = SymmOp.from_origin_axis_angle( coords1, axis, dih - adj, False) coord = op.operate(coord) vec = coord - coords1 coord = vec * bl / np.linalg.norm(vec) + coords1 coords.append(coord) def parse_species(sp_str): """ The species specification can take many forms. E.g., simple integers representing atomic numbers ("8"), actual species string ("C") or a labelled species ("C1"). Sometimes, the species string is also not properly capitalized, e.g, ("c1"). This method should take care of these known formats. """ try: return int(sp_str) except ValueError: sp = re.sub("\d", "", sp_str) return sp.capitalize() species = list(map(parse_species, species)) return Molecule(species, coords)
def __init__(self, struc, ref_mol=None, tol=0.2, relax_h=False): """ extract the mol_site information from the give cif file and reference molecule Args: struc: cif/poscar file or a Pymatgen Structure object ref_mol: xyz file or a reference Pymatgen molecule object tol: scale factor for covalent bond distance relax_h: whether or not relax the position for hydrogen atoms in structure """ if isinstance(ref_mol, str): ref_mol = Molecule.from_file(ref_mol) elif isinstance(ref_mol, Molecule): ref_mol = ref_mol else: print(type(ref_mol)) raise NameError("reference molecule cannot be defined") if isinstance(struc, str): pmg_struc = Structure.from_file(struc) elif isinstance(struc, Structure): pmg_struc = struc else: print(type(struc)) raise NameError("input structure cannot be intepretted") self.props = ref_mol.site_properties self.ref_mol = ref_mol.get_centered_molecule() self.tol = tol self.diag = False self.relax_h = relax_h sga = SpacegroupAnalyzer(pmg_struc) ops = sga.get_space_group_operations() self.wyc, perm = Wyckoff_position.from_symops( ops, sga.get_space_group_number()) if self.wyc is not None: self.group = Group(self.wyc.number) if isinstance(perm, list): if perm != [0, 1, 2]: lattice = Lattice.from_matrix(pmg_struc.lattice.matrix, self.group.lattice_type) latt = lattice.swap_axis(ids=perm, random=False).get_matrix() coor = pmg_struc.frac_coords[:, perm] pmg_struc = Structure(latt, pmg_struc.atomic_numbers, coor) else: self.diag = True self.perm = perm coords, numbers = search_molecule_in_crystal(pmg_struc, self.tol) #coords -= np.mean(coords, axis=0) if self.relax_h: self.molecule = self.addh(Molecule(numbers, coords)) else: self.molecule = Molecule(numbers, coords) self.pmg_struc = pmg_struc self.lattice = Lattice.from_matrix(pmg_struc.lattice.matrix, self.group.lattice_type) else: raise ValueError( "Cannot find the space group matching the symmetry operation")
def fit_with_mapper(self, mapper): coords = [[0.000000, 0.000000, 0.000000], [0.000000, 0.000000, 1.089000], [1.026719, 0.000000, -0.363000], [-0.513360, -0.889165, -0.363000], [-0.513360, 0.889165, -0.363000]] mol1 = Molecule(["C", "H", "H", "H", "H"], coords) op = SymmOp.from_origin_axis_angle([0, 0, 0], [0.1, 0.2, 0.3], 60) rotcoords = [op.operate(c) for c in coords] mol2 = Molecule(["C", "H", "H", "H", "H"], rotcoords) mm = MoleculeMatcher(mapper=mapper) self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join( test_dir, "benzene1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join( test_dir, "benzene2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join( test_dir, "benzene1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir, "t2.xyz")).pymatgen_mol self.assertFalse(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir, "c1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir, "c2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir, "t3.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir, "t4.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir, "j1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir, "j2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join( test_dir, "ethene1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join( test_dir, "ethene2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join( test_dir, "toluene1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join( test_dir, "toluene2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file( os.path.join(test_dir, "cyclohexane1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file( os.path.join(test_dir, "cyclohexane2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mol1 = BabelMolAdaptor.from_file(os.path.join( test_dir, "oxygen1.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join( test_dir, "oxygen2.xyz")).pymatgen_mol self.assertTrue(mm.fit(mol1, mol2)) mm = MoleculeMatcher(tolerance=0.001, mapper=mapper) mol1 = BabelMolAdaptor.from_file(os.path.join(test_dir, "t3.xyz")).pymatgen_mol mol2 = BabelMolAdaptor.from_file(os.path.join(test_dir, "t4.xyz")).pymatgen_mol self.assertFalse(mm.fit(mol1, mol2))
def test_init(self): mol = Molecule(["C", "H", "H", "H", "H"], self.coords) cellin = FiestaInput(mol) self.assertEqual(cellin.molecule.spin_multiplicity, 1)
from pymatgen.util.testing import PymatgenTest Si_structure = Structure( lattice=[[0, 2.734364, 2.734364], [2.734364, 0, 2.734364], [2.734364, 2.734364, 0]], species=["Si", "Si"], coords=[[0, 0, 0], [0.25, 0.25, 0.25]], ) nonsense_Structure = Structure( lattice=[[-1.0, -10.0, -100.0], [0.1, 0.01, 0.001], [7.0, 11.0, 21.0]], species=["H"], coords=[[-1, -1, -1]], ) molecule = Molecule(species=["C", "H"], coords=[[0, 0, 0], [1, 1, 1]]) class InputTest(PymatgenTest): def setUp(self): self.TEST_FILES_DIR = Path.joinpath(self.TEST_FILES_DIR, "cp2k") self.ci = Cp2kInput.from_file( Path.joinpath(self.TEST_FILES_DIR, "cp2k.inp")) def test_basic_sections(self): s = """ &GLOBAL RUN_TYPE ENERGY PROJECT_NAME CP2K ! default name &END """
def _parse_job(cls, output): heat_pattern = re.compile( "FINAL HEAT OF FORMATION =\s+(?P<energy>-?\d+\.\d+)\s+KCAL/MOL") total_energy_pattern = re.compile( "TOTAL ENERGY\s+=\s+(?P<energy>-\d+\.\d+)\s+EV") coord_pattern = re.compile("\s*\d+\s+(?P<element>[A-Z][a-z]*)\s+" "(?P<x>\-?\d+\.\d+)\s+" "(?P<y>\-?\d+\.\d+)\s+" "(?P<z>\-?\d+\.\d+)") error_defs = ( (re.compile("EXCESS NUMBER OF OPTIMIZATION CYCLES"), "Geometry optimization failed"), (re.compile("UNABLE TO ACHIEVE SELF-CONSISTENCE"), "Bad SCF convergence"), (re.compile("TO CONTINUE, START AGAIN WITH THE WORD \"PRECISE\""), "Not Accurate Enough") ) energies = [] parse_keywords = None result_section = False star_line_count = 0 parse_coords = False input_keywords = None jobtype = None gracefully_terminated = False errors = set() coords = [] species = [] molecules = [] for line in output.split('\n'): for ep, message in error_defs: if ep.search(line): errors.add(message) if parse_keywords and input_keywords is None: input_keywords = MopTask._parse_keywords([line]) jobtext = (set( input_keywords.keys()) & MopTask.available_sqm_tasktext).pop() jobtype = MopTask.jobtext2type[jobtext] parse_keywords = False if result_section and "*" * 50 in line: star_line_count += 1 if star_line_count == 2: parse_keywords = True if "PM7 CALCULATION RESULTS" in line: result_section = True if parse_coords: if "ATOM" in line: continue if len(line.strip()) == 0: if len(coords) == 0: continue else: parse_coords = False molecules.append(Molecule(species, coords)) species = None coords = None continue m = coord_pattern.match(line) coords.append([float(m.group("x")), float(m.group("y")), float(m.group("z"))]) species.append(m.group("element")) if "CARTESIAN COORDINATES" in line: parse_coords = True coords = [] species = [] m = heat_pattern.search(line) if m: heat_of_formation = float( m.group("energy")) * cls.kcal_per_mol_2_eV energies.append( tuple(["Heat of Formation", heat_of_formation])) m = total_energy_pattern.search(line) if m: total_energy = float(m.group("energy")) energies.append(tuple(["Total Energy", total_energy])) if "== MOPAC DONE ==" in line: gracefully_terminated = True if len(errors) == 0: for text in cls._expected_successful_pattern(input_keywords): sucess_pattern = re.compile(text) if not sucess_pattern.search(output): errors.add("Can't find text to indicate success") errors = list(errors) data = { "jobtype": jobtype, "energies": energies, "molecules": molecules, "errors": errors, "has_error": len(errors) > 0, "gracefully_terminated": gracefully_terminated } return data
def test_split(self): bonds = [(0, 1), (4, 5)] alterations = { (2, 3): { "weight": 1.0 }, (0, 5): { "weight": 2.0 }, (1, 2): { "weight": 2.0 }, (3, 4): { "weight": 2.0 }, } # Perform retro-Diels-Alder reaction - turn product into reactants reactants = self.cyclohexene.split_molecule_subgraphs( bonds, allow_reverse=True, alterations=alterations) self.assertTrue(isinstance(reactants, list)) reactants = sorted(reactants, key=len) # After alterations, reactants sholuld be ethylene and butadiene self.assertEqual(reactants[0], self.ethylene) self.assertEqual(reactants[1], self.butadiene) with self.assertRaises(MolGraphSplitError): self.cyclohexene.split_molecule_subgraphs([(0, 1)]) # Test naive charge redistribution hydroxide = Molecule(["O", "H"], [[0, 0, 0], [0.5, 0.5, 0.5]], charge=-1) oh_mg = MoleculeGraph.with_empty_graph(hydroxide) oh_mg.add_edge(0, 1) new_mgs = oh_mg.split_molecule_subgraphs([(0, 1)]) for mg in new_mgs: if str(mg.molecule[0].specie) == "O": self.assertEqual(mg.molecule.charge, -1) else: self.assertEqual(mg.molecule.charge, 0) # Trying to test to ensure that remapping of nodes to atoms works diff_species = Molecule( ["C", "I", "Cl", "Br", "F"], [ [0.8314, -0.2682, -0.9102], [1.3076, 1.3425, -2.2038], [-0.8429, -0.7410, -1.1554], [1.9841, -1.7636, -1.2953], [1.0098, 0.1231, 0.3916], ], ) diff_spec_mg = MoleculeGraph.with_empty_graph(diff_species) diff_spec_mg.add_edge(0, 1) diff_spec_mg.add_edge(0, 2) diff_spec_mg.add_edge(0, 3) diff_spec_mg.add_edge(0, 4) for i in range(1, 5): bond = (0, i) split_mgs = diff_spec_mg.split_molecule_subgraphs([bond]) for split_mg in split_mgs: species = nx.get_node_attributes(split_mg.graph, "specie") for j in range(len(split_mg.graph.nodes)): atom = split_mg.molecule[j] self.assertEqual(species[j], str(atom.specie))
def pymatgen_molecule(self): from pymatgen.core.structure import Molecule species = ['C'] * len(self.coords) return Molecule(species, self.coords)
def test_from_string(self): string = """$molecule 0 1 S -0.00250959 -0.05817469 -0.02921636 C 1.70755408 -0.03033788 -0.01382912 H 2.24317221 -0.05215019 0.92026728 C 2.21976393 0.01718014 -1.27293235 H 3.27786220 0.04082146 -1.48539646 C 1.20867399 0.04478540 -2.27007793 H 1.40292257 0.10591684 -3.33110912 C -0.05341046 0.01577217 -1.74839343 C -1.32843436 0.03545064 -2.45531187 C -1.55195156 0.08743920 -3.80184635 H -0.75245172 0.10267657 -4.52817967 C -2.93293778 0.08408786 -4.13352169 H -3.31125108 0.11340328 -5.14405819 C -3.73173288 0.02741365 -3.03412864 H -4.80776535 0.00535688 -2.99564645 S -2.81590978 -0.00516172 -1.58990580 $end $rem jobtype = opt method = wb97m-v basis = def2-tzvppd gen_scfman = true geom_opt_max_cycles = 75 max_scf_cycles = 300 scf_algorithm = diis scf_guess = sad sym_ignore = true symmetry = false thresh = 14 $end $opt CONSTRAINT tors 6 8 9 10 0.0 ENDCONSTRAINT $end """ qcinput_test = QCInput.from_string(string) species = [ "S", "C", "H", "C", "H", "C", "H", "C", "C", "C", "H", "C", "H", "C", "H", "S", ] coords = [ [-0.00250959, -0.05817469, -0.02921636], [1.70755408, -0.03033788, -0.01382912], [2.24317221, -0.05215019, 0.92026728], [2.21976393, 0.01718014, -1.27293235], [3.27786220, 0.04082146, -1.48539646], [1.20867399, 0.04478540, -2.27007793], [1.40292257, 0.10591684, -3.33110912], [-0.05341046, 0.01577217, -1.74839343], [-1.32843436, 0.03545064, -2.45531187], [-1.55195156, 0.08743920, -3.80184635], [-0.75245172, 0.10267657, -4.52817967], [-2.93293778, 0.08408786, -4.13352169], [-3.31125108, 0.11340328, -5.14405819], [-3.73173288, 0.02741365, -3.03412864], [-4.80776535, 0.00535688, -2.99564645], [-2.81590978, -0.00516172, -1.58990580], ] molecule_actual = Molecule(species, coords) self.assertEqual(molecule_actual, qcinput_test.molecule) rem_actual = { "job_type": "opt", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": "75", "max_scf_cycles": "300", "scf_algorithm": "diis", "scf_guess": "sad", "sym_ignore": "true", "symmetry": "false", "thresh": "14", } self.assertDictEqual(rem_actual, qcinput_test.rem) opt_actual = {"CONSTRAINT": ["tors 6 8 9 10 0.0"]} self.assertDictEqual(opt_actual, qcinput_test.opt)
E_binding[key] = E_interfaces[key] \ - E_slabs[key_slab] \ - cal.system['num_ligands'] * E_ligands[ key_ligand] logger.info('Binding energy = {}'.format(E_binding)) # test if __name__ == '__main__': from pymatgen.core.structure import Structure, Molecule from mpinterfaces.interface import Ligand # PbS 100 surface with single hydrazine as ligand strt = Structure.from_file("POSCAR.mp-21276_PbS") mol_struct = Structure.from_file("POSCAR_diacetate") mol = Molecule(mol_struct.species, mol_struct.cart_coords) hydrazine = Ligand([mol]) supercell = [1, 1, 1] hkl = [1, 1, 1] min_thick = 10 min_vac = 12 surface_coverage = 0.01 adsorb_on_species = 'S' adatom_on_lig = 'Pb' displacement = 3.0 iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01,
def test_from_multi_jobs_file(self): job_list_test = QCInput.from_multi_jobs_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "qchem", "pt_n2_wb97mv_0.0.in")) species = [ "S", "C", "H", "C", "H", "C", "H", "C", "C", "C", "H", "C", "H", "C", "H", "S", ] coords = [ [-0.00250959, -0.05817469, -0.02921636], [1.70755408, -0.03033788, -0.01382912], [2.24317221, -0.05215019, 0.92026728], [2.21976393, 0.01718014, -1.27293235], [3.27786220, 0.04082146, -1.48539646], [1.20867399, 0.04478540, -2.27007793], [1.40292257, 0.10591684, -3.33110912], [-0.05341046, 0.01577217, -1.74839343], [-1.32843436, 0.03545064, -2.45531187], [-1.55195156, 0.08743920, -3.80184635], [-0.75245172, 0.10267657, -4.52817967], [-2.93293778, 0.08408786, -4.13352169], [-3.31125108, 0.11340328, -5.14405819], [-3.73173288, 0.02741365, -3.03412864], [-4.80776535, 0.00535688, -2.99564645], [-2.81590978, -0.00516172, -1.58990580], ] molecule_1_actual = Molecule(species, coords) rem_1_actual = { "job_type": "opt", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": "75", "max_scf_cycles": "300", "scf_algorithm": "diis", "scf_guess": "sad", "sym_ignore": "true", "symmetry": "false", "thresh": "14", } opt_1_actual = {"CONSTRAINT": ["tors 6 8 9 10 0.0"]} self.assertEqual(molecule_1_actual, job_list_test[0].molecule) self.assertEqual(rem_1_actual, job_list_test[0].rem) self.assertEqual(opt_1_actual, job_list_test[0].opt) molecule_2_actual = "read" rem_2_actual = { "job_type": "sp", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": "75", "max_scf_cycles": "300", "scf_algorithm": "diis", "scf_guess": "read", "sym_ignore": "true", "symmetry": "false", "thresh": "14", } self.assertEqual(molecule_2_actual, job_list_test[1].molecule) self.assertEqual(rem_2_actual, job_list_test[1].rem)
import itertools from pymatgen import Composition from pymatgen.io.gaussian import GaussianInput from pymatgen.core.structure import Molecule from tinydb import TinyDB # define the substituents subs = [('nitro', 'nitro'), ('amine', 'amine'), ('cyano', 'cyano'), ('hydroxyl', 'hydroxyl'), ('fluoro', 'fluoro'), ('chloro', Molecule(['X', 'Cl'], [[0., 0., 0.], [0., 0., 1.11]])), ('bromo', Molecule(['X', 'Br'], [[0., 0., 0.], [0., 0., 1.11]])), [None]] # define the x, y, z substituent positions as {name: site_ids}, where name is # consistent with Pakapol naming convention and site_id is a list of zero based # array indexes sub_sites = {'x': [48, 49], 'y': [50, 51], 'z': [52, 53]} sub_sites_thiol = {'x': [47, 49], 'y': [30, 31], 'z': [32, 33]} # these lists give the nitrogen positions as (name, N site_ids, H site_ids), # where name is consistent with Pakapol naming convention, and site_id is a # list of zero based array indexes nx_sites = [(1, [21, 28], [43, 44]), (2, [22, 27], [52, 53]), (3, [23, 26], [50, 51]),
def _parse_job(self, output): energy_patt = re.compile(r'Total \w+ energy\s+=\s+([.\-\d]+)') energy_gas_patt = re.compile(r'gas phase energy\s+=\s+([.\-\d]+)') energy_sol_patt = re.compile(r'sol phase energy\s+=\s+([.\-\d]+)') coord_patt = re.compile(r'\d+\s+(\w+)\s+[.\-\d]+\s+([.\-\d]+)\s+' r'([.\-\d]+)\s+([.\-\d]+)') lat_vector_patt = re.compile(r'a[123]=<\s+([.\-\d]+)\s+' r'([.\-\d]+)\s+([.\-\d]+)\s+>') corrections_patt = re.compile(r'([\w\-]+ correction to \w+)\s+=' r'\s+([.\-\d]+)') preamble_patt = re.compile(r'(No. of atoms|No. of electrons' r'|SCF calculation type|Charge|Spin ' r'multiplicity)\s*:\s*(\S+)') force_patt = re.compile(r'\s+(\d+)\s+(\w+)' + 6 * r'\s+([0-9\.\-]+)') time_patt = re.compile( r'\s+ Task \s+ times \s+ cpu: \s+ ([.\d]+)s .+ ', re.VERBOSE) error_defs = { "calculations not reaching convergence": "Bad convergence", "Calculation failed to converge": "Bad convergence", "geom_binvr: #indep variables incorrect": "autoz error", "dft optimize failed": "Geometry optimization failed"} fort2py = lambda x: x.replace("D", "e") isfloatstring = lambda s: s.find(".") == -1 parse_hess = False parse_proj_hess = False hessian = None projected_hessian = None parse_force = False all_forces = [] forces = [] data = {} energies = [] frequencies = None normal_frequencies = None corrections = {} molecules = [] structures = [] species = [] coords = [] lattice = [] errors = [] basis_set = {} bset_header = [] parse_geom = False parse_freq = False parse_bset = False parse_projected_freq = False job_type = "" parse_time = False time = 0 for l in output.split("\n"): for e, v in error_defs.items(): if l.find(e) != -1: errors.append(v) if parse_time: m = time_patt.search(l) if m: time = m.group(1) parse_time = False if parse_geom: if l.strip() == "Atomic Mass": if lattice: structures.append(Structure(lattice, species, coords, coords_are_cartesian=True)) else: molecules.append(Molecule(species, coords)) species = [] coords = [] lattice = [] parse_geom = False else: m = coord_patt.search(l) if m: species.append(m.group(1).capitalize()) coords.append([float(m.group(2)), float(m.group(3)), float(m.group(4))]) m = lat_vector_patt.search(l) if m: lattice.append([float(m.group(1)), float(m.group(2)), float(m.group(3))]) if parse_force: m = force_patt.search(l) if m: forces.extend(map(float, m.groups()[5:])) elif len(forces) > 0: all_forces.append(forces) forces = [] parse_force = False elif parse_freq: if len(l.strip()) == 0: if len(normal_frequencies[-1][1]) == 0: continue else: parse_freq = False else: vibs = [float(vib) for vib in l.strip().split()[1:]] num_vibs = len(vibs) for mode, dis in zip(normal_frequencies[-num_vibs:], vibs): mode[1].append(dis) elif parse_projected_freq: if len(l.strip()) == 0: if len(frequencies[-1][1]) == 0: continue else: parse_projected_freq = False else: vibs = [float(vib) for vib in l.strip().split()[1:]] num_vibs = len(vibs) for mode, dis in zip( frequencies[-num_vibs:], vibs): mode[1].append(dis) elif parse_bset: if l.strip() == "": parse_bset = False else: toks = l.split() if toks[0] != "Tag" and not re.match(r"-+", toks[0]): basis_set[toks[0]] = dict(zip(bset_header[1:], toks[1:])) elif toks[0] == "Tag": bset_header = toks bset_header.pop(4) bset_header = [h.lower() for h in bset_header] elif parse_hess: if l.strip() == "": continue if len(hessian) > 0 and l.find("----------") != -1: parse_hess = False continue toks = l.strip().split() if len(toks) > 1: try: row = int(toks[0]) except Exception: continue if isfloatstring(toks[1]): continue vals = [float(fort2py(x)) for x in toks[1:]] if len(hessian) < row: hessian.append(vals) else: hessian[row - 1].extend(vals) elif parse_proj_hess: if l.strip() == "": continue nat3 = len(hessian) toks = l.strip().split() if len(toks) > 1: try: row = int(toks[0]) except Exception: continue if isfloatstring(toks[1]): continue vals = [float(fort2py(x)) for x in toks[1:]] if len(projected_hessian) < row: projected_hessian.append(vals) else: projected_hessian[row - 1].extend(vals) if len(projected_hessian[-1]) == nat3: parse_proj_hess = False else: m = energy_patt.search(l) if m: energies.append(Energy(m.group(1), "Ha").to("eV")) parse_time = True continue m = energy_gas_patt.search(l) if m: cosmo_scf_energy = energies[-1] energies[-1] = dict() energies[-1].update({"cosmo scf": cosmo_scf_energy}) energies[-1].update({"gas phase": Energy(m.group(1), "Ha").to("eV")}) m = energy_sol_patt.search(l) if m: energies[-1].update( {"sol phase": Energy(m.group(1), "Ha").to("eV")}) m = preamble_patt.search(l) if m: try: val = int(m.group(2)) except ValueError: val = m.group(2) k = m.group(1).replace("No. of ", "n").replace(" ", "_") data[k.lower()] = val elif l.find("Geometry \"geometry\"") != -1: parse_geom = True elif l.find("Summary of \"ao basis\"") != -1: parse_bset = True elif l.find("P.Frequency") != -1: parse_projected_freq = True if frequencies is None: frequencies = [] toks = l.strip().split()[1:] frequencies.extend([(float(freq), []) for freq in toks]) elif l.find("Frequency") != -1: toks = l.strip().split() if len(toks) > 1 and toks[0] == "Frequency": parse_freq = True if normal_frequencies is None: normal_frequencies = [] normal_frequencies.extend([(float(freq), []) for freq in l.strip().split()[1:]]) elif l.find("MASS-WEIGHTED NUCLEAR HESSIAN") != -1: parse_hess = True if not hessian: hessian = [] elif l.find("MASS-WEIGHTED PROJECTED HESSIAN") != -1: parse_proj_hess = True if not projected_hessian: projected_hessian = [] elif l.find("atom coordinates gradient") != -1: parse_force = True elif job_type == "" and l.strip().startswith("NWChem"): job_type = l.strip() if job_type == "NWChem DFT Module" and \ "COSMO solvation results" in output: job_type += " COSMO" else: m = corrections_patt.search(l) if m: corrections[m.group(1)] = FloatWithUnit( m.group(2), "kJ mol^-1").to("eV atom^-1") if frequencies: for freq, mode in frequencies: mode[:] = zip(*[iter(mode)]*3) if normal_frequencies: for freq, mode in normal_frequencies: mode[:] = zip(*[iter(mode)]*3) if hessian: n = len(hessian) for i in range(n): for j in range(i + 1, n): hessian[i].append(hessian[j][i]) if projected_hessian: n = len(projected_hessian) for i in range(n): for j in range(i + 1, n): projected_hessian[i].append(projected_hessian[j][i]) data.update({"job_type": job_type, "energies": energies, "corrections": corrections, "molecules": molecules, "structures": structures, "basis_set": basis_set, "errors": errors, "has_error": len(errors) > 0, "frequencies": frequencies, "normal_frequencies": normal_frequencies, "hessian": hessian, "projected_hessian": projected_hessian, "forces": all_forces, "task_time": time}) return data
def get_redo_workflow(self, qchem_input_params, sp_params, max_iterations=3): """ Identifies molecules which need to be re-run (for now, based only on presence of negative frequencies) and then performs a frequency flattening workflow on those molecules. This is a hack. In the future, a frequency flattening workflow should be used from the beginning. :param qchem_input_params: dict :param sp_params: For OptFreqSPFW, single-point calculations can be treated differently from Opt and Freq. In this case, another dict for sp must be used. :param max_iterations: Maximum number of iterations for frequency flattening. Default is 3. :return: Workflow """ if self.db is None: raise RuntimeError("Cannot access database to determine what" "molecules need to be re-calculated.") fws = [] collection = self.db.db["molecules"] for mol in collection.find({}): frequencies = mol["output"]["frequencies"] if any([True if x < 0 else False for x in frequencies]): min_molecule_perturb_scale = 0.1 max_molecule_perturb_scale = 0.3 scale_grid = 10 perturb_scale_grid = (max_molecule_perturb_scale - min_molecule_perturb_scale) / scale_grid msc = MoleculeStructureComparator() old_molecule = None for calc in mol["calcs_reversed"]: if calc["task"]["type"] in ["freq", "frequency" ] and old_molecule is None: negative_freq_vecs = calc.get( "frequency_mode_vectors")[0] old_coords = calc.get("initial_geometry") old_molecule = Molecule.from_dict( calc.get("initial_molecule")) structure_successfully_perturbed = False for molecule_perturb_scale in np.arange( max_molecule_perturb_scale, min_molecule_perturb_scale, -perturb_scale_grid): new_coords = perturb_coordinates( old_coords=old_coords, negative_freq_vecs=negative_freq_vecs, molecule_perturb_scale=molecule_perturb_scale, reversed_direction=False) new_molecule = Molecule( species=old_molecule.species, coords=new_coords, charge=old_molecule.charge, spin_multiplicity=old_molecule.spin_multiplicity) if msc.are_equal(old_molecule, new_molecule): structure_successfully_perturbed = True break if not structure_successfully_perturbed: raise Exception( "Unable to perturb coordinates to remove negative frequency without changing the bonding structure" ) mol_id = mol["mol_id"] dir_name = mol["dir_name"].split("/")[-1] if dir_name not in listdir(self.base_dir): os.mkdir(join(self.base_dir, dir_name)) fws.append( OptFreqSPFW(molecule=new_molecule, name="Flattening: {}/{}".format( mol_id, dir_name), qchem_cmd="qchem -slurm", input_file=join(self.base_dir, dir_name, mol_id + ".in"), output_file=join(self.base_dir, dir_name, mol_id + ".out"), qclog_file=join(self.base_dir, dir_name, mol_id + ".qclog"), max_cores=32, max_iterations=max_iterations, qchem_input_params=qchem_input_params, sp_params=sp_params, db_file=self.db_file)) if len(fws) == 0: return None else: return Workflow(fws)
import unittest from pymatgen.core.structure import Molecule from pymatgen.io.nwchem import NwInput, NwInputError, NwOutput, NwTask from pymatgen.util.testing import PymatgenTest test_dir = os.path.join(PymatgenTest.TEST_FILES_DIR, "nwchem") coords = [ [0.000000, 0.000000, 0.000000], [0.000000, 0.000000, 1.089000], [1.026719, 0.000000, -0.363000], [-0.513360, -0.889165, -0.363000], [-0.513360, 0.889165, -0.363000], ] mol = Molecule(["C", "H", "H", "H", "H"], coords) class NwTaskTest(unittest.TestCase): def setUp(self): self.task = NwTask( 0, 1, basis_set={"H": "6-31g"}, theory="dft", theory_directives={"xc": "b3lyp"}, ) self.task_cosmo = NwTask( 0, 1, basis_set={"H": "6-31g"},
if len(argv) < 3: exit("Usage: convert_trajectory_xyzs.py initial_molecule_file, trajectory, to_dir") initial_molecule_file = argv[1] trajectory = argv[2] to_dir = argv[3] init_mol = Molecule.from_file(initial_molecule_file) species = [str(e) for e in init_mol.species] num_atoms = len(species) if to_dir not in os.listdir(): os.mkdir(to_dir) iteration = 0 num_agent = 0 with open(trajectory) as traj_file: lines = traj_file.readlines() num_agents = int(lines[1].split()[1]) for line in lines[2:]: if line == "\n": iteration += 1 num_agent = 0 elif "." not in line: continue else: coords = np.array([float(e) for e in line.strip().split(" ")]).reshape(num_atoms, 3) mol = Molecule(species, coords) mol.to("xyz", os.path.join(to_dir, "{}_{}.xyz".format(iteration,num_agent))) num_agent += 1
def setUpClass(cls): h2o_coords = [[9.626, 6.787, 12.673], [9.626, 8.420, 12.673], [10.203, 7.604, 12.673]] molecule = Molecule(["H", "H", "O"], h2o_coords) box_size = [[0.0, 10.0], [0.0, 10.0], [0.0, 10.0]] cls.lammps_data = LammpsData.from_structure(molecule, box_size)
return stdout, stderr if __name__ == "__main__": ethanol_coords = [ [0.00720, -0.56870, 0.00000], [-1.28540, 0.24990, 0.00000], [1.13040, 0.31470, 0.00000], [0.03920, -1.19720, 0.89000], [0.03920, -1.19720, -0.89000], [-1.31750, 0.87840, 0.89000], [-1.31750, 0.87840, -0.89000], [-2.14220, -0.42390, -0.00000], [1.98570, -0.13650, -0.00000], ] ethanol = Molecule(["C", "C", "O", "H", "H", "H", "H", "H", "H"], ethanol_coords) water_coords = [ [9.626, 6.787, 12.673], [9.626, 8.420, 12.673], [10.203, 7.604, 12.673], ] water = Molecule(["H", "H", "O"], water_coords) pmr = PackmolRunner( [ethanol, water], [ { "number": 1, "fixed": [0, 0, 0, 0, 0, 0], "centerofmass": "" }, {