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 run_cdft_job(mol: Molecule, job: Type[ADFJob], s: Settings) -> pd.Series: """Run a conceptual DFT job and extract & return all global descriptors.""" results = mol.job_single_point(job, s.copy(), name='CDFT', ret_results=True, read_template=False) if results.job.status in {'crashed', 'failed'}: return _BACKUP ret = get_global_descriptors(results) ret.index = pd.MultiIndex.from_product([['cdft'], ret.index], names=['index', 'sub index']) return ret
def _asa_plams(mol_complete: Molecule, ligands: Iterable[Molecule], core: Molecule, read_template: bool, job: Type[Job], settings: Settings) -> Tuple[float, float, float, float, int]: """Perform an activation strain analyses with custom Job and Settings. Parameters ---------- mol_complete : |plams.Molecule| A Molecule representing the (unfragmented) relaxed structure of the system of interest. ligands : :class:`Iterable<collections.abc.Iterable>` [|plams.Molecule|] An iterable of Molecules containing all ligands in mol_complete. core : |plams.Molecule|, optional The core molecule from **mol_complete**. job : :class:`type` [|plams.Job|] The Job type for the ASA calculations. settings : |plams.Settings| The Job Settings for the ASA calculations. Returns ------- :class:`float`, :class:`float`, :class:`float`, :class:`float` and :class:`int` The energy of **mol_complete**, the energy of **ligands**, the energy of **core**, the energy of an optimized fragment within **ligands** and the total number of fragments within **ligands**. """ s = settings # Calculate the energy of the total system mol_complete.round_coords() mol_complete.properties.name += '_frags' mol_complete.job_single_point(job, s) E_complete = mol_complete.properties.energy.E # Calculate the (summed) energy of each individual fragment in the total system E_ligands = 0.0 E_min = np.inf mol_min = None for ligand_count, mol in enumerate(ligands, 1): mol.round_coords() mol.job_single_point(job, s) E = mol.properties.energy.E E_ligands += E if E < E_min: E_min, mol_min = E, mol # One of the calculations failed; better stop now if np.isnan(E_ligands): return np.nan, np.nan, np.nan, np.nan, ligand_count # Calculate the energy of the core core.job_single_point(job, s) E_core = mol.properties.energy.E # Calculate the energy of an optimizes fragment mol_min.job_geometry_opt(job, s) E_ligand_opt = mol_min.properties.energy.E return E_complete, E_ligands, E_core, E_ligand_opt, ligand_count
def get_bde_dE(tot: Molecule, lig: Molecule, core: Iterable[Molecule], job: Type[Job], s: Settings, forcefield: bool = False) -> np.ndarray: """Calculate the bond dissociation energy: dE = dE(mopac) + (dG(uff) - dE(uff)). Parameters ---------- tot : |plams.Molecule|_ The complete intact quantum dot. lig : |plams.Molecule|_ A ligand dissociated from the surface of the quantum dot core : |list|_ [|plams.Molecule|_] A list with one or more quantum dots (*i.e.* **tot**) with **lig** removed. job : |plams.Job|_ A :class:`.Job` subclass. s : |plams.Settings|_ The settings for **job**. """ # Optimize XYn len_core = len(core) if job is AMSJob: s_cp = Settings(s) s_cp.input.ams.GeometryOptimization.coordinatetype = 'Cartesian' lig.job_geometry_opt(job, s_cp, name='E_XYn_opt') elif forcefield: qd_opt_ff(lig, Settings({'job1': Cp2kJob, 's1': s}), name='E_XYn_opt') else: lig.job_geometry_opt(job, s, name='E_XYn_opt') E_lig = lig.properties.energy.E if E_lig in (None, np.nan): logger.error( 'The BDE XYn geometry optimization failed, skipping further jobs') return np.full(len_core, np.nan) # Perform a single point on the full quantum dot if forcefield: qd_opt_ff(tot, Settings({'job1': Cp2kJob, 's1': s}), name='E_QD_opt') else: tot.job_single_point(job, s, name='E_QD_sp') E_tot = tot.properties.energy.E if E_tot in (None, np.nan): logger.error( 'The BDE quantum dot single point failed, skipping further jobs') return np.full(len_core, np.nan) # Perform a single point on the quantum dot(s) - XYn for mol in core: if forcefield: qd_opt_ff(mol, Settings({ 'job1': Cp2kJob, 's1': s }), name='E_QD-XYn_opt') else: mol.job_single_point(job, s, name='E_QD-XYn_sp') E_core = np.fromiter([mol.properties.energy.E for mol in core], count=len_core, dtype=float) # Calculate and return dE dE = (E_lig + E_core) - E_tot return dE