def get_bonds(mol: Molecule) -> np.ndarray: """Return an array with the atomic indices defining all bonds in **mol**. Parameters ---------- mol : |plams.Molecule|_ A PLAMS molecule. Returns ------- :math:`n*2` |np.ndarray|_ [|np.int64|_]: A 2D array with atomic indices defining :math:`n` bonds. """ mol.set_atoms_id() bonds = [(b.atom1.id, b.atom2.id) for b in mol.bonds] ret = np.array(bonds, dtype=int, ndmin=2) mol.unset_atoms_id() if not bonds: # If no angles are found return ret # Sort horizontally mass = np.array([[mol[j].mass for j in i] for i in ret]) idx1 = np.argsort(mass, axis=1)[:, ::-1] ret[:] = np.take_along_axis(ret, idx1, axis=1) # Sort and return vertically idx2 = np.argsort(ret, axis=0)[:, 0] return ret[idx2]
def test_opt_gamess(): """ Test Optimization in Gamess using methanol in water. """ methanol = Molecule('test/test_files/ion_methanol.xyz') methanol.properties['symmetry'] = 'Cs' s = Settings() s.specific.gamess.contrl.nzvar = 12 s.specific.gamess.system.timlim = 2 s.specific.gamess.system.mwords = 2 s.specific.gamess.pcm.solvnt = 'water' s.specific.gamess.basis.gbasis = 'sto' s.specific.gamess.basis.ngauss = 3 s.specific.gamess.guess.guess = 'huckel' s.specific.gamess.stapt.optol = '1d-5' s.specific.gamess.zmat["izmat(1)"] = "1,1,2, 1,2,3, 1,3,4, 1,3,5, 1,3,6, \n"\ "2,1,2,3, 2,2,3,4, 2,2,3,5, 2,2,3,6, \n"\ "3,1,2,3,4, 3,1,2,3,5, 3,1,2,3,6" inp = templates.geometry.overlay(s) methanol_geometry = gamess(inp, methanol, work_dir='/tmp') mol_opt = run(methanol_geometry.molecule) coords = concat([a.coords for a in mol_opt.atoms]) expected_coords = [-0.9956983464, 0.9204754677, -0.0002616586, -0.72585581, -0.0802380791, 2.18166e-05, 0.741292161, 0.0371204735, -1.69738e-05, 1.1448441964, 0.5632291664, -0.9026112278, 1.1448447102, 0.562978981, 0.9027182521, 1.1454516521, -0.9993402516, 1.04943e-05] assert abs(sum(zipWith(operator.sub)(coords)(expected_coords))) < 1e-7
def string_array_to_molecule(parser_fun, file_name, mol=None): """ Convert a Numpy string array like: [['C', '-1.487460', '-0.028670', '-0.000060'], ['O', '0.376340', '0.028670', '-0.000060'], ['H', '-1.818910', '-1.067060', '-0.000060'], ['H', '-1.866470', '0.473700', '0.889930'], ['H', '-1.866470', '0.473700', '-0.890040'], ['H', '0.756720', '-0.950010', '-0.000060']] To a plams ``Molecule``. """ string_array_to_float = np.vectorize(float) mols = parse_file(parser_fun, file_name).asList() last_mol = np.array(mols[-1]) elems = last_mol[:, 0] coords = string_array_to_float(last_mol[:, 1:]) if mol: if len(coords) == len(mol): plams_mol = mol for i in range(len(plams_mol)): plams_mol.atoms[i].coords = tuple( [float(c) for c in coords[i]]) else: raise RuntimeError('Output molecule does not match input molecule') else: plams_mol = Molecule() for e, c in zip(elems, coords): plams_mol.add_atom(Atom(symbol=e, coords=tuple(c))) return plams_mol
def test_opt_gamess(): """ Test Optimization in Gamess using methanol in water. """ methanol = Molecule('test/test_files/ion_methanol.xyz') methanol.properties['symmetry'] = 'Cs' s = Settings() s.specific.gamess.contrl.nzvar = 12 s.specific.gamess.system.timlim = 2 s.specific.gamess.system.mwords = 2 s.specific.gamess.pcm.solvnt = 'water' s.specific.gamess.basis.gbasis = 'sto' s.specific.gamess.basis.ngauss = 3 s.specific.gamess.guess.guess = 'huckel' s.specific.gamess.stapt.optol = '1d-5' s.specific.gamess.zmat["izmat(1)"] = "1,1,2, 1,2,3, 1,3,4, 1,3,5, 1,3,6, \n"\ "2,1,2,3, 2,2,3,4, 2,2,3,5, 2,2,3,6, \n"\ "3,1,2,3,4, 3,1,2,3,5, 3,1,2,3,6" inp = templates.geometry.overlay(s) methanol_geometry = gamess(inp, methanol, work_dir='/tmp') mol_opt = run(methanol_geometry.molecule) coords = concat([a.coords for a in mol_opt.atoms]) expected_coords = [ -0.9956983464, 0.9204754677, -0.0002616586, -0.72585581, -0.0802380791, 2.18166e-05, 0.741292161, 0.0371204735, -1.69738e-05, 1.1448441964, 0.5632291664, -0.9026112278, 1.1448447102, 0.562978981, 0.9027182521, 1.1454516521, -0.9993402516, 1.04943e-05 ] assert abs(sum(zipWith(operator.sub)(coords)(expected_coords))) < 1e-7
def repr_Molecule(self, obj: Molecule, level: int) -> str: # noqa: N802 """Create a :class:`str` representation of a |plams.Molecule| instance.""" if level <= 0: return f'{obj.__class__.__name__}(...)' elif not obj: return f'{obj.__class__.__name__}()' obj.set_atoms_id() ret = 'Atoms: \n' i = self.maxMolecule # Print atoms kwargs = {'decimal': self.maxfloat, 'space': 14 - (6 - self.maxfloat)} for atom in obj.atoms[:i]: ret += f' {atom.id:<5d}{atom.str(**kwargs).strip()}\n' if len(obj.atoms) > i: ret += ' ...\n' # Print bonds if len(obj.bonds): ret += 'Bonds: \n' for bond in obj.bonds[:i]: ret += f' ({bond.atom1.id})--{bond.order:1.1f}--({bond.atom2.id})\n' if len(obj.bonds) > i: ret += ' ...\n' # Print lattice vectors if obj.lattice: ret += 'Lattice:\n' for vec in obj.lattice: ret += ' {:16.10f} {:16.10f} {:16.10f}\n'.format(*vec) obj.unset_atoms_id() indent = 4 * ' ' return f'{obj.__class__.__name__}(\n{textwrap.indent(ret[:-1], indent)}\n)'
def string_array_to_molecule(parser_fun, file_name, mol=None): """ Convert a Numpy string array like: [['C', '-1.487460', '-0.028670', '-0.000060'], ['O', '0.376340', '0.028670', '-0.000060'], ['H', '-1.818910', '-1.067060', '-0.000060'], ['H', '-1.866470', '0.473700', '0.889930'], ['H', '-1.866470', '0.473700', '-0.890040'], ['H', '0.756720', '-0.950010', '-0.000060']] To a plams ``Molecule``. """ string_array_to_float = np.vectorize(float) mols = parse_file(parser_fun, file_name).asList() last_mol = np.array(mols[-1]) elems = last_mol[:, 0] coords = string_array_to_float(last_mol[:, 1:]) if mol: if len(coords) == len(mol): plams_mol = mol for i in range(len(plams_mol)): plams_mol.atoms[i].coords = tuple([float(c) for c in coords[i]]) else: raise RuntimeError('Output molecule does not match input molecule') else: plams_mol = Molecule() for e, c in zip(elems, coords): plams_mol.add_atom(Atom(symbol=e, coords=tuple(c))) return plams_mol
def modified_minimum_scan_rdkit(ligand: Molecule, bond_tuple: Tuple[int, int], anchor: Atom) -> None: """A modified version of the :func:`.global_minimum_scan_rdkit` function. * Uses the ligand vector as criteria rather than the energy. * Geometry optimizations are constrained during the conformation search. * Finish with a final unconstrained geometry optimization. See Also -------- :func:`global_minimum_scan_rdkit<scm.plams.recipes.global_minimum.minimum_scan_rdkit>`: Optimize the molecule (RDKit UFF) with 3 different values for the given dihedral angle and find the lowest energy conformer. :param |Molecule| mol: The input molecule :param tuple bond_tuple: A 2-tuples containing the atomic indices of valid bonds :return |Molecule|: A copy of *mol* with a newly optimized geometry """ # Define a number of variables and create 3 copies of the ligand angles = (-120, 0, 120) mol_list = [ligand.copy() for _ in range(3)] for angle, mol in zip(angles, mol_list): bond = mol[bond_tuple] atom = mol[bond_tuple[0]] mol.rotate_bond(bond, atom, angle, unit='degree') rdmol_list = [molkit.to_rdmol(mol, properties=False) for mol in mol_list] # Optimize the (constrained) geometry for all dihedral angles in angle_list # The geometry that yields the minimum energy is returned fixed = _find_idx(mol, bond) for rdmol in rdmol_list: ff = UFF(rdmol) for f in fixed: ff.AddFixedPoint(f) ff.Minimize() # Find the conformation with the optimal ligand vector cost_list = [] try: i = ligand.atoms.index(anchor) except ValueError: i = -1 # Default to the origin as anchor for rdmol in rdmol_list: xyz = rdmol_as_array(rdmol) if i == -1: # Default to the origin as anchor xyz = np.vstack([xyz, [0, 0, 0]]) rotmat = optimize_rotmat(xyz, i) xyz[:] = xyz @ rotmat.T xyz -= xyz[i] cost = np.exp(xyz[:, 1:]).sum() cost_list.append(cost) # Perform an unconstrained optimization on the best geometry and update the geometry of ligand j = np.argmin(cost_list) rdmol_best = rdmol_list[j] UFF(rdmol).Minimize() ligand.from_rdmol(rdmol_best)
def store_optimized_molecule(optimized_geometry: Molecule, name: str, path_results: str): """Store the xyz molecular geometry.""" path_geometry = f"{path_results}/{name}" if not os.path.exists(path_geometry): os.mkdir(path_geometry) with open(f"{path_geometry}/{name}_OPT.xyz", 'w') as f: optimized_geometry.writexyz(f)
def __init__(self, mol: Molecule) -> None: """Initialize the instance.""" mol.set_atoms_id(start=0) self._mol = mol self._dist_mat = _get_dist_mat(mol) self._dist_mat.setflags(write=False) self.id_set = set() self.neighbor_dict = {}
def tuplesXYZ_to_plams(xs): """ Transform a list of namedTuples to a Plams molecule """ plams_mol = Molecule() for at in xs: symb = at.symbol cs = at.xyz plams_mol.add_atom(Atom(symbol=symb, coords=tuple(cs))) return plams_mol
def tuplesXYZ_to_plams(xs): """ Transform a list of namedTuples to a Plams molecule """ plams_mol = Molecule() for at in xs: symb = at.symbol cs = at.xyz plams_mol.add_atom(Atom(symbol=symb, coords=tuple(cs))) return plams_mol
def _bond_id_generator( mol: Molecule) -> Generator[Tuple[int, int, int, int], None, None]: """Yield all permutations of the bond-defining atoms indices in **mol**.""" mol.set_atoms_id(start=0) for b in mol.bonds: id1 = b.atom1.id id2 = b.atom2.id yield id1, id2, id2, id1 mol.unset_atoms_id()
def _protonate_mol(mol: Molecule) -> Molecule: mol_cp = mol.copy() i = mol.index(mol.properties.dummies) anchor = mol_cp[i] if anchor.properties.charge != -1: raise NotImplementedError("Non-anionic anchors are not supported") anchor.properties.charge = 0 return add_Hs(mol_cp, forcefield="uff")
def read_mol_xyz(mol_dict: Settings) -> Optional[Molecule]: """Read an .xyz file.""" try: mol = Molecule(mol_dict.mol, inputformat='xyz') if mol_dict.guess_bonds and not mol_dict.is_qd: mol.guess_bonds() if not mol_dict.is_core: canonicalize_mol(mol) return mol except Exception as ex: print_exception('read_mol_xyz', mol_dict.name, ex)
def geometry_to_molecule(geometry): """ Convert a list of XYZ coordinates to a Molecule object """ mol = Molecule() for i in range(0, len(geometry)): mol.add_atom( Atom(symbol=geometry[i][0], coords=(geometry[i][1], geometry[i][2], geometry[i][3]))) return mol
def sanitize_dim_3(value: Any, padding: float = np.nan) -> np.ndarray: """Convert a Molecule or sequence of :math:`m` molecules into an :math:`m*n*3` array. If necessary, the to-be returned array is padded with **padding** . Parameters ---------- arg : object The to be parsed object. Acceptable types are: * A PLAMS :class:`Atom` * A PLAMS :class:`Molecule` * A (nested) Sequences consisting of PLAMS :class:`Atom` * A (nested) Sequences consisting of PLAMS :class:`Molecule` * An array-like object with a dimensionality smaller than 3 and float-compatible elements. padding : float A value used for padding the to-be returned array. Only relevant if **arg** consists of multiple molecule with different numbers of atoms. Returns ------- :math:`m*n*3` |np.ndarray|_ [|np.float64|_] A 3D array consisting of floats. Raises ------ ValueError Raised if dimensionality of the to-be returned array is higher than 3 or the content of **arg** cannot be converted into an array of floats. """ if _is_atom(value): return np.array(value.coords)[None, None, :] elif _is_atom_sequence(value): return Molecule.as_array(None, atom_subset=value)[None, :] elif _is_mol_sequence(value): max_at = max(len(mol) for mol in value) ret = np.full((len(value), max_at, 3), padding, order='F') for i, mol in enumerate(value): j = len(mol) ret[i, :j] = Molecule.as_array(None, atom_subset=mol) return ret else: ret = np.array(value, ndmin=3, dtype=float, copy=False) if ret.ndim > 3: raise ValueError(f"Failed to create a 3D array; observed dimensionality: {ret.ndim}") return ret
def allign_axis(mol: Molecule, anchor: Atom): """Allign a molecule with the Cartesian X-axis; setting **anchor** as the origin.""" try: idx = mol.atoms.index(anchor) except ValueError as ex: raise MoleculeError("The passed anchor is not in mol") from ex xyz = mol.as_array() # Allign the molecule with the X-axis rotmat = optimize_rotmat(xyz, idx) xyz[:] = xyz @ rotmat.T xyz -= xyz[idx] xyz[:] = xyz.round(decimals=3) mol.from_array(xyz)
def parse_molecule_traj(file_traj: PathLike) -> Molecule: """Read Molecules from the job_name.traj file.""" mols = manyXYZ(file_traj) # Last geometry corresponds to the optimized structure opt_mol = mols[-1] plams_mol = Molecule() for at in opt_mol: symb = at.symbol cs = at.xyz plams_mol.add_atom(Atom(symbol=symb, coords=tuple(cs))) return plams_mol
def _get_ligand(mol: Molecule) -> Molecule: """Extract a single ligand from **mol** as a copy.""" at_list = [] res = mol.atoms[-1].properties.pdb_info.ResidueNumber for at in reversed(mol.atoms): if at.properties.pdb_info.ResidueNumber == res: at_list.append(at) else: ret = Molecule() ret.atoms = at_list ret.bonds = list( set(chain.from_iterable(at.bonds for at in at_list))) return ret.copy()
def supstitution_symmetry(mol): """Returns atomic symbols of substituted atoms (or first conection of non diatomic ligand). Writes type of substitution symetry at the molecular properties Parameters ---------- mol : |plams.Molecule| A PLAMS molecule Returns ------- str Type of subsymmetry """ dataframe, type_of_symetry = [], [] ligand_identity = mol.properties.ligID # Defining C atoms conected to substituents and making Molecule object (cmol) out of them catoms = mol.properties.coords_other_arrays cmol = Molecule() for at in catoms: cmol.add_atom(mol.closest_atom(at)) # If substitution is linear, simple combinations without repetition can be applied if len(ligand_identity) <= 2: if len(ligand_identity) == 1: logger.warning( "One does not simply ask for subsymmetry of one atom!") return elif len(ligand_identity) == 0: logger.warning( "One does not simply ask for subsymmetry of no atom") return else: subsymmetry = 'linear' else: # Getting non zero row indices from data frame - defines symmetry type dataframe = get_symmetry(cmol, decimals=2) type_of_symetry = np.unique(dataframe.to_numpy().nonzero()[0]) # Assign type of symetry and atomic symbols if list(type_of_symetry) == [0, 1, 8, 9]: subsymmetry = 'D2h' else: logger.warning("Subsymmetry is not recognized") return return subsymmetry
def get_asa_fragments(qd: Molecule) -> Tuple[List[Molecule], Molecule]: """Construct the fragments for an activation strain analyses. Parameters ---------- qd : |plams.Molecule| A Molecule whose atoms' properties should be marked with `pdb_info.ResidueName`. Atoms in the core should herein be marked with ``"COR"``. Returns ------- :class:`list` [|plams.Molecule|] and |plams.Molecule| A list of ligands and the core. Fragments are defined based on connectivity patterns (or lack thereof). """ # Delete all atoms within the core mol_complete = qd.copy() core = Molecule() core.properties = mol_complete.properties.copy() core_atoms = [at for at in mol_complete if at.properties.pdb_info.ResidueName == 'COR'] for atom in core_atoms: mol_complete.delete_atom(atom) atom.mol = core core.atoms = core_atoms mol_complete.properties.name += '_frags' core.properties.name += '_core' # Fragment the molecule ligand_list = mol_complete.separate() # Set atomic properties for at1, at2 in zip(chain(*ligand_list), mol_complete): at1.properties.symbol = at2.properties.symbol at1.properties.charge_float = at2.properties.charge_float for at1, at2 in zip(core, qd): at1.properties.symbol = at2.properties.symbol at1.properties.charge_float = at2.properties.charge_float # Set the prm parameter which points to the created .prm file name = mol_complete.properties.name[:-1] path = mol_complete.properties.path prm = mol_complete.properties.prm for mol in ligand_list: mol.properties.name = name mol.properties.path = path mol.properties.prm = prm return ligand_list, core
def set_qd(qd: Molecule, mol_dict: Settings) -> Molecule: """Update quantum dots imported by :func:`.read_mol`.""" # Create ligand (and anchor) molecules ligand = molkit.from_smiles(mol_dict.ligand_smiles) ligand_rdmol = molkit.to_rdmol(ligand) anchor = molkit.from_smiles(mol_dict.ligand_anchor) anchor_rdmol = molkit.to_rdmol(anchor) qd_rdmol = molkit.to_rdmol(qd) # Create arrays of atomic indices of the core and ligands lig_idx = 1 + np.array(qd_rdmol.GetSubstructMatches(ligand_rdmol)) core_idx = np.arange(1, len(qd))[~lig_idx] lig_idx = lig_idx.ravel().tolist() core_idx = core_idx.tolist() # Guess bonds if mol_dict.guess_bonds: qd.guess_bonds(atom_subset=[qd[i] for i in lig_idx]) # Reorder all atoms: core atoms first followed by ligands qd.atoms = [qd[i] for i in core_idx] + [qd[j] for i in lig_idx for j in i] # Construct a list with the indices of all ligand anchor atoms core_idx_max = 1 + len(core_idx) _anchor_idx = ligand_rdmol.GetSubstructMatch(anchor_rdmol)[0] start = core_idx_max + _anchor_idx stop = core_idx_max + _anchor_idx + np.product(lig_idx.shape) step = len(ligand) anchor_idx = list(range(start, stop, step)) # Update the properties of **qd** for i in anchor_idx: qd[i].properties.anchor = True qd.properties.indices = list(range(1, core_idx_max)) + anchor_idx qd.properties.job_path = [] qd.properties.name = mol_dict.name qd.properties.path = mol_dict.path qd.properties.ligand_smiles = Chem.CanonSmiles(mol_dict.ligand_smiles) qd.properties.ligand_anchor = f'{ligand[_anchor_idx].symbol}{_anchor_idx}' # Update the pdb_info of all atoms for i, at in enumerate(qd, 1): at.properties.pdb_info.SerialNumber = i if i <= core_idx_max: # A core atom at.properties.pdb_info.ResidueNumber = 1 else: # A ligand atom at.properties.pdb_info.ResidueNumber = 2 + int( (i - core_idx_max) / len(ligand))
def test_adf_mock(mocker: MockFixture): """Mock the ADF output.""" mol = Molecule(PATH_MOLECULES / "acetonitrile.xyz") job = adf(templates.geometry, mol) run_mocked = mocker.patch("qmflows.run") jobname = "ADFjob" dill_path = WORKDIR / jobname / "ADFjob.dill" plams_dir = WORKDIR / jobname run_mocked.return_value = ADF_Result(templates.geometry, mol, jobname, dill_path=dill_path, work_dir=plams_dir, plams_dir=plams_dir) rs = run_mocked(job) assertion.isfinite(rs.energy) assertion.isfinite(rs.h**o) assertion.isfinite(rs.lumo) # Array of runtime for each optimization assertion.isfinite(rs.runtime[-1]) # 3-dimensional vector assertion.len_eq(rs.dipole, 3) # number of steps until convergence assertion.eq(rs.optcycles, 8) # Test molecule # Molecule mol = rs.molecule assertion.isinstance(mol, Molecule) assertion.len_eq(mol, 6) # there are 6 atoms
def fun_ethylene(scratch_path): """ Test Ethylene single """ geometry = Molecule('test/test_files/ethylene.xyz') job_settings = prepare_cp2k_settings(geometry, scratch_path) cp2k_result = run(cp2k(job_settings, geometry, work_dir=scratch_path)) # Path to the HDF5 file hdf5_file = 'quantum.hdf5' # Path to the molecular orbitals energies and coefficients path_es = 'ethylene/cp2k_job/cp2k/mo/eigenvalues' path_css = 'ethylene/cp2k_job/cp2k/mo/coefficients' with h5py.File(hdf5_file) as f5: dump_to_hdf5(cp2k_result.orbitals, 'cp2k', f5, project_name='ethylene', job_name=cp2k_result.job_name, property_to_dump='orbitals') energies = f5[path_es].value coefficients = f5[path_css].value print("Energy array shape: ", energies.shape) print("Coefficients array shape: ", coefficients.shape) assert (energies.shape == (40, )) and (coefficients.shape == (46, 40))
def test_opt_orca(): """Test Orca input generation and run functions.""" h2o = Molecule(PATH_MOLECULES / "h2o.xyz", 'xyz', charge=0, multiplicity=1) h2o_geometry = dftb(templates.geometry, h2o) s = Settings() # generic keyword "basis" must be present in the generic dictionary s.basis = "sto_dzp" # s.specific.adf.basis.core = "large" r = templates.singlepoint.overlay(s) h2o_singlepoint = orca(r, h2o_geometry.molecule) dipole = h2o_singlepoint.dipole final_result = run(dipole, n_processes=1) expected_dipole = [0.82409, 0.1933, -0.08316] diff = sqrt(sum((x - y)**2 for x, y in zip(final_result, expected_dipole))) logger.info( f"Expected dipole computed with Orca 3.0.3 is: {expected_dipole}") logger.info(f"Actual dipole is: {final_result}") assertion.lt(diff, 1e-2)
def test_linear_ts(): """ compute a first approximation to the TS. """ # Read the Molecule from file cnc = Molecule('test/test_files/C-N-C.mol', 'mol') # User define Settings settings = Settings() settings.functional = "pbe" settings.basis = "SZ" settings.specific.dftb.dftb.scc constraint1 = Distance(1, 5) constraint2 = Distance(3, 4) # scan input pes = PES(cnc, constraints=[constraint1, constraint2], offset=[2.3, 2.3], get_current_values=False, nsteps=2, stepsize=[0.1, 0.1]) # returns a set of results object containing the output of # each point in the scan lt = pes.scan([dftb, adf], settings) # Gets the object presenting the molecule # with the maximum energy calculated from the scan apprTS = select_max(lt, "energy") # Run the TS optimization, using the default TS template ts = run(apprTS) expected_energy = -3.219708290363864 assert abs(ts.energy - expected_energy) < 0.02
def string_array_to_molecule(parser_fun: ParserElement, file_name: PathLike, mol: Optional_[Molecule] = None) -> Molecule: """Convert a Numpy string array. It takes an array like: [['C', '-1.487460', '-0.028670', '-0.000060'], ['O', '0.376340', '0.028670', '-0.000060'], ['H', '-1.818910', '-1.067060', '-0.000060'], ['H', '-1.866470', '0.473700', '0.889930'], ['H', '-1.866470', '0.473700', '-0.890040'], ['H', '0.756720', '-0.950010', '-0.000060']] and covert it to a plams ``Molecule``. """ mols = parse_file(parser_fun, file_name).asList() last_mol = np.array(mols[-1]) elems = last_mol[:, 0] coords = np.array(last_mol[:, 1:], dtype=float) if mol: if len(coords) == len(mol): mol.from_array(coords) else: raise RuntimeError('Output molecule does not match input molecule') else: mol = Molecule() for e, c in zip(elems, coords): mol.add_atom(Atom(symbol=e, coords=tuple(c))) return mol
def test_c2pk_cell_opt() -> None: """Test CP2K cell optimization calculations with the :class:`CP2K_MM` class.""" mol = Molecule(PATH / 'cspbbr3_3d.xyz') s = Settings() s.specific.cp2k += cell_opt.specific.cp2k_mm.copy() s.specific.cp2k.motion.cell_opt.max_iter = 10 s.specific.cp2k.motion.print['forces low'].filename = '' s.gmax = [22, 22, 22] s.cell_parameters = [25.452, 35.995, 24.452] s.charge = { 'param': 'charge', 'Cs': 0.2, 'Pb': 0.4, 'Br': -0.2, } s.lennard_jones = { 'param': ('sigma', 'epsilon'), 'unit': ('nm', 'kjmol'), 'Cs Cs': (0.585, 1), 'Cs Pb': (0.510, 1), 'Br Se': (0.385, 1), 'Pb Pb': (0.598, 1), 'Br Pb': (0.290, 1), 'Br Br': (0.426, 1), } job = cp2k_mm(settings=s, mol=mol, job_name='cp2k_mm_cell_opt') result = run(job, path=PATH) assertion.eq(result.status, 'successful')
def read_unique_atomic_labels(path_traj_xyz: str) -> set: """ Return the unique atomic labels """ mol = Molecule(path_traj_xyz, 'xyz') return set(at.symbol for at in mol.atoms)
def get_surface_charge_adf(mol: Molecule, job: Type[Job], s: Settings) -> Settings: """Perform a gas-phase ADF single point and return settings for a COSMO-ADF single point. The previous gas-phase calculation as moleculair fragment. Parameters ---------- mol : |plams.Molecule|_ A PLAMS Molecule. job : |Callable|_ A type Callable of a class derived from :class:`Job`, e.g. :class:`AMSJob` or :class:`Cp2kJob`. s : |plams.Settings|_ The settings for **job**. Returns ------- |plams.Settings|_ A new Settings intance, constructed from **s**, suitable for DFT COSMO-RS calculations. """ s.input.allpoints = '' results = mol.job_single_point(job, s, ret_results=True) coskf = get_coskf(results) for at in mol: at.properties.adf.fragment = 'gas' s.update(get_template('qd.yaml')['COSMO-ADF']) s.input.fragments.gas = coskf return s
def get_surface_charge(mol: Molecule, job: Type[Job], s: Settings) -> Optional[str]: """Construct the COSMO surface of the **mol**. Parameters ---------- mol : |plams.Molecule|_ A PLAMS Molecule. job : |Callable|_ A type Callable of a class derived from :class:`Job`, e.g. :class:`AMSJob` or :class:`Cp2kJob`. s : |plams.Settings|_ The settings for **job**. Returns ------- |plams.Settings|_ Optional: The path+filename of a file containing COSMO surface charges. """ s = Settings(s) # Special procedure for ADF jobs # Use the gas-phase electronic structure as a fragment for the COSMO single point if job is ADFJob: s = get_surface_charge_adf(mol, job, s) s.runscript.post = '$ADFBIN/cosmo2kf "mopac.cos" "mopac.coskf"' results = mol.job_single_point(job, s, ret_results=True) return get_coskf(results)
def get_plamsmol(self): """ Creates a PLAMS molecule object from the xyz-trajectory file """ section_dict = self.file_object.read_section('Molecule') plamsmol = Molecule._mol_from_rkf_section(section_dict) return plamsmol
def main(file_xyz, cell, restart, basis, basis_folder): """Define which systems need to be calculated.""" system = Molecule(file_xyz) # Set path for basis set basisCP2K = join(basis_folder, "BASIS_MOLOPT") potCP2K = join(basis_folder, "GTH_POTENTIALS") # Settings specifics s = templates.geometry s.basis = basis s.potential = "GTH-PBE" s.cell_parameters = cell s.specific.cp2k.force_eval.dft.basis_set_file_name = basisCP2K s.specific.cp2k.force_eval.dft.potential_file_name = potCP2K s.specific.cp2k.force_eval.dft.uks = '' s.specific.cp2k.force_eval.dft.charge = '-1' s.specific.cp2k.force_eval.dft.multiplicity = '2' s.specific.cp2k.force_eval.dft.wfn_restart_file_name = f'{restart}' # ======================= # Compute OPT files with CP2k # ======================= result = run(cp2k(s, system)) # ====================== # Output the results # ====================== print(result.energy)
def example_FDE_fragments(): # For the purpose of the example, define xyz files here: xyz1 = io.StringIO('''3 O 0.00000000000000 -2.29819386240000 1.63037963360000 H -0.76925379540000 -2.28223123190000 2.22684542850000 H 0.76925379540000 -2.28223123190000 2.22684542850000''') xyz2 = io.StringIO('''3 O 0.00000000000000 2.29819386240000 1.63037963360000 H -0.76925379540000 2.28223123190000 2.22684542850000 H 0.76925379540000 2.28223123190000 2.22684542850000''') xyz3 = io.StringIO('''3 O 0.00000000000000 0.00000000000000 -0.26192472620000 H 0.00000000000000 0.77162768440000 0.34261631290000 H 0.00000000000000 -0.77162768440000 0.34261631290000''') # Read the Molecule from file m_h2o_1 = Molecule() m_h2o_1.readxyz(xyz1, 1) m_h2o_2 = Molecule() m_h2o_2.readxyz(xyz2, 1) m_mol = Molecule() m_mol.readxyz(xyz3, 1) settings = Settings() settings.basis = 'SZ' settings.specific.adf.nosymfit = '' # Prepare first water fragment r_h2o_1 = adf(templates.singlepoint.overlay(settings), m_h2o_1, job_name="h2o_1") # Prepare second water fragment r_h2o_2 = adf(templates.singlepoint.overlay(settings), m_h2o_2, job_name="h2o_2") frags = gather(schedule(Fragment)(r_h2o_1, m_h2o_1, isfrozen=True), schedule(Fragment)(r_h2o_2, m_h2o_2, isfrozen=True), Fragment(None, m_mol)) job_fde = adf_fragmentsjob(templates.singlepoint. overlay(settings), frags, job_name="test_fde_fragments") # Perform FDE job and get dipole # This gets the dipole moment of the active subsystem only dipole_fde = run(job_fde.dipole) print('FDE dipole:', dipole_fde) return dipole_fde
def test_fail_gamess(): """ Gamess should return ``None`` if a calculation fails. """ folder = tempfile.mkdtemp(prefix="qmflows_") symmetry = "Cpi" # Erroneous Keyowrkd methanol = Molecule('test/test_files/ion_methanol.xyz') methanol.properties['symmetry'] = symmetry s = Settings() s.specific.gamess.contrl.nzvar = 12 s.specific.gamess.pcm.solvnt = 'water' s.specific.gamess.basis.gbasis = 'sto' s.specific.gamess.basis.ngauss = 3 inp = templates.geometry.overlay(s) methanol_geometry = gamess(inp, methanol, job_name="fail_gamess", work_dir='/tmp') try: result = run(methanol_geometry.molecule, path=folder) assert isNone(result) finally: remove(folder)
def create_molecule(name, r=2.25): mol = Molecule() mol.add_atom(Atom(symbol='Ba', coords=(0, 0, 0))) mol.add_atom(Atom(symbol='F', coords=(0, 0, r))) return mol